commit 6f0e0aca4f4e614eea4ce10e226aed73ed4ab68b
Author: Alan T. DeKok <aland@freeradius.org>
Date:   Fri Jul 17 08:37:08 2020 -0400

    merge constant time fixes from "master"
    
    Based on a patch from Daniel De Almeida Braga.
    
    The code is now largely the same between master and v3.0.x,
    which makes it easier to see that it's correct

commit d3d3aa67213159f5bca5e72e609f4859e47ddb1b
Author: Alan T. DeKok <aland@freeradius.org>
Date:   Fri Jul 17 08:53:41 2020 -0400

    not available in older versions of OpenSSL

commit 1df6f266231816171d2662eacf0e528b8ad1d7d8
Author: Alan T. DeKok <aland@freeradius.org>
Date:   Sun Dec 26 12:02:30 2021 -0500

    switch to non-deprecated API

commit 9e5e8f2f912ad2da8ac6e176ac3a606333469937
Author: Alan T. DeKok <aland@freeradius.org>
Date:   Fri Feb 4 09:36:26 2022 -0500

    port fixes from master
    
    via the simple expedient of copying the entire function, with
    some minor changes to work in v3

Index: freeradius-server-3.0.3/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h
===================================================================
--- /dev/null
+++ freeradius-server-3.0.3/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h
@@ -0,0 +1,190 @@
+/*
+ * Helper functions for constant time operations
+ * Copyright (c) 2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * These helper functions can be used to implement logic that needs to minimize
+ * externally visible differences in execution path by avoiding use of branches,
+ * avoiding early termination or other time differences, and forcing same memory
+ * access pattern regardless of values.
+ */
+
+#ifndef CONST_TIME_H
+#define CONST_TIME_H
+
+
+#if defined(__clang__)
+#define NO_UBSAN_UINT_OVERFLOW                                        \
+	__attribute__((no_sanitize("unsigned-integer-overflow")))
+#else
+#define NO_UBSAN_UINT_OVERFLOW
+#endif
+
+/**
+ * const_time_fill_msb - Fill all bits with MSB value
+ * @param	val Input value
+ * @return	Value with all the bits set to the MSB of the input val
+ */
+static inline unsigned int const_time_fill_msb(unsigned int val)
+{
+	/* Move the MSB to LSB and multiple by -1 to fill in all bits. */
+	return (val >> (sizeof(val) * 8 - 1)) * ~0U;
+}
+
+
+/* @return	-1 if val is zero; 0 if val is not zero */
+static inline unsigned int const_time_is_zero(unsigned int val)
+	NO_UBSAN_UINT_OVERFLOW
+{
+	/* Set MSB to 1 for 0 and fill rest of bits with the MSB value */
+	return const_time_fill_msb(~val & (val - 1));
+}
+
+
+/* @return	-1 if a == b; 0 if a != b */
+static inline unsigned int const_time_eq(unsigned int a, unsigned int b)
+{
+	return const_time_is_zero(a ^ b);
+}
+
+
+/* @return	-1 if a == b; 0 if a != b */
+static inline unsigned char const_time_eq_u8(unsigned int a, unsigned int b)
+{
+	return (unsigned char) const_time_eq(a, b);
+}
+
+
+/**
+ * const_time_eq_bin - Constant time memory comparison
+ * @param	a First buffer to compare
+ * @param	b Second buffer to compare
+ * @param	len Number of octets to compare
+ * @return	-1 if buffers are equal, 0 if not
+ *
+ * This function is meant for comparing passwords or hash values where
+ * difference in execution time or memory access pattern could provide external
+ * observer information about the location of the difference in the memory
+ * buffers. The return value does not behave like memcmp(), i.e.,
+ * const_time_eq_bin() cannot be used to sort items into a defined order. Unlike
+ * memcmp(), the execution time of const_time_eq_bin() does not depend on the
+ * contents of the compared memory buffers, but only on the total compared
+ * length.
+ */
+static inline unsigned int const_time_eq_bin(const void *a, const void *b,
+					     size_t len)
+{
+	const unsigned char *aa = a;
+	const unsigned char *bb = b;
+	size_t i;
+	unsigned char res = 0;
+
+	for (i = 0; i < len; i++)
+		res |= aa[i] ^ bb[i];
+
+	return const_time_is_zero(res);
+}
+
+
+/**
+ * const_time_select - Constant time unsigned int selection
+ * @param	mask 0 (false) or -1 (true) to identify which value to select
+ * @param	true_val Value to select for the true case
+ * @param	false_val Value to select for the false case
+ * @return	true_val if mask == -1, false_val if mask == 0
+ */
+static inline unsigned int const_time_select(unsigned int mask,
+					     unsigned int true_val,
+					     unsigned int false_val)
+{
+	return (mask & true_val) | (~mask & false_val);
+}
+
+
+/**
+ * const_time_select_int - Constant time int selection
+ * @param	mask 0 (false) or -1 (true) to identify which value to select
+ * @param	true_val Value to select for the true case
+ * @param	false_val Value to select for the false case
+ * @return	true_val if mask == -1, false_val if mask == 0
+ */
+static inline int const_time_select_int(unsigned int mask, int true_val,
+					int false_val)
+{
+	return (int) const_time_select(mask, (unsigned int) true_val,
+				       (unsigned int) false_val);
+}
+
+
+/**
+ * const_time_select_u8 - Constant time u8 selection
+ * @param	mask 0 (false) or -1 (true) to identify which value to select
+ * @param	true_val Value to select for the true case
+ * @param	false_val Value to select for the false case
+ * @return	true_val if mask == -1, false_val if mask == 0
+ */
+static inline unsigned char const_time_select_u8(unsigned char mask, unsigned char true_val, unsigned char false_val)
+{
+	return (unsigned char) const_time_select(mask, true_val, false_val);
+}
+
+
+/**
+ * const_time_select_s8 - Constant time s8 selection
+ * @param	mask 0 (false) or -1 (true) to identify which value to select
+ * @param	true_val Value to select for the true case
+ * @param	false_val Value to select for the false case
+ * @return	true_val if mask == -1, false_val if mask == 0
+ */
+static inline char const_time_select_s8(char mask, char true_val, char false_val)
+{
+	return (char) const_time_select(mask, (unsigned int) true_val,
+				      (unsigned int) false_val);
+}
+
+
+/**
+ * const_time_select_bin - Constant time binary buffer selection copy
+ * @param	mask 0 (false) or -1 (true) to identify which value to copy
+ * @param	true_val Buffer to copy for the true case
+ * @param	false_val Buffer to copy for the false case
+ * @param	len Number of octets to copy
+ * @param	dst Destination buffer for the copy
+ *
+ * This function copies the specified buffer into the destination buffer using
+ * operations with identical memory access pattern regardless of which buffer
+ * is being copied.
+ */
+static inline void const_time_select_bin(unsigned char mask, const unsigned char *true_val,
+					 const unsigned char *false_val, size_t len,
+					 unsigned char *dst)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++)
+		dst[i] = const_time_select_u8(mask, true_val[i], false_val[i]);
+}
+
+
+static inline int const_time_memcmp(const void *a, const void *b, size_t len)
+{
+	const unsigned char *aa = a;
+	const unsigned char *bb = b;
+	int diff, res = 0;
+	unsigned int mask;
+
+	if (len == 0)
+		return 0;
+	do {
+		len--;
+		diff = (int) aa[len] - (int) bb[len];
+		mask = const_time_is_zero((unsigned int) diff);
+		res = const_time_select_int(mask, res, diff);
+	} while (len);
+
+	return res;
+}
+
+#endif /* CONST_TIME_H */
Index: freeradius-server-3.0.3/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c
===================================================================
--- freeradius-server-3.0.3.orig/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c
+++ freeradius-server-3.0.3/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,9 +33,9 @@ RCSID("$Id: 0b8783073732b9be5442524f6a4a
 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
@@ -59,63 +57,230 @@ static void
 H_Final(HMAC_CTX *ctx, uint8_t *digest)
 {
     unsigned int mdlen = SHA256_DIGEST_LENGTH;
-
+    
     HMAC_Final(ctx, digest, &mdlen);
     HMAC_CTX_cleanup(ctx);
 }
 
-/* a counter-based KDF based on NIST SP800-108 */
 static void
-eap_pwd_kdf(uint8_t *key, int keylen, char const *label, int labellen,
-	    uint8_t *result, int resultbitlen)
+pwd_hmac_final(HMAC_CTX *hmac_ctx, uint8_t *digest)
 {
-    HMAC_CTX hctx;
-    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;
+       unsigned int mdlen = SHA256_DIGEST_LENGTH;
+       HMAC_Final(hmac_ctx, digest, &mdlen);
+//     HMAC_CTX_reset(hmac_ctx);
+}
 
-    resultbytelen = (resultbitlen + 7)/8;
-    ctr = 0;
-    L = htons(resultbitlen);
-    while (len < resultbytelen) {
-	ctr++; i = htons(ctr);
-	HMAC_Init(&hctx, key, keylen, EVP_sha256());
-	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;
-	HMAC_CTX_cleanup(&hctx);
-    }
-
-    /* since we're expanding to a bit length, mask off the excess */
-    if (resultbitlen % 8) {
-	mask <<= (8 - (resultbitlen % 8));
-	result[resultbytelen - 1] &= mask;
-    }
+/* 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;
+
+       H_Init(&hmac_ctx);
+       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_cleanup(&hmac_ctx);
+}
+
+static BIGNUM *consttime_BN (void)
+{
+       BIGNUM *bn;
+
+       bn = BN_new();
+       if (bn) BN_set_flags(bn, BN_FLG_CONSTTIME);
+       return bn;
+}
+
+/*
+ * compute the legendre symbol in constant time
+ */
+static int legendre(BIGNUM *a, BIGNUM *p, BN_CTX *bnctx)
+{
+       int             symbol;
+       unsigned int    mask;
+       BIGNUM          *res, *pm1over2;
+
+       pm1over2 = consttime_BN();
+       res = consttime_BN();
+
+       if (!BN_sub(pm1over2, p, BN_value_one()) ||
+           !BN_rshift1(pm1over2, pm1over2) ||
+           !BN_mod_exp_mont_consttime(res, a, pm1over2, p, bnctx, NULL)) {
+               BN_free(pm1over2);
+               BN_free(res);
+               return -2;
+       }
+
+       symbol = -1;
+       mask = const_time_eq(BN_is_word(res, 1), 1);
+       symbol = const_time_select_int(mask, 1, symbol);
+       mask = const_time_eq(BN_is_zero(res), 1);
+       symbol = const_time_select_int(mask, -1, symbol);
+
+       BN_free(pm1over2);
+       BN_free(res);
+
+       return symbol;
+}
+
+static void do_equation(EC_GROUP *group, BIGNUM *y2, BIGNUM *x, BN_CTX *bnctx)
+{
+       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_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;
+       }
+
+       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;
+       }
+
+       /*
+        * 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);
+
+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 *sess, uint16_t grp_num,
+compute_password_element (REQUEST *request, pwd_session_t *sess, uint16_t grp_num,
 			  char const *password, int password_len,
 			  char *id_server, int id_server_len,
 			  char *id_peer, int id_peer_len,
 			  uint32_t *token)
 {
-    BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
-    HMAC_CTX ctx;
-    uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
-    int nid, is_odd, primebitlen, primebytelen, ret = 0;
+       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_create());
+       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:
@@ -147,12 +312,18 @@ compute_password_element (pwd_session_t
 	goto fail;
     }
 
-    if (((rnd = BN_new()) == NULL) ||
-	((cofactor = BN_new()) == NULL) ||
-	((sess->pwe = EC_POINT_new(sess->group)) == NULL) ||
-	((sess->order = BN_new()) == NULL) ||
-	((sess->prime = BN_new()) == NULL) ||
-	((x_candidate = BN_new()) == NULL)) {
+       if (((rnd = consttime_BN()) == NULL) ||
+           ((sess->pwe = EC_POINT_new(sess->group)) == NULL) ||
+           ((sess->order = consttime_BN()) == NULL) ||
+           ((sess->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;
     }
@@ -166,22 +337,55 @@ compute_password_element (pwd_session_t
 	DEBUG("unable to get order for curve");
 	goto fail;
     }
-    if (!EC_GROUP_get_cofactor(sess->group, cofactor, NULL)) {
-	DEBUG("unable to get cofactor for curve");
-	goto fail;
-    }
     primebitlen = BN_num_bits(sess->prime);
     primebytelen = BN_num_bytes(sess->prime);
     if ((prfbuf = talloc_zero_array(sess, 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, sess->prime);
+       } while (legendre(qr, sess->prime, sess->bnctx) != 1);
+
+       do {
+               BN_rand_range(qnr, sess->prime);
+       } while (legendre(qnr, sess->prime, sess->bnctx) != -1);
+
+       if (!BN_sub(rnd, sess->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++;
 
 	/*
@@ -189,21 +393,25 @@ compute_password_element (pwd_session_t
 	 *    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 *)id_peer, id_peer_len);
-	H_Update(&ctx, (uint8_t *)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);
-
-	BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd);
-	eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH,
-		    "EAP-pwd Hunting And Pecking",
-		    strlen("EAP-pwd Hunting And Pecking"),
-		    prfbuf, primebitlen);
+               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);
+               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
@@ -211,253 +419,290 @@ compute_password_element (pwd_session_t
 	 * 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, sess->prime) >= 0) {
-	    continue;
-	}
-	/*
-	 * need to unambiguously identify the solution, if there is
-	 * one...
-	 */
-	if (BN_is_odd(rnd)) {
-	    is_odd = 1;
-	} else {
-	    is_odd = 0;
-	}
-	/*
-	 * solve the quadratic equation, if it's not solvable then we
-	 * don't have a point
-	 */
-	if (!EC_POINT_set_compressed_coordinates_GFp(sess->group,
-						     sess->pwe,
-						     x_candidate,
-						     is_odd, NULL)) {
-	    continue;
-	}
-	/*
-	 * 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(sess->group, sess->pwe, NULL)) {
-	    DEBUG("EAP-pwd: point is not on curve");
-	    continue;
-	}
-
-	if (BN_cmp(cofactor, BN_value_one())) {
-	    /* make sure the point is not in a small sub-group */
-	    if (!EC_POINT_mul(sess->group, sess->pwe, NULL, sess->pwe,
-			      cofactor, NULL)) {
-		DEBUG("EAP-pwd: cannot multiply generator by order");
-		continue;
-	    }
-	    if (EC_POINT_is_at_infinity(sess->group, sess->pwe)) {
-		DEBUG("EAP-pwd: point is at infinity");
-		continue;
-	    }
-	}
-	/* if we got here then we have a new generator. */
-	break;
-    }
+               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);
+
+               /* 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);
+
+               /* 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(sess->group, y_sqrd, x_candidate, sess->bnctx);
+               qr_or_qnr = is_quadratic_residue(y_sqrd, sess->prime, qr, qnr, sess->bnctx);
+
+               /*
+               * if the candidate >= prime then we want to skip it
+               */
+               qr_or_qnr = const_time_select(skip, 0, qr_or_qnr);
+
+               /*
+               * 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(sess->group, y_sqrd, x_candidate, sess->bnctx);
+       if ( !BN_add(exp, sess->prime, BN_value_one()) ||
+                !BN_rshift(exp, exp, 2) ||
+                !BN_mod_exp_mont_consttime(y1, y_sqrd, exp, sess->prime, sess->bnctx, NULL) ||
+                !BN_sub(y2, sess->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_GFp(sess->group, sess->pwe, x_candidate, y, sess->bnctx)) {
+               DEBUG("unable to set point coordinate");
+               goto fail;
+        }
+
     sess->group_num = grp_num;
     if (0) {
 fail:				/* DON'T free sess, it's in handler->opaque */
 	ret = -1;
     }
