]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
merge constant time fixes from "master"
authorAlan T. DeKok <aland@freeradius.org>
Fri, 17 Jul 2020 12:37:08 +0000 (08:37 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 17 Jul 2020 12:37:08 +0000 (08:37 -0400)
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

src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c
src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h
src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c

diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h b/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h
new file mode 100644 (file)
index 0000000..b717dd5
--- /dev/null
@@ -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 d94851c3aa0fc31db9be2d01a4fb94c1a6c81e00..17a0bb462f89654c9dbb0608981788f9c35aad04 100644 (file)
@@ -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
  * 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$")
 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;
+
+       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(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL);
+               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;
 
-       hctx = HMAC_CTX_new();
-       if (hctx == NULL) {
-               DEBUG("failed allocating HMAC context");
-               return -1;
+       tmp1 = BN_new();
+       pm1 = BN_new();
+       p = BN_new();
+       a = BN_new();
+       b = BN_new();
+       EC_GROUP_get_curve_GFp(group, p, a, b, bnctx);
+
+       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;
+       BIGNUM *x_candidate = NULL, *rnd = NULL, *y_sqrd = NULL, *qr = NULL, *qnr = NULL;
        HMAC_CTX *ctx = NULL;
-       uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
-       int nid, is_odd, primebitlen, primebytelen, ret = 0;
+       uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, *xbuf = NULL, *pm1buf = 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;
 
        ctx = HMAC_CTX_new();
        if (ctx == NULL) {
@@ -159,12 +295,14 @@ 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)) {
                DEBUG("unable to create bignums");
                goto fail;
        }
@@ -179,46 +317,61 @@ 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;
+       }
+
+       /*
+       * 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);
+               HMAC_Init_ex(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(),NULL);
+               HMAC_Update(ctx, (uint8_t *)token, sizeof(*token));
+               HMAC_Update(ctx, (uint8_t const *)id_peer, id_peer_len);
+               HMAC_Update(ctx, (uint8_t const *)id_server, id_server_len);
+               HMAC_Update(ctx, (uint8_t const *)password, password_len);
+               HMAC_Update(ctx, (uint8_t *)&ctr, sizeof(ctr));
+               pwd_hmac_final(ctx, pwe_digest);
 
                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 +379,73 @@ 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...
-                */
+               * 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);
+
+               /*
+               * need to unambiguously identify the solution, if there is
+               * one..
+               */
                is_odd = BN_is_odd(rnd) ? 1 : 0;
 
                /*
-                * 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;
-               }
+               * 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 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;
-               }
+               * if the candidate >= prime then we want to skip it
+               */
+               qr_or_qnr = const_time_select(skip, 0, qr_or_qnr);
 
-               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 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);
 
-                       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;
+               /*
+               * 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);
+       if (!EC_POINT_set_compressed_coordinates_GFp(session->group, session->pwe,
+                                                    x_candidate, save_is_odd, NULL)) {
+               goto fail;
        }
 
        session->group_num = grp_num;
@@ -278,78 +455,81 @@ 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);
+
+       if (prfbuf) talloc_free(prfbuf);
+       if (xbuf) talloc_free(xbuf);
+       if (pm1buf) talloc_free(pm1buf);
+
        HMAC_CTX_free(ctx);
 
        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 +541,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 +557,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_GFp(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 +616,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_GFp(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 +633,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 +665,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_GFp(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 +690,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_GFp(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 +716,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 +765,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_GFp(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 +791,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_GFp(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 +816,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;
 }
-
-
-
-
index ca12778f612c2f5b1c41f66a1705072d3257c46e..8c5d55b4ce37008914a93dc4b5b6dcc8ecf18eee 100644 (file)
@@ -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 18ab97f1485ab354b2d8caeb2c5d8276ed548355..b3930a457e7ee5b9214c69f57552e77618cd920f 100644 (file)
@@ -473,7 +473,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
                        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),
@@ -487,7 +487,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
                /*
                 * 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;
                }
@@ -543,7 +543,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
                /*
                 * 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;
                }
@@ -551,7 +551,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
                /*
                 * 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;
                }
@@ -582,7 +582,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
                        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;
                }
@@ -590,7 +590,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
                        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;
                }