From 397bf9c0bd92bc573af46e8c606f7d20e13f4196 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Fri, 31 Aug 2018 15:37:54 -0700 Subject: [PATCH] crypto: pwd: sae: Made H function common The "H" function used by SAE and EAP-PWD was effectively the same function, EAP-PWD just used a zero key for its calls. This removes the duplicate implementations and merges them into crypto.c as "hkdf_256". Since EAP-PWD always uses a zero'ed key, passing in a NULL key to hkdf_256 will actually use a 32 byte zero'ed array as the key. This avoids the need for EAP-PWD to store or create a zero'ed key for every call. Both the original "H" functions never called va_end, so that was added to hkdf_256. --- src/crypto.c | 42 +++++++++++++++++++++++++++++++++++++++- src/crypto.h | 4 +++- src/eap-pwd.c | 53 +++++++++++++-------------------------------------- src/sae.c | 31 +----------------------------- 4 files changed, 58 insertions(+), 72 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 7428087c..e922805a 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -2,7 +2,7 @@ * * Wireless daemon for Linux * - * Copyright (C) 2013-2014 Intel Corporation. All rights reserved. + * Copyright (C) 2013-2018 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 @@ -406,6 +406,46 @@ bool kdf_sha256(const void *key, size_t key_len, return true; } +/* + * Defined in RFC 5869 - HMAC-based Extract-and-Expand Key Derivation Function + * + * Null key equates to a zero key (makes calls in EAP-PWD more convenient) + */ +bool hkdf_256(const uint8_t *key, size_t key_len, uint8_t num_args, + uint8_t *out, ...) +{ + struct l_checksum *hmac; + struct iovec iov[num_args]; + const uint8_t zero_key[32] = { 0 }; + const uint8_t *k = key ? key : zero_key; + size_t k_len = key ? key_len : 32; + va_list va; + int i; + int ret; + + hmac = l_checksum_new_hmac(L_CHECKSUM_SHA256, k, k_len); + if (!hmac) + return false; + + va_start(va, out); + + for (i = 0; i < num_args; i++) { + iov[i].iov_base = va_arg(va, void *); + iov[i].iov_len = va_arg(va, size_t); + } + + if (!l_checksum_updatev(hmac, iov, num_args)) { + va_end(va); + return false; + } + + ret = l_checksum_get_digest(hmac, out, 32); + l_checksum_free(hmac); + + va_end(va); + return (ret == 32); +} + /* * 802.11, Section 11.6.6.7: * PTK = PRF-X(PMK, "Pairwise key expansion", Min(AA, SA) || Max(AA, SA) || diff --git a/src/crypto.h b/src/crypto.h index 7b97e25b..7ff08d19 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -2,7 +2,7 @@ * * Wireless daemon for Linux * - * Copyright (C) 2013-2014 Intel Corporation. All rights reserved. + * Copyright (C) 2013-2018 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 @@ -92,6 +92,8 @@ bool kdf_sha256(const void *key, size_t key_len, bool prf_sha1(const void *key, size_t key_len, const void *prefix, size_t prefix_len, const void *data, size_t data_len, void *output, size_t size); +bool hkdf_256(const uint8_t *key, size_t key_len, uint8_t num_args, + uint8_t *out, ...); bool crypto_derive_pairwise_ptk(const uint8_t *pmk, const uint8_t *addr1, const uint8_t *addr2, diff --git a/src/eap-pwd.c b/src/eap-pwd.c index cdb7875b..bdc6b21e 100644 --- a/src/eap-pwd.c +++ b/src/eap-pwd.c @@ -28,6 +28,7 @@ #include "eap.h" #include "eap-private.h" +#include "crypto.h" #include "util.h" #include "ecc.h" @@ -82,35 +83,6 @@ struct eap_pwd_handle { static uint64_t curve_p[NUM_ECC_DIGITS] = CURVE_P_32; -static bool H(uint8_t num_args, uint8_t *out, ...) -{ - struct l_checksum *hmac; - struct iovec iov[num_args]; - uint8_t k[32] = { 0 }; - va_list va; - int i; - int ret; - - va_start(va, out); - - hmac = l_checksum_new_hmac(L_CHECKSUM_SHA256, k, 32); - if (!hmac) - return false; - - for (i = 0; i < num_args; i++) { - iov[i].iov_base = va_arg(va, void *); - iov[i].iov_len = va_arg(va, size_t); - } - - if (!l_checksum_updatev(hmac, iov, num_args)) - return false; - - ret = l_checksum_get_digest(hmac, out, 32); - l_checksum_free(hmac); - - return (ret == 32); -} - /* RFC 5931, Section 2.5 - Key Derivation Function */ static bool kdf(uint8_t *key, size_t key_len, const char *label, size_t label_len, void *out, size_t olen) @@ -310,9 +282,10 @@ static void eap_pwd_handle_id(struct eap_state *eap, while (counter < 20) { /* pwd-seed = H(token|peer-ID|server-ID|password|counter) */ - H(5, pwd_seed, &token, 4, pwd->identity, strlen(pwd->identity), - pkt + 9, len - 9, pwd->password, - strlen(pwd->password), &counter, 1); + hkdf_256(NULL, 0, 5, pwd_seed, &token, 4, pwd->identity, + strlen(pwd->identity), pkt + 9, len - 9, + pwd->password, strlen(pwd->password), + &counter, 1); /* * pwd-value = KDF(pwd-seed, "EAP-pwd Hunting And Pecking", @@ -519,15 +492,15 @@ static void eap_pwd_handle_confirm(struct eap_state *eap, * compute Confirm_P = H(kp | Element_P | Scalar_P | * Element_S | Scalar_S | Ciphersuite) */ - H(8, confirm_p, kp.x, ECC_BYTES, pwd->element_p.x, ECC_BYTES, - pwd->element_p.y, ECC_BYTES, pwd->scalar_p, + hkdf_256(NULL, 0, 8, confirm_p, kp.x, ECC_BYTES, pwd->element_p.x, + ECC_BYTES, pwd->element_p.y, ECC_BYTES, pwd->scalar_p, ECC_BYTES, pwd->element_s.x, ECC_BYTES, pwd->element_s.y, ECC_BYTES, pwd->scalar_s, ECC_BYTES, &pwd->ciphersuite, 4); - H(8, expected_confirm_s, kp.x, ECC_BYTES, pwd->element_s.x, - ECC_BYTES, pwd->element_s.y, ECC_BYTES, - pwd->scalar_s, ECC_BYTES, pwd->element_p.x, + hkdf_256(NULL, 0, 8, expected_confirm_s, kp.x, ECC_BYTES, + pwd->element_s.x, ECC_BYTES, pwd->element_s.y, + ECC_BYTES, pwd->scalar_s, ECC_BYTES, pwd->element_p.x, ECC_BYTES, pwd->element_p.y, ECC_BYTES, pwd->scalar_p, ECC_BYTES, &pwd->ciphersuite, 4); @@ -542,7 +515,7 @@ static void eap_pwd_handle_confirm(struct eap_state *eap, pos += 32; /* derive MK = H(kp | Confirm_P | Confirm_S ) */ - H(3, mk, kp.x, ECC_BYTES, confirm_p, ECC_BYTES, + hkdf_256(NULL, 0, 3, mk, kp.x, ECC_BYTES, confirm_p, ECC_BYTES, confirm_s, ECC_BYTES); eap_pwd_send_response(eap, resp, pos - resp); @@ -550,8 +523,8 @@ static void eap_pwd_handle_confirm(struct eap_state *eap, eap_method_success(eap); session_id[0] = 52; - H(3, session_id + 1, &pwd->ciphersuite, 4, pwd->scalar_p, ECC_BYTES, - pwd->scalar_s, ECC_BYTES); + hkdf_256(NULL, 0, 3, session_id + 1, &pwd->ciphersuite, 4, + pwd->scalar_p, ECC_BYTES, pwd->scalar_s, ECC_BYTES); kdf(mk, 32, (const char *) session_id, 33, msk_emsk, 128); eap_set_key_material(eap, msk_emsk, 64, msk_emsk + 64, 64, NULL, 0); diff --git a/src/sae.c b/src/sae.c index 8584a71a..87e79f35 100644 --- a/src/sae.c +++ b/src/sae.c @@ -72,35 +72,6 @@ struct sae_sm { static uint64_t curve_p[NUM_ECC_DIGITS] = CURVE_P_32; static uint64_t curve_n[NUM_ECC_DIGITS] = CURVE_N_32; -static bool H(const uint8_t *key, size_t key_len, uint8_t num_args, - uint8_t *out, ...) -{ - struct l_checksum *hmac; - struct iovec iov[num_args]; - va_list va; - int i; - int ret; - - va_start(va, out); - - hmac = l_checksum_new_hmac(L_CHECKSUM_SHA256, key, key_len); - if (!hmac) - return false; - - for (i = 0; i < num_args; i++) { - iov[i].iov_base = va_arg(va, void *); - iov[i].iov_len = va_arg(va, size_t); - } - - if (!l_checksum_updatev(hmac, iov, num_args)) - return false; - - ret = l_checksum_get_digest(hmac, out, 32); - l_checksum_free(hmac); - - return (ret == 32); -} - /* calculate random quadratic residue */ static void sae_get_qr(uint64_t *qr) { @@ -166,7 +137,7 @@ static bool sae_pwd_seed(const uint8_t *addr1, const uint8_t *addr2, memcpy(key + 6, addr1, 6); } - return H(key, 12, 2, out, base, base_len, &counter, 1); + return hkdf_256(key, 12, 2, out, base, base_len, &counter, 1); } static bool sae_pwd_value(uint8_t *pwd_seed, uint64_t *pwd_value)