-    /* cleanliness and order.... */
-    BN_free(cofactor);
-    BN_free(x_candidate);
-    BN_free(rnd);
-    talloc_free(prfbuf);
 
-    return ret;
+        /* cleanliness and order.... */
+        BN_clear_free(x_candidate);
+       BN_clear_free(y_sqrd);
+       BN_clear_free(qr);
+       BN_clear_free(qnr);
+        BN_clear_free(rnd);
+       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_destroy(hmac_ctx);
+       EVP_PKEY_free(hmac_pkey);
+ 
+       return ret;
 }
 
 int
-compute_scalar_element (pwd_session_t *sess, BN_CTX *bnctx)
+compute_scalar_element (REQUEST *request, pwd_session_t *session, BN_CTX *bn_ctx)
 {
-    BIGNUM *mask = NULL;
-    int ret = -1;
-
-    if (((sess->private_value = BN_new()) == NULL) ||
-	((sess->my_element = EC_POINT_new(sess->group)) == NULL) ||
-	((sess->my_scalar = BN_new()) == NULL) ||
-	((mask = BN_new()) == NULL)) {
-	DEBUG2("server scalar allocation failed");
-	goto fail;
-    }
-
-    BN_rand_range(sess->private_value, sess->order);
-    BN_rand_range(mask, sess->order);
-    BN_add(sess->my_scalar, sess->private_value, mask);
-    BN_mod(sess->my_scalar, sess->my_scalar, sess->order,
-	   bnctx);
-
-    if (!EC_POINT_mul(sess->group, sess->my_element, NULL,
-		      sess->pwe, mask, bnctx)) {
-	DEBUG2("server element allocation failed");
-	goto fail;
-    }
-
-    if (!EC_POINT_invert(sess->group, sess->my_element, bnctx)) {
-	DEBUG2("server element inversion failed");
-	goto fail;
-    }
-
-    ret = 0;
-fail:
-    BN_free(mask);
-
-    return ret;
+        BIGNUM *mask = NULL;
+        int ret = -1;
+ 
+       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) {
+               REDEBUG("Unable to get randomness for private_value");
+               goto error;
+        }
+        if (BN_rand_range(mask, session->order) != 1) {
+               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, bn_ctx);
+ 
+       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, bn_ctx)) {
+               REDEBUG("Server element inversion failed");
+               goto error;
+        }
+ 
+        ret = 0;
+ 
+error:
+        BN_clear_free(mask);
+ 
+        return ret;
 }
 
 int
