diff options
Diffstat (limited to 'lib/decoding/osmocom/gsm/auth_core.c')
-rw-r--r-- | lib/decoding/osmocom/gsm/auth_core.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/lib/decoding/osmocom/gsm/auth_core.c b/lib/decoding/osmocom/gsm/auth_core.c new file mode 100644 index 0000000..230500e --- /dev/null +++ b/lib/decoding/osmocom/gsm/auth_core.c @@ -0,0 +1,252 @@ +/* (C) 2010-2012 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +//#include "config.h" + +#include <errno.h> +#include <stdint.h> +#include <string.h> + +#include <osmocom/core/utils.h> +#include <osmocom/core/linuxlist.h> +//#include <osmocom/core/plugin.h> + +#include <osmocom/crypt/auth.h> + +/*! \addtogroup auth + * @{ + * GSM/GPRS/3G authentication core infrastructure + * + * \file auth_core.c */ + +static LLIST_HEAD(osmo_auths); + +static struct osmo_auth_impl *selected_auths[_OSMO_AUTH_ALG_NUM]; + +/*! Register an authentication algorithm implementation with the core + * \param[in] impl Structure describing implementation and it's callbacks + * \returns 0 on success, or a negative error code on failure + * + * This function is called by an authentication implementation plugin to + * register itself with the authentication core. + */ +int osmo_auth_register(struct osmo_auth_impl *impl) +{ + if (impl->algo >= ARRAY_SIZE(selected_auths)) + return -ERANGE; + + llist_add_tail(&impl->list, &osmo_auths); + + /* check if we want to select this implementation over others */ + if (!selected_auths[impl->algo] || + (selected_auths[impl->algo]->priority > impl->priority)) + selected_auths[impl->algo] = impl; + + return 0; +} + +/*! Load all available authentication plugins from the given path + * \param[in] path Path name of the directory containing the plugins + * \returns number of plugins loaded in case of success, negative in case of error + * + * This function will load all plugins contained in the specified path. + */ +int osmo_auth_load(const char *path) +{ + /* load all plugins available from path */ +/*#if !defined(EMBEDDED) + return osmo_plugin_load_all(path); +#else*/ + return -1; +/*#endif*/ +} + +/*! Determine if a given authentication algorithm is supported + * \param[in] algo Algorithm which should be checked + * \returns 1 if algo is supported, 0 if not, negative error on failure + * + * This function is used by an application to determine at runtime if a + * given authentication algorithm is supported or not. + */ +int osmo_auth_supported(enum osmo_auth_algo algo) +{ + if (algo >= ARRAY_SIZE(selected_auths)) + return -ERANGE; + + if (selected_auths[algo]) + return 1; + + return 0; +} + +/* C5 function to derive UMTS IK from GSM Kc */ +static inline void c5_function(uint8_t *ik, const uint8_t *kc) +{ + unsigned int i; + + for (i = 0; i < 4; i++) + ik[i] = kc[i] ^ kc[i+4]; + memcpy(ik+4, kc, 8); + for (i = 12; i < 16; i++) + ik[i] = ik[i-12]; +} + +/* C4 function to derive UMTS CK from GSM Kc */ +void osmo_c4(uint8_t *ck, const uint8_t *kc) +{ + memcpy(ck, kc, 8); + memcpy(ck+8, kc, 8); +} + +/*! Generate 3G CK + IK from 2G authentication vector + * \param vec Authentication Vector to be modified + * \returns 1 if the vector was changed, 0 otherwise + * + * This function performs the C5 and C4 functions to derive the UMTS key + * material from the GSM key material in the supplied vector, _if_ the input + * vector doesn't yet have UMTS authentication capability. + */ +int osmo_auth_3g_from_2g(struct osmo_auth_vector *vec) +{ + if ((vec->auth_types & OSMO_AUTH_TYPE_GSM) && + !(vec->auth_types & OSMO_AUTH_TYPE_UMTS)) { + c5_function(vec->ik, vec->kc); + osmo_c4(vec->ck, vec->kc); + /* We cannot actually set OSMO_AUTH_TYPE_UMTS as we have no + * AUTN and no RES, and thus can only perform GSM + * authentication with this tuple. + */ + return 1; + } + + return 0; +} + +/*! Generate authentication vector + * \param[out] vec Generated authentication vector + * \param[in] aud Subscriber-specific key material + * \param[in] _rand Random challenge to be used + * \returns 0 on success, negative error on failure + * + * This function performs the core cryptographic function of the AUC, + * computing authentication triples/quintuples based on the permanent + * subscriber data and a random value. The result is what is forwarded + * by the AUC via HLR and VLR to the MSC which will then be able to + * invoke authentication with the MS + */ +int osmo_auth_gen_vec(struct osmo_auth_vector *vec, + struct osmo_sub_auth_data *aud, + const uint8_t *_rand) +{ + struct osmo_auth_impl *impl = selected_auths[aud->algo]; + int rc; + + if (!impl) + return -ENOENT; + + rc = impl->gen_vec(vec, aud, _rand); + if (rc < 0) + return rc; + + memcpy(vec->rand, _rand, sizeof(vec->rand)); + + return 0; +} + +/*! Generate authentication vector and re-sync sequence + * \param[out] vec Generated authentication vector + * \param[in] aud Subscriber-specific key material + * \param[in] auts AUTS value sent by the SIM/MS + * \param[in] rand_auts RAND value sent by the SIM/MS + * \param[in] _rand Random challenge to be used to generate vector + * \returns 0 on success, negative error on failure + * + * This function performs a special variant of the core cryptographic + * function of the AUC: computing authentication triples/quintuples + * based on the permanent subscriber data, a random value as well as the + * AUTS and RAND values returned by the SIM/MS. This special variant is + * needed if the sequence numbers between MS and AUC have for some + * reason become different. + */ +int osmo_auth_gen_vec_auts(struct osmo_auth_vector *vec, + struct osmo_sub_auth_data *aud, + const uint8_t *auts, const uint8_t *rand_auts, + const uint8_t *_rand) +{ + struct osmo_auth_impl *impl = selected_auths[aud->algo]; + int rc; + + if (!impl || !impl->gen_vec_auts) + return -ENOENT; + + rc = impl->gen_vec_auts(vec, aud, auts, rand_auts, _rand); + if (rc < 0) + return rc; + + memcpy(vec->rand, _rand, sizeof(vec->rand)); + + return 0; +} + +static const struct value_string auth_alg_vals[] = { + { OSMO_AUTH_ALG_NONE, "None" }, + { OSMO_AUTH_ALG_COMP128v1, "COMP128v1" }, + { OSMO_AUTH_ALG_COMP128v2, "COMP128v2" }, + { OSMO_AUTH_ALG_COMP128v3, "COMP128v3" }, + { OSMO_AUTH_ALG_XOR, "XOR" }, + { OSMO_AUTH_ALG_MILENAGE, "MILENAGE" }, + { 0, NULL } +}; + +/*! Get human-readable name of authentication algorithm * +const char *osmo_auth_alg_name(enum osmo_auth_algo alg) +{ + return get_value_string(auth_alg_vals, alg); +} + +/*! Parse human-readable name of authentication algorithm */ +/*enum osmo_auth_algo osmo_auth_alg_parse(const char *name) +{ + return get_string_value(auth_alg_vals, name); +} +*/ +const struct value_string osmo_sub_auth_type_names[] = { + { OSMO_AUTH_TYPE_NONE, "None" }, + { OSMO_AUTH_TYPE_GSM, "GSM" }, + { OSMO_AUTH_TYPE_UMTS, "UMTS" }, + { 0, NULL } +}; + +/* Derive GSM AKA ciphering key Kc from UMTS AKA CK and IK (auth function c3 from 3GPP TS 33.103 ยง + * 4.6.1). + * \param[out] kc GSM AKA Kc, 8 byte target buffer. + * \param[in] ck UMTS AKA CK, 16 byte input buffer. + * \param[in] ik UMTS AKA IK, 16 byte input buffer. + */ +void osmo_auth_c3(uint8_t kc[], const uint8_t ck[], const uint8_t ik[]) +{ + int i; + for (i = 0; i < 8; i++) + kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8]; +} + +/*! @} */ |