From: Arran Cudbard-Bell Date: Sun, 10 Dec 2017 12:56:54 +0000 (+0000) Subject: Remove fr_sim_crypto_mac_verify and use fr_sim_crypto_sign_packet X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb1ea6b40cda8a2f61ec9ac25dc41540cf4f6e27;p=thirdparty%2Ffreeradius-server.git Remove fr_sim_crypto_mac_verify and use fr_sim_crypto_sign_packet for signing and validating --- diff --git a/src/modules/rlm_eap/lib/sim/crypto.c b/src/modules/rlm_eap/lib/sim/crypto.c index 6ef090d5aeb..bb6b68520c7 100644 --- a/src/modules/rlm_eap/lib/sim/crypto.c +++ b/src/modules/rlm_eap/lib/sim/crypto.c @@ -35,92 +35,53 @@ RCSID("$Id$") #include #include -/* - * calculate the MAC for the EAP message, given the key. - * The "extra" will be appended to the EAP message and included in the - * HMAC. +/** Locate the start of the AT_MAC value in the buffer * + * @param[in,out] data to search for the AT_MAC in. + * @param[in] data_len size of the data. + * @return + * - 1 if we couldn't find a MAC. + * - 0 if we found and zeroed out the mac field. + * - -1 if the field was malformed. */ -int fr_sim_crypto_mac_verify(TALLOC_CTX *ctx, fr_dict_attr_t const *root, - VALUE_PAIR *reply, - eap_packet_raw_t *packet, - uint8_t key[EAP_SIM_AUTH_SIZE], - uint8_t *extra, int extra_len, uint8_t calc_mac[20]) +static int fr_sim_find_mac(uint8_t const **out, uint8_t *data, size_t data_len) { - int ret; - uint8_t *buffer; - int elen, len; - VALUE_PAIR *mac; - fr_dict_attr_t const *da; - - da = fr_dict_attr_child_by_num(root, FR_EAP_SIM_MAC); - if (!da) { - fr_strerror_printf("Missing definition for EAP-SIM-MAC"); - return -1; - } - - mac = fr_pair_find_by_da(reply, da, TAG_ANY); - if (!mac || mac->vp_length != 16) { - /* can't check a packet with no AT_MAC attribute */ - return 0; - } - - /* make copy big enough for everything */ - elen = (packet->length[0] * 256) + packet->length[1]; - len = elen + extra_len; - - buffer = talloc_array(ctx, uint8_t, len); - if (!buffer) return 0; - - memcpy(buffer, packet, elen); - memcpy(buffer + elen, extra, extra_len); + uint8_t *p = data, *end = p + data_len; + size_t len; + + *out = NULL; + + p += 3; /* Skip header */ + while ((p + 2) < end) { + if (p[0] == FR_SIM_MAC) { + len = p[1] << 2; + if ((p + len) > end) { + fr_strerror_printf("Malformed AT_MAC: Length (%zu) exceeds buffer (%zu)", len, end - p); + return -1; + } - /* - * now look for the AT_MAC attribute in the copy of the buffer - * and make sure that the checksum is zero. - * - */ - { - uint8_t *attr; - - /* first attribute is 8 bytes into the EAP packet. - * 4 bytes for EAP, 1 for type, 1 for subtype, 2 reserved. - */ - attr = buffer + 8; - while (attr < (buffer + elen)) { - if (attr[0] == FR_EAP_SIM_MAC) { - /* zero the data portion, after making sure - * the size is >=5. Maybe future versions. - * will use more bytes, so be liberal. - */ - if (attr[1] < 5) { - ret = 0; - goto done; - } - memset(&attr[4], 0, (attr[1]-1)*4); + if (len != SIM_MAC_SIZE) { + fr_strerror_printf("Malformed AT_MAC: Length (%zu) incorrect (%u)", + len, SIM_MAC_SIZE); + return -1; } - /* advance the pointer */ - attr += attr[1]*4; + *out = p + 4; + + return 0; } + p += p[1] << 2; /* Advance */ } - /* now, HMAC-SHA1 it with the key. */ - fr_hmac_sha1(calc_mac, buffer, len, key, 16); + fr_strerror_printf("No MAC attribute found"); - ret = memcmp(&mac->vp_strvalue, calc_mac, 16) == 0 ? 1 : 0; //-V512 - done: - talloc_free(buffer); - return ret; + return 1; } - /** Append AT_MAC to the end a packet. * * Run SHA1 digest over a fake EAP header, the entire SIM packet and any extra HMAC data, * writing out the complete AT_HMAC and digest to out. * - * @note out must point to (buff) end - 20. It's easier to write AT_MAC last. - * * @param[out] out Where to write the digest. * @param[in] eap_packet to extract header values from. * @param[in] key to use to sign the packet. @@ -129,19 +90,22 @@ int fr_sim_crypto_mac_verify(TALLOC_CTX *ctx, fr_dict_attr_t const *root, * (may be NULL). * @param[in] hmac_extra_len Length of hmac_extra. * @return - * - <= 0 on failure. + * - < 0 on failure. + * - 0 if there's no MAC attribute to verify. * - > 0 the number of bytes written to out. */ -ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, +ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, bool zero_mac, uint8_t const *key, size_t const key_len, uint8_t const *hmac_extra, size_t const hmac_extra_len) { EVP_MD_CTX *md_ctx = NULL; - EVP_MD const *md = EVP_get_digestbyname("SHA1"); + EVP_MD const *md = EVP_sha1(); EVP_PKEY *pkey; uint8_t digest[SHA1_DIGEST_LENGTH]; size_t digest_len = 0; + uint8_t const *mac; + uint8_t *p = eap_packet->type.data, *end = p + eap_packet->type.length; eap_packet_raw_t eap_hdr; uint16_t packet_len; @@ -184,11 +148,51 @@ ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, } /* - * Digest most of the packet, except the bit at - * the end we're leaving for the HMAC. + * Digest the packet up to the AT_MAC, value, then + * ingest 16 bytes of zero. + */ + if (zero_mac) { + switch (fr_sim_find_mac(&mac, p, end - p)) { + case 0: + { + uint8_t zero[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + /* + * Digest everything up to the hash + * part of the AT_MAC, including + * AT_MAC header and reserved bytes. + */ + if (EVP_DigestSignUpdate(md_ctx, p, mac - p) != 1) { + tls_strerror_printf(true, "Failed digesting header"); + goto error; + } + p += mac - p; + + /* + * Feed in 16 bytes of zeroes to + * simulated the zeroed out Mac. + */ + if (EVP_DigestSignUpdate(md_ctx, zero, sizeof(zero)) != 1) { + tls_strerror_printf(true, "Failed zeroes mac"); + goto error; + } + p += sizeof(zero); + } + break; + + case 1: + return 0; + + case -1: + rad_assert(0); /* Should have been checked by encoder or decoder */ + goto error; + } + } + + /* + * Digest the rest of the packet. */ - FR_PROTO_HEX_DUMP("hmac input sim_body", eap_packet->type.data, eap_packet->type.length); - if (EVP_DigestSignUpdate(md_ctx, eap_packet->type.data, eap_packet->type.length) != 1) { + if (EVP_DigestSignUpdate(md_ctx, p, end - p) != 1) { tls_strerror_printf(true, "Failed digesting body"); goto error; } @@ -584,11 +588,11 @@ int fr_sim_crypto_kdf_1_umts(fr_sim_keys_t *keys) */ void fr_sim_crypto_keys_log(REQUEST *request, fr_sim_keys_t *keys) { - RDEBUG3("Key data from AuC/static vectors"); + RDEBUG3("Cryptographic inputs"); RINDENT(); RHEXDUMP_INLINE(L_DBG_LVL_3, keys->identity, keys->identity_len, - "identity :"); + "Identity :"); switch (keys->vector_type) { case SIM_VECTOR_GSM: { diff --git a/src/modules/rlm_eap/lib/sim/encode.c b/src/modules/rlm_eap/lib/sim/encode.c index 4f25a45cf16..739418c10c8 100644 --- a/src/modules/rlm_eap/lib/sim/encode.c +++ b/src/modules/rlm_eap/lib/sim/encode.c @@ -972,7 +972,7 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty unsigned int id, eap_code; - uint8_t *buff, *p, *end; + uint8_t *buff, *p, *end, *hmac = NULL; size_t len = 0; ssize_t slen; @@ -998,22 +998,15 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty } subtype = vp->vp_uint16; - vp = fr_pair_find_by_child_num(to_encode, parent, FR_EAP_ID, TAG_ANY); - id = vp ? vp->vp_uint32 : ((int)getpid() & 0xff); - vp = fr_pair_find_by_child_num(to_encode, parent, FR_EAP_CODE, TAG_ANY); eap_code = vp ? vp->vp_uint32 : FR_EAP_CODE_REQUEST; - vp = fr_pair_find_by_child_num(to_encode, parent, FR_EAP_SIM_MAC, TAG_ANY); - if (vp) do_hmac = true; - /* * Fill in some bits in the EAP packet * * These are needed even if we're sending an almost empty packet. */ if (eap_packet->code != FR_EAP_CODE_SUCCESS) eap_packet->code = eap_code; - eap_packet->id = (id & 0xff); eap_packet->type.num = type; /* @@ -1041,12 +1034,32 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty MEM(p = buff = talloc_zero_array(eap_packet, uint8_t, 1024)); /* We'll shrink this later */ end = p + talloc_array_length(p); - if (do_hmac) end -= SIM_CALC_MAC_SIZE; *p++ = subtype; /* Subtype */ *p++ = 0; /* Reserved (0) */ *p++ = 0; /* Reserved (1) */ + /* + * Add space in the packet for AT_MAC + */ + vp = fr_pair_find_by_child_num(to_encode, parent, FR_EAP_SIM_MAC, TAG_ANY); + if (vp) { + if ((end - p) < SIM_MAC_SIZE) { + fr_strerror_printf("Insufficient space to store AT_MAC"); + return -1; + } + + do_hmac = true; + + *p++ = FR_SIM_MAC; + *p++ = (SIM_MAC_SIZE >> 2); + *p++ = 0x00; + *p++ = 0x00; + hmac = p; + memset(p, 0, 16); + p += 16; + } + /* * Encode all the things... */ @@ -1069,26 +1082,12 @@ ssize_t fr_sim_encode(REQUEST *request, fr_dict_attr_t const *parent, uint8_t ty * Calculate a SHA1-HMAC over the complete EAP packet */ if (do_hmac) { -#ifndef NDEBUG - uint8_t *start = p; -#endif - - /* - * We left some room earlier... - */ - *p++ = FR_SIM_MAC; - *p++ = (SIM_CALC_MAC_SIZE >> 2); - *p++ = 0x00; - *p++ = 0x00; - - slen = fr_sim_crypto_sign_packet(p, eap_packet, - keys->k_aut, keys->k_aut_len, + slen = fr_sim_crypto_sign_packet(hmac, eap_packet, false, + keys->k_aut, keys->k_aut_len, keys->vector_type == SIM_VECTOR_GSM ? keys->gsm.nonce_mt : NULL, keys->vector_type == SIM_VECTOR_GSM ? sizeof(keys->gsm.nonce_mt) : 0); if (slen < 0) goto error; - - eap_packet->type.length += SIM_CALC_MAC_SIZE; - FR_PROTO_HEX_DUMP("hmac attribute", start, (p - start) + slen); + FR_PROTO_HEX_DUMP("hmac attribute", hmac - 4, SIM_MAC_SIZE); } FR_PROTO_HEX_DUMP("sim packet", buff, eap_packet->type.length); diff --git a/src/modules/rlm_eap/lib/sim/sim_proto.h b/src/modules/rlm_eap/lib/sim/sim_proto.h index 13c1ea7fc19..8b3099e6ccd 100644 --- a/src/modules/rlm_eap/lib/sim/sim_proto.h +++ b/src/modules/rlm_eap/lib/sim/sim_proto.h @@ -222,19 +222,10 @@ int fr_sim_global_init(void); /* * crypto.c */ -ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, +ssize_t fr_sim_crypto_sign_packet(uint8_t out[16], eap_packet_t *eap_packet, bool zero_mac, uint8_t const *key, size_t const key_len, uint8_t const *hmac_extra, size_t const hmac_extra_len); -int fr_sim_crypto_mac_verify(TALLOC_CTX *ctx, fr_dict_attr_t const *root, - VALUE_PAIR *rvps, - eap_packet_raw_t *packet, - uint8_t key[8], - uint8_t *extra, int extra_len, - uint8_t calc_mac[20]) - CC_BOUNDED(__size__, 3, 8, 8) - CC_BOUNDED(__size__, 6, 20, 20); - int fr_sim_crypto_kdf_0_gsm(fr_sim_keys_t *keys); int fr_sim_crypto_kdf_0_umts(fr_sim_keys_t *keys); diff --git a/src/modules/rlm_eap/types/rlm_eap_aka/rlm_eap_aka.c b/src/modules/rlm_eap/types/rlm_eap_aka/rlm_eap_aka.c index b016719f239..94019825c3b 100644 --- a/src/modules/rlm_eap/types/rlm_eap_aka/rlm_eap_aka.c +++ b/src/modules/rlm_eap/types/rlm_eap_aka/rlm_eap_aka.c @@ -415,7 +415,7 @@ static int process_eap_aka_challenge(eap_session_t *eap_session, VALUE_PAIR *vps ssize_t slen; VALUE_PAIR *vp = NULL, *mac; - mac = fr_pair_find_by_child_num(vps, dict_aka_root, FR_EAP_AKA_RES, TAG_ANY); + mac = fr_pair_find_by_child_num(vps, dict_aka_root, FR_EAP_AKA_MAC, TAG_ANY); if (!mac) { REDEBUG("Missing AT_MAC attribute"); return -1; diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c b/src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c index b53c28ffddd..4ac0b661978 100644 --- a/src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c +++ b/src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c @@ -366,13 +366,15 @@ static int process_eap_sim_start(eap_session_t *eap_session, VALUE_PAIR *vps) */ static int process_eap_sim_challenge(eap_session_t *eap_session, VALUE_PAIR *vps) { - REQUEST *request = eap_session->request; - eap_sim_session_t *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t); + REQUEST *request = eap_session->request; + eap_sim_session_t *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t); - uint8_t sres_cat[SIM_VECTOR_GSM_SRES_SIZE * 3]; - uint8_t *p = sres_cat; + uint8_t sres_cat[SIM_VECTOR_GSM_SRES_SIZE * 3]; + uint8_t *p = sres_cat; - uint8_t calc_mac[SIM_CALC_MAC_SIZE]; + uint8_t calc_mac[SIM_MAC_SIZE]; + ssize_t slen; + VALUE_PAIR *mac; memcpy(p, eap_sim_session->keys.gsm.vector[0].sres, SIM_VECTOR_GSM_SRES_SIZE); p += SIM_VECTOR_GSM_SRES_SIZE; @@ -380,30 +382,36 @@ static int process_eap_sim_challenge(eap_session_t *eap_session, VALUE_PAIR *vps p += SIM_VECTOR_GSM_SRES_SIZE; memcpy(p, eap_sim_session->keys.gsm.vector[2].sres, SIM_VECTOR_GSM_SRES_SIZE); - /* - * Verify the MAC, now that we have all the keys - */ - if (fr_sim_crypto_mac_verify(eap_session, dict_sim_root, vps, - (eap_packet_raw_t *)eap_session->this_round->response->packet, - eap_sim_session->keys.k_aut, - sres_cat, sizeof(sres_cat), calc_mac)) { + mac = fr_pair_find_by_child_num(vps, dict_aka_root, FR_EAP_AKA_RES, TAG_ANY); + if (!mac) { + REDEBUG("Missing AT_MAC attribute"); + return -1; + } + if (mac->vp_length != SIM_MAC_SIZE) { + REDEBUG("AT_MAC incorrect length, expected %u bytes got %zu bytes", + SIM_MAC_SIZE, mac->vp_length); + return -1; + } + + slen = fr_sim_crypto_sign_packet(calc_mac, eap_session->this_round->response, true, + eap_sim_session->keys.k_aut, sizeof(eap_sim_session->keys.k_aut), + NULL, 0); + if (slen < 0) { + RPEDEBUG("Failed calculating MAC"); + return -1; + } + + if (slen == 0) { + REDEBUG("Missing AT_MAC attribute in packet buffer"); + return -1; + } + + if (memcmp(mac->vp_octets, calc_mac, sizeof(calc_mac)) == 0) { RDEBUG2("MAC check succeed"); } else { - int i, j; - char macline[20*3]; - char *m = macline; - - for (i = 0, j = 0; i < SIM_CALC_MAC_SIZE; i++) { - if (j == 4) { - *m++ = '_'; - j=0; - } - j++; - - sprintf(m, "%02x", calc_mac[i]); - m = m + strlen(m); - } - REDEBUG("Calculated MAC (%s) did not match", macline); + REDEBUG("MAC checked failed"); + RHEXDUMP_INLINE(L_DBG_LVL_2, mac->vp_octets, SIM_MAC_SIZE, "Received"); + RHEXDUMP_INLINE(L_DBG_LVL_2, calc_mac, SIM_MAC_SIZE, "Expected"); return -1; } @@ -441,6 +449,7 @@ static rlm_rcode_t mod_process(UNUSED void *arg, eap_session_t *eap_session) vps = eap_session->request->packet->vps; fr_pair_cursor_init(&cursor, &request->packet->vps); + fr_pair_cursor_last(&cursor); ret = fr_sim_decode(eap_session->request, &cursor, @@ -449,9 +458,9 @@ static rlm_rcode_t mod_process(UNUSED void *arg, eap_session_t *eap_session) &ctx); if (ret < 0) return 0; - vp = fr_pair_cursor_next(&cursor); + vp = fr_pair_cursor_current(&cursor); if (vp && RDEBUG_ENABLED2) { - RDEBUG2("Eecoded EAP-SIM attributes"); + RDEBUG2("Decoded EAP-SIM attributes"); rdebug_pair_list(L_DBG_LVL_2, request, vp, NULL); }