-process_peer_commit (pwd_session_t *sess, uint8_t *commit, BN_CTX *bnctx)
-{
-    uint8_t *ptr;
-    BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
-    EC_POINT *K = NULL, *point = NULL;
-    int res = 1;
-
-    if (((sess->peer_scalar = BN_new()) == NULL) ||
-	((sess->k = BN_new()) == NULL) ||
-	((cofactor = BN_new()) == NULL) ||
-	((x = BN_new()) == NULL) ||
-	((y = BN_new()) == NULL) ||
-	((point = EC_POINT_new(sess->group)) == NULL) ||
-	((K = EC_POINT_new(sess->group)) == NULL) ||
-	((sess->peer_element = EC_POINT_new(sess->group)) == NULL)) {
-	DEBUG2("pwd: failed to allocate room to process peer's commit");
-	goto fin;
-    }
-
-    if (!EC_GROUP_get_cofactor(sess->group, cofactor, NULL)) {
-	DEBUG2("pwd: unable to get group co-factor");
-	goto fin;
-    }
-
-    /* element, x then y, followed by scalar */
-    ptr = (uint8_t *)commit;
-    BN_bin2bn(ptr, BN_num_bytes(sess->prime), x);
-    ptr += BN_num_bytes(sess->prime);
-    BN_bin2bn(ptr, BN_num_bytes(sess->prime), y);
-    ptr += BN_num_bytes(sess->prime);
-    BN_bin2bn(ptr, BN_num_bytes(sess->order), sess->peer_scalar);
-
-    /* validate received scalar */
-    if (BN_is_zero(sess->peer_scalar) ||
-        BN_is_one(sess->peer_scalar) ||
-        BN_cmp(sess->peer_scalar, sess->order) >= 0) {
-            ERROR("Peer's scalar is not within the allowed range");
-            goto fin;
-    }
-
-    if (!EC_POINT_set_affine_coordinates_GFp(sess->group,
-					     sess->peer_element, x, y,
-					     bnctx)) {
-	DEBUG2("pwd: unable to get coordinates of peer's element");
-	goto fin;
-    }
-
-    /* validate received element */
-    if (!EC_POINT_is_on_curve(sess->group, sess->peer_element, bnctx) ||
-        EC_POINT_is_at_infinity(sess->group, sess->peer_element)) {
-           ERROR("Peer's element is not a point on the elliptic curve");
-           goto fin;
-    }
-
-    /* check to ensure peer's element is not in a small sub-group */
-    if (BN_cmp(cofactor, BN_value_one())) {
-	if (!EC_POINT_mul(sess->group, point, NULL,
-			  sess->peer_element, cofactor, NULL)) {
-	    DEBUG2("pwd: unable to multiply element by co-factor");
-	    goto fin;
-	}
-	if (EC_POINT_is_at_infinity(sess->group, point)) {
-	    DEBUG2("pwd: peer's element is in small sub-group");
-	    goto fin;
-	}
-    }
-
-    /* detect reflection attacks */
-    if (BN_cmp(sess->peer_scalar, sess->my_scalar) == 0 ||
-        EC_POINT_cmp(sess->group, sess->peer_element, sess->my_element, bnctx) == 0) {
-            ERROR("Reflection attack detected");
-            goto fin;
-    }
-
-    /* compute the shared key, k */
-    if ((!EC_POINT_mul(sess->group, K, NULL, sess->pwe,
-		       sess->peer_scalar, bnctx)) ||
-	(!EC_POINT_add(sess->group, K, K, sess->peer_element,
-		       bnctx)) ||
-	(!EC_POINT_mul(sess->group, K, NULL, K, sess->private_value,
-		       bnctx))) {
-	DEBUG2("pwd: unable to compute shared key, k");
-	goto fin;
-    }
-
-    /* ensure that the shared key isn't in a small sub-group */
-    if (BN_cmp(cofactor, BN_value_one())) {
-	if (!EC_POINT_mul(sess->group, K, NULL, K, cofactor,
-			  NULL)) {
-	    DEBUG2("pwd: unable to multiply k by co-factor");
-	    goto fin;
-	}
-    }
-
-    /*
-     * This check is strictly speaking just for the case above where
-     * co-factor > 1 but it was suggested that even though this is probably
-     * never going to happen it is a simple and safe check "just to be
-     * sure" so let's be safe.
-     */
-    if (EC_POINT_is_at_infinity(sess->group, K)) {
-	DEBUG2("pwd: k is point-at-infinity!");
-	goto fin;
-    }
-    if (!EC_POINT_get_affine_coordinates_GFp(sess->group, K, sess->k,
-					     NULL, bnctx)) {
-	DEBUG2("pwd: unable to get shared secret from K");
-	goto fin;
-    }
-    res = 0;
-
-  fin:
-    EC_POINT_free(K);
-    EC_POINT_free(point);
-    BN_free(cofactor);
-    BN_free(x);
-    BN_free(y);
+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             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)) {
+               REDEBUG("Unable to get group co-factor");
+                goto finish;
+        }   
+ 
+        /* element, x then y, followed by scalar */
+        ptr = (uint8_t *)in;
+        data_len = BN_num_bytes(session->prime);
+
+        /*
+         *      Did the peer send enough data?
+         */
+        if (in_len < (2 * data_len + BN_num_bytes(session->order))) {
+                REDEBUG("Invalid commit packet");
+                goto finish;
+        }
+
+        BN_bin2bn(ptr, data_len, x);
+        ptr += data_len;
+        BN_bin2bn(ptr, data_len, y);
+        ptr += data_len;
+
+        data_len = BN_num_bytes(session->order);
+        BN_bin2bn(ptr, data_len, session->peer_scalar);
+
+        /* validate received element */
+        if (!EC_POINT_is_on_curve(session->group, session->peer_element, bn_ctx) ||
+            EC_POINT_is_at_infinity(session->group, session->peer_element)) {
+                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)) {
+                        REDEBUG("Unable to multiply element by co-factor");
+                        goto finish;
+                }
+
+                if (EC_POINT_is_at_infinity(session->group, point)) {
+                        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, 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, 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)) {
+                        REDEBUG("Unable to multiply k by co-factor");
+                        goto finish;
+                }
+        }
+
+        /*
+         * This check is strictly speaking just for the case above where
+         * co-factor > 1 but it was suggested that even though this is probably
+         * never going to happen it is a simple and safe check "just to be
+         * sure" so let's be safe.
+         */
+        if (EC_POINT_is_at_infinity(session->group, K)) {
+                REDEBUG("K is point-at-infinity");
+                goto finish;
+        }
+
+        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;
+        }
+        ret = 0;
+
+finish:
+        EC_POINT_clear_free(K);
+        EC_POINT_clear_free(point);
+        BN_clear_free(cofactor);
+        BN_clear_free(x);
+        BN_clear_free(y);
 
