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: 218a246cd8557221cd5d8ca3c47cf9ea1a51036c $")
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 DEBUG("unable to compute y");
482 goto fail;
483 }
484 /*
485 * y1 / y2 are mod-prime values uniformly distributed in [0, p-1]; either may
486 * have leading zero bytes (~1/256 per byte). We need fixed-width big-endian
487 * encoding for the const_time_select_bin / BN_bin2bn round-trip below, so
488 * pad with leading zeros rather than letting BN_bn2bin shift bytes to the
489 * front of the buffer.
490 */
491 {
492 size_t y1_pad = primebytelen - BN_num_bytes(y1);
493 size_t y2_pad = primebytelen - BN_num_bytes(y2);
494
495 memset(y1buf, 0, y1_pad);
496 memset(y2buf, 0, y2_pad);
497 if ((BN_bn2bin(y1, y1buf + y1_pad) < 0) ||
498 (BN_bn2bin(y2, y2buf + y2_pad) < 0)) {
499 DEBUG("unable to write y to buffer");
500 goto fail;
501 }
502 }
503 mask = const_time_eq(save_is_odd, BN_is_odd(y1));
504 const_time_select_bin(mask, y1buf, y2buf, primebytelen, ybuf);
505 if (BN_bin2bn(ybuf, primebytelen, y) == NULL ||
506 !EC_POINT_set_affine_coordinates(session->group, session->pwe, x_candidate, y, bnctx)) {
507 DEBUG("unable to set point coordinate");
508 goto fail;
509 }
510
511 session->group_num = grp_num;
512 if (0) {
513 fail: /* DON'T free session, it's in handler->opaque */
514 ret = -1;
515 }
516
517 /* cleanliness and order.... */
518 BN_clear_free(x_candidate);
519 BN_clear_free(y_sqrd);
520 BN_clear_free(qr);
521 BN_clear_free(qnr);
522 BN_clear_free(rnd);
523 BN_clear_free(y1);
524 BN_clear_free(y2);
525 BN_clear_free(y);
526 BN_clear_free(exp);
527
528 if (prfbuf) talloc_free(prfbuf);
529 if (xbuf) talloc_free(xbuf);
530 if (pm1buf) talloc_free(pm1buf);
531 if (y1buf) talloc_free(y1buf);
532 if (y2buf) talloc_free(y2buf);
533 if (ybuf) talloc_free(ybuf);
534
535 EVP_MD_CTX_free(hmac_ctx);
536 EVP_PKEY_free(hmac_pkey);
537
538 return ret;
539}
540
541int compute_scalar_element(request_t *request, pwd_session_t *session, BN_CTX *bn_ctx)
542{
543 BIGNUM *mask = NULL;
544 int ret = -1;
545
546 MEM(session->private_value = BN_new());
547 MEM(session->my_element = EC_POINT_new(session->group));
548 MEM(session->my_scalar = BN_new());
549
550 MEM(mask = BN_new());
551
552 if (BN_rand_range(session->private_value, session->order) != 1) {
553 REDEBUG("Unable to get randomness for private_value");
554 goto error;
555 }
556 if (BN_rand_range(mask, session->order) != 1) {
557 REDEBUG("Unable to get randomness for mask");
558 goto error;
559 }
560 BN_add(session->my_scalar, session->private_value, mask);
561 BN_mod(session->my_scalar, session->my_scalar, session->order, bn_ctx);
562
563 if (!EC_POINT_mul(session->group, session->my_element, NULL, session->pwe, mask, bn_ctx)) {
564 REDEBUG("Server element allocation failed");
565 goto error;
566 }
567
568 if (!EC_POINT_invert(session->group, session->my_element, bn_ctx)) {
569 REDEBUG("Server element inversion failed");
570 goto error;
571 }
572
573 ret = 0;
574
575error:
576 BN_clear_free(mask);
577
578 return ret;
579}
580
581int process_peer_commit(request_t *request, pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bn_ctx)
582{
583 uint8_t *ptr;
584 size_t data_len;
585 BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
586 EC_POINT *K = NULL, *point = NULL;
587 int ret = 1;
588
589 MEM(session->peer_scalar = BN_new());
590 MEM(session->k = BN_new());
591 MEM(session->peer_element = EC_POINT_new(session->group));
592 MEM(point = EC_POINT_new(session->group));
593 MEM(K = EC_POINT_new(session->group));
594
595 MEM(cofactor = BN_new());
596 MEM(x = BN_new());
597 MEM(y = BN_new());
598
599 if (!EC_GROUP_get_cofactor(session->group, cofactor, NULL)) {
600 REDEBUG("Unable to get group co-factor");
601 goto finish;
602 }
603
604 /* element, x then y, followed by scalar */
605 ptr = (uint8_t *)in;
606 data_len = BN_num_bytes(session->prime);
607
608 /*
609 * Did the peer send enough data?
610 */
611 if (in_len < (2 * data_len + BN_num_bytes(session->order))) {
612 REDEBUG("Invalid commit packet");
613 goto finish;
614 }
615
616 BN_bin2bn(ptr, data_len, x);
617 ptr += data_len;
618 BN_bin2bn(ptr, data_len, y);
619 ptr += data_len;
620
621 data_len = BN_num_bytes(session->order);
622 BN_bin2bn(ptr, data_len, session->peer_scalar);
623
624 /* validate received scalar */
625 if (BN_is_zero(session->peer_scalar) ||
626 BN_is_one(session->peer_scalar) ||
627 BN_cmp(session->peer_scalar, session->order) >= 0) {
628 REDEBUG("Peer's scalar is not within the allowed range");
629 goto finish;
630 }
631
632 if (!EC_POINT_set_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) {
633 REDEBUG("Unable to get coordinates of peer's element");
634 goto finish;
635 }
636
637 /* validate received element */
638 if (!EC_POINT_is_on_curve(session->group, session->peer_element, bn_ctx) ||
639 EC_POINT_is_at_infinity(session->group, session->peer_element)) {
640 REDEBUG("Peer's element is not a point on the elliptic curve");
641 goto finish;
642 }
643
644 /* check to ensure peer's element is not in a small sub-group */
645 if (BN_cmp(cofactor, BN_value_one())) {
646 if (!EC_POINT_mul(session->group, point, NULL, session->peer_element, cofactor, NULL)) {
647 REDEBUG("Unable to multiply element by co-factor");
648 goto finish;
649 }
650
651 if (EC_POINT_is_at_infinity(session->group, point)) {
652 REDEBUG("Peer's element is in small sub-group");
653 goto finish;
654 }
655 }
656
657 /* detect reflection attacks */
658 if (BN_cmp(session->peer_scalar, session->my_scalar) == 0 ||
659 EC_POINT_cmp(session->group, session->peer_element, session->my_element, bn_ctx) == 0) {
660 REDEBUG("Reflection attack detected");
661 goto finish;
662 }
663
664 /* compute the shared key, k */
665 if ((!EC_POINT_mul(session->group, K, NULL, session->pwe, session->peer_scalar, bn_ctx)) ||
666 (!EC_POINT_add(session->group, K, K, session->peer_element, bn_ctx)) ||
667 (!EC_POINT_mul(session->group, K, NULL, K, session->private_value, bn_ctx))) {
668 REDEBUG("Unable to compute shared key, k");
669 goto finish;
670 }
671
672 /* ensure that the shared key isn't in a small sub-group */
673 if (BN_cmp(cofactor, BN_value_one())) {
674 if (!EC_POINT_mul(session->group, K, NULL, K, cofactor, NULL)) {
675 REDEBUG("Unable to multiply k by co-factor");
676 goto finish;
677 }
678 }
679
680 /*
681 * This check is strictly speaking just for the case above where
682 * co-factor > 1 but it was suggested that even though this is probably
683 * never going to happen it is a simple and safe check "just to be
684 * sure" so let's be safe.
685 */
686 if (EC_POINT_is_at_infinity(session->group, K)) {
687 REDEBUG("K is point-at-infinity");
688 goto finish;
689 }
690
691 if (!EC_POINT_get_affine_coordinates(session->group, K, session->k, NULL, bn_ctx)) {
692 REDEBUG("Unable to get shared secret from K");
693 goto finish;
694 }
695 ret = 0;
696
697finish:
698 EC_POINT_clear_free(K);
699 EC_POINT_clear_free(point);
700 BN_clear_free(cofactor);
701 BN_clear_free(x);
702 BN_clear_free(y);
703
704 return ret;
705}
706
707int compute_server_confirm(request_t *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx)
708{
709 BIGNUM *x = NULL, *y = NULL;
710 EVP_MD_CTX *hmac_ctx;
711 EVP_PKEY *hmac_pkey;
712 uint8_t *cruft = NULL;
713 int offset, req = -1;
714
715 /*
716 * Each component of the cruft will be at most as big as the prime
717 */
718 MEM(cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime)));
719 MEM(x = BN_new());
720 MEM(y = BN_new());
721
722 /*
723 * commit is H(k | server_element | server_scalar | peer_element |
724 * peer_scalar | ciphersuite)
725 */
726 MEM(hmac_ctx = EVP_MD_CTX_new());
727 MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, allzero, sizeof(allzero)));
728 EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
729
730 /*
731 * Zero the memory each time because this is mod prime math and some
732 * value may start with a few zeros and the previous one did not.
733 *
734 * First is k
735 */
736 offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
737 BN_bn2bin(session->k, cruft + offset);
738 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
739
740 /*
741 * next is server element: x, y
742 */
743 if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, bn_ctx)) {
744 REDEBUG("Unable to get coordinates of server element");
745 goto finish;
746 }
747 memset(cruft, 0, BN_num_bytes(session->prime));
748 offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
749 BN_bn2bin(x, cruft + offset);
750 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
751
752 memset(cruft, 0, BN_num_bytes(session->prime));
753 offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
754 BN_bn2bin(y, cruft + offset);
755 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
756
757 /*
758 * and server scalar
759 */
760 memset(cruft, 0, BN_num_bytes(session->prime));
761 offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
762 BN_bn2bin(session->my_scalar, cruft + offset);
763 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
764
765 /*
766 * next is peer element: x, y
767 */
768 if (!EC_POINT_get_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) {
769 REDEBUG("Unable to get coordinates of peer's element");
770 goto finish;
771 }
772
773 memset(cruft, 0, BN_num_bytes(session->prime));
774 offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
775 BN_bn2bin(x, cruft + offset);
776 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
777
778 memset(cruft, 0, BN_num_bytes(session->prime));
779 offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
780 BN_bn2bin(y, cruft + offset);
781 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
782
783 /*
784 * and peer scalar
785 */
786 memset(cruft, 0, BN_num_bytes(session->prime));
787 offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
788 BN_bn2bin(session->peer_scalar, cruft + offset);
789 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
790
791 /*
792 * finally, ciphersuite
793 */
794 EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
795
796 pwd_hmac_final(hmac_ctx, out);
797
798 req = 0;
799
800finish:
801 EVP_MD_CTX_free(hmac_ctx);
802 EVP_PKEY_free(hmac_pkey);
803 talloc_free(cruft);
804 BN_free(x);
805 BN_free(y);
806
807 return req;
808}
809
810int compute_peer_confirm(request_t *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx)
811{
812 BIGNUM *x = NULL, *y = NULL;
813 EVP_MD_CTX *hmac_ctx;
814 EVP_PKEY *hmac_pkey;
815 uint8_t *cruft = NULL;
816 int offset, req = -1;
817
818 /*
819 * Each component of the cruft will be at most as big as the prime
820 */
821 MEM(cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime)));
822 MEM(x = BN_new());
823 MEM(y = BN_new());
824
825 /*
826 * commit is H(k | server_element | server_scalar | peer_element |
827 * peer_scalar | ciphersuite)
828 */
829 MEM(hmac_ctx = EVP_MD_CTX_new());
830 MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, allzero, sizeof(allzero)));
831 EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
832
833 /*
834 * Zero the memory each time because this is mod prime math and some
835 * value may start with a few zeros and the previous one did not.
836 *
837 * First is k
838 */
839 offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
840 BN_bn2bin(session->k, cruft + offset);
841 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
842
843 /*
844 * then peer element: x, y
845 */
846 if (!EC_POINT_get_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) {
847 REDEBUG("Unable to get coordinates of peer's element");
848 goto finish;
849 }
850
851 memset(cruft, 0, BN_num_bytes(session->prime));
852 offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
853 BN_bn2bin(x, cruft + offset);
854 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
855
856 memset(cruft, 0, BN_num_bytes(session->prime));
857 offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
858 BN_bn2bin(y, cruft + offset);
859 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
860
861 /*
862 * and peer scalar
863 */
864 memset(cruft, 0, BN_num_bytes(session->prime));
865 offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
866 BN_bn2bin(session->peer_scalar, cruft + offset);
867 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
868
869 /*
870 * then server element: x, y
871 */
872 if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, bn_ctx)) {
873 REDEBUG("Unable to get coordinates of server element");
874 goto finish;
875 }
876 memset(cruft, 0, BN_num_bytes(session->prime));
877 offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
878 BN_bn2bin(x, cruft + offset);
879 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
880
881 memset(cruft, 0, BN_num_bytes(session->prime));
882 offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
883 BN_bn2bin(y, cruft + offset);
884 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
885
886 /*
887 * and server scalar
888 */
889 memset(cruft, 0, BN_num_bytes(session->prime));
890 offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
891 BN_bn2bin(session->my_scalar, cruft + offset);
892 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
893
894 /*
895 * finally, ciphersuite
896 */
897 EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
898
899 pwd_hmac_final(hmac_ctx, out);
900
901 req = 0;
902finish:
903 EVP_MD_CTX_free(hmac_ctx);
904 EVP_PKEY_free(hmac_pkey);
905 talloc_free(cruft);
906 BN_free(x);
907 BN_free(y);
908
909 return req;
910}
911
912int compute_keys(UNUSED request_t *request, pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk)
913{
914 EVP_MD_CTX *hmac_ctx;
915 EVP_PKEY *hmac_pkey;
916 uint8_t mk[SHA256_DIGEST_LENGTH], *cruft;
917 uint8_t session_id[SHA256_DIGEST_LENGTH + 1];
918 uint8_t msk_emsk[128]; /* 64 each */
919 int offset;
920
921 MEM(cruft = talloc_array(session, uint8_t, BN_num_bytes(session->prime)));
922 MEM(hmac_ctx = EVP_MD_CTX_new());
923 MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, allzero, sizeof(allzero)));
924
925 /*
926 * first compute the session-id = TypeCode | H(ciphersuite | scal_p |
927 * scal_s)
928 */
929 session_id[0] = FR_EAP_METHOD_PWD;
930 EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
931 EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
932 offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
933 memset(cruft, 0, BN_num_bytes(session->prime));
934 BN_bn2bin(session->peer_scalar, cruft + offset);
935 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
936 offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
937 memset(cruft, 0, BN_num_bytes(session->prime));
938 BN_bn2bin(session->my_scalar, cruft + offset);
939 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->order));
940 pwd_hmac_final(hmac_ctx, (uint8_t *)&session_id[1]);
941
942 /* then compute MK = H(k | commit-peer | commit-server) */
943 EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
944
945 memset(cruft, 0, BN_num_bytes(session->prime));
946 offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
947 BN_bn2bin(session->k, cruft + offset);
948 EVP_DigestSignUpdate(hmac_ctx, cruft, BN_num_bytes(session->prime));
949
950 EVP_DigestSignUpdate(hmac_ctx, peer_confirm, SHA256_DIGEST_LENGTH);
951
952 EVP_DigestSignUpdate(hmac_ctx, session->my_confirm, SHA256_DIGEST_LENGTH);
953
954 pwd_hmac_final(hmac_ctx, mk);
955
956 /* stretch the mk with the session-id to get MSK | EMSK */
957 eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH, (char const *)session_id,
958 SHA256_DIGEST_LENGTH + 1, msk_emsk, 1024); /* it's bits, ((64 + 64) * 8) */
959
960 memcpy(msk, msk_emsk, 64);
961 memcpy(emsk, msk_emsk + 64, 64);
962
963 EVP_MD_CTX_free(hmac_ctx);
964 EVP_PKEY_free(hmac_pkey);
965 talloc_free(cruft);
966 return 0;
967}
#define USES_APPLE_DEPRECATED_API
Definition build.h:499
#define RCSID(id)
Definition build.h:512
#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:36
#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:541
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:581
int compute_server_confirm(request_t *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx)
Definition eap_pwd.c:707
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:912
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:810
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