blob: 68228eeeeef604ef0527e3fb155389c8a1e0fd8b [file] [log] [blame]
/*
*
* 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);