The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
eap_pwd.c
Go to the documentation of this file.
1/**
2 * copyright holder grants permission for redistribution and use in source
3 * and binary forms, with or without modification, provided that the
4 * following conditions are met:
5 * 1. Redistribution of source code must retain the above copyright
6 * notice, this list of conditions, and the following disclaimer
7 * in all source files.
8 * 2. Redistribution in binary form must retain the above copyright
9 * notice, this list of conditions, and the following disclaimer
10 * in the documentation and/or other materials provided with the
11 * distribution.
12 *
13 * "DISCLAIMER OF LIABILITY
14 *
15 * THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE."
26 *
27 * This license and distribution terms cannot be changed. In other words,
28 * this code cannot simply be copied and put under a different distribution
29 * license (including the GNU public license).
30 *
31 * @copyright (c) Dan Harkins, 2012
32 */
33
34RCSID("$Id: 4de28e61b17c25cdc8e310ed676e2709f0fc3500 $")
35USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
36
37#include <freeradius-devel/server/base.h>
38#include <freeradius-devel/tls/base.h>
39#include <freeradius-devel/server/module_rlm.h>
40
41#include "eap_pwd.h"
42#include "const_time.h"
43
44static uint8_t allzero[SHA256_DIGEST_LENGTH] = { 0x00 };
45
46/* The random function H(x) = HMAC-SHA256(0^32, x) */
47static void pwd_hmac_final(EVP_MD_CTX *hmac_ctx, uint8_t digest[static SHA256_DIGEST_LENGTH])
48{
49 size_t mdlen = SHA256_DIGEST_LENGTH;
50
51 EVP_DigestSignFinal(hmac_ctx, digest, &mdlen);
52 EVP_MD_CTX_reset(hmac_ctx);
53}
54
55/* a counter-based KDF based on NIST SP800-108 */
56static void eap_pwd_kdf(uint8_t *key, int keylen, char const *label,
57 int label_len, uint8_t *result, int result_bit_len)
58{
59 EVP_MD_CTX *hmac_ctx;
60 EVP_PKEY *hmac_pkey;
61 uint8_t digest[SHA256_DIGEST_LENGTH];
62 uint16_t i, ctr, L;
63 int result_byte_len, len = 0;
64 size_t mdlen = SHA256_DIGEST_LENGTH;
65 uint8_t mask = 0xff;
66
67 result_byte_len = (result_bit_len + 7) / 8;
68
69 ctr = 0;
70 L = htons(result_bit_len);
71
72 MEM(hmac_ctx = EVP_MD_CTX_new());
73 MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, keylen));
74 while (len < result_byte_len) {
75 ctr++; i = htons(ctr);
76
77 EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
78 if (ctr > 1) EVP_DigestSignUpdate(hmac_ctx, digest, mdlen);
79 EVP_DigestSignUpdate(hmac_ctx, (uint8_t *) &i, sizeof(uint16_t));
80 EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)label, label_len);
81 EVP_DigestSignUpdate(hmac_ctx, (uint8_t *) &L, sizeof(uint16_t));
82 EVP_DigestSignFinal(hmac_ctx, digest, &mdlen);
83 if ((len + (int) mdlen) > result_byte_len) {
84 memcpy(result + len, digest, result_byte_len - len);
85 } else {
86 memcpy(result + len, digest, mdlen);
87 }
88 len += mdlen;
89 EVP_MD_CTX_reset(hmac_ctx);
90 }
91
92 /* since we're expanding to a bit length, mask off the excess */
93 if (result_bit_len % 8) {
94 mask <<= (8 - (result_bit_len % 8));
95 result[result_byte_len - 1] &= mask;
96 }
97
98 EVP_MD_CTX_free(hmac_ctx);
99 EVP_PKEY_free(hmac_pkey);
100}
101
102static BIGNUM *consttime_BN (void)
103{
104 BIGNUM *bn;
105
106 bn = BN_new();
107 if (bn) BN_set_flags(bn, BN_FLG_CONSTTIME);
108 return bn;
109}
110
111/*
112 * compute the legendre symbol in constant time
113 */
114static int legendre(bool *fail, BIGNUM *a, BIGNUM *p, BN_CTX *bnctx)
115{
116 int symbol;
117 unsigned int mask;
118 BIGNUM *res, *pm1over2;
119
120 MEM(pm1over2 = consttime_BN());
121 MEM(res = consttime_BN());
122
123 if (!BN_sub(pm1over2, p, BN_value_one()) ||
124 !BN_rshift1(pm1over2, pm1over2) ||
125 !BN_mod_exp_mont_consttime(res, a, pm1over2, p, bnctx, NULL)) {
126 BN_free(pm1over2);
127 BN_free(res);
128 *fail = true;
129 return -2;
130 }
131
132 symbol = -1;
133 mask = const_time_eq(BN_is_word(res, 1), 1);
134 symbol = const_time_select_int(mask, 1, symbol);
135 mask = const_time_eq(BN_is_zero(res), 1);
136 symbol = const_time_select_int(mask, -1, symbol);
137
138 BN_free(pm1over2);
139 BN_free(res);
140
141 *fail = false;
142 return symbol;
143}
144
145static void do_equation(EC_GROUP *group, BIGNUM *y2, BIGNUM *x, BN_CTX *bnctx)
146{
147 BIGNUM *p, *a, *b, *tmp1, *pm1;
148
149 MEM(tmp1 = BN_new());
150 MEM(pm1 = BN_new());
151 MEM(p = BN_new());
152 MEM(a = BN_new());
153 MEM(b = BN_new());
154 EC_GROUP_get_curve(group, p, a, b, bnctx);
155
156 BN_sub(pm1, p, BN_value_one());
157
158 /*
159 * y2 = x^3 + ax + b
160 */
161 BN_mod_sqr(tmp1, x, p, bnctx);
162 BN_mod_mul(y2, tmp1, x, p, bnctx);
163 BN_mod_mul(tmp1, a, x, p, bnctx);
164 BN_mod_add_quick(y2, y2, tmp1, p);
165 BN_mod_add_quick(y2, y2, b, p);
166
167 BN_free(tmp1);
168 BN_free(pm1);
169 BN_free(p);
170 BN_free(a);
171 BN_free(b);
172
173 return;
174}
175
176static int is_quadratic_residue(BIGNUM *val, BIGNUM *p, BIGNUM *qr, BIGNUM *qnr, BN_CTX *bnctx)
177{
178 int offset, check, ret = 0;
179 bool fail;
180 BIGNUM *r = NULL, *pm1 = NULL, *res = NULL, *qr_or_qnr = NULL;
181 unsigned int mask;
182 unsigned char *qr_bin = NULL, *qnr_bin = NULL, *qr_or_qnr_bin = NULL;
183
184 if (((r = consttime_BN()) == NULL) ||
185 ((res = consttime_BN()) == NULL) ||
186 ((qr_or_qnr = consttime_BN()) == NULL) ||
187 ((pm1 = consttime_BN()) == NULL)) {
188 ret = -2;
189 goto fail;
190 }
191
192 if (((qr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL) ||
193 ((qnr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL) ||
194 ((qr_or_qnr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL)) {
195 ret = -2;
196 goto fail;
197 }
198
199 /*
200 * we select binary in constant time so make them binary
201 */
202 memset(qr_bin, 0, BN_num_bytes(p));
203 memset(qnr_bin, 0, BN_num_bytes(p));
204 memset(qr_or_qnr_bin, 0, BN_num_bytes(p));
205
206 offset = BN_num_bytes(p) - BN_num_bytes(qr);
207 BN_bn2bin(qr, qr_bin + offset);
208
209 offset = BN_num_bytes(p) - BN_num_bytes(qnr);
210 BN_bn2bin(qnr, qnr_bin + offset);
211
212 /*
213 * r = (random() mod p-1) + 1
214 */
215 BN_sub(pm1, p, BN_value_one());
216 BN_rand_range(r, pm1);
217 BN_add(r, r, BN_value_one());
218
219 BN_copy(res, val);
220
221 /*
222 * res = val * r * r which ensures res != val but has same quadratic residocity
223 */
224 BN_mod_mul(res, res, r, p, bnctx);
225 BN_mod_mul(res, res, r, p, bnctx);
226
227 /*
228 * if r is even (mask is -1) then multiply by qnr and our check is qnr
229 * otherwise multiply by qr and our check is qr
230 */
231 mask = const_time_is_zero(BN_is_odd(r));
232 const_time_select_bin(mask, qnr_bin, qr_bin, BN_num_bytes(p), qr_or_qnr_bin);
233 BN_bin2bn(qr_or_qnr_bin, BN_num_bytes(p), qr_or_qnr);
234 BN_mod_mul(res, res, qr_or_qnr, p, bnctx);
235 check = const_time_select_int(mask, -1, 1);
236
237 if ((ret = legendre(&fail, res, p, bnctx)) == -2) {
238 ret = -1; /* just say no it's not */
239 goto fail;
240 }
241 mask = const_time_eq(ret, check);
242 ret = const_time_select_int(mask, 1, 0);
243
244fail:
245 if (qr_bin != NULL) free(qr_bin);
246 if (qnr_bin != NULL) free(qnr_bin);
247 if (qr_or_qnr_bin != NULL) free(qr_or_qnr_bin);
248 BN_free(r);
249 BN_free(res);
250 BN_free(qr_or_qnr);
251 BN_free(pm1);
252
253 return ret;
254}
255
257 char const *password, int password_len,
258 char const *id_server, int id_server_len,
259 char const *id_peer, int id_peer_len,
260 uint32_t *token, BN_CTX *bnctx)
261{
262 BIGNUM *x_candidate = NULL, *rnd = NULL, *y_sqrd = NULL, *qr = NULL, *qnr = NULL, *y1 = NULL, *y2 = NULL, *y = NULL, *exp = NULL;
263 EVP_MD_CTX *hmac_ctx;
264 EVP_PKEY *hmac_pkey;
265 uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, *xbuf = NULL, *pm1buf = NULL, *y1buf = NULL, *y2buf = NULL, *ybuf = NULL, ctr;
266 int nid, is_odd, primebitlen, primebytelen, ret = 0, found = 0, mask;
267 int save, i, rbits, qr_or_qnr, save_is_odd = 0, cmp;
268 unsigned int skip;
269 bool error;
270
271 MEM(hmac_ctx = EVP_MD_CTX_new());
272 MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, allzero, sizeof(allzero)));
273
274 switch (grp_num) { /* from IANA registry for IKE D-H groups */
275 case 19:
276 nid = NID_X9_62_prime256v1;
277 break;
278
279 case 20:
280 nid = NID_secp384r1;
281 break;
282
283 case 21:
284 nid = NID_secp521r1;
285 break;
286
287 case 25:
288 nid = NID_X9_62_prime192v1;
289 break;
290
291 case 26:
292 nid = NID_secp224r1;
293 break;
294
295 default:
296 DEBUG("unknown group %d", grp_num);
297 goto fail;
298 }
299
300 session->pwe = NULL;
301 session->order = NULL;
302 session->prime = NULL;
303
304 if ((session->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
305 DEBUG("unable to create EC_GROUP");
306 goto fail;
307 }
308
309 if (((rnd = consttime_BN()) == NULL) ||
310 ((session->pwe = EC_POINT_new(session->group)) == NULL) ||
311 ((session->order = consttime_BN()) == NULL) ||
312 ((session->prime = consttime_BN()) == NULL) ||
313 ((qr = consttime_BN()) == NULL) ||
314 ((qnr = consttime_BN()) == NULL) ||
315 ((x_candidate = consttime_BN()) == NULL) ||
316 ((y_sqrd = consttime_BN()) == NULL) ||
317 ((y1 = consttime_BN()) == NULL) ||
318 ((y2 = consttime_BN()) == NULL) ||
319 ((y = consttime_BN()) == NULL) ||
320 ((exp = consttime_BN()) == NULL)) {
321 DEBUG("unable to create bignums");
322 goto fail;
323 }
324
325 if (!EC_GROUP_get_curve(session->group, session->prime, NULL, NULL, NULL)) {
326 DEBUG("unable to get prime for GFp curve");
327 goto fail;
328 }
329
330 if (!EC_GROUP_get_order(session->group, session->order, NULL)) {
331 DEBUG("unable to get order for curve");
332 goto fail;
333 }
334
335 primebitlen = BN_num_bits(session->prime);
336 primebytelen = BN_num_bytes(session->prime);
337 if ((prfbuf = talloc_zero_array(session, uint8_t, primebytelen)) == NULL) {
338 DEBUG("unable to alloc space for prf buffer");
339 goto fail;
340 }
341 if ((xbuf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) {
342 DEBUG("unable to alloc space for x buffer");
343 goto fail;
344 }
345 if ((pm1buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) {
346 DEBUG("unable to alloc space for pm1 buffer");
347 goto fail;
348 }
349 if ((y1buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) {
350 DEBUG("unable to alloc space for y1 buffer");
351 goto fail;
352 }
353 if ((y2buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) {
354 DEBUG("unable to alloc space for y2 buffer");
355 goto fail;
356 }
357 if ((ybuf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) {
358 DEBUG("unable to alloc space for y buffer");
359 goto fail;
360 }
361
362
363 /*
364 * derive random quadradic residue and quadratic non-residue
365 */
366 do {
367 BN_rand_range(qr, session->prime);
368 } while ((legendre(&error, qr, session->prime, bnctx) != 1) && !error);
369 if (error) goto fail;
370
371 do {
372 BN_rand_range(qnr, session->prime);
373 } while ((legendre(&error, qnr, session->prime, bnctx) != -1) && !error);
374 if (error) goto fail;
375
376 if (!BN_sub(rnd, session->prime, BN_value_one())) {
377 goto fail;
378 }
379 BN_bn2bin(rnd, pm1buf);
380
381 save_is_odd = 0;
382 found = 0;
383 memset(xbuf, 0, primebytelen);
384 ctr = 0;
385 while (ctr < 40) {
386 ctr++;
387
388 /*
389 * compute counter-mode password value and stretch to prime
390 * pwd-seed = H(token | peer-id | server-id | password |
391 * counter)
392 */
393 EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
394 EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)token, sizeof(*token));
395 EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)id_peer, id_peer_len);
396 EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)id_server, id_server_len);
397 EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)password, password_len);
398 EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)&ctr, sizeof(ctr));
399 pwd_hmac_final(hmac_ctx, pwe_digest);
400
401 BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd);
402 eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH, "EAP-pwd Hunting And Pecking",
403 strlen("EAP-pwd Hunting And Pecking"), prfbuf, primebitlen);
404
405 /*
406 * eap_pwd_kdf() returns a string of bits 0..primebitlen but
407 * BN_bin2bn will treat that string of bits as a big endian
408 * number. If the primebitlen is not an even multiple of 8
409 * then excessive bits-- those _after_ primebitlen-- so now
410 * we have to shift right the amount we masked off.
411 */
412 if (primebitlen % 8) {
413 rbits = 8 - (primebitlen % 8);
414 for (i = primebytelen - 1; i > 0; i--) {
415 prfbuf[i] = (prfbuf[i - 1] << (8 - rbits)) | (prfbuf[i] >> rbits);
416 }
417 prfbuf[0] >>= rbits;
418 }
419 BN_bin2bn(prfbuf, primebytelen, x_candidate);
420
421 /*
422 * it would've been better if the spec reduced the candidate
423 * modulo the prime but it didn't. So if the candidate >= prime
424 * we need to skip it but still run through the operations below
425 */
426 cmp = const_time_memcmp(pm1buf, prfbuf, primebytelen);
427 skip = const_time_fill_msb((unsigned int)cmp);
428
429 /*
430 * need to unambiguously identify the solution, if there is
431 * one..
432 */
433 is_odd = BN_is_odd(rnd);
434
435 /*
436 * check whether x^3 + a*x + b is a quadratic residue
437 *
438 * save the first quadratic residue we find in the loop but do
439 * it in constant time.
440 */
441 do_equation(session->group, y_sqrd, x_candidate, bnctx);
442 qr_or_qnr = is_quadratic_residue(y_sqrd, session->prime, qr, qnr, bnctx);
443
444 /*
445 * if the candidate >= prime then we want to skip it
446 */
447 qr_or_qnr = const_time_select(skip, 0, qr_or_qnr);
448
449 /*
450 * if we haven't found PWE yet (found = 0) then mask will be true,
451 * if we have found PWE then mask will be false
452 */
453 mask = const_time_select(found, 0, -1);
454
455 /*
456 * save will be 1 if we want to save this value-- i.e. we haven't
457 * found PWE yet and this is a quadratic residue-- and 0 otherwise
458 */
459 save = const_time_select(mask, qr_or_qnr, 0);
460
461 /*
462 * mask will be true (-1) if we want to save this and false (0)
463 * otherwise
464 */
465 mask = const_time_eq(save, 1);
466
467 const_time_select_bin(mask, prfbuf, xbuf, primebytelen, xbuf);
468 save_is_odd = const_time_select(mask, is_odd, save_is_odd);
469 found = const_time_select(mask, -1, found);
470 }
471
472 /*
473 * now we can safely construct PWE
474 */
475 BN_bin2bn(xbuf, primebytelen, x_candidate);
476 do_equation(session->group, y_sqrd, x_candidate, bnctx);
477 if ( !BN_add(exp, session->prime, BN_value_one()) ||
478 !BN_rshift(exp, exp, 2) ||
479 !BN_mod_exp_mont_consttime(y1, y_sqrd, exp, session->prime, bnctx, NULL) ||
480 !BN_sub(y2, session->prime, y1) ||
481 !BN_bn2bin(y1, y1buf) ||
482 !BN_bn2bin(y2, y2buf)) {
483 DEBUG("unable to compute y");
484 goto fail;
485 }
486 mask = const_time_eq(save_is_odd, BN_is_odd(y1));
487 const_time_select_bin(mask, y1buf, y2buf, primebytelen, ybuf);
488 if (BN_bin2bn(ybuf, primebytelen, y) == NULL ||
489 !EC_POINT_set_affine_coordinates(session->group, session->pwe, x_candidate, y, bnctx)) {
490 DEBUG("unable to set point coordinate");
491 goto fail;
492 }
493
494 session->group_num = grp_num;
495 if (0) {
496 fail: /* DON'T free session, it's in handler->opaque */
497 ret = -1;
498 }
499
500 /* cleanliness and order.... */
501 BN_clear_free(x_candidate);
502 BN_clear_free(y_sqrd);
503 BN_clear_free(qr);
504 BN_clear_free(qnr);
505 BN_clear_free(rnd);
506 BN_clear_free(y1);
507 BN_clear_free(y2);
508 BN_clear_free(y);
509 BN_clear_free(exp);
510
511 if (prfbuf) talloc_free(prfbuf);
512 if (xbuf) talloc_free(xbuf);
513 if (pm1buf) talloc_free(pm1buf);
514 if (y1buf) talloc_free(y1buf);
515 if (y2buf) talloc_free(y2buf);
516 if (ybuf) talloc_free(ybuf);
517
518 EVP_MD_CTX_free(hmac_ctx);
519 EVP_PKEY_free(hmac_pkey);
520
521 return ret;
522}
523
524int compute_scalar_element(request_t *request, pwd_session_t *session, BN_CTX *bn_ctx)
525{
526 BIGNUM *mask = NULL;
527 int ret = -1;
528
529 MEM(session->private_value = BN_new());
530 MEM(session->my_element = EC_POINT_new(session->group));
531 MEM(session->my_scalar = BN_new());
532
533 MEM(mask = BN_new());
534
535 if (BN_rand_range(session->private_value, session->order) != 1) {
536 REDEBUG("Unable to get randomness for private_value");
537 goto error;
538 }
539 if (BN_rand_range(mask, session->order) != 1) {
540 REDEBUG("Unable to get randomness for mask");
541 goto error;
542 }
543 BN_add(session->my_scalar, session->private_value, mask);
544 BN_mod(session->my_scalar, session->my_scalar, session->order, bn_ctx);
545
546 if (!EC_POINT_mul(session->group, session->my_element, NULL, session->pwe, mask, bn_ctx)) {
547 REDEBUG("Server element allocation failed");
548 goto error;
549 }
550
551 if (!EC_POINT_invert(session->group, session->my_element, bn_ctx)) {
552 REDEBUG("Server element inversion failed");
553 goto error;
554 }
555
556 ret = 0;
557
558error:
559 BN_clear_free(mask);
560
561 return ret;
562}
563
564int process_peer_commit(request_t *request, pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bn_ctx)
565{
566 uint8_t *ptr;
567 size_t data_len;
568 BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
569 EC_POINT *K = NULL, *point = NULL;
570 int ret = 1;
571
572 MEM(session->peer_scalar = BN_new());
573 MEM(session->k = BN_new());
574 MEM(session->peer_element = EC_POINT_new(session->group));
575 MEM(point = EC_POINT_new(session->group));
576 MEM(K = EC_POINT_new(session->group));
577
578 MEM(cofactor = BN_new());
579 MEM(x = BN_new());
580 MEM(y = BN_new());
581
582 if (!EC_GROUP_get_cofactor(session->group, cofactor, NULL)) {
583 REDEBUG("Unable to get group co-factor");
584 goto finish;
585 }
586
587 /* element, x then y, followed by scalar */
588 ptr = (uint8_t *)in;
589 data_len = BN_num_bytes(session->prime);
590
591 /*
592 * Did the peer send enough data?
593 */
594 if (in_len < (2 * data_len + BN_num_bytes(session->order))) {
595 REDEBUG("Invalid commit packet");
596 goto finish;
597 }
598
599 BN_bin2bn(ptr, data_len, x);
600 ptr += data_len;
601 BN_bin2bn(ptr, data_len, y);
602 ptr += data_len;
603
604 data_len = BN_num_bytes(session->order);
605 BN_bin2bn(ptr, data_len, session->peer_scalar);
606
607 /* validate received scalar */
608 if (BN_is_zero(session->peer_scalar) ||
609 BN_is_one(session->peer_scalar) ||
610 BN_cmp(session->peer_scalar, session->order) >= 0) {
611 REDEBUG("Peer's scalar is not within the allowed range");
612 goto finish;
613 }
614
615 if (!EC_POINT_set_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) {
616 REDEBUG("Unable to get coordinates of peer's element");
617 goto finish;
618 }
619
620 /* validate received element */
621 if (!EC_POINT_is_on_curve(session->group, session->peer_element, bn_ctx) ||
622 EC_POINT_is_at_infinity(session->group, session->peer_element)) {
623 REDEBUG("Peer's element is not a point on the elliptic curve");
624 goto finish;
625 }
626
627 /* check to ensure peer's element is not in a small sub-group */
628 if (BN_cmp(cofactor, BN_value_one())) {
629 if (!EC_POINT_mul(session->group, point, NULL, session->peer_element, cofactor, NULL)) {
630 REDEBUG("Unable to multiply element by co-factor");
631 goto finish;
632 }
633
634 if (EC_POINT_is_at_infinity(session->group, point)) {
635 REDEBUG("Peer's element is in small sub-group");
636 goto finish;
637 }
638 }
639
640 /* detect reflection attacks */
641 if (BN_cmp(session->peer_scalar, session->my_scalar) == 0 ||
642 EC_POINT_cmp(session->group, session->peer_element, session->my_element, bn_ctx) == 0) {
643 REDEBUG("Reflection attack detected");
644 goto finish;
645 }
646
647 /* compute the shared key, k */
648 if ((!EC_POINT_mul(session->group, K, NULL, session->pwe, session->peer_scalar, bn_ctx)) ||
649 (!EC_POINT_add(session->group, K, K, session->peer_element, bn_ctx)) ||
650 (!EC_POINT_mul(session->group, K, NULL, K, session->private_value, bn_ctx))) {
651 REDEBUG("Unable to compute shared key, k");
652 goto finish;
653 }
654
655 /* ensure that the shared key isn't in a small sub-group */
656 if (BN_cmp(cofactor, BN_value_one())) {
657 if (!EC_POINT_mul(session->group, K, NULL, K, cofactor, NULL)) {
658 REDEBUG("Unable to multiply k by co-factor");
659 goto finish;
660 }
661 }
662
663 /*
664 * This check is strictly speaking just for the case above where
665 * co-factor > 1 but it was suggested that even though this is probably
666 * never going to happen it is a simple and safe check "just to be
667 * sure" so let's be safe.
668 */
669 if (EC_POINT_is_at_infinity(session->group, K)) {
670 REDEBUG("K is point-at-infinity");
671 goto finish;
672 }
673
674 if (!EC_POINT_get_affine_coordinates(session->group, K, session->k, NULL, bn_ctx)) {
675 REDEBUG("Unable to get shared secret from K");
676 goto finish;
677 }
678 ret = 0;
679
680finish:
681 EC_POINT_clear_free(K);
682 EC_POINT_clear_free(point);
683 BN_clear_free(cofactor);
684 BN_clear_free(x);
685 BN_clear_free(y);
686
687 return ret;
688}
689
690int compute_server_confirm(request_t *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx)
691{
692 BIGNUM *x = NULL, *y = NULL;
693 EVP_MD_CTX *hmac_ctx;
694 EVP_PKEY *hmac_pkey;
695 uint8_t *cruft = NULL;
696 int offset, req = -1;
697
698 /*
699 * Each component of the cruft will be at most as big as the prime
700 */
701 MEM(cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime)));
702 MEM(x = BN_new());
703 MEM(y = BN_new());
704
705 /*
706 * commit is H(k | server_element | server_scalar | peer_element |
707 * peer_scalar | ciphersuite)
708 */
709 MEM(hmac_ctx = EVP_MD_CTX_new());
710 MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, allzero, sizeof(allzero)));
711 EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
712
713 /*
714 * Zero the memory each time because this is mod prime math and some
715 * value may start with a few zeros and the previous one did not.
716 *
717 * First is k
718 */
719 offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
720 BN_bn2bin(session->k, cruft + offset);
721 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
722
723 /*
724 * next is server element: x, y
725 */
726 if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, bn_ctx)) {
727 REDEBUG("Unable to get coordinates of server element");
728 goto finish;
729 }
730 memset(cruft, 0, BN_num_bytes(session->prime));
731 offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
732 BN_bn2bin(x, cruft + offset);
733 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
734
735 memset(cruft, 0, BN_num_bytes(session->prime));
736 offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
737 BN_bn2bin(y, cruft + offset);
738 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
739
740 /*
741 * and server scalar
742 */
743 memset(cruft, 0, BN_num_bytes(session->prime));
744 offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
745 BN_bn2bin(session->my_scalar, cruft + offset);
746 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
747
748 /*
749 * next is peer element: x, y
750 */
751 if (!EC_POINT_get_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) {
752 REDEBUG("Unable to get coordinates of peer's element");
753 goto finish;
754 }
755
756 memset(cruft, 0, BN_num_bytes(session->prime));
757 offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
758 BN_bn2bin(x, cruft + offset);
759 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
760
761 memset(cruft, 0, BN_num_bytes(session->prime));
762 offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
763 BN_bn2bin(y, cruft + offset);
764 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
765
766 /*
767 * and peer scalar
768 */
769 memset(cruft, 0, BN_num_bytes(session->prime));
770 offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
771 BN_bn2bin(session->peer_scalar, cruft + offset);
772 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
773
774 /*
775 * finally, ciphersuite
776 */
777 EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
778
779 pwd_hmac_final(hmac_ctx, out);
780
781 req = 0;
782
783finish:
784 EVP_MD_CTX_free(hmac_ctx);
785 EVP_PKEY_free(hmac_pkey);
786 talloc_free(cruft);
787 BN_free(x);
788 BN_free(y);
789
790 return req;
791}
792
793int compute_peer_confirm(request_t *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx)
794{
795 BIGNUM *x = NULL, *y = NULL;
796 EVP_MD_CTX *hmac_ctx;
797 EVP_PKEY *hmac_pkey;
798 uint8_t *cruft = NULL;
799 int offset, req = -1;
800
801 /*
802 * Each component of the cruft will be at most as big as the prime
803 */
804 MEM(cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime)));
805 MEM(x = BN_new());
806 MEM(y = BN_new());
807
808 /*
809 * commit is H(k | server_element | server_scalar | peer_element |
810 * peer_scalar | ciphersuite)
811 */
812 MEM(hmac_ctx = EVP_MD_CTX_new());
813 MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, allzero, sizeof(allzero)));
814 EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
815
816 /*
817 * Zero the memory each time because this is mod prime math and some
818 * value may start with a few zeros and the previous one did not.
819 *
820 * First is k
821 */
822 offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
823 BN_bn2bin(session->k, cruft + offset);
824 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
825
826 /*
827 * then peer element: x, y
828 */
829 if (!EC_POINT_get_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) {
830 REDEBUG("Unable to get coordinates of peer's element");
831 goto finish;
832 }
833
834 memset(cruft, 0, BN_num_bytes(session->prime));
835 offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
836 BN_bn2bin(x, cruft + offset);
837 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
838
839 memset(cruft, 0, BN_num_bytes(session->prime));
840 offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
841 BN_bn2bin(y, cruft + offset);
842 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
843
844 /*
845 * and peer scalar
846 */
847 memset(cruft, 0, BN_num_bytes(session->prime));
848 offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
849 BN_bn2bin(session->peer_scalar, cruft + offset);
850 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
851
852 /*
853 * then server element: x, y
854 */
855 if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, bn_ctx)) {
856 REDEBUG("Unable to get coordinates of server element");
857 goto finish;
858 }
859 memset(cruft, 0, BN_num_bytes(session->prime));
860 offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
861 BN_bn2bin(x, cruft + offset);
862 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
863
864 memset(cruft, 0, BN_num_bytes(session->prime));
865 offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
866 BN_bn2bin(y, cruft + offset);
867 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
868
869 /*
870 * and server scalar
871 */
872 memset(cruft, 0, BN_num_bytes(session->prime));
873 offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
874 BN_bn2bin(session->my_scalar, cruft + offset);
875 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
876
877 /*
878 * finally, ciphersuite
879 */
880 EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
881
882 pwd_hmac_final(hmac_ctx, out);
883
884 req = 0;
885finish:
886 EVP_MD_CTX_free(hmac_ctx);
887 EVP_PKEY_free(hmac_pkey);
888 talloc_free(cruft);
889 BN_free(x);
890 BN_free(y);
891
892 return req;
893}
894
895int compute_keys(UNUSED request_t *request, pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk)
896{
897 EVP_MD_CTX *hmac_ctx;
898 EVP_PKEY *hmac_pkey;
899 uint8_t mk[SHA256_DIGEST_LENGTH], *cruft;
900 uint8_t session_id[SHA256_DIGEST_LENGTH + 1];
901 uint8_t msk_emsk[128]; /* 64 each */
902 int offset;
903
904 MEM(cruft = talloc_array(session, uint8_t, BN_num_bytes(session->prime)));
905 MEM(hmac_ctx = EVP_MD_CTX_new());
906 MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, allzero, sizeof(allzero)));
907
908 /*
909 * first compute the session-id = TypeCode | H(ciphersuite | scal_p |
910 * scal_s)
911 */
912 session_id[0] = FR_EAP_METHOD_PWD;
913 EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
914 EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
915 offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
916 memset(cruft, 0, BN_num_bytes(session->prime));
917 BN_bn2bin(session->peer_scalar, cruft + offset);
918 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
919 offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
920 memset(cruft, 0, BN_num_bytes(session->prime));
921 BN_bn2bin(session->my_scalar, cruft + offset);
922 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
923 pwd_hmac_final(hmac_ctx, (uint8_t *)&session_id[1]);
924
925 /* then compute MK = H(k | commit-peer | commit-server) */
926 EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
927
928 memset(cruft, 0, BN_num_bytes(session->prime));
929 offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
930 BN_bn2bin(session->k, cruft + offset);
931 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
932
933 EVP_DigestSignUpdate(hmac_ctx, peer_confirm, SHA256_DIGEST_LENGTH);
934
935 EVP_DigestSignUpdate(hmac_ctx, session->my_confirm, SHA256_DIGEST_LENGTH);
936
937 pwd_hmac_final(hmac_ctx, mk);
938
939 /* stretch the mk with the session-id to get MSK | EMSK */
940 eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH, (char const *)session_id,
941 SHA256_DIGEST_LENGTH + 1, msk_emsk, 1024); /* it's bits, ((64 + 64) * 8) */
942
943 memcpy(msk, msk_emsk, 64);
944 memcpy(emsk, msk_emsk + 64, 64);
945
946 EVP_MD_CTX_free(hmac_ctx);
947 EVP_PKEY_free(hmac_pkey);
948 talloc_free(cruft);
949 return 0;
950}
#define USES_APPLE_DEPRECATED_API
Definition build.h:493
#define RCSID(id)
Definition build.h:506
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
#define UNUSED
Definition build.h:336
static int const_time_select_int(unsigned int mask, int true_val, int false_val)
const_time_select_int - Constant time int selection
Definition const_time.h:113
static void const_time_select_bin(unsigned char mask, const unsigned char *true_val, const unsigned char *false_val, size_t len, unsigned char *dst)
const_time_select_bin - Constant time binary buffer selection copy
Definition const_time.h:160
static unsigned int const_time_is_zero(unsigned int val) NO_UBSAN_UINT_OVERFLOW
Definition const_time.h:38
static unsigned int const_time_eq(unsigned int a, unsigned int b)
Definition const_time.h:47
static int const_time_memcmp(const void *a, const void *b, size_t len)
Definition const_time.h:171
static unsigned int const_time_fill_msb(unsigned int val)
const_time_fill_msb - Fill all bits with MSB value
Definition const_time.h:30
static unsigned int const_time_select(unsigned int mask, unsigned int true_val, unsigned int false_val)
const_time_select - Constant time unsigned int selection
Definition const_time.h:98
#define MEM(x)
Definition debug.h:46
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
static fr_slen_t in
Definition dict.h:882
@ FR_EAP_METHOD_PWD
Definition types.h:98
static int legendre(bool *fail, BIGNUM *a, BIGNUM *p, BN_CTX *bnctx)
Definition eap_pwd.c:114
int compute_scalar_element(request_t *request, pwd_session_t *session, BN_CTX *bn_ctx)
Definition eap_pwd.c:524
static int is_quadratic_residue(BIGNUM *val, BIGNUM *p, BIGNUM *qr, BIGNUM *qnr, BN_CTX *bnctx)
Definition eap_pwd.c:176
int process_peer_commit(request_t *request, pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bn_ctx)
Definition eap_pwd.c:564
int compute_server_confirm(request_t *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx)
Definition eap_pwd.c:690
static void pwd_hmac_final(EVP_MD_CTX *hmac_ctx, uint8_t digest[static SHA256_DIGEST_LENGTH])
Definition eap_pwd.c:47
int compute_keys(UNUSED request_t *request, pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk)
Definition eap_pwd.c:895
static void eap_pwd_kdf(uint8_t *key, int keylen, char const *label, int label_len, uint8_t *result, int result_bit_len)
Definition eap_pwd.c:56
static USES_APPLE_DEPRECATED_API uint8_t allzero[SHA256_DIGEST_LENGTH]
copyright holder grants permission for redistribution and use in source and binary forms,...
Definition eap_pwd.c:44
int compute_password_element(request_t *request, pwd_session_t *session, uint16_t grp_num, char const *password, int password_len, char const *id_server, int id_server_len, char const *id_peer, int id_peer_len, uint32_t *token, BN_CTX *bnctx)
Definition eap_pwd.c:256
int compute_peer_confirm(request_t *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx)
Definition eap_pwd.c:793
static void do_equation(EC_GROUP *group, BIGNUM *y2, BIGNUM *x, BN_CTX *bnctx)
Definition eap_pwd.c:145
static BIGNUM * consttime_BN(void)
Definition eap_pwd.c:102
BIGNUM * private_value
Definition eap_pwd.h:96
uint16_t group_num
Definition eap_pwd.h:79
BIGNUM * my_scalar
Definition eap_pwd.h:98
uint8_t my_confirm[SHA256_DIGEST_LENGTH]
Definition eap_pwd.h:101
BIGNUM * prime
Definition eap_pwd.h:94
EC_GROUP * group
Definition eap_pwd.h:91
BIGNUM * peer_scalar
Definition eap_pwd.h:97
EC_POINT * pwe
Definition eap_pwd.h:92
BIGNUM * k
Definition eap_pwd.h:95
uint32_t ciphersuite
Definition eap_pwd.h:80
BIGNUM * order
Definition eap_pwd.h:93
EC_POINT * peer_element
Definition eap_pwd.h:100
EC_POINT * my_element
Definition eap_pwd.h:99
free(array)
talloc_free(hp)
unsigned short uint16_t
unsigned int uint32_t
unsigned char uint8_t
#define REDEBUG(fmt,...)
static uint32_t mask
Definition rbmonkey.c:39
static size_t char ** out
Definition value.h:1030