2 * Copyright (c) Dan Harkins, 2012
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
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
15 * "DISCLAIMER OF LIABILITY
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
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).
35 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
39 #include <freeradius-devel/radiusd.h>
40 #include <freeradius-devel/modules.h>
42 /* The random function H(x) = HMAC-SHA256(0^32, x) */
46 uint8_t allzero[SHA256_DIGEST_LENGTH];
48 memset(allzero, 0, SHA256_DIGEST_LENGTH);
49 HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256());
53 H_Update(HMAC_CTX *ctx, uint8_t const *data, int len)
55 HMAC_Update(ctx, data, len);
59 H_Final(HMAC_CTX *ctx, uint8_t *digest)
61 unsigned int mdlen = SHA256_DIGEST_LENGTH;
63 HMAC_Final(ctx, digest, &mdlen);
64 HMAC_CTX_cleanup(ctx);
67 /* a counter-based KDF based on NIST SP800-108 */
69 eap_pwd_kdf(uint8_t *key, int keylen, char const *label, int labellen,
70 uint8_t *result, int resultbitlen)
73 uint8_t digest[SHA256_DIGEST_LENGTH];
75 int resultbytelen, len = 0;
76 unsigned int mdlen = SHA256_DIGEST_LENGTH;
79 resultbytelen = (resultbitlen + 7)/8;
81 L = htons(resultbitlen);
82 while (len < resultbytelen) {
83 ctr++; i = htons(ctr);
84 HMAC_Init(&hctx, key, keylen, EVP_sha256());
86 HMAC_Update(&hctx, digest, mdlen);
88 HMAC_Update(&hctx, (uint8_t *) &i, sizeof(uint16_t));
89 HMAC_Update(&hctx, (uint8_t const *)label, labellen);
90 HMAC_Update(&hctx, (uint8_t *) &L, sizeof(uint16_t));
91 HMAC_Final(&hctx, digest, &mdlen);
92 if ((len + (int) mdlen) > resultbytelen) {
93 memcpy(result + len, digest, resultbytelen - len);
95 memcpy(result + len, digest, mdlen);
98 HMAC_CTX_cleanup(&hctx);
101 /* since we're expanding to a bit length, mask off the excess */
102 if (resultbitlen % 8) {
103 mask <<= (8 - (resultbitlen % 8));
104 result[resultbytelen - 1] &= mask;
109 compute_password_element (pwd_session_t *sess, uint16_t grp_num,
110 char const *password, int password_len,
111 char const *id_server, int id_server_len,
112 char const *id_peer, int id_peer_len,
115 BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
117 uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr;
118 int nid, is_odd, primebitlen, primebytelen, ret = 0;
120 switch (grp_num) { /* from IANA registry for IKE D-H groups */
122 nid = NID_X9_62_prime256v1;
131 nid = NID_X9_62_prime192v1;
137 DEBUG("unknown group %d", grp_num);
145 if ((sess->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
146 DEBUG("unable to create EC_GROUP");
150 if (((rnd = BN_new()) == NULL) ||
151 ((cofactor = BN_new()) == NULL) ||
152 ((sess->pwe = EC_POINT_new(sess->group)) == NULL) ||
153 ((sess->order = BN_new()) == NULL) ||
154 ((sess->prime = BN_new()) == NULL) ||
155 ((x_candidate = BN_new()) == NULL)) {
156 DEBUG("unable to create bignums");
160 if (!EC_GROUP_get_curve_GFp(sess->group, sess->prime, NULL, NULL, NULL))
162 DEBUG("unable to get prime for GFp curve");
165 if (!EC_GROUP_get_order(sess->group, sess->order, NULL)) {
166 DEBUG("unable to get order for curve");
169 if (!EC_GROUP_get_cofactor(sess->group, cofactor, NULL)) {
170 DEBUG("unable to get cofactor for curve");
173 primebitlen = BN_num_bits(sess->prime);
174 primebytelen = BN_num_bytes(sess->prime);
175 if ((prfbuf = talloc_zero_array(sess, uint8_t, primebytelen)) == NULL) {
176 DEBUG("unable to alloc space for prf buffer");
182 DEBUG("unable to find random point on curve for group %d, something's fishy", grp_num);
188 * compute counter-mode password value and stretch to prime
189 * pwd-seed = H(token | peer-id | server-id | password |
193 H_Update(&ctx, (uint8_t *)token, sizeof(*token));
194 H_Update(&ctx, (uint8_t const *)id_peer, id_peer_len);
195 H_Update(&ctx, (uint8_t const *)id_server, id_server_len);
196 H_Update(&ctx, (uint8_t const *)password, password_len);
197 H_Update(&ctx, (uint8_t *)&ctr, sizeof(ctr));
198 H_Final(&ctx, pwe_digest);
200 BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd);
201 eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH,
202 "EAP-pwd Hunting And Pecking",
203 strlen("EAP-pwd Hunting And Pecking"),
204 prfbuf, primebitlen);
206 BN_bin2bn(prfbuf, primebytelen, x_candidate);
208 * eap_pwd_kdf() returns a string of bits 0..primebitlen but
209 * BN_bin2bn will treat that string of bits as a big endian
210 * number. If the primebitlen is not an even multiple of 8
211 * then excessive bits-- those _after_ primebitlen-- so now
212 * we have to shift right the amount we masked off.
214 if (primebitlen % 8) {
215 BN_rshift(x_candidate, x_candidate, (8 - (primebitlen % 8)));
217 if (BN_ucmp(x_candidate, sess->prime) >= 0) {
221 * need to unambiguously identify the solution, if there is
224 if (BN_is_odd(rnd)) {
230 * solve the quadratic equation, if it's not solvable then we
233 if (!EC_POINT_set_compressed_coordinates_GFp(sess->group,
240 * If there's a solution to the equation then the point must be
241 * on the curve so why check again explicitly? OpenSSL code
242 * says this is required by X9.62. We're not X9.62 but it can't
243 * hurt just to be sure.
245 if (!EC_POINT_is_on_curve(sess->group, sess->pwe, NULL)) {
246 DEBUG("EAP-pwd: point is not on curve");
250 if (BN_cmp(cofactor, BN_value_one())) {
251 /* make sure the point is not in a small sub-group */
252 if (!EC_POINT_mul(sess->group, sess->pwe, NULL, sess->pwe,
254 DEBUG("EAP-pwd: cannot multiply generator by order");
257 if (EC_POINT_is_at_infinity(sess->group, sess->pwe)) {
258 DEBUG("EAP-pwd: point is at infinity");
262 /* if we got here then we have a new generator. */
265 sess->group_num = grp_num;
267 fail: /* DON'T free sess, it's in handler->opaque */
270 /* cleanliness and order.... */
272 BN_free(x_candidate);
280 compute_scalar_element (pwd_session_t *sess, BN_CTX *bnctx)
285 if (((sess->private_value = BN_new()) == NULL) ||
286 ((sess->my_element = EC_POINT_new(sess->group)) == NULL) ||
287 ((sess->my_scalar = BN_new()) == NULL) ||
288 ((mask = BN_new()) == NULL)) {
289 DEBUG2("server scalar allocation failed");
293 BN_rand_range(sess->private_value, sess->order);
294 BN_rand_range(mask, sess->order);
295 BN_add(sess->my_scalar, sess->private_value, mask);
296 BN_mod(sess->my_scalar, sess->my_scalar, sess->order,
299 if (!EC_POINT_mul(sess->group, sess->my_element, NULL,
300 sess->pwe, mask, bnctx)) {
301 DEBUG2("server element allocation failed");
305 if (!EC_POINT_invert(sess->group, sess->my_element, bnctx)) {
306 DEBUG2("server element inversion failed");
318 process_peer_commit (pwd_session_t *sess, uint8_t *commit, BN_CTX *bnctx)
321 BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
322 EC_POINT *K = NULL, *point = NULL;
325 if (((sess->peer_scalar = BN_new()) == NULL) ||
326 ((sess->k = BN_new()) == NULL) ||
327 ((cofactor = BN_new()) == NULL) ||
328 ((x = BN_new()) == NULL) ||
329 ((y = BN_new()) == NULL) ||
330 ((point = EC_POINT_new(sess->group)) == NULL) ||
331 ((K = EC_POINT_new(sess->group)) == NULL) ||
332 ((sess->peer_element = EC_POINT_new(sess->group)) == NULL)) {
333 DEBUG2("pwd: failed to allocate room to process peer's commit");
337 if (!EC_GROUP_get_cofactor(sess->group, cofactor, NULL)) {
338 DEBUG2("pwd: unable to get group co-factor");
342 /* element, x then y, followed by scalar */
343 ptr = (uint8_t *)commit;
344 BN_bin2bn(ptr, BN_num_bytes(sess->prime), x);
345 ptr += BN_num_bytes(sess->prime);
346 BN_bin2bn(ptr, BN_num_bytes(sess->prime), y);
347 ptr += BN_num_bytes(sess->prime);
348 BN_bin2bn(ptr, BN_num_bytes(sess->order), sess->peer_scalar);
349 if (!EC_POINT_set_affine_coordinates_GFp(sess->group,
350 sess->peer_element, x, y,
352 DEBUG2("pwd: unable to get coordinates of peer's element");
356 /* check to ensure peer's element is not in a small sub-group */
357 if (BN_cmp(cofactor, BN_value_one())) {
358 if (!EC_POINT_mul(sess->group, point, NULL,
359 sess->peer_element, cofactor, NULL)) {
360 DEBUG2("pwd: unable to multiply element by co-factor");
363 if (EC_POINT_is_at_infinity(sess->group, point)) {
364 DEBUG2("pwd: peer's element is in small sub-group");
369 /* compute the shared key, k */
370 if ((!EC_POINT_mul(sess->group, K, NULL, sess->pwe,
371 sess->peer_scalar, bnctx)) ||
372 (!EC_POINT_add(sess->group, K, K, sess->peer_element,
374 (!EC_POINT_mul(sess->group, K, NULL, K, sess->private_value,
376 DEBUG2("pwd: unable to compute shared key, k");
380 /* ensure that the shared key isn't in a small sub-group */
381 if (BN_cmp(cofactor, BN_value_one())) {
382 if (!EC_POINT_mul(sess->group, K, NULL, K, cofactor,
384 DEBUG2("pwd: unable to multiply k by co-factor");
390 * This check is strictly speaking just for the case above where
391 * co-factor > 1 but it was suggested that even though this is probably
392 * never going to happen it is a simple and safe check "just to be
393 * sure" so let's be safe.
395 if (EC_POINT_is_at_infinity(sess->group, K)) {
396 DEBUG2("pwd: k is point-at-infinity!");
399 if (!EC_POINT_get_affine_coordinates_GFp(sess->group, K, sess->k,
401 DEBUG2("pwd: unable to get shared secret from K");
408 EC_POINT_free(point);
417 compute_server_confirm (pwd_session_t *sess, uint8_t *buf, BN_CTX *bnctx)
419 BIGNUM *x = NULL, *y = NULL;
421 uint8_t *cruft = NULL;
422 int offset, req = -1;
425 * Each component of the cruft will be at most as big as the prime
427 if (((cruft = talloc_zero_array(sess, uint8_t, BN_num_bytes(sess->prime))) == NULL) ||
428 ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
429 DEBUG2("pwd: unable to allocate space to compute confirm!");
434 * commit is H(k | server_element | server_scalar | peer_element |
435 * peer_scalar | ciphersuite)
440 * Zero the memory each time because this is mod prime math and some
441 * value may start with a few zeros and the previous one did not.
445 offset = BN_num_bytes(sess->prime) - BN_num_bytes(sess->k);
446 BN_bn2bin(sess->k, cruft + offset);
447 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
450 * next is server element: x, y
452 if (!EC_POINT_get_affine_coordinates_GFp(sess->group,
453 sess->my_element, x, y,
455 DEBUG2("pwd: unable to get coordinates of server element");
458 memset(cruft, 0, BN_num_bytes(sess->prime));
459 offset = BN_num_bytes(sess->prime) - BN_num_bytes(x);
460 BN_bn2bin(x, cruft + offset);
461 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
463 memset(cruft, 0, BN_num_bytes(sess->prime));
464 offset = BN_num_bytes(sess->prime) - BN_num_bytes(y);
465 BN_bn2bin(y, cruft + offset);
466 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
471 memset(cruft, 0, BN_num_bytes(sess->prime));
472 offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->my_scalar);
473 BN_bn2bin(sess->my_scalar, cruft + offset);
474 H_Update(&ctx, cruft, BN_num_bytes(sess->order));
477 * next is peer element: x, y
479 if (!EC_POINT_get_affine_coordinates_GFp(sess->group,
480 sess->peer_element, x, y,
482 DEBUG2("pwd: unable to get coordinates of peer's element");
486 memset(cruft, 0, BN_num_bytes(sess->prime));
487 offset = BN_num_bytes(sess->prime) - BN_num_bytes(x);
488 BN_bn2bin(x, cruft + offset);
489 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
491 memset(cruft, 0, BN_num_bytes(sess->prime));
492 offset = BN_num_bytes(sess->prime) - BN_num_bytes(y);
493 BN_bn2bin(y, cruft + offset);
494 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
499 memset(cruft, 0, BN_num_bytes(sess->prime));
500 offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->peer_scalar);
501 BN_bn2bin(sess->peer_scalar, cruft + offset);
502 H_Update(&ctx, cruft, BN_num_bytes(sess->order));
505 * finally, ciphersuite
507 H_Update(&ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
523 compute_peer_confirm (pwd_session_t *sess, uint8_t *buf, BN_CTX *bnctx)
525 BIGNUM *x = NULL, *y = NULL;
527 uint8_t *cruft = NULL;
528 int offset, req = -1;
531 * Each component of the cruft will be at most as big as the prime
533 if (((cruft = talloc_zero_array(sess, uint8_t, BN_num_bytes(sess->prime))) == NULL) ||
534 ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
535 DEBUG2("pwd: unable to allocate space to compute confirm!");
540 * commit is H(k | server_element | server_scalar | peer_element |
541 * peer_scalar | ciphersuite)
546 * Zero the memory each time because this is mod prime math and some
547 * value may start with a few zeros and the previous one did not.
551 offset = BN_num_bytes(sess->prime) - BN_num_bytes(sess->k);
552 BN_bn2bin(sess->k, cruft + offset);
553 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
556 * then peer element: x, y
558 if (!EC_POINT_get_affine_coordinates_GFp(sess->group,
559 sess->peer_element, x, y,
561 DEBUG2("pwd: unable to get coordinates of peer's element");
565 memset(cruft, 0, BN_num_bytes(sess->prime));
566 offset = BN_num_bytes(sess->prime) - BN_num_bytes(x);
567 BN_bn2bin(x, cruft + offset);
568 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
570 memset(cruft, 0, BN_num_bytes(sess->prime));
571 offset = BN_num_bytes(sess->prime) - BN_num_bytes(y);
572 BN_bn2bin(y, cruft + offset);
573 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
578 memset(cruft, 0, BN_num_bytes(sess->prime));
579 offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->peer_scalar);
580 BN_bn2bin(sess->peer_scalar, cruft + offset);
581 H_Update(&ctx, cruft, BN_num_bytes(sess->order));
584 * then server element: x, y
586 if (!EC_POINT_get_affine_coordinates_GFp(sess->group,
587 sess->my_element, x, y,
589 DEBUG2("pwd: unable to get coordinates of server element");
592 memset(cruft, 0, BN_num_bytes(sess->prime));
593 offset = BN_num_bytes(sess->prime) - BN_num_bytes(x);
594 BN_bn2bin(x, cruft + offset);
595 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
597 memset(cruft, 0, BN_num_bytes(sess->prime));
598 offset = BN_num_bytes(sess->prime) - BN_num_bytes(y);
599 BN_bn2bin(y, cruft + offset);
600 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
605 memset(cruft, 0, BN_num_bytes(sess->prime));
606 offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->my_scalar);
607 BN_bn2bin(sess->my_scalar, cruft + offset);
608 H_Update(&ctx, cruft, BN_num_bytes(sess->order));
611 * finally, ciphersuite
613 H_Update(&ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
629 compute_keys (pwd_session_t *sess, uint8_t *peer_confirm,
630 uint8_t *msk, uint8_t *emsk)
633 uint8_t mk[SHA256_DIGEST_LENGTH], *cruft;
634 uint8_t session_id[SHA256_DIGEST_LENGTH + 1];
635 uint8_t msk_emsk[128]; /* 64 each */
638 if ((cruft = talloc_array(sess, uint8_t, BN_num_bytes(sess->prime))) == NULL) {
639 DEBUG2("pwd: unable to allocate space to compute keys");
643 * first compute the session-id = TypeCode | H(ciphersuite | scal_p |
646 session_id[0] = PW_EAP_PWD;
648 H_Update(&ctx, (uint8_t *)&sess->ciphersuite, sizeof(sess->ciphersuite));
649 offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->peer_scalar);
650 memset(cruft, 0, BN_num_bytes(sess->prime));
651 BN_bn2bin(sess->peer_scalar, cruft + offset);
652 H_Update(&ctx, cruft, BN_num_bytes(sess->order));
653 offset = BN_num_bytes(sess->order) - BN_num_bytes(sess->my_scalar);
654 memset(cruft, 0, BN_num_bytes(sess->prime));
655 BN_bn2bin(sess->my_scalar, cruft + offset);
656 H_Update(&ctx, cruft, BN_num_bytes(sess->order));
657 H_Final(&ctx, (uint8_t *)&session_id[1]);
659 /* then compute MK = H(k | commit-peer | commit-server) */
662 memset(cruft, 0, BN_num_bytes(sess->prime));
663 offset = BN_num_bytes(sess->prime) - BN_num_bytes(sess->k);
664 BN_bn2bin(sess->k, cruft + offset);
665 H_Update(&ctx, cruft, BN_num_bytes(sess->prime));
667 H_Update(&ctx, peer_confirm, SHA256_DIGEST_LENGTH);
669 H_Update(&ctx, sess->my_confirm, SHA256_DIGEST_LENGTH);
673 /* stretch the mk with the session-id to get MSK | EMSK */
674 eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH,
675 (char const *)session_id, SHA256_DIGEST_LENGTH+1,
676 msk_emsk, 1024); /* it's bits, ((64 + 64) * 8) */
678 memcpy(msk, msk_emsk, 64);
679 memcpy(emsk, msk_emsk + 64, 64);