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