-    return res;
+        return ret;
 }
 
 int
-compute_server_confirm (pwd_session_t *sess, uint8_t *buf, BN_CTX *bnctx)
+compute_server_confirm (REQUEST *request, pwd_session_t *sess, uint8_t *buf, BN_CTX *bnctx)
 {
     BIGNUM *x = NULL, *y = NULL;
-    HMAC_CTX ctx;
+    HMAC_CTX hmac_ctx;
     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(sess, uint8_t, BN_num_bytes(sess->prime))) == NULL) ||
-	((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
-	DEBUG2("pwd: unable to allocate space to compute confirm!");
-	goto fin;
-    }
-
-    /*
-     * commit is H(k | server_element | server_scalar | peer_element |
-     *	       peer_scalar | ciphersuite)
-     */
-    H_Init(&ctx);
+        /*
+         * Each component of the cruft will be at most as big as the prime
+         */
+       MEM(cruft = talloc_zero_array(sess, uint8_t, BN_num_bytes(sess->prime)));
+       MEM(x = BN_new());
+       MEM(y = BN_new());
+
+ 
+        /*
+         * commit is H(k | server_element | server_scalar | peer_element |
+         *             peer_scalar | ciphersuite)
+         */
+       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
@@ -467,26 +712,24 @@ compute_server_confirm (pwd_session_t *s
      */
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(sess->k);
     BN_bn2bin(sess->k, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
 
     /*
      * next is server element: x, y
      */
-    if (!EC_POINT_get_affine_coordinates_GFp(sess->group,
-					     sess->my_element, x, y,
-					     bnctx)) {
-	DEBUG2("pwd: unable to get coordinates of server element");
-	goto fin;
+   if (!EC_POINT_get_affine_coordinates_GFp(sess->group, sess->my_element, x, y, bnctx)) {
+       REDEBUG("Unable to get coordinates of server element");
+	goto finish;
     }
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(x);
     BN_bn2bin(x, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
 
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(y);
     BN_bn2bin(y, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
 
     /*
      * and server scalar
@@ -494,27 +737,25 @@ compute_server_confirm (pwd_session_t *s
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->my_scalar);
     BN_bn2bin(sess->my_scalar, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->order));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->order));
 
     /*
      * next is peer element: x, y
      */
-    if (!EC_POINT_get_affine_coordinates_GFp(sess->group,
-					     sess->peer_element, x, y,
-					     bnctx)) {
-	DEBUG2("pwd: unable to get coordinates of peer's element");
-	goto fin;
+       if (!EC_POINT_get_affine_coordinates_GFp(sess->group, sess->peer_element, x, y, bnctx)) {
+               REDEBUG("Unable to get coordinates of peer's element");
+	goto finish;
     }
 
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(x);
     BN_bn2bin(x, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
 
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(y);
     BN_bn2bin(y, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
 
     /*
      * and peer scalar
@@ -522,20 +763,19 @@ compute_server_confirm (pwd_session_t *s
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->peer_scalar);
     BN_bn2bin(sess->peer_scalar, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->order));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->order));
 
     /*
      * finally, ciphersuite
      */
-    H_Update(&ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
-
-    H_Final(&ctx, buf);
+       HMAC_Update(&hmac_ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
+ 
+       pwd_hmac_final(&hmac_ctx, buf);
 
     req = 0;
-fin:
-    if (cruft != NULL) {
-	    talloc_free(cruft);
-    }
+finish:
+    HMAC_CTX_cleanup(&hmac_ctx);
+    talloc_free(cruft);
     BN_free(x);
     BN_free(y);
 
@@ -543,27 +783,25 @@ fin:
 }
 
 int
-compute_peer_confirm (pwd_session_t *sess, uint8_t *buf, BN_CTX *bnctx)
+compute_peer_confirm(REQUEST *request, pwd_session_t *sess, uint8_t *out, BN_CTX *bn_ctx)
 {
     BIGNUM *x = NULL, *y = NULL;
-    HMAC_CTX ctx;
+    HMAC_CTX hmac_ctx;
     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(sess, uint8_t, BN_num_bytes(sess->prime))) == NULL) ||
-	((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
-	DEBUG2("pwd: unable to allocate space to compute confirm!");
-	goto fin;
-    }
+       MEM(cruft = talloc_zero_array(sess, uint8_t, BN_num_bytes(sess->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);
+       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
@@ -573,27 +811,25 @@ compute_peer_confirm (pwd_session_t *ses
      */
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(sess->k);
     BN_bn2bin(sess->k, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
 
     /*
      * then peer element: x, y
      */
-    if (!EC_POINT_get_affine_coordinates_GFp(sess->group,
-					     sess->peer_element, x, y,
-					     bnctx)) {
-	DEBUG2("pwd: unable to get coordinates of peer's element");
+       if (!EC_POINT_get_affine_coordinates_GFp(sess->group, sess->peer_element, x, y, bn_ctx)) {
+               REDEBUG("Unable to get coordinates of peer's element");
 	goto fin;
     }
 
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(x);
     BN_bn2bin(x, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
 
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(y);
     BN_bn2bin(y, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
 
     /*
      * and peer scalar
@@ -601,26 +837,24 @@ compute_peer_confirm (pwd_session_t *ses
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->peer_scalar);
     BN_bn2bin(sess->peer_scalar, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->order));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->order));
 
     /*
      * then server element: x, y
      */
-    if (!EC_POINT_get_affine_coordinates_GFp(sess->group,
-					     sess->my_element, x, y,
-					     bnctx)) {
-	DEBUG2("pwd: unable to get coordinates of server element");
+       if (!EC_POINT_get_affine_coordinates_GFp(sess->group, sess->my_element, x, y, bn_ctx)) {
+               REDEBUG("Unable to get coordinates of server element");
 	goto fin;
     }
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(x);
     BN_bn2bin(x, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
 
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(y);
     BN_bn2bin(y, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
 
     /*
      * and server scalar
@@ -628,17 +862,18 @@ compute_peer_confirm (pwd_session_t *ses
     memset(cruft, 0, BN_num_bytes(sess->prime));
     offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->my_scalar);
     BN_bn2bin(sess->my_scalar, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->order));
+    HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->order));
 
     /*
      * finally, ciphersuite
      */
-    H_Update(&ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
-
-    H_Final(&ctx, buf);
+       HMAC_Update(&hmac_ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
+    
+       pwd_hmac_final(&hmac_ctx, out);
 
     req = 0;
 fin:
+    HMAC_CTX_cleanup(&hmac_ctx);
     if (cruft != NULL) {
 	    talloc_free(cruft);
     }
@@ -649,62 +884,58 @@ fin:
 }
 
 int
-compute_keys (pwd_session_t *sess, uint8_t *peer_confirm,
+compute_keys (UNUSED REQUEST *request, pwd_session_t *sess, uint8_t *peer_confirm,
 	      uint8_t *msk, uint8_t *emsk)
 {
-    HMAC_CTX ctx;
+    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(sess, uint8_t, BN_num_bytes(sess->prime))) == NULL) {
-	DEBUG2("pwd: unable to allocate space to compute keys");
-	return -1;
-    }
-    /*
-     * first compute the session-id = TypeCode | H(ciphersuite | scal_p |
-     *	scal_s)
-     */
+       MEM(cruft = talloc_array(sess, uint8_t, BN_num_bytes(sess->prime)));
+    
+        /*
+         * 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 *)&sess->ciphersuite, sizeof(sess->ciphersuite));
+       HMAC_Init_ex(&hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL);
+       HMAC_Update(&hmac_ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
     offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->peer_scalar);
     memset(cruft, 0, BN_num_bytes(sess->prime));
     BN_bn2bin(sess->peer_scalar, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->order));
+       HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->order));
     offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->my_scalar);
     memset(cruft, 0, BN_num_bytes(sess->prime));
     BN_bn2bin(sess->my_scalar, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->order));
-    H_Final(&ctx, (uint8_t *)&session_id[1]);
+       HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->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(sess->prime));
     offset = BN_num_bytes(sess->prime) - BN_num_bytes(sess->k);
     BN_bn2bin(sess->k, cruft + offset);
-    H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
-
-    H_Update(&ctx, peer_confirm, SHA256_DIGEST_LENGTH);
-
-    H_Update(&ctx, sess->my_confirm, SHA256_DIGEST_LENGTH);
-
-    H_Final(&ctx, mk);
+       HMAC_Update(&hmac_ctx, cruft, BN_num_bytes(sess->prime));
+ 
+       HMAC_Update(&hmac_ctx, peer_confirm, SHA256_DIGEST_LENGTH);
+    
+       HMAC_Update(&hmac_ctx, sess->my_confirm, SHA256_DIGEST_LENGTH);
+ 
+       pwd_hmac_final(&hmac_ctx, mk);
 
     /* stretch the mk with the session-id to get MSK | EMSK */
-    eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH,
-		(char const *)session_id, SHA256_DIGEST_LENGTH+1,
-		msk_emsk, 1024);  /* it's bits, ((64 + 64) * 8) */
+       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);
 
+    HMAC_CTX_cleanup(&hmac_ctx);
     talloc_free(cruft);
     return 0;
 }
 
-
-
-
Index: freeradius-server-3.0.3/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h
===================================================================
--- freeradius-server-3.0.3.orig/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h
+++ freeradius-server-3.0.3/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h
@@ -104,16 +104,16 @@ typedef struct _pwd_session_t {
     uint8_t my_confirm[SHA256_DIGEST_LENGTH];
 } pwd_session_t;
 
-int compute_password_element(pwd_session_t *sess, uint16_t grp_num,
+int compute_password_element(REQUEST *request,pwd_session_t *sess, uint16_t grp_num,
 			     char const *password, int password_len,
 			     char *id_server, int id_server_len,
 			     char *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 *commit, BN_CTX *bnctx);
-int compute_server_confirm(pwd_session_t *sess, uint8_t *buf, BN_CTX *bnctx);
-int compute_peer_confirm(pwd_session_t *sess, uint8_t *buf, 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 *buf, BN_CTX *bnctx);
+int compute_peer_confirm(REQUEST *request,pwd_session_t *sess, uint8_t *buf, BN_CTX *bnctx);
+int compute_keys(REQUEST *request,pwd_session_t *sess, uint8_t *peer_confirm,
 		 uint8_t *msk, uint8_t *emsk);
 #ifdef PRINTBUF
 void print_buf(char *str, uint8_t *buf, int len);
Index: freeradius-server-3.0.3/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c
===================================================================
--- freeradius-server-3.0.3.orig/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c
+++ freeradius-server-3.0.3/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c
@@ -472,7 +472,7 @@ mod_authenticate (void *arg, eap_handler
 		return 0;
 	    }
 
-	    if (compute_password_element(pwd_session, pwd_session->group_num,
+	    if (compute_password_element(request, pwd_session, pwd_session->group_num,
 					 pw->data.strvalue, strlen(pw->data.strvalue),
 					 inst->conf->server_id, strlen(inst->conf->server_id),
 					 pwd_session->peer_id, strlen(pwd_session->peer_id),
@@ -486,7 +486,7 @@ mod_authenticate (void *arg, eap_handler
 	    /*
 	     * compute our scalar and element
 	     */
-	    if (compute_scalar_element(pwd_session, pwd_session->bnctx)) {
+	    if (compute_scalar_element(request, pwd_session, pwd_session->bnctx)) {
 		DEBUG2("failed to compute server's scalar and element");
 		return 0;
 	    }
@@ -540,7 +540,7 @@ mod_authenticate (void *arg, eap_handler
 	    /*
 	     * process the peer's commit and generate the shared key, k
 	     */
-	    if (process_peer_commit(pwd_session, buf, pwd_session->bnctx)) {
+	    if (process_peer_commit(request, pwd_session, buf, len, pwd_session->bnctx)) {
 		RDEBUG2("failed to process peer's commit");
 		return 0;
 	    }
@@ -548,7 +548,7 @@ mod_authenticate (void *arg, eap_handler
 	    /*
 	     * compute our confirm blob
 	     */
-	    if (compute_server_confirm(pwd_session, pwd_session->my_confirm, pwd_session->bnctx)) {
+	    if (compute_server_confirm(request, pwd_session, pwd_session->my_confirm, pwd_session->bnctx)) {
 		ERROR("rlm_eap_pwd: failed to compute confirm!");
 		return 0;
 	    }
@@ -571,7 +571,7 @@ mod_authenticate (void *arg, eap_handler
 		RDEBUG2("pwd exchange is incorrect: not commit!");
 		return 0;
 	    }
-	    if (compute_peer_confirm(pwd_session, peer_confirm, pwd_session->bnctx)) {
+	    if (compute_peer_confirm(request, pwd_session, peer_confirm, pwd_session->bnctx)) {
 		RDEBUG2("pwd exchange cannot compute peer's confirm");
 		return 0;
 	    }
@@ -579,7 +579,7 @@ mod_authenticate (void *arg, eap_handler
 		RDEBUG2("pwd exchange fails: peer confirm is incorrect!");
 		return 0;
 	    }
-	    if (compute_keys(pwd_session, peer_confirm, msk, emsk)) {
+	    if (compute_keys(request, pwd_session, peer_confirm, msk, emsk)) {
 		RDEBUG2("pwd exchange cannot generate (E)MSK!");
 		return 0;
 	    }
