Merge remote-tracking branch 'freeradius/v3.0.x' into tr-upgrade
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_pwd / eap_pwd.c
index 00c0687..058de06 100644 (file)
@@ -40,646 +40,615 @@ USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
 #include <freeradius-devel/modules.h>
 
 /* The random function H(x) = HMAC-SHA256(0^32, x) */
-static void
-H_Init(HMAC_CTX *ctx)
+static void H_Init(HMAC_CTX *ctx)
 {
-    uint8_t allzero[SHA256_DIGEST_LENGTH];
+       uint8_t allzero[SHA256_DIGEST_LENGTH];
 
-    memset(allzero, 0, SHA256_DIGEST_LENGTH);
-    HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256());
+       memset(allzero, 0, SHA256_DIGEST_LENGTH);
+       HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256());
 }
 
-static void
-H_Update(HMAC_CTX *ctx, uint8_t const *data, int len)
+static void H_Update(HMAC_CTX *ctx, uint8_t const *data, int len)
 {
-    HMAC_Update(ctx, data, len);
+       HMAC_Update(ctx, data, len);
 }
 
-static void
-H_Final(HMAC_CTX *ctx, uint8_t *digest)
+static void H_Final(HMAC_CTX *ctx, uint8_t *digest)
 {
-    unsigned int mdlen = SHA256_DIGEST_LENGTH;
+       unsigned int mdlen = SHA256_DIGEST_LENGTH;
 
-    HMAC_Final(ctx, digest, &mdlen);
-    HMAC_CTX_cleanup(ctx);
+       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)
+static void eap_pwd_kdf(uint8_t *key, int keylen, char const *label, int labellen, uint8_t *result, int resultbitlen)
 {
-    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;
-
-    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_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;
+
+       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);
        }
-       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);
+
+       /* since we're expanding to a bit length, mask off the excess */
+       if (resultbitlen % 8) {
+               mask <<= (8 - (resultbitlen % 8));
+               result[resultbytelen - 1] &= mask;
        }
-       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;
-    }
 }
 
-int
-compute_password_element (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_password_element (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)
 {
-    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, *cofactor = NULL;
+       HMAC_CTX ctx;
+       uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
+       int nid, is_odd, primebitlen, primebytelen, ret = 0;
 
-    switch (grp_num) { /* from IANA registry for IKE D-H groups */
+       switch (grp_num) { /* from IANA registry for IKE D-H groups */
        case 19:
-           nid = NID_X9_62_prime256v1;
-           break;
+               nid = NID_X9_62_prime256v1;
+               break;
+
        case 20:
-           nid = NID_secp384r1;
-           break;
+               nid = NID_secp384r1;
+               break;
+
        case 21:
-           nid = NID_secp521r1;
-           break;
+               nid = NID_secp521r1;
+               break;
+
        case 25:
-           nid = NID_X9_62_prime192v1;
-           break;
+               nid = NID_X9_62_prime192v1;
+               break;
+
        case 26:
-           nid = NID_secp224r1;
-           break;
+               nid = NID_secp224r1;
+               break;
+
        default:
-           DEBUG("unknown group %d", grp_num);
-           goto fail;
-    }
-
-    sess->pwe = NULL;
-    sess->order = NULL;
-    sess->prime = NULL;
-
-    if ((sess->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
-       DEBUG("unable to create EC_GROUP");
-       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)) {
-       DEBUG("unable to create bignums");
-       goto fail;
-    }
-
-    if (!EC_GROUP_get_curve_GFp(sess->group, sess->prime, NULL, NULL, NULL))
-    {
-       DEBUG("unable to get prime for GFp curve");
-       goto fail;
-    }
-    if (!EC_GROUP_get_order(sess->group, sess->order, NULL)) {
-       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;
-    }
-    ctr = 0;
-    while (1) {
-       if (ctr > 10) {
-           DEBUG("unable to find random point on curve for group %d, something's fishy", grp_num);
-           goto fail;
+               DEBUG("unknown group %d", grp_num);
+               goto fail;
+       }
+
+       sess->pwe = NULL;
+       sess->order = NULL;
+       sess->prime = NULL;
+
+       if ((sess->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
+               DEBUG("unable to create EC_GROUP");
+               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)) {
+               DEBUG("unable to create bignums");
+               goto fail;
+       }
+
+       if (!EC_GROUP_get_curve_GFp(sess->group, sess->prime, NULL, NULL, NULL)) {
+               DEBUG("unable to get prime for GFp curve");
+               goto fail;
+       }
+
+       if (!EC_GROUP_get_order(sess->group, sess->order, NULL)) {
+               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;
+       }
+       ctr = 0;
+       while (1) {
+               if (ctr > 10) {
+                       DEBUG("unable to find random point on curve for group %d, something's fishy", grp_num);
+                       goto fail;
+               }
+               ctr++;
+
+               /*
+                * compute counter-mode password value and stretch to prime
+                *    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);
+
+               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
+                * number. If the primebitlen is not an even multiple of 8
+                * 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...
+                */
+               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(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;
+       }
+
+       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;
+}
+
+int compute_scalar_element (pwd_session_t *sess, BN_CTX *bnctx) {
+       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;
+}
+
+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 finish;
+       }
+
+       if (!EC_GROUP_get_cofactor(sess->group, cofactor, NULL)) {
+               DEBUG2("pwd: unable to get group co-factor");
+               goto finish;
+       }
+
+       /* 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);
+
+       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 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(sess->group, point, NULL, sess->peer_element, cofactor, NULL)) {
+                       DEBUG2("pwd: unable to multiply element by co-factor");
+                       goto finish;
+               }
+
+               if (EC_POINT_is_at_infinity(sess->group, point)) {
+                       DEBUG2("pwd: peer's element is in small sub-group");
+                       goto finish;
+               }
+       }
+
+       /* 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 finish;
+       }
+
+       /* 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 finish;
+               }
        }
-       ctr++;
 
        /*
-        * compute counter-mode password value and stretch to prime
-        *    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);
-
-       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
-        * number. If the primebitlen is not an even multiple of 8
-        * then excessive bits-- those _after_ primebitlen-- so now
-        * we have to shift right the amount we masked off.
+        * 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 (primebitlen % 8) {
-           BN_rshift(x_candidate, x_candidate, (8 - (primebitlen % 8)));
+       if (EC_POINT_is_at_infinity(sess->group, K)) {
+               DEBUG2("pwd: k is point-at-infinity!");
+               goto finish;
        }
-       if (BN_ucmp(x_candidate, sess->prime) >= 0) {
-           continue;
+
+       if (!EC_POINT_get_affine_coordinates_GFp(sess->group, K, sess->k, NULL, bnctx)) {
+               DEBUG2("pwd: unable to get shared secret from K");
+               goto finish;
        }
+       res = 0;
+
+finish:
+       EC_POINT_free(K);
+       EC_POINT_free(point);
+       BN_free(cofactor);
+       BN_free(x);
+       BN_free(y);
+
+       return res;
+}
+
+int compute_server_confirm (pwd_session_t *sess, uint8_t *buf, BN_CTX *bnctx)
+{
+       BIGNUM *x = NULL, *y = NULL;
+       HMAC_CTX ctx;
+       uint8_t *cruft = NULL;
+       int offset, req = -1;
+
        /*
-        * need to unambiguously identify the solution, if there is
-        * one...
+        * Each component of the cruft will be at most as big as the prime
         */
-       if (BN_is_odd(rnd)) {
-           is_odd = 1;
-       } else {
-           is_odd = 0;
+       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 finish;
        }
+
        /*
-        * solve the quadratic equation, if it's not solvable then we
-        * don't have a point
+        * commit is H(k | server_element | server_scalar | peer_element |
+        *             peer_scalar | ciphersuite)
         */
-       if (!EC_POINT_set_compressed_coordinates_GFp(sess->group,
-                                                    sess->pwe,
-                                                    x_candidate,
-                                                    is_odd, NULL)) {
-           continue;
-       }
+       H_Init(&ctx);
+
        /*
-        * 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.
+        * Zero the memory each time because this is mod prime math and some
+        * value may start with a few zeros and the previous one did not.
+        *
+        * First is k
         */
-       if (!EC_POINT_is_on_curve(sess->group, sess->pwe, NULL)) {
-           DEBUG("EAP-pwd: point is not on curve");
-           continue;
+       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));
+
+       /*
+        * 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 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));
 
-       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;
-           }
+       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));
+
+       /*
+        * and server scalar
+        */
+       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));
+
+       /*
+        * 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 finish;
        }
-       /* if we got here then we have a new generator. */
-       break;
-    }
-    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;
-}
 
-int
-compute_scalar_element (pwd_session_t *sess, BN_CTX *bnctx)
-{
-    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);
+       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));
+
+       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));
+
+       /*
+        * and peer scalar
+        */
+       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));
 
-    return ret;
+       /*
+        * finally, ciphersuite
+        */
+       H_Update(&ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
+
+       H_Final(&ctx, buf);
+
+       req = 0;
+finish:
+       talloc_free(cruft);
+       BN_free(x);
+       BN_free(y);
+
+       return req;
 }
 
-int
-process_peer_commit (pwd_session_t *sess, uint8_t *commit, BN_CTX *bnctx)
+int compute_peer_confirm (pwd_session_t *sess, uint8_t *buf, 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);
-    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;
-    }
-
-    /* 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;
+       BIGNUM *x = NULL, *y = NULL;
+       HMAC_CTX 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 finish;
        }
-       if (EC_POINT_is_at_infinity(sess->group, point)) {
-           DEBUG2("pwd: peer's element is in small sub-group");
-           goto fin;
+
+       /*
+        * commit is H(k | server_element | server_scalar | peer_element |
+        *             peer_scalar | ciphersuite)
+        */
+       H_Init(&ctx);
+
+       /*
+        * Zero the memory each time because this is mod prime math and some
+        * value may start with a few zeros and the previous one did not.
+        *
+        * First is k
+        */
+       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));
+
+       /*
+       * 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");
+               goto finish;
        }
-    }
-
-    /* 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;
+
+       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));
+
+       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));
+
+       /*
+        * and peer scalar
+        */
+       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));
+
+       /*
+        * 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");
+               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(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);
-
-    return res;
-}
+       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));
 
-int
-compute_server_confirm (pwd_session_t *sess, uint8_t *buf, BN_CTX *bnctx)
-{
-    BIGNUM *x = NULL, *y = NULL;
-    HMAC_CTX 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);
-
-    /*
-     * Zero the memory each time because this is mod prime math and some
-     * value may start with a few zeros and the previous one did not.
-     *
-     * First is k
-     */
-    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));
-
-    /*
-     * 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;
-    }
-    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));
-
-    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));
-
-    /*
-     * and server scalar
-     */
-    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));
-
-    /*
-     * 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;
-    }
-
-    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));
-
-    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));
-
-    /*
-     * and peer scalar
-     */
-    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));
-
-    /*
-     * finally, ciphersuite
-     */
-    H_Update(&ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
-
-    H_Final(&ctx, buf);
-
-    req = 0;
-fin:
-    if (cruft != NULL) {
-           talloc_free(cruft);
-    }
-    BN_free(x);
-    BN_free(y);
-
-    return req;
-}
+       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));
 
-int
-compute_peer_confirm (pwd_session_t *sess, uint8_t *buf, BN_CTX *bnctx)
-{
-    BIGNUM *x = NULL, *y = NULL;
-    HMAC_CTX 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);
-
-    /*
-     * Zero the memory each time because this is mod prime math and some
-     * value may start with a few zeros and the previous one did not.
-     *
-     * First is k
-     */
-    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));
-
-    /*
-     * 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");
-       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));
-
-    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));
-
-    /*
-     * and peer scalar
-     */
-    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));
-
-    /*
-     * 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");
-       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));
-
-    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));
-
-    /*
-     * and server scalar
-     */
-    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));
-
-    /*
-     * finally, ciphersuite
-     */
-    H_Update(&ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
-
-    H_Final(&ctx, buf);
-
-    req = 0;
-fin:
-    if (cruft != NULL) {
-           talloc_free(cruft);
-    }
-    BN_free(x);
-    BN_free(y);
-
-    return req;
+       /*
+        * and server scalar
+        */
+       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));
+
+       /*
+        * finally, ciphersuite
+        */
+       H_Update(&ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
+
+       H_Final(&ctx, buf);
+
+       req = 0;
+finish:
+       talloc_free(cruft);
+       BN_free(x);
+       BN_free(y);
+
+       return req;
 }
 
-int
-compute_keys (pwd_session_t *sess, uint8_t *peer_confirm,
-             uint8_t *msk, uint8_t *emsk)
+int compute_keys (pwd_session_t *sess, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk)
 {
-    HMAC_CTX 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)
-     */
-    session_id[0] = PW_EAP_PWD;
-    H_Init(&ctx);
-    H_Update(&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));
-    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]);
-
-    /* then compute MK = H(k | commit-peer | commit-server) */
-    H_Init(&ctx);
-
-    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);
-
-    /* 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) */
-
-    memcpy(msk, msk_emsk, 64);
-    memcpy(emsk, msk_emsk + 64, 64);
-
-    talloc_free(cruft);
-    return 0;
+       HMAC_CTX 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)
+        */
+       session_id[0] = PW_EAP_PWD;
+       H_Init(&ctx);
+       H_Update(&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));
+       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]);
+
+       /* then compute MK = H(k | commit-peer | commit-server) */
+       H_Init(&ctx);
+
+       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);
+
+       /* 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) */
+
+       memcpy(msk, msk_emsk, 64);
+       memcpy(emsk, msk_emsk + 64, 64);
+
+       talloc_free(cruft);
+       return 0;
 }