1159 lines
39 KiB
Diff
1159 lines
39 KiB
Diff
From: Markus Koschany <apo@debian.org>
|
|
Date: Thu, 23 Feb 2023 13:46:09 +0100
|
|
Subject: CVE-2022-41859 part2
|
|
|
|
Origin: https://github.com/FreeRADIUS/freeradius-server/commit/9e5e8f2f912ad2da8ac6e176ac3a606333469937
|
|
---
|
|
src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c | 776 +++++++++++++++---------
|
|
1 file changed, 482 insertions(+), 294 deletions(-)
|
|
|
|
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c
|
|
index d94851c..5b11a33 100644
|
|
--- a/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c
|
|
+++ b/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
|
|
@@ -35,94 +33,228 @@ RCSID("$Id: ae311d50658c4dd72e52a1daa19d87f1faade114 $")
|
|
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);
|
|
+}
|
|
|
|
- memset(allzero, 0, SHA256_DIGEST_LENGTH);
|
|
+/* 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;
|
|
|
|
- HMAC_Init_ex(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL);
|
|
+ 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;
|
|
+ }
|
|
+
|
|
+ HMAC_CTX_free(hmac_ctx);
|
|
}
|
|
|
|
-static void H_Update(HMAC_CTX *ctx, uint8_t const *data, int len)
|
|
+static BIGNUM *consttime_BN (void)
|
|
{
|
|
- HMAC_Update(ctx, data, len);
|
|
+ BIGNUM *bn;
|
|
+
|
|
+ bn = BN_new();
|
|
+ if (bn) BN_set_flags(bn, BN_FLG_CONSTTIME);
|
|
+ return bn;
|
|
}
|
|
|
|
-static void H_Final(HMAC_CTX *ctx, uint8_t *digest)
|
|
+/*
|
|
+ * compute the legendre symbol in constant time
|
|
+ */
|
|
+static int legendre(BIGNUM *a, BIGNUM *p, BN_CTX *bnctx)
|
|
{
|
|
- unsigned int mdlen = SHA256_DIGEST_LENGTH;
|
|
+ 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;
|
|
+ }
|
|
|
|
- HMAC_Final(ctx, digest, &mdlen);
|
|
+ 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;
|
|
}
|
|
|
|
-/* 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 void do_equation(EC_GROUP *group, BIGNUM *y2, BIGNUM *x, 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;
|
|
+ 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);
|
|
|
|
- hctx = HMAC_CTX_new();
|
|
- if (hctx == NULL) {
|
|
- DEBUG("failed allocating HMAC context");
|
|
- return -1;
|
|
+ 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;
|
|
+}
|
|
+
|
|
+static int is_quadratic_residue(BIGNUM *val, BIGNUM *p, BIGNUM *qr, BIGNUM *qnr, BN_CTX *bnctx)
|
|
+{
|
|
+ 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;
|
|
+
|
|
+ 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 +291,23 @@ int compute_password_element (pwd_session_t *session, uint16_t grp_num,
|
|
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 +317,80 @@ int compute_password_element (pwd_session_t *session, uint16_t grp_num,
|
|
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));
|
|
+
|
|
+ {
|
|
+ size_t mdlen = SHA256_DIGEST_LENGTH;
|
|
+
|
|
+ EVP_DigestSignFinal(hmac_ctx, pwe_digest, &mdlen);
|
|
+ EVP_MD_CTX_reset(hmac_ctx);
|
|
+ }
|
|
|
|
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;
|
|
- }
|
|
+ eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH, "EAP-pwd Hunting And Pecking",
|
|
+ strlen("EAP-pwd Hunting And Pecking"), prfbuf, primebitlen);
|
|
|
|
- BN_bin2bn(prfbuf, primebytelen, x_candidate);
|
|
/*
|
|
* 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 +398,86 @@ int compute_password_element (pwd_session_t *session, uint16_t grp_num,
|
|
* 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 +487,89 @@ int compute_password_element (pwd_session_t *session, uint16_t grp_num,
|
|
}
|
|
|
|
/* 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 +581,7 @@ int process_peer_commit (pwd_session_t *session, uint8_t *in, size_t in_len, BN_
|
|
* 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 +597,54 @@ int process_peer_commit (pwd_session_t *session, uint8_t *in, size_t in_len, BN_
|
|
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 +656,15 @@ int process_peer_commit (pwd_session_t *session, uint8_t *in, size_t in_len, BN_
|
|
* 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 +673,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 +705,24 @@ int compute_server_confirm (pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
|
|
*/
|
|
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 +730,25 @@ int compute_server_confirm (pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
|
|
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 +756,46 @@ int compute_server_confirm (pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
|
|
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 +805,25 @@ int compute_peer_confirm (pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
|
|
*/
|
|
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 +831,24 @@ int compute_peer_confirm (pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
|
|
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 +856,75 @@ int compute_peer_confirm (pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
|
|
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;
|
|
-
|
|
- ctx = HMAC_CTX_new();
|
|
- if (ctx == NULL) {
|
|
- DEBUG2("pwd: unable to allocate HMAC context!");
|
|
- goto finish;
|
|
- }
|
|
+ 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;
|
|
|
|
- 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;
|
|
}
|
|
-
|
|
-
|
|
-
|
|
-
|