/* * * Wireless daemon for Linux * * Copyright (C) 2017-2019 Intel Corporation. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /* * EAP-SIM/EAP-AKA shared values */ #define EAP_SIM_MK_LEN 20 #define EAP_SIM_K_ENCR_LEN 16 #define EAP_SIM_K_AUT_LEN 16 #define EAP_AKA_PRIME_K_AUT_LEN 32 #define EAP_SIM_MSK_LEN 64 #define EAP_SIM_EMSK_LEN 64 #define EAP_SIM_IV_LEN 16 #define EAP_SIM_MAC_LEN 16 #define EAP_SIM_RAND_LEN 16 #define EAP_AKA_K_RE_LEN 32 #define EAP_AKA_IK_LEN 16 #define EAP_AKA_CK_LEN 16 /* * Possible pad types for EAP-SIM/EAP-AKA attributes * * NONE - No padding, data passed in immediately follows type/size * ZERO - Zero pad where "real" length would be * LENGTH - A "real" data length in bytes immediately follows type/size * LENGTH_BITS - A "real" data length in bits follows type/size */ #define EAP_SIM_PAD_NONE 0 #define EAP_SIM_PAD_ZERO 1 #define EAP_SIM_PAD_LENGTH 2 #define EAP_SIM_PAD_LENGTH_BITS 3 /* * Round up value to nearest word */ #define EAP_SIM_ROUND(x) ((x + 3) & ~0x3) struct eap_sim_tlv_iter { const uint8_t *pos; const uint8_t *end; uint8_t tag; uint16_t len; const uint8_t *data; }; /* * RFC 4187, section 11 */ enum eap_sim_at { EAP_SIM_AT_RAND = 0x01, EAP_SIM_AT_AUTN = 0x02, EAP_SIM_AT_RES = 0x03, EAP_SIM_AT_AUTS = 0x04, EAP_SIM_AT_PADDING = 0x06, EAP_SIM_AT_NONCE = 0x07, EAP_SIM_AT_PERMANENT_ID_REQ = 0x0a, EAP_SIM_AT_MAC = 0x0b, EAP_SIM_AT_NOTIFICATION = 0x0c, EAP_SIM_AT_ANY_ID_REQ = 0x0d, EAP_SIM_AT_IDENTITY = 0x0e, EAP_SIM_AT_VERSION_LIST = 0x0f, EAP_SIM_AT_SELECTED_VERSION = 0x10, EAP_SIM_AT_FULLAUTH_ID_REQ = 0x11, EAP_SIM_AT_COUNTER = 0x13, EAP_SIM_AT_NONCE_S = 0x15, EAP_SIM_AT_CLIENT_ERROR_CODE = 0x16, EAP_SIM_AT_KDF_INPUT = 0x17, EAP_SIM_AT_KDF = 0x18, EAP_SIM_AT_IV = 0x81, EAP_SIM_AT_ENCR_DATA = 0x82, EAP_SIM_AT_NEXT_PSEUDONYM = 0x84, EAP_SIM_AT_NEXT_REAUTH_ID = 0x85, EAP_SIM_AT_CHECKCODE = 0x86, EAP_SIM_AT_RESULT_IND = 0x87, EAP_SIM_AT_BIDDING = 0x88 }; /* * Possible client error's */ enum eap_sim_error { EAP_SIM_ERROR_PROCESS = 0, EAP_SIM_ERROR_VERSION_VERSION, EAP_SIM_ERROR_CHALLENGE, EAP_SIM_ERROR_RANDS }; /* * Notification error codes (and success). */ enum eap_sim_fail { EAP_SIM_FAIL_AFTER_AUTH = 0, EAP_SIM_FAIL_DENIED_ACCESS = 1026, EAP_SIM_FAIL_NOT_SUBSCRIBED = 1031, EAP_SIM_FAIL_BEFORE_AUTH = 16384, EAP_SIM_SUCCESS = 32768 }; /* * RFC 4186 Appendix B. FIPS 186 Pseudo-random number generator * * seed - PRF seed, e.g. the Master Key (MK) * slen - seed length * out - PRF output buffer * olen - length of out */ void eap_sim_fips_prf(const void *seed, size_t slen, uint8_t *out, size_t olen); /* * 3GPP TS 35.206 * * Algorithm for generating milenage parameters. * * opc - Input: OPc value * k - Input: K key value * rand - Input: Rand from server * sqn - Input: Sequence number * amf - Input: AMF value * * autn - Output: AUTN computed * ck - Output: CK computed * ik - Output: IK computed * res - Output: RES computed * * Internal Functions used: * f1 and f1* output MAC-A and MAC-S. MAC-A along with SQN/AK/AMF make AUTN * f2 outputs RES where RES == OUT2[8-16] * f3 outputs CK where CK == OUT3[0-16] * f4 outputs IK where IK == OUT4[0-16] * f5 outputs AK where AK == OUT2[0-6] * * f5* outputs AK', not used with EAP-AKA */ bool eap_aka_get_milenage(const uint8_t *opc, const uint8_t *k, const uint8_t *rand, const uint8_t *sqn, const uint8_t *amf, uint8_t *autn, uint8_t *ck, uint8_t *ik, uint8_t *res); /* * 3GPP TS 33.402 * Derivation of CK' and IK' from CK and IK * * FC = 0x20 * P0 = access network identity ('network') * L0 = length of P0 * P1 = SQN ^ AK = first 6 bytes of AUTN * L1 = length of P1 = 0x0006 * * (CK' | IK') = HMAC_SHA256(FC |P0 | L0 | P1 | L1) */ bool eap_aka_derive_primes(const uint8_t *ck, const uint8_t *ik, const uint8_t *autn, const uint8_t *network, uint16_t net_len, uint8_t *ck_p, uint8_t *ik_p); /* * RFC 5448, Section 3.4.1 * * PRF'(K,S) = T1 | T2 | T3 | T4 | ... * * where: * T1 = HMAC-SHA-256 (K, S | 0x01) * T2 = HMAC-SHA-256 (K, T1 | S | 0x02) * T3 = HMAC-SHA-256 (K, T2 | S | 0x03) * T4 = HMAC-SHA-256 (K, T3 | S | 0x04) * ... * * RFC 5448, Section 3.3 * * MK = PRF'(IK'|CK',"EAP-AKA'"|Identity) * K_encr = MK[0..127] * K_aut = MK[128..383] * K_re = MK[384..639] * MSK = MK[640..1151] * EMSK = MK[1152..1663] */ bool eap_aka_prf_prime(const uint8_t *ik_p, const uint8_t *ck_p, const char *identity, uint8_t *k_encr, uint8_t *k_aut, uint8_t *k_re, uint8_t *msk, uint8_t *emsk); /* * Separate PRNG data into encryption keys. k_encr and k_aut may be NULL in the * case of fast re-authentication. * * buf - output data from the PRNG, 160 bytes * k_encr - first 16 bytes of buf * k_aut - next 16 bytes of buf * msk - next 64 bytes of buf * emsk - next 64 bytes of buf */ bool eap_sim_get_encryption_keys(const uint8_t *buf, uint8_t *k_encr, uint8_t *k_aut, uint8_t *msk, uint8_t *emsk); /* * Derive a packets MAC. This can be used to compute the packets MAC in place, * by setting mac to the proper zero'ed location in buf. * * buf - the SIM packet, including MAC portion zero'ed, plus extra (e.g. SRES) * len - the total length of buf * key - encryption key to use (e.g. K_encr) * mac - buffer for the 16 byte MAC */ bool eap_sim_derive_mac(enum eap_type type, const uint8_t *buf, size_t len, const uint8_t *key, uint8_t *mac); /* * Helper to build the EAP packet header * * eap - eap_state, used to get the identifier * method - EAP method (SIM or AKA) * type - EAP-SIM subtype * buf - EAP packet * len - length of packet */ size_t eap_sim_build_header(struct eap_state *eap, enum eap_type method, uint8_t type, uint8_t *buf, uint16_t len); /* * Signal that the client has detected an error * * eap - eap_state * type - type of EAP method (SIM or AKA) * code - error code to send */ void eap_sim_client_error(struct eap_state *eap, enum eap_type type, uint16_t code); /* * Add an EAP-SIM attribute to a buffer. * * buf - pointer to start of EAP-SIM attribute * attr - type of attribute * ptype - Padding type AT_PAD_ZERO, AT_PAD_NONE or AT_PAD_LENGTH * data - EAP-SIM attribute data, if NULL zeros will be written * dlen - length of data pointer in bytes * * Returns the number of bytes written to buf. */ size_t eap_sim_add_attribute(uint8_t *buf, enum eap_sim_at attr, uint8_t ptype, const uint8_t *data, uint16_t dlen); /* * Verify a packets MAC * * eap - eap_state pointer, used to rebuild the EAP header * buf - should point to the start of the EAP-SIM packet * len - length of EAP packet * extra - Any extra block of data needed to compute the MAC * elen - Length of 'extra' */ bool eap_sim_verify_mac(struct eap_state *eap, enum eap_type type, const uint8_t *buf, uint16_t len, uint8_t *k_aut, uint8_t *extra, size_t elen); bool eap_sim_tlv_iter_init(struct eap_sim_tlv_iter *iter, const uint8_t *data, uint32_t len); bool eap_sim_tlv_iter_next(struct eap_sim_tlv_iter *iter); uint8_t eap_sim_tlv_iter_get_type(struct eap_sim_tlv_iter *iter); uint16_t eap_sim_tlv_iter_get_length(struct eap_sim_tlv_iter *iter); const void *eap_sim_tlv_iter_get_data(struct eap_sim_tlv_iter *iter);