All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
eap_pwd.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) Dan Harkins, 2012
3  *
4  * Copyright holder grants permission for redistribution and use in source
5  * and binary forms, with or without modification, provided that the
6  * following conditions are met:
7  * 1. Redistribution of source code must retain the above copyright
8  * notice, this list of conditions, and the following disclaimer
9  * in all source files.
10  * 2. Redistribution in binary form must retain the above copyright
11  * notice, this list of conditions, and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *
15  * "DISCLAIMER OF LIABILITY
16  *
17  * THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE."
28  *
29  * This license and distribution terms cannot be changed. In other words,
30  * this code cannot simply be copied and put under a different distribution
31  * license (including the GNU public license).
32  */
33 
34 RCSID("$Id: 1c17e39563515b6aeb4acd74683d73663a295190 $")
35 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
36 
37 #include "eap_pwd.h"
38 
39 #include <freeradius-devel/radiusd.h>
40 #include <freeradius-devel/modules.h>
41 
42 /* The random function H(x) = HMAC-SHA256(0^32, x) */
43 static void H_Init(HMAC_CTX *ctx)
44 {
45  uint8_t allzero[SHA256_DIGEST_LENGTH];
46 
47  memset(allzero, 0, SHA256_DIGEST_LENGTH);
48  HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256());
49 }
50 
51 static void H_Update(HMAC_CTX *ctx, uint8_t const *data, int len)
52 {
53  HMAC_Update(ctx, data, len);
54 }
55 
56 static void H_Final(HMAC_CTX *ctx, uint8_t *digest)
57 {
58  unsigned int mdlen = SHA256_DIGEST_LENGTH;
59 
60  HMAC_Final(ctx, digest, &mdlen);
61  HMAC_CTX_cleanup(ctx);
62 }
63 
64 /* a counter-based KDF based on NIST SP800-108 */
65 static void eap_pwd_kdf(uint8_t *key, int keylen, char const *label, int labellen, uint8_t *result, int resultbitlen)
66 {
67  HMAC_CTX hctx;
68  uint8_t digest[SHA256_DIGEST_LENGTH];
69  uint16_t i, ctr, L;
70  int resultbytelen, len = 0;
71  unsigned int mdlen = SHA256_DIGEST_LENGTH;
72  uint8_t mask = 0xff;
73 
74  resultbytelen = (resultbitlen + 7)/8;
75  ctr = 0;
76  L = htons(resultbitlen);
77  while (len < resultbytelen) {
78  ctr++; i = htons(ctr);
79  HMAC_Init(&hctx, key, keylen, EVP_sha256());
80  if (ctr > 1) {
81  HMAC_Update(&hctx, digest, mdlen);
82  }
83  HMAC_Update(&hctx, (uint8_t *) &i, sizeof(uint16_t));
84  HMAC_Update(&hctx, (uint8_t const *)label, labellen);
85  HMAC_Update(&hctx, (uint8_t *) &L, sizeof(uint16_t));
86  HMAC_Final(&hctx, digest, &mdlen);
87  if ((len + (int) mdlen) > resultbytelen) {
88  memcpy(result + len, digest, resultbytelen - len);
89  } else {
90  memcpy(result + len, digest, mdlen);
91  }
92  len += mdlen;
93  HMAC_CTX_cleanup(&hctx);
94  }
95 
96  /* since we're expanding to a bit length, mask off the excess */
97  if (resultbitlen % 8) {
98  mask <<= (8 - (resultbitlen % 8));
99  result[resultbytelen - 1] &= mask;
100  }
101 }
102 
103 int compute_password_element (pwd_session_t *session, uint16_t grp_num,
104  char const *password, int password_len,
105  char const *id_server, int id_server_len,
106  char const *id_peer, int id_peer_len,
107  uint32_t *token)
108 {
109  BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
110  HMAC_CTX ctx;
111  uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
112  int nid, is_odd, primebitlen, primebytelen, ret = 0;
113 
114  switch (grp_num) { /* from IANA registry for IKE D-H groups */
115  case 19:
116  nid = NID_X9_62_prime256v1;
117  break;
118 
119  case 20:
120  nid = NID_secp384r1;
121  break;
122 
123  case 21:
124  nid = NID_secp521r1;
125  break;
126 
127  case 25:
128  nid = NID_X9_62_prime192v1;
129  break;
130 
131  case 26:
132  nid = NID_secp224r1;
133  break;
134 
135  default:
136  DEBUG("unknown group %d", grp_num);
137  goto fail;
138  }
139 
140  session->pwe = NULL;
141  session->order = NULL;
142  session->prime = NULL;
143 
144  if ((session->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
145  DEBUG("unable to create EC_GROUP");
146  goto fail;
147  }
148 
149  if (((rnd = BN_new()) == NULL) ||
150  ((cofactor = BN_new()) == NULL) ||
151  ((session->pwe = EC_POINT_new(session->group)) == NULL) ||
152  ((session->order = BN_new()) == NULL) ||
153  ((session->prime = BN_new()) == NULL) ||
154  ((x_candidate = BN_new()) == NULL)) {
155  DEBUG("unable to create bignums");
156  goto fail;
157  }
158 
159  if (!EC_GROUP_get_curve_GFp(session->group, session->prime, NULL, NULL, NULL)) {
160  DEBUG("unable to get prime for GFp curve");
161  goto fail;
162  }
163 
164  if (!EC_GROUP_get_order(session->group, session->order, NULL)) {
165  DEBUG("unable to get order for curve");
166  goto fail;
167  }
168 
169  if (!EC_GROUP_get_cofactor(session->group, cofactor, NULL)) {
170  DEBUG("unable to get cofactor for curve");
171  goto fail;
172  }
173 
174  primebitlen = BN_num_bits(session->prime);
175  primebytelen = BN_num_bytes(session->prime);
176  if ((prfbuf = talloc_zero_array(session, uint8_t, primebytelen)) == NULL) {
177  DEBUG("unable to alloc space for prf buffer");
178  goto fail;
179  }
180  ctr = 0;
181  while (1) {
182  if (ctr > 10) {
183  DEBUG("unable to find random point on curve for group %d, something's fishy", grp_num);
184  goto fail;
185  }
186  ctr++;
187 
188  /*
189  * compute counter-mode password value and stretch to prime
190  * pwd-seed = H(token | peer-id | server-id | password |
191  * counter)
192  */
193  H_Init(&ctx);
194  H_Update(&ctx, (uint8_t *)token, sizeof(*token));
195  H_Update(&ctx, (uint8_t const *)id_peer, id_peer_len);
196  H_Update(&ctx, (uint8_t const *)id_server, id_server_len);
197  H_Update(&ctx, (uint8_t const *)password, password_len);
198  H_Update(&ctx, (uint8_t *)&ctr, sizeof(ctr));
199  H_Final(&ctx, pwe_digest);
200 
201  BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd);
202  eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH, "EAP-pwd Hunting And Pecking",
203  strlen("EAP-pwd Hunting And Pecking"), prfbuf, primebitlen);
204 
205  BN_bin2bn(prfbuf, primebytelen, x_candidate);
206  /*
207  * eap_pwd_kdf() returns a string of bits 0..primebitlen but
208  * BN_bin2bn will treat that string of bits as a big endian
209  * number. If the primebitlen is not an even multiple of 8
210  * then excessive bits-- those _after_ primebitlen-- so now
211  * we have to shift right the amount we masked off.
212  */
213  if (primebitlen % 8) BN_rshift(x_candidate, x_candidate, (8 - (primebitlen % 8)));
214  if (BN_ucmp(x_candidate, session->prime) >= 0) continue;
215 
216  /*
217  * need to unambiguously identify the solution, if there is
218  * one...
219  */
220  is_odd = BN_is_odd(rnd) ? 1 : 0;
221 
222  /*
223  * solve the quadratic equation, if it's not solvable then we
224  * don't have a point
225  */
226  if (!EC_POINT_set_compressed_coordinates_GFp(session->group, session->pwe, x_candidate, is_odd, NULL)) {
227  continue;
228  }
229 
230  /*
231  * If there's a solution to the equation then the point must be
232  * on the curve so why check again explicitly? OpenSSL code
233  * says this is required by X9.62. We're not X9.62 but it can't
234  * hurt just to be sure.
235  */
236  if (!EC_POINT_is_on_curve(session->group, session->pwe, NULL)) {
237  DEBUG("EAP-pwd: point is not on curve");
238  continue;
239  }
240 
241  if (BN_cmp(cofactor, BN_value_one())) {
242  /* make sure the point is not in a small sub-group */
243  if (!EC_POINT_mul(session->group, session->pwe, NULL, session->pwe,
244  cofactor, NULL)) {
245  DEBUG("EAP-pwd: cannot multiply generator by order");
246  continue;
247  }
248 
249  if (EC_POINT_is_at_infinity(session->group, session->pwe)) {
250  DEBUG("EAP-pwd: point is at infinity");
251  continue;
252  }
253  }
254  /* if we got here then we have a new generator. */
255  break;
256  }
257 
258  session->group_num = grp_num;
259  if (0) {
260  fail: /* DON'T free session, it's in eap_session->opaque */
261  ret = -1;
262  }
263 
264  /* cleanliness and order.... */
265  BN_clear_free(cofactor);
266  BN_clear_free(x_candidate);
267  BN_clear_free(rnd);
268  talloc_free(prfbuf);
269 
270  return ret;
271 }
272 
273 int compute_scalar_element (pwd_session_t *session, BN_CTX *bnctx)
274 {
275  BIGNUM *mask = NULL;
276  int ret = -1;
277 
278  if (((session->private_value = BN_new()) == NULL) ||
279  ((session->my_element = EC_POINT_new(session->group)) == NULL) ||
280  ((session->my_scalar = BN_new()) == NULL) ||
281  ((mask = BN_new()) == NULL)) {
282  DEBUG2("server scalar allocation failed");
283  goto fail;
284  }
285 
286  if (BN_rand_range(session->private_value, session->order) != 1) {
287  DEBUG2("Unable to get randomness for private_value");
288  goto fail;
289  }
290  if (BN_rand_range(mask, session->order) != 1) {
291  DEBUG2("Unable to get randomness for mask");
292  goto fail;
293  }
294  BN_add(session->my_scalar, session->private_value, mask);
295  BN_mod(session->my_scalar, session->my_scalar, session->order, bnctx);
296 
297  if (!EC_POINT_mul(session->group, session->my_element, NULL, session->pwe, mask, bnctx)) {
298  DEBUG2("server element allocation failed");
299  goto fail;
300  }
301 
302  if (!EC_POINT_invert(session->group, session->my_element, bnctx)) {
303  DEBUG2("server element inversion failed");
304  goto fail;
305  }
306 
307  ret = 0;
308 
309 fail:
310  BN_clear_free(mask);
311 
312  return ret;
313 }
314 
315 int process_peer_commit (pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bnctx)
316 {
317  uint8_t *ptr;
318  size_t data_len;
319  BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
320  EC_POINT *K = NULL, *point = NULL;
321  int res = 1;
322 
323  if (((session->peer_scalar = BN_new()) == NULL) ||
324  ((session->k = BN_new()) == NULL) ||
325  ((cofactor = BN_new()) == NULL) ||
326  ((x = BN_new()) == NULL) ||
327  ((y = BN_new()) == NULL) ||
328  ((point = EC_POINT_new(session->group)) == NULL) ||
329  ((K = EC_POINT_new(session->group)) == NULL) ||
330  ((session->peer_element = EC_POINT_new(session->group)) == NULL)) {
331  DEBUG2("pwd: failed to allocate room to process peer's commit");
332  goto finish;
333  }
334 
335  if (!EC_GROUP_get_cofactor(session->group, cofactor, NULL)) {
336  DEBUG2("pwd: unable to get group co-factor");
337  goto finish;
338  }
339 
340  /* element, x then y, followed by scalar */
341  ptr = (uint8_t *)in;
342  data_len = BN_num_bytes(session->prime);
343 
344  /*
345  * Did the peer send enough data?
346  */
347  if (in_len < (2 * data_len + BN_num_bytes(session->order))) {
348  DEBUG("pwd: Invalid commit packet");
349  goto finish;
350  }
351 
352  BN_bin2bn(ptr, data_len, x);
353  ptr += data_len;
354  BN_bin2bn(ptr, data_len, y);
355  ptr += data_len;
356 
357  data_len = BN_num_bytes(session->order);
358  BN_bin2bn(ptr, data_len, session->peer_scalar);
359 
360  if (!EC_POINT_set_affine_coordinates_GFp(session->group, session->peer_element, x, y, bnctx)) {
361  DEBUG2("pwd: unable to get coordinates of peer's element");
362  goto finish;
363  }
364 
365  /* check to ensure peer's element is not in a small sub-group */
366  if (BN_cmp(cofactor, BN_value_one())) {
367  if (!EC_POINT_mul(session->group, point, NULL, session->peer_element, cofactor, NULL)) {
368  DEBUG2("pwd: unable to multiply element by co-factor");
369  goto finish;
370  }
371 
372  if (EC_POINT_is_at_infinity(session->group, point)) {
373  DEBUG2("pwd: peer's element is in small sub-group");
374  goto finish;
375  }
376  }
377 
378  /* compute the shared key, k */
379  if ((!EC_POINT_mul(session->group, K, NULL, session->pwe, session->peer_scalar, bnctx)) ||
380  (!EC_POINT_add(session->group, K, K, session->peer_element, bnctx)) ||
381  (!EC_POINT_mul(session->group, K, NULL, K, session->private_value, bnctx))) {
382  DEBUG2("pwd: unable to compute shared key, k");
383  goto finish;
384  }
385 
386  /* ensure that the shared key isn't in a small sub-group */
387  if (BN_cmp(cofactor, BN_value_one())) {
388  if (!EC_POINT_mul(session->group, K, NULL, K, cofactor, NULL)) {
389  DEBUG2("pwd: unable to multiply k by co-factor");
390  goto finish;
391  }
392  }
393 
394  /*
395  * This check is strictly speaking just for the case above where
396  * co-factor > 1 but it was suggested that even though this is probably
397  * never going to happen it is a simple and safe check "just to be
398  * sure" so let's be safe.
399  */
400  if (EC_POINT_is_at_infinity(session->group, K)) {
401  DEBUG2("pwd: k is point-at-infinity!");
402  goto finish;
403  }
404 
405  if (!EC_POINT_get_affine_coordinates_GFp(session->group, K, session->k, NULL, bnctx)) {
406  DEBUG2("pwd: unable to get shared secret from K");
407  goto finish;
408  }
409  res = 0;
410 
411 finish:
412  EC_POINT_clear_free(K);
413  EC_POINT_clear_free(point);
414  BN_clear_free(cofactor);
415  BN_clear_free(x);
416  BN_clear_free(y);
417 
418  return res;
419 }
420 
421 int compute_server_confirm (pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
422 {
423  BIGNUM *x = NULL, *y = NULL;
424  HMAC_CTX ctx;
425  uint8_t *cruft = NULL;
426  int offset, req = -1;
427 
428  /*
429  * Each component of the cruft will be at most as big as the prime
430  */
431  if (((cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime))) == NULL) ||
432  ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
433  DEBUG2("pwd: unable to allocate space to compute confirm!");
434  goto finish;
435  }
436 
437  /*
438  * commit is H(k | server_element | server_scalar | peer_element |
439  * peer_scalar | ciphersuite)
440  */
441  H_Init(&ctx);
442 
443  /*
444  * Zero the memory each time because this is mod prime math and some
445  * value may start with a few zeros and the previous one did not.
446  *
447  * First is k
448  */
449  offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
450  BN_bn2bin(session->k, cruft + offset);
451  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
452 
453  /*
454  * next is server element: x, y
455  */
456  if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->my_element, x, y, bnctx)) {
457  DEBUG2("pwd: unable to get coordinates of server element");
458  goto finish;
459  }
460  memset(cruft, 0, BN_num_bytes(session->prime));
461  offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
462  BN_bn2bin(x, cruft + offset);
463  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
464 
465  memset(cruft, 0, BN_num_bytes(session->prime));
466  offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
467  BN_bn2bin(y, cruft + offset);
468  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
469 
470  /*
471  * and server scalar
472  */
473  memset(cruft, 0, BN_num_bytes(session->prime));
474  offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
475  BN_bn2bin(session->my_scalar, cruft + offset);
476  H_Update(&ctx, cruft, BN_num_bytes(session->order));
477 
478  /*
479  * next is peer element: x, y
480  */
481  if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->peer_element, x, y, bnctx)) {
482  DEBUG2("pwd: unable to get coordinates of peer's element");
483  goto finish;
484  }
485 
486  memset(cruft, 0, BN_num_bytes(session->prime));
487  offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
488  BN_bn2bin(x, cruft + offset);
489  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
490 
491  memset(cruft, 0, BN_num_bytes(session->prime));
492  offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
493  BN_bn2bin(y, cruft + offset);
494  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
495 
496  /*
497  * and peer scalar
498  */
499  memset(cruft, 0, BN_num_bytes(session->prime));
500  offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
501  BN_bn2bin(session->peer_scalar, cruft + offset);
502  H_Update(&ctx, cruft, BN_num_bytes(session->order));
503 
504  /*
505  * finally, ciphersuite
506  */
507  H_Update(&ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
508 
509  H_Final(&ctx, out);
510 
511  req = 0;
512 finish:
513  talloc_free(cruft);
514  BN_free(x);
515  BN_free(y);
516 
517  return req;
518 }
519 
520 int compute_peer_confirm (pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
521 {
522  BIGNUM *x = NULL, *y = NULL;
523  HMAC_CTX ctx;
524  uint8_t *cruft = NULL;
525  int offset, req = -1;
526 
527  /*
528  * Each component of the cruft will be at most as big as the prime
529  */
530  if (((cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime))) == NULL) ||
531  ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
532  DEBUG2("pwd: unable to allocate space to compute confirm!");
533  goto finish;
534  }
535 
536  /*
537  * commit is H(k | server_element | server_scalar | peer_element |
538  * peer_scalar | ciphersuite)
539  */
540  H_Init(&ctx);
541 
542  /*
543  * Zero the memory each time because this is mod prime math and some
544  * value may start with a few zeros and the previous one did not.
545  *
546  * First is k
547  */
548  offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
549  BN_bn2bin(session->k, cruft + offset);
550  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
551 
552  /*
553  * then peer element: x, y
554  */
555  if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->peer_element, x, y, bnctx)) {
556  DEBUG2("pwd: unable to get coordinates of peer's element");
557  goto finish;
558  }
559 
560  memset(cruft, 0, BN_num_bytes(session->prime));
561  offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
562  BN_bn2bin(x, cruft + offset);
563  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
564 
565  memset(cruft, 0, BN_num_bytes(session->prime));
566  offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
567  BN_bn2bin(y, cruft + offset);
568  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
569 
570  /*
571  * and peer scalar
572  */
573  memset(cruft, 0, BN_num_bytes(session->prime));
574  offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
575  BN_bn2bin(session->peer_scalar, cruft + offset);
576  H_Update(&ctx, cruft, BN_num_bytes(session->order));
577 
578  /*
579  * then server element: x, y
580  */
581  if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->my_element, x, y, bnctx)) {
582  DEBUG2("pwd: unable to get coordinates of server element");
583  goto finish;
584  }
585  memset(cruft, 0, BN_num_bytes(session->prime));
586  offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
587  BN_bn2bin(x, cruft + offset);
588  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
589 
590  memset(cruft, 0, BN_num_bytes(session->prime));
591  offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
592  BN_bn2bin(y, cruft + offset);
593  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
594 
595  /*
596  * and server scalar
597  */
598  memset(cruft, 0, BN_num_bytes(session->prime));
599  offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
600  BN_bn2bin(session->my_scalar, cruft + offset);
601  H_Update(&ctx, cruft, BN_num_bytes(session->order));
602 
603  /*
604  * finally, ciphersuite
605  */
606  H_Update(&ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
607 
608  H_Final(&ctx, out);
609 
610  req = 0;
611 finish:
612  talloc_free(cruft);
613  BN_free(x);
614  BN_free(y);
615 
616  return req;
617 }
618 
619 int compute_keys (pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk)
620 {
621  HMAC_CTX ctx;
622  uint8_t mk[SHA256_DIGEST_LENGTH], *cruft;
623  uint8_t session_id[SHA256_DIGEST_LENGTH + 1];
624  uint8_t msk_emsk[128]; /* 64 each */
625  int offset;
626 
627  if ((cruft = talloc_array(session, uint8_t, BN_num_bytes(session->prime))) == NULL) {
628  DEBUG2("pwd: unable to allocate space to compute keys");
629  return -1;
630  }
631 
632  /*
633  * first compute the session-id = TypeCode | H(ciphersuite | scal_p |
634  * scal_s)
635  */
636  session_id[0] = PW_EAP_PWD;
637  H_Init(&ctx);
638  H_Update(&ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
639  offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
640  memset(cruft, 0, BN_num_bytes(session->prime));
641  BN_bn2bin(session->peer_scalar, cruft + offset);
642  H_Update(&ctx, cruft, BN_num_bytes(session->order));
643  offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
644  memset(cruft, 0, BN_num_bytes(session->prime));
645  BN_bn2bin(session->my_scalar, cruft + offset);
646  H_Update(&ctx, cruft, BN_num_bytes(session->order));
647  H_Final(&ctx, (uint8_t *)&session_id[1]);
648 
649  /* then compute MK = H(k | commit-peer | commit-server) */
650  H_Init(&ctx);
651 
652  memset(cruft, 0, BN_num_bytes(session->prime));
653  offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
654  BN_bn2bin(session->k, cruft + offset);
655  H_Update(&ctx, cruft, BN_num_bytes(session->prime));
656 
657  H_Update(&ctx, peer_confirm, SHA256_DIGEST_LENGTH);
658 
659  H_Update(&ctx, session->my_confirm, SHA256_DIGEST_LENGTH);
660 
661  H_Final(&ctx, mk);
662 
663  /* stretch the mk with the session-id to get MSK | EMSK */
664  eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH, (char const *)session_id,
665  SHA256_DIGEST_LENGTH + 1, msk_emsk, 1024); /* it's bits, ((64 + 64) * 8) */
666 
667  memcpy(msk, msk_emsk, 64);
668  memcpy(emsk, msk_emsk + 64, 64);
669 
670  talloc_free(cruft);
671  return 0;
672 }
673 
674 
675 
676 
static void eap_pwd_kdf(uint8_t *key, int keylen, char const *label, int labellen, uint8_t *result, int resultbitlen)
Definition: eap_pwd.c:65
static void H_Final(HMAC_CTX *ctx, uint8_t *digest)
Definition: eap_pwd.c:56
BIGNUM * k
Definition: eap_pwd.h:97
uint32_t ciphersuite
Definition: eap_pwd.h:82
BIGNUM * peer_scalar
Definition: eap_pwd.h:99
int process_peer_commit(pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bnctx)
Definition: eap_pwd.c:315
BIGNUM * my_scalar
Definition: eap_pwd.h:100
int compute_scalar_element(pwd_session_t *session, BN_CTX *bnctx)
Definition: eap_pwd.c:273
int compute_password_element(pwd_session_t *session, uint16_t grp_num, char const *password, int password_len, char const *id_server, int id_server_len, char const *id_peer, int id_peer_len, uint32_t *token)
Definition: eap_pwd.c:103
int compute_keys(pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk)
Definition: eap_pwd.c:619
BIGNUM * prime
Definition: eap_pwd.h:96
int compute_peer_confirm(pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
Definition: eap_pwd.c:520
static USES_APPLE_DEPRECATED_API void H_Init(HMAC_CTX *ctx)
Definition: eap_pwd.c:43
#define DEBUG(fmt,...)
Definition: log.h:175
static uint32_t mask
Definition: rbmonkey.c:75
#define DEBUG2(fmt,...)
Definition: log.h:176
uint8_t my_confirm[SHA256_DIGEST_LENGTH]
Definition: eap_pwd.h:103
EC_POINT * peer_element
Definition: eap_pwd.h:102
EC_POINT * my_element
Definition: eap_pwd.h:101
int compute_server_confirm(pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
Definition: eap_pwd.c:421
static void H_Update(HMAC_CTX *ctx, uint8_t const *data, int len)
Definition: eap_pwd.c:51
BIGNUM * private_value
Definition: eap_pwd.h:98
uint8_t data[]
Definition: eap_pwd.h:625
uint8_t token[4]
Definition: eap_pwd.h:625
BIGNUM * order
Definition: eap_pwd.h:95
uint16_t group_num
Definition: eap_pwd.h:81
#define RCSID(id)
Definition: build.h:135
EC_POINT * pwe
Definition: eap_pwd.h:94
EC_GROUP * group
Definition: eap_pwd.h:93
#define USES_APPLE_DEPRECATED_API
Definition: build.h:122