Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP2:Update
freeradius-server.34053
CVE-2022-41859.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File CVE-2022-41859.patch of Package freeradius-server.34053
commit 6f0e0aca4f4e614eea4ce10e226aed73ed4ab68b Author: Alan T. DeKok <aland@freeradius.org> Date: Fri Jul 17 08:37:08 2020 -0400 merge constant time fixes from "master" Based on a patch from Daniel De Almeida Braga. The code is now largely the same between master and v3.0.x, which makes it easier to see that it's correct commit d3d3aa67213159f5bca5e72e609f4859e47ddb1b Author: Alan T. DeKok <aland@freeradius.org> Date: Fri Jul 17 08:53:41 2020 -0400 not available in older versions of OpenSSL commit 1df6f266231816171d2662eacf0e528b8ad1d7d8 Author: Alan T. DeKok <aland@freeradius.org> Date: Sun Dec 26 12:02:30 2021 -0500 switch to non-deprecated API commit 9e5e8f2f912ad2da8ac6e176ac3a606333469937 Author: Alan T. DeKok <aland@freeradius.org> Date: Fri Feb 4 09:36:26 2022 -0500 port fixes from master via the simple expedient of copying the entire function, with some minor changes to work in v3 Index: freeradius-server-3.0.19/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h =================================================================== --- /dev/null +++ freeradius-server-3.0.19/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h @@ -0,0 +1,190 @@ +/* + * Helper functions for constant time operations + * Copyright (c) 2019, The Linux Foundation + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + * + * These helper functions can be used to implement logic that needs to minimize + * externally visible differences in execution path by avoiding use of branches, + * avoiding early termination or other time differences, and forcing same memory + * access pattern regardless of values. + */ + +#ifndef CONST_TIME_H +#define CONST_TIME_H + + +#if defined(__clang__) +#define NO_UBSAN_UINT_OVERFLOW \ + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#else +#define NO_UBSAN_UINT_OVERFLOW +#endif + +/** + * const_time_fill_msb - Fill all bits with MSB value + * @param val Input value + * @return Value with all the bits set to the MSB of the input val + */ +static inline unsigned int const_time_fill_msb(unsigned int val) +{ + /* Move the MSB to LSB and multiple by -1 to fill in all bits. */ + return (val >> (sizeof(val) * 8 - 1)) * ~0U; +} + + +/* @return -1 if val is zero; 0 if val is not zero */ +static inline unsigned int const_time_is_zero(unsigned int val) + NO_UBSAN_UINT_OVERFLOW +{ + /* Set MSB to 1 for 0 and fill rest of bits with the MSB value */ + return const_time_fill_msb(~val & (val - 1)); +} + + +/* @return -1 if a == b; 0 if a != b */ +static inline unsigned int const_time_eq(unsigned int a, unsigned int b) +{ + return const_time_is_zero(a ^ b); +} + + +/* @return -1 if a == b; 0 if a != b */ +static inline unsigned char const_time_eq_u8(unsigned int a, unsigned int b) +{ + return (unsigned char) const_time_eq(a, b); +} + + +/** + * const_time_eq_bin - Constant time memory comparison + * @param a First buffer to compare + * @param b Second buffer to compare + * @param len Number of octets to compare + * @return -1 if buffers are equal, 0 if not + * + * This function is meant for comparing passwords or hash values where + * difference in execution time or memory access pattern could provide external + * observer information about the location of the difference in the memory + * buffers. The return value does not behave like memcmp(), i.e., + * const_time_eq_bin() cannot be used to sort items into a defined order. Unlike + * memcmp(), the execution time of const_time_eq_bin() does not depend on the + * contents of the compared memory buffers, but only on the total compared + * length. + */ +static inline unsigned int const_time_eq_bin(const void *a, const void *b, + size_t len) +{ + const unsigned char *aa = a; + const unsigned char *bb = b; + size_t i; + unsigned char res = 0; + + for (i = 0; i < len; i++) + res |= aa[i] ^ bb[i]; + + return const_time_is_zero(res); +} + + +/** + * const_time_select - Constant time unsigned int selection + * @param mask 0 (false) or -1 (true) to identify which value to select + * @param true_val Value to select for the true case + * @param false_val Value to select for the false case + * @return true_val if mask == -1, false_val if mask == 0 + */ +static inline unsigned int const_time_select(unsigned int mask, + unsigned int true_val, + unsigned int false_val) +{ + return (mask & true_val) | (~mask & false_val); +} + + +/** + * const_time_select_int - Constant time int selection + * @param mask 0 (false) or -1 (true) to identify which value to select + * @param true_val Value to select for the true case + * @param false_val Value to select for the false case + * @return true_val if mask == -1, false_val if mask == 0 + */ +static inline int const_time_select_int(unsigned int mask, int true_val, + int false_val) +{ + return (int) const_time_select(mask, (unsigned int) true_val, + (unsigned int) false_val); +} + + +/** + * const_time_select_u8 - Constant time u8 selection + * @param mask 0 (false) or -1 (true) to identify which value to select + * @param true_val Value to select for the true case + * @param false_val Value to select for the false case + * @return true_val if mask == -1, false_val if mask == 0 + */ +static inline unsigned char const_time_select_u8(unsigned char mask, unsigned char true_val, unsigned char false_val) +{ + return (unsigned char) const_time_select(mask, true_val, false_val); +} + + +/** + * const_time_select_s8 - Constant time s8 selection + * @param mask 0 (false) or -1 (true) to identify which value to select + * @param true_val Value to select for the true case + * @param false_val Value to select for the false case + * @return true_val if mask == -1, false_val if mask == 0 + */ +static inline char const_time_select_s8(char mask, char true_val, char false_val) +{ + return (char) const_time_select(mask, (unsigned int) true_val, + (unsigned int) false_val); +} + + +/** + * const_time_select_bin - Constant time binary buffer selection copy + * @param mask 0 (false) or -1 (true) to identify which value to copy + * @param true_val Buffer to copy for the true case + * @param false_val Buffer to copy for the false case + * @param len Number of octets to copy + * @param dst Destination buffer for the copy + * + * This function copies the specified buffer into the destination buffer using + * operations with identical memory access pattern regardless of which buffer + * is being copied. + */ +static inline void const_time_select_bin(unsigned char mask, const unsigned char *true_val, + const unsigned char *false_val, size_t len, + unsigned char *dst) +{ + size_t i; + + for (i = 0; i < len; i++) + dst[i] = const_time_select_u8(mask, true_val[i], false_val[i]); +} + + +static inline int const_time_memcmp(const void *a, const void *b, size_t len) +{ + const unsigned char *aa = a; + const unsigned char *bb = b; + int diff, res = 0; + unsigned int mask; + + if (len == 0) + return 0; + do { + len--; + diff = (int) aa[len] - (int) bb[len]; + mask = const_time_is_zero((unsigned int) diff); + res = const_time_select_int(mask, res, diff); + } while (len); + + return res; +} + +#endif /* CONST_TIME_H */ Index: freeradius-server-3.0.19/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c =================================================================== --- freeradius-server-3.0.19.orig/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c +++ freeradius-server-3.0.19/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c @@ -1,7 +1,5 @@ -/* - * Copyright (c) Dan Harkins, 2012 - * - * Copyright holder grants permission for redistribution and use in source +/** + * copyright holder grants permission for redistribution and use in source * and binary forms, with or without modification, provided that the * following conditions are met: * 1. Redistribution of source code must retain the above copyright @@ -29,100 +27,236 @@ * This license and distribution terms cannot be changed. In other words, * this code cannot simply be copied and put under a different distribution * license (including the GNU public license). + * + * @copyright (c) Dan Harkins, 2012 */ RCSID("$Id: 7f91e4b230a15c81b830738924b9d741534fc256 $") USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ #include "eap_pwd.h" +#include "const_time.h" -#include <freeradius-devel/radiusd.h> -#include <freeradius-devel/modules.h> +static uint8_t allzero[SHA256_DIGEST_LENGTH] = { 0x00 }; /* The random function H(x) = HMAC-SHA256(0^32, x) */ -static void H_Init(HMAC_CTX *ctx) +static void pwd_hmac_final(HMAC_CTX *hmac_ctx, uint8_t *digest) { - uint8_t allzero[SHA256_DIGEST_LENGTH]; + unsigned int mdlen = SHA256_DIGEST_LENGTH; + HMAC_Final(hmac_ctx, digest, &mdlen); +// HMAC_CTX_reset(hmac_ctx); +} + +/* a counter-based KDF based on NIST SP800-108 */ +static void eap_pwd_kdf(uint8_t *key, int keylen, char const *label, + int label_len, uint8_t *result, int result_bit_len) +{ + HMAC_CTX *hmac_ctx; + uint8_t digest[SHA256_DIGEST_LENGTH]; + uint16_t i, ctr, L; + int result_byte_len, len = 0; + unsigned int mdlen = SHA256_DIGEST_LENGTH; + uint8_t mask = 0xff; + + MEM(hmac_ctx = HMAC_CTX_new()); + result_byte_len = (result_bit_len + 7) / 8; + + ctr = 0; + L = htons(result_bit_len); + while (len < result_byte_len) { + ctr++; i = htons(ctr); + + HMAC_Init_ex(hmac_ctx, key, keylen, EVP_sha256(), NULL); + if (ctr > 1) HMAC_Update(hmac_ctx, digest, mdlen); + HMAC_Update(hmac_ctx, (uint8_t *) &i, sizeof(uint16_t)); + HMAC_Update(hmac_ctx, (uint8_t const *)label, label_len); + HMAC_Update(hmac_ctx, (uint8_t *) &L, sizeof(uint16_t)); + HMAC_Final(hmac_ctx, digest, &mdlen); + if ((len + (int) mdlen) > result_byte_len) { + memcpy(result + len, digest, result_byte_len - len); + } else { + memcpy(result + len, digest, mdlen); + } + len += mdlen; +// HMAC_CTX_reset(hmac_ctx); + } + + /* since we're expanding to a bit length, mask off the excess */ + if (result_bit_len % 8) { + mask <<= (8 - (result_bit_len % 8)); + result[result_byte_len - 1] &= mask; + } - memset(allzero, 0, SHA256_DIGEST_LENGTH); + HMAC_CTX_free(hmac_ctx); +} + +static BIGNUM *consttime_BN (void) +{ + BIGNUM *bn; - HMAC_Init_ex(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL); + bn = BN_new(); + if (bn) BN_set_flags(bn, BN_FLG_CONSTTIME); + return bn; } -static void H_Update(HMAC_CTX *ctx, uint8_t const *data, int len) +/* + * compute the legendre symbol in constant time + */ +static int legendre(BIGNUM *a, BIGNUM *p, BN_CTX *bnctx) { - HMAC_Update(ctx, data, len); + int symbol; + unsigned int mask; + BIGNUM *res, *pm1over2; + + pm1over2 = consttime_BN(); + res = consttime_BN(); + + if (!BN_sub(pm1over2, p, BN_value_one()) || + !BN_rshift1(pm1over2, pm1over2) || + !BN_mod_exp_mont_consttime(res, a, pm1over2, p, bnctx, NULL)) { + BN_free(pm1over2); + BN_free(res); + return -2; + } + + symbol = -1; + mask = const_time_eq(BN_is_word(res, 1), 1); + symbol = const_time_select_int(mask, 1, symbol); + mask = const_time_eq(BN_is_zero(res), 1); + symbol = const_time_select_int(mask, -1, symbol); + + BN_free(pm1over2); + BN_free(res); + + return symbol; } -static void H_Final(HMAC_CTX *ctx, uint8_t *digest) +static void do_equation(EC_GROUP *group, BIGNUM *y2, BIGNUM *x, BN_CTX *bnctx) { - unsigned int mdlen = SHA256_DIGEST_LENGTH; + BIGNUM *p, *a, *b, *tmp1, *pm1; + + tmp1 = BN_new(); + pm1 = BN_new(); + p = BN_new(); + a = BN_new(); + b = BN_new(); + EC_GROUP_get_curve(group, p, a, b, bnctx); - HMAC_Final(ctx, digest, &mdlen); + BN_sub(pm1, p, BN_value_one()); + + /* + * y2 = x^3 + ax + b + */ + BN_mod_sqr(tmp1, x, p, bnctx); + BN_mod_mul(y2, tmp1, x, p, bnctx); + BN_mod_mul(tmp1, a, x, p, bnctx); + BN_mod_add_quick(y2, y2, tmp1, p); + BN_mod_add_quick(y2, y2, b, p); + + BN_free(tmp1); + BN_free(pm1); + BN_free(p); + BN_free(a); + BN_free(b); + + return; } -/* a counter-based KDF based on NIST SP800-108 */ -static int eap_pwd_kdf(uint8_t *key, int keylen, char const *label, int labellen, uint8_t *result, int resultbitlen) +static int is_quadratic_residue(BIGNUM *val, BIGNUM *p, BIGNUM *qr, BIGNUM *qnr, BN_CTX *bnctx) { - HMAC_CTX *hctx = NULL; - uint8_t digest[SHA256_DIGEST_LENGTH]; - uint16_t i, ctr, L; - int resultbytelen, len = 0; - unsigned int mdlen = SHA256_DIGEST_LENGTH; - uint8_t mask = 0xff; + int offset, check, ret = 0; + BIGNUM *r = NULL, *pm1 = NULL, *res = NULL, *qr_or_qnr = NULL; + unsigned int mask; + unsigned char *qr_bin = NULL, *qnr_bin = NULL, *qr_or_qnr_bin = NULL; - hctx = HMAC_CTX_new(); - if (hctx == NULL) { - DEBUG("failed allocating HMAC context"); - return -1; + if (((r = consttime_BN()) == NULL) || + ((res = consttime_BN()) == NULL) || + ((qr_or_qnr = consttime_BN()) == NULL) || + ((pm1 = consttime_BN()) == NULL)) { + ret = -2; + goto fail; } - resultbytelen = (resultbitlen + 7)/8; - ctr = 0; - L = htons(resultbitlen); - while (len < resultbytelen) { - ctr++; i = htons(ctr); - HMAC_Init_ex(hctx, key, keylen, EVP_sha256(), NULL); - if (ctr > 1) { - HMAC_Update(hctx, digest, mdlen); - } - HMAC_Update(hctx, (uint8_t *) &i, sizeof(uint16_t)); - HMAC_Update(hctx, (uint8_t const *)label, labellen); - HMAC_Update(hctx, (uint8_t *) &L, sizeof(uint16_t)); - HMAC_Final(hctx, digest, &mdlen); - if ((len + (int) mdlen) > resultbytelen) { - memcpy(result + len, digest, resultbytelen - len); - } else { - memcpy(result + len, digest, mdlen); - } - len += mdlen; + + if (((qr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL) || + ((qnr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL) || + ((qr_or_qnr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL)) { + ret = -2; + goto fail; } - HMAC_CTX_free(hctx); - /* since we're expanding to a bit length, mask off the excess */ - if (resultbitlen % 8) { - mask <<= (8 - (resultbitlen % 8)); - result[resultbytelen - 1] &= mask; + /* + * we select binary in constant time so make them binary + */ + memset(qr_bin, 0, BN_num_bytes(p)); + memset(qnr_bin, 0, BN_num_bytes(p)); + memset(qr_or_qnr_bin, 0, BN_num_bytes(p)); + + offset = BN_num_bytes(p) - BN_num_bytes(qr); + BN_bn2bin(qr, qr_bin + offset); + + offset = BN_num_bytes(p) - BN_num_bytes(qnr); + BN_bn2bin(qnr, qnr_bin + offset); + + /* + * r = (random() mod p-1) + 1 + */ + BN_sub(pm1, p, BN_value_one()); + BN_rand_range(r, pm1); + BN_add(r, r, BN_value_one()); + + BN_copy(res, val); + + /* + * res = val * r * r which ensures res != val but has same quadratic residocity + */ + BN_mod_mul(res, res, r, p, bnctx); + BN_mod_mul(res, res, r, p, bnctx); + + /* + * if r is even (mask is -1) then multiply by qnr and our check is qnr + * otherwise multiply by qr and our check is qr + */ + mask = const_time_is_zero(BN_is_odd(r)); + const_time_select_bin(mask, qnr_bin, qr_bin, BN_num_bytes(p), qr_or_qnr_bin); + BN_bin2bn(qr_or_qnr_bin, BN_num_bytes(p), qr_or_qnr); + BN_mod_mul(res, res, qr_or_qnr, p, bnctx); + check = const_time_select_int(mask, -1, 1); + + if ((ret = legendre(res, p, bnctx)) == -2) { + ret = -1; /* just say no it's not */ + goto fail; } + mask = const_time_eq(ret, check); + ret = const_time_select_int(mask, 1, 0); - return 0; +fail: + if (qr_bin != NULL) free(qr_bin); + if (qnr_bin != NULL) free(qnr_bin); + if (qr_or_qnr_bin != NULL) free(qr_or_qnr_bin); + BN_free(r); + BN_free(res); + BN_free(qr_or_qnr); + BN_free(pm1); + + return ret; } -int compute_password_element (pwd_session_t *session, uint16_t grp_num, +int compute_password_element (REQUEST *request, pwd_session_t *session, uint16_t grp_num, char const *password, int password_len, char const *id_server, int id_server_len, char const *id_peer, int id_peer_len, uint32_t *token) { - BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; - HMAC_CTX *ctx = NULL; - uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr; - int nid, is_odd, primebitlen, primebytelen, ret = 0; - - ctx = HMAC_CTX_new(); - if (ctx == NULL) { - DEBUG("failed allocating HMAC context"); - goto fail; - } + BIGNUM *x_candidate = NULL, *rnd = NULL, *y_sqrd = NULL, *qr = NULL, *qnr = NULL, *y1 = NULL, *y2 = NULL, *y = NULL, *exp = NULL; + EVP_MD_CTX *hmac_ctx; + EVP_PKEY *hmac_pkey; + uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, *xbuf = NULL, *pm1buf = NULL, *y1buf = NULL, *y2buf = NULL, *ybuf = NULL, ctr; + int nid, is_odd, primebitlen, primebytelen, ret = 0, found = 0, mask; + int save, i, rbits, qr_or_qnr, save_is_odd = 0, cmp; + unsigned int skip; + + MEM(hmac_ctx = EVP_MD_CTX_new()); + MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, allzero, sizeof(allzero))); switch (grp_num) { /* from IANA registry for IKE D-H groups */ case 19: @@ -159,17 +293,23 @@ int compute_password_element (pwd_sessio goto fail; } - if (((rnd = BN_new()) == NULL) || - ((cofactor = BN_new()) == NULL) || + if (((rnd = consttime_BN()) == NULL) || ((session->pwe = EC_POINT_new(session->group)) == NULL) || - ((session->order = BN_new()) == NULL) || - ((session->prime = BN_new()) == NULL) || - ((x_candidate = BN_new()) == NULL)) { + ((session->order = consttime_BN()) == NULL) || + ((session->prime = consttime_BN()) == NULL) || + ((qr = consttime_BN()) == NULL) || + ((qnr = consttime_BN()) == NULL) || + ((x_candidate = consttime_BN()) == NULL) || + ((y_sqrd = consttime_BN()) == NULL) || + ((y1 = consttime_BN()) == NULL) || + ((y2 = consttime_BN()) == NULL) || + ((y = consttime_BN()) == NULL) || + ((exp = consttime_BN()) == NULL)) { DEBUG("unable to create bignums"); goto fail; } - if (!EC_GROUP_get_curve_GFp(session->group, session->prime, NULL, NULL, NULL)) { + if (!EC_GROUP_get_curve(session->group, session->prime, NULL, NULL, NULL)) { DEBUG("unable to get prime for GFp curve"); goto fail; } @@ -179,46 +319,80 @@ int compute_password_element (pwd_sessio goto fail; } - if (!EC_GROUP_get_cofactor(session->group, cofactor, NULL)) { - DEBUG("unable to get cofactor for curve"); - goto fail; - } - primebitlen = BN_num_bits(session->prime); primebytelen = BN_num_bytes(session->prime); if ((prfbuf = talloc_zero_array(session, uint8_t, primebytelen)) == NULL) { DEBUG("unable to alloc space for prf buffer"); goto fail; } + if ((xbuf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for x buffer"); + goto fail; + } + if ((pm1buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for pm1 buffer"); + goto fail; + } + if ((y1buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for y1 buffer"); + goto fail; + } + if ((y2buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for y2 buffer"); + goto fail; + } + if ((ybuf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) { + DEBUG("unable to alloc space for y buffer"); + goto fail; + } + + + /* + * derive random quadradic residue and quadratic non-residue + */ + do { + BN_rand_range(qr, session->prime); + } while (legendre(qr, session->prime, session->bnctx) != 1); + + do { + BN_rand_range(qnr, session->prime); + } while (legendre(qnr, session->prime, session->bnctx) != -1); + + if (!BN_sub(rnd, session->prime, BN_value_one())) { + goto fail; + } + BN_bn2bin(rnd, pm1buf); + + save_is_odd = 0; + found = 0; + memset(xbuf, 0, primebytelen); ctr = 0; - while (1) { - if (ctr > 100) { - DEBUG("unable to find random point on curve for group %d, something's fishy", grp_num); - goto fail; - } + while (ctr < 40) { ctr++; /* * compute counter-mode password value and stretch to prime - * pwd-seed = H(token | peer-id | server-id | password | - * counter) + * pwd-seed = H(token | peer-id | server-id | password | + * counter) */ - H_Init(ctx); - H_Update(ctx, (uint8_t *)token, sizeof(*token)); - H_Update(ctx, (uint8_t const *)id_peer, id_peer_len); - H_Update(ctx, (uint8_t const *)id_server, id_server_len); - H_Update(ctx, (uint8_t const *)password, password_len); - H_Update(ctx, (uint8_t *)&ctr, sizeof(ctr)); - H_Final(ctx, pwe_digest); + EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey); + EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)token, sizeof(*token)); + EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)id_peer, id_peer_len); + EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)id_server, id_server_len); + EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)password, password_len); + EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)&ctr, sizeof(ctr)); - BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd); - if (eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH, "EAP-pwd Hunting And Pecking", - strlen("EAP-pwd Hunting And Pecking"), prfbuf, primebitlen) != 0) { - DEBUG("key derivation function failed"); - goto fail; + { + size_t mdlen = SHA256_DIGEST_LENGTH; + + EVP_DigestSignFinal(hmac_ctx, pwe_digest, &mdlen); + EVP_MD_CTX_reset(hmac_ctx); } - BN_bin2bn(prfbuf, primebytelen, x_candidate); + BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd); + eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH, "EAP-pwd Hunting And Pecking", + strlen("EAP-pwd Hunting And Pecking"), prfbuf, primebitlen); + /* * eap_pwd_kdf() returns a string of bits 0..primebitlen but * BN_bin2bn will treat that string of bits as a big endian @@ -226,49 +400,86 @@ int compute_password_element (pwd_sessio * then excessive bits-- those _after_ primebitlen-- so now * we have to shift right the amount we masked off. */ - if (primebitlen % 8) BN_rshift(x_candidate, x_candidate, (8 - (primebitlen % 8))); - if (BN_ucmp(x_candidate, session->prime) >= 0) continue; + if (primebitlen % 8) { + rbits = 8 - (primebitlen % 8); + for (i = primebytelen - 1; i > 0; i--) { + prfbuf[i] = (prfbuf[i - 1] << (8 - rbits)) | (prfbuf[i] >> rbits); + } + prfbuf[0] >>= rbits; + } + BN_bin2bn(prfbuf, primebytelen, x_candidate); /* - * need to unambiguously identify the solution, if there is - * one... - */ - is_odd = BN_is_odd(rnd) ? 1 : 0; + * it would've been better if the spec reduced the candidate + * modulo the prime but it didn't. So if the candidate >= prime + * we need to skip it but still run through the operations below + */ + cmp = const_time_memcmp(pm1buf, prfbuf, primebytelen); + skip = const_time_fill_msb((unsigned int)cmp); /* - * solve the quadratic equation, if it's not solvable then we - * don't have a point - */ - if (!EC_POINT_set_compressed_coordinates_GFp(session->group, session->pwe, x_candidate, is_odd, NULL)) { - continue; - } + * need to unambiguously identify the solution, if there is + * one.. + */ + is_odd = BN_is_odd(rnd); /* - * If there's a solution to the equation then the point must be - * on the curve so why check again explicitly? OpenSSL code - * says this is required by X9.62. We're not X9.62 but it can't - * hurt just to be sure. - */ - if (!EC_POINT_is_on_curve(session->group, session->pwe, NULL)) { - DEBUG("EAP-pwd: point is not on curve"); - continue; - } + * check whether x^3 + a*x + b is a quadratic residue + * + * save the first quadratic residue we find in the loop but do + * it in constant time. + */ + do_equation(session->group, y_sqrd, x_candidate, session->bnctx); + qr_or_qnr = is_quadratic_residue(y_sqrd, session->prime, qr, qnr, session->bnctx); - if (BN_cmp(cofactor, BN_value_one())) { - /* make sure the point is not in a small sub-group */ - if (!EC_POINT_mul(session->group, session->pwe, NULL, session->pwe, - cofactor, NULL)) { - DEBUG("EAP-pwd: cannot multiply generator by order"); - continue; - } + /* + * if the candidate >= prime then we want to skip it + */ + qr_or_qnr = const_time_select(skip, 0, qr_or_qnr); - if (EC_POINT_is_at_infinity(session->group, session->pwe)) { - DEBUG("EAP-pwd: point is at infinity"); - continue; - } - } - /* if we got here then we have a new generator. */ - break; + /* + * if we haven't found PWE yet (found = 0) then mask will be true, + * if we have found PWE then mask will be false + */ + mask = const_time_select(found, 0, -1); + + /* + * save will be 1 if we want to save this value-- i.e. we haven't + * found PWE yet and this is a quadratic residue-- and 0 otherwise + */ + save = const_time_select(mask, qr_or_qnr, 0); + + /* + * mask will be true (-1) if we want to save this and false (0) + * otherwise + */ + mask = const_time_eq(save, 1); + + const_time_select_bin(mask, prfbuf, xbuf, primebytelen, xbuf); + save_is_odd = const_time_select(mask, is_odd, save_is_odd); + found = const_time_select(mask, -1, found); + } + + /* + * now we can savely construct PWE + */ + BN_bin2bn(xbuf, primebytelen, x_candidate); + do_equation(session->group, y_sqrd, x_candidate, session->bnctx); + if ( !BN_add(exp, session->prime, BN_value_one()) || + !BN_rshift(exp, exp, 2) || + !BN_mod_exp_mont_consttime(y1, y_sqrd, exp, session->prime, session->bnctx, NULL) || + !BN_sub(y2, session->prime, y1) || + !BN_bn2bin(y1, y1buf) || + !BN_bn2bin(y2, y2buf)) { + DEBUG("unable to compute y"); + goto fail; + } + mask = const_time_eq(save_is_odd, BN_is_odd(y1)); + const_time_select_bin(mask, y1buf, y2buf, primebytelen, ybuf); + if (BN_bin2bn(ybuf, primebytelen, y) == NULL || + !EC_POINT_set_affine_coordinates(session->group, session->pwe, x_candidate, y, session->bnctx)) { + DEBUG("unable to set point coordinate"); + goto fail; } session->group_num = grp_num; @@ -278,78 +489,89 @@ int compute_password_element (pwd_sessio } /* cleanliness and order.... */ - BN_clear_free(cofactor); BN_clear_free(x_candidate); + BN_clear_free(y_sqrd); + BN_clear_free(qr); + BN_clear_free(qnr); BN_clear_free(rnd); - talloc_free(prfbuf); - HMAC_CTX_free(ctx); + BN_clear_free(y1); + BN_clear_free(y2); + BN_clear_free(y); + BN_clear_free(exp); + + if (prfbuf) talloc_free(prfbuf); + if (xbuf) talloc_free(xbuf); + if (pm1buf) talloc_free(pm1buf); + if (y1buf) talloc_free(y1buf); + if (y2buf) talloc_free(y2buf); + if (ybuf) talloc_free(ybuf); + + EVP_MD_CTX_free(hmac_ctx); + EVP_PKEY_free(hmac_pkey); return ret; } -int compute_scalar_element (pwd_session_t *session, BN_CTX *bnctx) { +int compute_scalar_element(REQUEST *request, pwd_session_t *session, BN_CTX *bn_ctx) +{ BIGNUM *mask = NULL; int ret = -1; - if (((session->private_value = BN_new()) == NULL) || - ((session->my_element = EC_POINT_new(session->group)) == NULL) || - ((session->my_scalar = BN_new()) == NULL) || - ((mask = BN_new()) == NULL)) { - DEBUG2("server scalar allocation failed"); - goto fail; - } + MEM(session->private_value = BN_new()); + MEM(session->my_element = EC_POINT_new(session->group)); + MEM(session->my_scalar = BN_new()); + + MEM(mask = BN_new()); if (BN_rand_range(session->private_value, session->order) != 1) { - DEBUG2("Unable to get randomness for private_value"); - goto fail; + REDEBUG("Unable to get randomness for private_value"); + goto error; } if (BN_rand_range(mask, session->order) != 1) { - DEBUG2("Unable to get randomness for mask"); - goto fail; + REDEBUG("Unable to get randomness for mask"); + goto error; } BN_add(session->my_scalar, session->private_value, mask); - BN_mod(session->my_scalar, session->my_scalar, session->order, bnctx); + BN_mod(session->my_scalar, session->my_scalar, session->order, bn_ctx); - if (!EC_POINT_mul(session->group, session->my_element, NULL, session->pwe, mask, bnctx)) { - DEBUG2("server element allocation failed"); - goto fail; + if (!EC_POINT_mul(session->group, session->my_element, NULL, session->pwe, mask, bn_ctx)) { + REDEBUG("Server element allocation failed"); + goto error; } - if (!EC_POINT_invert(session->group, session->my_element, bnctx)) { - DEBUG2("server element inversion failed"); - goto fail; + if (!EC_POINT_invert(session->group, session->my_element, bn_ctx)) { + REDEBUG("Server element inversion failed"); + goto error; } ret = 0; -fail: +error: BN_clear_free(mask); return ret; } -int process_peer_commit (pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bnctx) +int process_peer_commit(REQUEST *request, pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bn_ctx) { - uint8_t *ptr; - size_t data_len; - BIGNUM *x = NULL, *y = NULL, *cofactor = NULL; - EC_POINT *K = NULL, *point = NULL; - int res = 1; - - if (((session->peer_scalar = BN_new()) == NULL) || - ((session->k = BN_new()) == NULL) || - ((cofactor = BN_new()) == NULL) || - ((x = BN_new()) == NULL) || - ((y = BN_new()) == NULL) || - ((point = EC_POINT_new(session->group)) == NULL) || - ((K = EC_POINT_new(session->group)) == NULL) || - ((session->peer_element = EC_POINT_new(session->group)) == NULL)) { - DEBUG2("pwd: failed to allocate room to process peer's commit"); - goto finish; - } + uint8_t *ptr; + size_t data_len; + BIGNUM *x = NULL, *y = NULL, *cofactor = NULL; + EC_POINT *K = NULL, *point = NULL; + int ret = 1; + + MEM(session->peer_scalar = BN_new()); + MEM(session->k = BN_new()); + MEM(session->peer_element = EC_POINT_new(session->group)); + MEM(point = EC_POINT_new(session->group)); + MEM(K = EC_POINT_new(session->group)); + + MEM(cofactor = BN_new()); + MEM(x = BN_new()); + MEM(y = BN_new()); if (!EC_GROUP_get_cofactor(session->group, cofactor, NULL)) { - DEBUG2("pwd: unable to get group co-factor"); + REDEBUG("Unable to get group co-factor"); goto finish; } @@ -361,7 +583,7 @@ int process_peer_commit (pwd_session_t * * Did the peer send enough data? */ if (in_len < (2 * data_len + BN_num_bytes(session->order))) { - DEBUG("pwd: Invalid commit packet"); + REDEBUG("Invalid commit packet"); goto finish; } @@ -377,54 +599,54 @@ int process_peer_commit (pwd_session_t * if (BN_is_zero(session->peer_scalar) || BN_is_one(session->peer_scalar) || BN_cmp(session->peer_scalar, session->order) >= 0) { - ERROR("Peer's scalar is not within the allowed range"); + REDEBUG("Peer's scalar is not within the allowed range"); goto finish; } - if (!EC_POINT_set_affine_coordinates_GFp(session->group, session->peer_element, x, y, bnctx)) { - DEBUG2("pwd: unable to get coordinates of peer's element"); + if (!EC_POINT_set_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) { + REDEBUG("Unable to get coordinates of peer's element"); goto finish; } /* validate received element */ - if (!EC_POINT_is_on_curve(session->group, session->peer_element, bnctx) || + if (!EC_POINT_is_on_curve(session->group, session->peer_element, bn_ctx) || EC_POINT_is_at_infinity(session->group, session->peer_element)) { - ERROR("Peer's element is not a point on the elliptic curve"); + REDEBUG("Peer's element is not a point on the elliptic curve"); goto finish; } /* check to ensure peer's element is not in a small sub-group */ if (BN_cmp(cofactor, BN_value_one())) { if (!EC_POINT_mul(session->group, point, NULL, session->peer_element, cofactor, NULL)) { - DEBUG2("pwd: unable to multiply element by co-factor"); + REDEBUG("Unable to multiply element by co-factor"); goto finish; } if (EC_POINT_is_at_infinity(session->group, point)) { - DEBUG2("pwd: peer's element is in small sub-group"); + REDEBUG("Peer's element is in small sub-group"); goto finish; } } /* detect reflection attacks */ if (BN_cmp(session->peer_scalar, session->my_scalar) == 0 || - EC_POINT_cmp(session->group, session->peer_element, session->my_element, bnctx) == 0) { - ERROR("Reflection attack detected"); + EC_POINT_cmp(session->group, session->peer_element, session->my_element, bn_ctx) == 0) { + REDEBUG("Reflection attack detected"); goto finish; } /* compute the shared key, k */ - if ((!EC_POINT_mul(session->group, K, NULL, session->pwe, session->peer_scalar, bnctx)) || - (!EC_POINT_add(session->group, K, K, session->peer_element, bnctx)) || - (!EC_POINT_mul(session->group, K, NULL, K, session->private_value, bnctx))) { - DEBUG2("pwd: unable to compute shared key, k"); + if ((!EC_POINT_mul(session->group, K, NULL, session->pwe, session->peer_scalar, bn_ctx)) || + (!EC_POINT_add(session->group, K, K, session->peer_element, bn_ctx)) || + (!EC_POINT_mul(session->group, K, NULL, K, session->private_value, bn_ctx))) { + REDEBUG("Unable to compute shared key, k"); goto finish; } /* ensure that the shared key isn't in a small sub-group */ if (BN_cmp(cofactor, BN_value_one())) { if (!EC_POINT_mul(session->group, K, NULL, K, cofactor, NULL)) { - DEBUG2("pwd: unable to multiply k by co-factor"); + REDEBUG("Unable to multiply k by co-factor"); goto finish; } } @@ -436,15 +658,15 @@ int process_peer_commit (pwd_session_t * * sure" so let's be safe. */ if (EC_POINT_is_at_infinity(session->group, K)) { - DEBUG2("pwd: k is point-at-infinity!"); + REDEBUG("K is point-at-infinity"); goto finish; } - if (!EC_POINT_get_affine_coordinates_GFp(session->group, K, session->k, NULL, bnctx)) { - DEBUG2("pwd: unable to get shared secret from K"); + if (!EC_POINT_get_affine_coordinates(session->group, K, session->k, NULL, bn_ctx)) { + REDEBUG("Unable to get shared secret from K"); goto finish; } - res = 0; + ret = 0; finish: EC_POINT_clear_free(K); @@ -453,36 +675,29 @@ finish: BN_clear_free(x); BN_clear_free(y); - return res; + return ret; } -int compute_server_confirm (pwd_session_t *session, uint8_t *out, BN_CTX *bnctx) +int compute_server_confirm(REQUEST *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx) { - BIGNUM *x = NULL, *y = NULL; - HMAC_CTX *ctx = NULL; - uint8_t *cruft = NULL; - int offset, req = -1; - - ctx = HMAC_CTX_new(); - if (ctx == NULL) { - DEBUG2("pwd: unable to allocate HMAC context!"); - goto finish; - } + BIGNUM *x = NULL, *y = NULL; + HMAC_CTX *hmac_ctx = NULL; + uint8_t *cruft = NULL; + int offset, req = -1; /* * Each component of the cruft will be at most as big as the prime */ - if (((cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime))) == NULL) || - ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { - DEBUG2("pwd: unable to allocate space to compute confirm!"); - goto finish; - } + MEM(cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime))); + MEM(x = BN_new()); + MEM(y = BN_new()); /* * commit is H(k | server_element | server_scalar | peer_element | * peer_scalar | ciphersuite) */ - H_Init(ctx); + MEM(hmac_ctx = HMAC_CTX_new()); + HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL); /* * Zero the memory each time because this is mod prime math and some @@ -492,24 +707,24 @@ int compute_server_confirm (pwd_session_ */ offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k); BN_bn2bin(session->k, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); /* * next is server element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->my_element, x, y, bnctx)) { - DEBUG2("pwd: unable to get coordinates of server element"); + if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, bn_ctx)) { + REDEBUG("Unable to get coordinates of server element"); goto finish; } memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->prime) - BN_num_bytes(x); BN_bn2bin(x, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->prime) - BN_num_bytes(y); BN_bn2bin(y, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); /* * and server scalar @@ -517,25 +732,25 @@ int compute_server_confirm (pwd_session_ memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar); BN_bn2bin(session->my_scalar, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->order)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); /* * next is peer element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->peer_element, x, y, bnctx)) { - DEBUG2("pwd: unable to get coordinates of peer's element"); + if (!EC_POINT_get_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) { + REDEBUG("Unable to get coordinates of peer's element"); goto finish; } memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->prime) - BN_num_bytes(x); BN_bn2bin(x, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->prime) - BN_num_bytes(y); BN_bn2bin(y, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); /* * and peer scalar @@ -543,52 +758,46 @@ int compute_server_confirm (pwd_session_ memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar); BN_bn2bin(session->peer_scalar, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->order)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); /* * finally, ciphersuite */ - H_Update(ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite)); + HMAC_Update(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite)); - H_Final(ctx, out); + pwd_hmac_final(hmac_ctx, out); req = 0; + finish: + HMAC_CTX_free(hmac_ctx); talloc_free(cruft); BN_free(x); BN_free(y); - HMAC_CTX_free(ctx); return req; } -int compute_peer_confirm (pwd_session_t *session, uint8_t *out, BN_CTX *bnctx) +int compute_peer_confirm(REQUEST *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx) { - BIGNUM *x = NULL, *y = NULL; - HMAC_CTX *ctx = NULL; - uint8_t *cruft = NULL; - int offset, req = -1; - - ctx = HMAC_CTX_new(); - if (ctx == NULL) { - DEBUG2("pwd: unable to allocate HMAC context!"); - goto finish; - } + BIGNUM *x = NULL, *y = NULL; + HMAC_CTX *hmac_ctx = NULL; + uint8_t *cruft = NULL; + int offset, req = -1; /* * Each component of the cruft will be at most as big as the prime */ - if (((cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime))) == NULL) || - ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { - DEBUG2("pwd: unable to allocate space to compute confirm!"); - goto finish; - } + MEM(cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime))); + MEM(x = BN_new()); + MEM(y = BN_new()); /* * commit is H(k | server_element | server_scalar | peer_element | * peer_scalar | ciphersuite) */ - H_Init(ctx); + MEM(hmac_ctx = HMAC_CTX_new()); + HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL); /* * Zero the memory each time because this is mod prime math and some @@ -598,25 +807,25 @@ int compute_peer_confirm (pwd_session_t */ offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k); BN_bn2bin(session->k, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); /* * then peer element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->peer_element, x, y, bnctx)) { - DEBUG2("pwd: unable to get coordinates of peer's element"); + if (!EC_POINT_get_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) { + REDEBUG("Unable to get coordinates of peer's element"); goto finish; } memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->prime) - BN_num_bytes(x); BN_bn2bin(x, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->prime) - BN_num_bytes(y); BN_bn2bin(y, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); /* * and peer scalar @@ -624,24 +833,24 @@ int compute_peer_confirm (pwd_session_t memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar); BN_bn2bin(session->peer_scalar, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->order)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); /* * then server element: x, y */ - if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->my_element, x, y, bnctx)) { - DEBUG2("pwd: unable to get coordinates of server element"); + if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, bn_ctx)) { + REDEBUG("Unable to get coordinates of server element"); goto finish; } memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->prime) - BN_num_bytes(x); BN_bn2bin(x, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->prime) - BN_num_bytes(y); BN_bn2bin(y, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); /* * and server scalar @@ -649,94 +858,75 @@ int compute_peer_confirm (pwd_session_t memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar); BN_bn2bin(session->my_scalar, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->order)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); /* * finally, ciphersuite */ - H_Update(ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite)); + HMAC_Update(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite)); - H_Final(ctx, out); + pwd_hmac_final(hmac_ctx, out); req = 0; finish: + HMAC_CTX_free(hmac_ctx); talloc_free(cruft); BN_free(x); BN_free(y); - HMAC_CTX_free(ctx); return req; } -int compute_keys (pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk) +int compute_keys(UNUSED REQUEST *request, pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk) { - HMAC_CTX *ctx = NULL; - uint8_t mk[SHA256_DIGEST_LENGTH], *cruft = NULL; - uint8_t session_id[SHA256_DIGEST_LENGTH + 1]; - uint8_t msk_emsk[128]; /* 64 each */ - int offset, ret = -1; + HMAC_CTX *hmac_ctx; + uint8_t mk[SHA256_DIGEST_LENGTH], *cruft; + uint8_t session_id[SHA256_DIGEST_LENGTH + 1]; + uint8_t msk_emsk[128]; /* 64 each */ + int offset; - ctx = HMAC_CTX_new(); - if (ctx == NULL) { - DEBUG2("pwd: unable to allocate HMAC context!"); - goto finish; - } - - if ((cruft = talloc_array(session, uint8_t, BN_num_bytes(session->prime))) == NULL) { - DEBUG2("pwd: unable to allocate space to compute keys"); - goto finish; - } + MEM(cruft = talloc_array(session, uint8_t, BN_num_bytes(session->prime))); + MEM(hmac_ctx = HMAC_CTX_new()); /* * first compute the session-id = TypeCode | H(ciphersuite | scal_p | * scal_s) */ session_id[0] = PW_EAP_PWD; - H_Init(ctx); - H_Update(ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite)); + HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL); + HMAC_Update(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite)); offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar); memset(cruft, 0, BN_num_bytes(session->prime)); BN_bn2bin(session->peer_scalar, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->order)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar); memset(cruft, 0, BN_num_bytes(session->prime)); BN_bn2bin(session->my_scalar, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->order)); - H_Final(ctx, (uint8_t *)&session_id[1]); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order)); + pwd_hmac_final(hmac_ctx, (uint8_t *)&session_id[1]); /* then compute MK = H(k | commit-peer | commit-server) */ - H_Init(ctx); + HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL); memset(cruft, 0, BN_num_bytes(session->prime)); offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k); BN_bn2bin(session->k, cruft + offset); - H_Update(ctx, cruft, BN_num_bytes(session->prime)); + HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime)); - H_Update(ctx, peer_confirm, SHA256_DIGEST_LENGTH); + HMAC_Update(hmac_ctx, peer_confirm, SHA256_DIGEST_LENGTH); - H_Update(ctx, session->my_confirm, SHA256_DIGEST_LENGTH); + HMAC_Update(hmac_ctx, session->my_confirm, SHA256_DIGEST_LENGTH); - H_Final(ctx, mk); + pwd_hmac_final(hmac_ctx, mk); /* stretch the mk with the session-id to get MSK | EMSK */ - if (eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH, (char const *)session_id, - SHA256_DIGEST_LENGTH + 1, msk_emsk, - /* it's bits, ((64 + 64) * 8) */ - 1024) != 0) { - DEBUG("key derivation function failed"); - goto finish; - } + eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH, (char const *)session_id, + SHA256_DIGEST_LENGTH + 1, msk_emsk, 1024); /* it's bits, ((64 + 64) * 8) */ memcpy(msk, msk_emsk, 64); memcpy(emsk, msk_emsk + 64, 64); - ret = 0; -finish: + HMAC_CTX_free(hmac_ctx); talloc_free(cruft); - HMAC_CTX_free(ctx); - return ret; + return 0; } - - - - Index: freeradius-server-3.0.19/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h =================================================================== --- freeradius-server-3.0.19.orig/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h +++ freeradius-server-3.0.19/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h @@ -104,16 +104,16 @@ typedef struct _pwd_session_t { uint8_t my_confirm[SHA256_DIGEST_LENGTH]; } pwd_session_t; -int compute_password_element(pwd_session_t *sess, uint16_t grp_num, +int compute_password_element(REQUEST *request, pwd_session_t *sess, uint16_t grp_num, char const *password, int password_len, char const *id_server, int id_server_len, char const *id_peer, int id_peer_len, uint32_t *token); -int compute_scalar_element(pwd_session_t *sess, BN_CTX *bnctx); -int process_peer_commit (pwd_session_t *sess, uint8_t *in, size_t in_len, BN_CTX *bnctx); -int compute_server_confirm(pwd_session_t *sess, uint8_t *out, BN_CTX *bnctx); -int compute_peer_confirm(pwd_session_t *sess, uint8_t *out, BN_CTX *bnctx); -int compute_keys(pwd_session_t *sess, uint8_t *peer_confirm, +int compute_scalar_element(REQUEST *request, pwd_session_t *sess, BN_CTX *bnctx); +int process_peer_commit(REQUEST *request, pwd_session_t *sess, uint8_t *in, size_t in_len, BN_CTX *bnctx); +int compute_server_confirm(REQUEST *request, pwd_session_t *sess, uint8_t *out, BN_CTX *bnctx); +int compute_peer_confirm(REQUEST *request, pwd_session_t *sess, uint8_t *out, BN_CTX *bnctx); +int compute_keys(REQUEST *request, pwd_session_t *sess, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk); #ifdef PRINTBUF void print_buf(char *str, uint8_t *buf, int len); Index: freeradius-server-3.0.19/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c =================================================================== --- freeradius-server-3.0.19.orig/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c +++ freeradius-server-3.0.19/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c @@ -479,7 +479,7 @@ static int mod_process(void *arg, eap_ha return 0; } - if (compute_password_element(session, session->group_num, + if (compute_password_element(request, session, session->group_num, pw->data.strvalue, strlen(pw->data.strvalue), inst->server_id, strlen(inst->server_id), session->peer_id, strlen(session->peer_id), @@ -493,7 +493,7 @@ static int mod_process(void *arg, eap_ha /* * compute our scalar and element */ - if (compute_scalar_element(session, session->bnctx)) { + if (compute_scalar_element(request, session, session->bnctx)) { DEBUG2("failed to compute server's scalar and element"); return 0; } @@ -549,7 +549,7 @@ static int mod_process(void *arg, eap_ha /* * process the peer's commit and generate the shared key, k */ - if (process_peer_commit(session, in, in_len, session->bnctx)) { + if (process_peer_commit(request, session, in, in_len, session->bnctx)) { RDEBUG2("failed to process peer's commit"); return 0; } @@ -557,7 +557,7 @@ static int mod_process(void *arg, eap_ha /* * compute our confirm blob */ - if (compute_server_confirm(session, session->my_confirm, session->bnctx)) { + if (compute_server_confirm(request, session, session->my_confirm, session->bnctx)) { ERROR("rlm_eap_pwd: failed to compute confirm!"); return 0; } @@ -588,7 +588,7 @@ static int mod_process(void *arg, eap_ha RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } - if (compute_peer_confirm(session, peer_confirm, session->bnctx)) { + if (compute_peer_confirm(request, session, peer_confirm, session->bnctx)) { RDEBUG2("pwd exchange cannot compute peer's confirm"); return 0; } @@ -596,7 +596,7 @@ static int mod_process(void *arg, eap_ha RDEBUG2("pwd exchange fails: peer confirm is incorrect!"); return 0; } - if (compute_keys(session, peer_confirm, msk, emsk)) { + if (compute_keys(request, session, peer_confirm, msk, emsk)) { RDEBUG2("pwd exchange cannot generate (E)MSK!"); return 0; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor