34 RCSID(
"$Id: 1c17e39563515b6aeb4acd74683d73663a295190 $")
39 #include <freeradius-devel/radiusd.h>
40 #include <freeradius-devel/modules.h>
45 uint8_t allzero[SHA256_DIGEST_LENGTH];
47 memset(allzero, 0, SHA256_DIGEST_LENGTH);
48 HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256());
53 HMAC_Update(ctx, data, len);
56 static void H_Final(HMAC_CTX *ctx, uint8_t *digest)
58 unsigned int mdlen = SHA256_DIGEST_LENGTH;
60 HMAC_Final(ctx, digest, &mdlen);
61 HMAC_CTX_cleanup(ctx);
65 static void eap_pwd_kdf(uint8_t *key,
int keylen,
char const *label,
int labellen, uint8_t *result,
int resultbitlen)
68 uint8_t digest[SHA256_DIGEST_LENGTH];
70 int resultbytelen, len = 0;
71 unsigned int mdlen = SHA256_DIGEST_LENGTH;
74 resultbytelen = (resultbitlen + 7)/8;
76 L = htons(resultbitlen);
77 while (len < resultbytelen) {
78 ctr++; i = htons(ctr);
79 HMAC_Init(&hctx, key, keylen, EVP_sha256());
81 HMAC_Update(&hctx, digest, mdlen);
83 HMAC_Update(&hctx, (uint8_t *) &i,
sizeof(uint16_t));
84 HMAC_Update(&hctx, (uint8_t
const *)label, labellen);
85 HMAC_Update(&hctx, (uint8_t *) &L,
sizeof(uint16_t));
86 HMAC_Final(&hctx, digest, &mdlen);
87 if ((len + (
int) mdlen) > resultbytelen) {
88 memcpy(result + len, digest, resultbytelen - len);
90 memcpy(result + len, digest, mdlen);
93 HMAC_CTX_cleanup(&hctx);
97 if (resultbitlen % 8) {
98 mask <<= (8 - (resultbitlen % 8));
99 result[resultbytelen - 1] &=
mask;
104 char const *password,
int password_len,
105 char const *id_server,
int id_server_len,
106 char const *id_peer,
int id_peer_len,
109 BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
111 uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
112 int nid, is_odd, primebitlen, primebytelen, ret = 0;
116 nid = NID_X9_62_prime256v1;
128 nid = NID_X9_62_prime192v1;
136 DEBUG(
"unknown group %d", grp_num);
141 session->
order = NULL;
142 session->
prime = NULL;
144 if ((session->
group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
145 DEBUG(
"unable to create EC_GROUP");
149 if (((rnd = BN_new()) == NULL) ||
150 ((cofactor = BN_new()) == NULL) ||
151 ((session->
pwe = EC_POINT_new(session->
group)) == NULL) ||
152 ((session->
order = BN_new()) == NULL) ||
153 ((session->
prime = BN_new()) == NULL) ||
154 ((x_candidate = BN_new()) == NULL)) {
155 DEBUG(
"unable to create bignums");
159 if (!EC_GROUP_get_curve_GFp(session->
group, session->
prime, NULL, NULL, NULL)) {
160 DEBUG(
"unable to get prime for GFp curve");
164 if (!EC_GROUP_get_order(session->
group, session->
order, NULL)) {
165 DEBUG(
"unable to get order for curve");
169 if (!EC_GROUP_get_cofactor(session->
group, cofactor, NULL)) {
170 DEBUG(
"unable to get cofactor for curve");
174 primebitlen = BN_num_bits(session->
prime);
175 primebytelen = BN_num_bytes(session->
prime);
176 if ((prfbuf = talloc_zero_array(session, uint8_t, primebytelen)) == NULL) {
177 DEBUG(
"unable to alloc space for prf buffer");
183 DEBUG(
"unable to find random point on curve for group %d, something's fishy", grp_num);
194 H_Update(&ctx, (uint8_t *)token,
sizeof(*token));
195 H_Update(&ctx, (uint8_t
const *)id_peer, id_peer_len);
196 H_Update(&ctx, (uint8_t
const *)id_server, id_server_len);
197 H_Update(&ctx, (uint8_t
const *)password, password_len);
198 H_Update(&ctx, (uint8_t *)&ctr,
sizeof(ctr));
201 BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd);
202 eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH,
"EAP-pwd Hunting And Pecking",
203 strlen(
"EAP-pwd Hunting And Pecking"), prfbuf, primebitlen);
205 BN_bin2bn(prfbuf, primebytelen, x_candidate);
213 if (primebitlen % 8) BN_rshift(x_candidate, x_candidate, (8 - (primebitlen % 8)));
214 if (BN_ucmp(x_candidate, session->
prime) >= 0)
continue;
220 is_odd = BN_is_odd(rnd) ? 1 : 0;
226 if (!EC_POINT_set_compressed_coordinates_GFp(session->
group, session->
pwe, x_candidate, is_odd, NULL)) {
236 if (!EC_POINT_is_on_curve(session->
group, session->
pwe, NULL)) {
237 DEBUG(
"EAP-pwd: point is not on curve");
241 if (BN_cmp(cofactor, BN_value_one())) {
243 if (!EC_POINT_mul(session->
group, session->
pwe, NULL, session->
pwe,
245 DEBUG(
"EAP-pwd: cannot multiply generator by order");
249 if (EC_POINT_is_at_infinity(session->
group, session->
pwe)) {
250 DEBUG(
"EAP-pwd: point is at infinity");
265 BN_clear_free(cofactor);
266 BN_clear_free(x_candidate);
280 ((session->
my_scalar = BN_new()) == NULL) ||
281 ((mask = BN_new()) == NULL)) {
282 DEBUG2(
"server scalar allocation failed");
287 DEBUG2(
"Unable to get randomness for private_value");
290 if (BN_rand_range(mask, session->
order) != 1) {
291 DEBUG2(
"Unable to get randomness for mask");
297 if (!EC_POINT_mul(session->
group, session->
my_element, NULL, session->
pwe, mask, bnctx)) {
298 DEBUG2(
"server element allocation failed");
303 DEBUG2(
"server element inversion failed");
319 BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
320 EC_POINT *K = NULL, *point = NULL;
324 ((session->
k = BN_new()) == NULL) ||
325 ((cofactor = BN_new()) == NULL) ||
326 ((x = BN_new()) == NULL) ||
327 ((y = BN_new()) == NULL) ||
328 ((point = EC_POINT_new(session->
group)) == NULL) ||
329 ((K = EC_POINT_new(session->
group)) == NULL) ||
331 DEBUG2(
"pwd: failed to allocate room to process peer's commit");
335 if (!EC_GROUP_get_cofactor(session->
group, cofactor, NULL)) {
336 DEBUG2(
"pwd: unable to get group co-factor");
342 data_len = BN_num_bytes(session->
prime);
347 if (in_len < (2 * data_len + BN_num_bytes(session->
order))) {
348 DEBUG(
"pwd: Invalid commit packet");
352 BN_bin2bn(ptr, data_len, x);
354 BN_bin2bn(ptr, data_len, y);
357 data_len = BN_num_bytes(session->
order);
360 if (!EC_POINT_set_affine_coordinates_GFp(session->
group, session->
peer_element, x, y, bnctx)) {
361 DEBUG2(
"pwd: unable to get coordinates of peer's element");
366 if (BN_cmp(cofactor, BN_value_one())) {
367 if (!EC_POINT_mul(session->
group, point, NULL, session->
peer_element, cofactor, NULL)) {
368 DEBUG2(
"pwd: unable to multiply element by co-factor");
372 if (EC_POINT_is_at_infinity(session->
group, point)) {
373 DEBUG2(
"pwd: peer's element is in small sub-group");
382 DEBUG2(
"pwd: unable to compute shared key, k");
387 if (BN_cmp(cofactor, BN_value_one())) {
388 if (!EC_POINT_mul(session->
group, K, NULL, K, cofactor, NULL)) {
389 DEBUG2(
"pwd: unable to multiply k by co-factor");
400 if (EC_POINT_is_at_infinity(session->
group, K)) {
401 DEBUG2(
"pwd: k is point-at-infinity!");
405 if (!EC_POINT_get_affine_coordinates_GFp(session->
group, K, session->
k, NULL, bnctx)) {
406 DEBUG2(
"pwd: unable to get shared secret from K");
412 EC_POINT_clear_free(K);
413 EC_POINT_clear_free(point);
414 BN_clear_free(cofactor);
423 BIGNUM *x = NULL, *y = NULL;
425 uint8_t *cruft = NULL;
426 int offset, req = -1;
431 if (((cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->
prime))) == NULL) ||
432 ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
433 DEBUG2(
"pwd: unable to allocate space to compute confirm!");
449 offset = BN_num_bytes(session->
prime) - BN_num_bytes(session->
k);
450 BN_bn2bin(session->
k, cruft + offset);
456 if (!EC_POINT_get_affine_coordinates_GFp(session->
group, session->
my_element, x, y, bnctx)) {
457 DEBUG2(
"pwd: unable to get coordinates of server element");
460 memset(cruft, 0, BN_num_bytes(session->
prime));
461 offset = BN_num_bytes(session->
prime) - BN_num_bytes(x);
462 BN_bn2bin(x, cruft + offset);
465 memset(cruft, 0, BN_num_bytes(session->
prime));
466 offset = BN_num_bytes(session->
prime) - BN_num_bytes(y);
467 BN_bn2bin(y, cruft + offset);
473 memset(cruft, 0, BN_num_bytes(session->
prime));
474 offset = BN_num_bytes(session->
order) - BN_num_bytes(session->
my_scalar);
475 BN_bn2bin(session->
my_scalar, cruft + offset);
481 if (!EC_POINT_get_affine_coordinates_GFp(session->
group, session->
peer_element, x, y, bnctx)) {
482 DEBUG2(
"pwd: unable to get coordinates of peer's element");
486 memset(cruft, 0, BN_num_bytes(session->
prime));
487 offset = BN_num_bytes(session->
prime) - BN_num_bytes(x);
488 BN_bn2bin(x, cruft + offset);
491 memset(cruft, 0, BN_num_bytes(session->
prime));
492 offset = BN_num_bytes(session->
prime) - BN_num_bytes(y);
493 BN_bn2bin(y, cruft + offset);
499 memset(cruft, 0, BN_num_bytes(session->
prime));
522 BIGNUM *x = NULL, *y = NULL;
524 uint8_t *cruft = NULL;
525 int offset, req = -1;
530 if (((cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->
prime))) == NULL) ||
531 ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
532 DEBUG2(
"pwd: unable to allocate space to compute confirm!");
548 offset = BN_num_bytes(session->
prime) - BN_num_bytes(session->
k);
549 BN_bn2bin(session->
k, cruft + offset);
555 if (!EC_POINT_get_affine_coordinates_GFp(session->
group, session->
peer_element, x, y, bnctx)) {
556 DEBUG2(
"pwd: unable to get coordinates of peer's element");
560 memset(cruft, 0, BN_num_bytes(session->
prime));
561 offset = BN_num_bytes(session->
prime) - BN_num_bytes(x);
562 BN_bn2bin(x, cruft + offset);
565 memset(cruft, 0, BN_num_bytes(session->
prime));
566 offset = BN_num_bytes(session->
prime) - BN_num_bytes(y);
567 BN_bn2bin(y, cruft + offset);
573 memset(cruft, 0, BN_num_bytes(session->
prime));
581 if (!EC_POINT_get_affine_coordinates_GFp(session->
group, session->
my_element, x, y, bnctx)) {
582 DEBUG2(
"pwd: unable to get coordinates of server element");
585 memset(cruft, 0, BN_num_bytes(session->
prime));
586 offset = BN_num_bytes(session->
prime) - BN_num_bytes(x);
587 BN_bn2bin(x, cruft + offset);
590 memset(cruft, 0, BN_num_bytes(session->
prime));
591 offset = BN_num_bytes(session->
prime) - BN_num_bytes(y);
592 BN_bn2bin(y, cruft + offset);
598 memset(cruft, 0, BN_num_bytes(session->
prime));
599 offset = BN_num_bytes(session->
order) - BN_num_bytes(session->
my_scalar);
600 BN_bn2bin(session->
my_scalar, cruft + offset);
622 uint8_t mk[SHA256_DIGEST_LENGTH], *cruft;
623 uint8_t session_id[SHA256_DIGEST_LENGTH + 1];
624 uint8_t msk_emsk[128];
627 if ((cruft = talloc_array(session, uint8_t, BN_num_bytes(session->
prime))) == NULL) {
628 DEBUG2(
"pwd: unable to allocate space to compute keys");
640 memset(cruft, 0, BN_num_bytes(session->
prime));
643 offset = BN_num_bytes(session->
order) - BN_num_bytes(session->
my_scalar);
644 memset(cruft, 0, BN_num_bytes(session->
prime));
645 BN_bn2bin(session->
my_scalar, cruft + offset);
647 H_Final(&ctx, (uint8_t *)&session_id[1]);
652 memset(cruft, 0, BN_num_bytes(session->
prime));
653 offset = BN_num_bytes(session->
prime) - BN_num_bytes(session->
k);
654 BN_bn2bin(session->
k, cruft + offset);
657 H_Update(&ctx, peer_confirm, SHA256_DIGEST_LENGTH);
664 eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH, (
char const *)session_id,
665 SHA256_DIGEST_LENGTH + 1, msk_emsk, 1024);
667 memcpy(msk, msk_emsk, 64);
668 memcpy(emsk, msk_emsk + 64, 64);
static void eap_pwd_kdf(uint8_t *key, int keylen, char const *label, int labellen, uint8_t *result, int resultbitlen)
static void H_Final(HMAC_CTX *ctx, uint8_t *digest)
int process_peer_commit(pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bnctx)
int compute_scalar_element(pwd_session_t *session, BN_CTX *bnctx)
int compute_password_element(pwd_session_t *session, uint16_t grp_num, char const *password, int password_len, char const *id_server, int id_server_len, char const *id_peer, int id_peer_len, uint32_t *token)
int compute_keys(pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk)
int compute_peer_confirm(pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
static USES_APPLE_DEPRECATED_API void H_Init(HMAC_CTX *ctx)
uint8_t my_confirm[SHA256_DIGEST_LENGTH]
int compute_server_confirm(pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
static void H_Update(HMAC_CTX *ctx, uint8_t const *data, int len)
#define USES_APPLE_DEPRECATED_API