5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * Copyright 2001,2002 Google, Inc.
20 * Copyright 2005 TRI-D Systems, Inc.
24 * This file implements passcode (password) checking functions for each
25 * supported encoding (PAP, CHAP, etc.). The current libradius interface
26 * is not sufficient for X9.9 use.
32 #include <rad_assert.h>
37 #include <openssl/des.h>
38 #include <openssl/md4.h>
39 #include <openssl/md5.h>
40 #include <openssl/sha.h>
44 static const char rcsid[] = "$Id$";
47 /* Attribute IDs for supported password encodings. */
51 /* Initialize the pwattr array for supported password encodings. */
59 * Setup known password types. These are pairs.
60 * NB: Increase pwattr array size when adding a type.
61 * It should be sized as (number of password types * 2)
63 (void) memset(pwattr, 0, sizeof(pwattr));
66 if ((da = dict_attrbyname("User-Password")) != NULL) {
67 pwattr[i++] = da->attr;
68 pwattr[i++] = da->attr;
72 if ((da = dict_attrbyname("CHAP-Challenge")) != NULL) {
73 pwattr[i++] = da->attr;
74 if ((da = dict_attrbyname("CHAP-Password")) != NULL)
75 pwattr[i++] = da->attr;
81 /* MS-CHAP (recommended not to use) */
82 if ((da = dict_attrbyname("MS-CHAP-Challenge")) != NULL) {
83 pwattr[i++] = da->attr;
84 if ((da = dict_attrbyname("MS-CHAP-Response")) != NULL)
85 pwattr[i++] = da->attr;
92 if ((da = dict_attrbyname("MS-CHAP-Challenge")) != NULL) {
93 pwattr[i++] = da->attr;
94 if ((da = dict_attrbyname("MS-CHAP2-Response")) != NULL)
95 pwattr[i++] = da->attr;
103 * Test for password presence in an Access-Request packet.
104 * Returns 0 for "no supported password present", or an non-zero
105 * opaque value that must be used when calling otp_pwe_cmp().
108 otp_pwe_present(const REQUEST *request, const char *log_prefix)
112 for (i = 0; i < sizeof(pwattr) && pwattr[i]; i += 2) {
113 if (pairfind(request->packet->vps, pwattr[i]) &&
114 pairfind(request->packet->vps, pwattr[i + 1])) {
115 DEBUG("%s: %s: password attributes %d, %d", log_prefix, __func__,
116 pwattr[i], pwattr[i + 1]);
117 return i + 1; /* Can't return 0 (indicates failure) */
121 DEBUG("%s: %s: no password attributes present", log_prefix, __func__);
127 * Test for passcode (password) equality.
128 * returns 0 for match, non-zero for non-match.
129 * If data->returned_vps is non-null, then on matches, it will point to
130 * vps that should be added to an Access-Accept packet. If access is denied,
131 * the caller is responsible for freeing any vps returned.
134 otp_pwe_cmp(struct otp_pwe_cmp_t *data, const char *password,
135 const char *log_prefix)
137 const REQUEST *request = data->request;
138 const otp_option_t *inst = data->inst;
139 int attr = data->pwattr;
140 VALUE_PAIR **vps = data->returned_vps;
143 VALUE_PAIR *chal_vp, *resp_vp;
146 * A module that does this might want to verify the presence of these.
147 * This code is self contained to otp, so I know these exist.
149 chal_vp = pairfind(request->packet->vps, pwattr[attr - 1]);
150 resp_vp = pairfind(request->packet->vps, pwattr[attr]);
152 /* Prepare for failure return. */
156 /* If modular, this would actually call the authentication function. */
157 switch(pwattr[attr]) {
159 DEBUG("%s: %s: handling PW_PASSWORD", log_prefix, __func__);
160 nmatch = strcmp(password, resp_vp->strvalue);
163 case PW_CHAP_PASSWORD:
167 * A CHAP password is MD5(CHAP_ID|SECRET|CHAP_CHALLENGE).
168 * CHAP_ID is a value set by the authenticator (the NAS), and used
169 * in the response calculation. It is available as the first byte
170 * of the CHAP-Password attribute.
171 * SECRET is the password.
172 * CHAP_CHALLENGE is the challenge given to the peer (the user).
173 * The CHAP-Challenge Attribute may be missing, in which case the
174 * challenge is taken to be the Request Authenticator. We don't
177 /* ID password chal */
178 unsigned char input[1 + MAX_STRING_LEN + 16];
179 unsigned char output[MD5_DIGEST_LENGTH];
181 DEBUG("%s: %s: handling PW_CHAP_PASSWORD", log_prefix, __func__);
182 if (1 + strlen(password) + chal_vp->length > sizeof(input)) {
183 DEBUG("%s: %s: CHAP-Challenge/password too long", log_prefix, __func__);
187 if (resp_vp->length != 17) {
188 otp_log(OTP_LOG_AUTH, "%s: %s: CHAP-Password wrong size",
189 log_prefix, __func__);
193 input[0] = *(resp_vp->strvalue);
194 (void) memcpy(&input[1], password, strlen(password));
195 (void) memcpy(&input[1+strlen(password)], chal_vp->strvalue,
197 (void) MD5(input, 1 + strlen(password) + chal_vp->length, output);
198 nmatch = memcmp(output, &(resp_vp->strvalue)[1], MD5_DIGEST_LENGTH);
199 } /* case PW_CHAP_PASSWORD */
203 case PW_MS_CHAP_RESPONSE:
206 * See RFCs 2548, 2433, 3079.
207 * An MS-CHAP response is (IDENT|FLAGS|LM_RESPONSE|NT_RESPONSE).
209 * IDENT is not used by RADIUS (it is the PPP MS-CHAP Identifier).
210 * FLAGS is 1 to indicate the NT_RESPONSE should be preferred.
211 * LM_RESPONSE is the LAN Manager compatible response.
212 * NT_RESPONSE is the NT compatible response.
213 * Either response may be zero-filled indicating its absence.
214 * Use of the LM response has been deprecated (RFC 2433, par. 6),
215 * so we don't handle it.
217 * The NT_RESPONSE is (DES(CHAL,K1)|DES(CHAL,K2)|DES(CHAL,K3)), where
218 * CHAL is the 8-octet challenge, and K1, K2, K3 are 7-octet pieces
219 * of MD4(unicode(password)), zero-filled to 21 octets. Sigh.
221 unsigned char nt_keys[21]; /* sized for 3 DES keys */
222 unsigned char input[MAX_STRING_LEN * 2]; /* doubled for unicode */
223 unsigned char output[24];
227 DEBUG("%s: %s: handling PW_MS_CHAP_RESPONSE", log_prefix, __func__);
228 if (chal_vp->length != 8) {
229 otp_log(OTP_LOG_AUTH, "%s: %s: MS-CHAP-Challenge wrong size",
230 log_prefix, __func__);
234 if (resp_vp->length != 50) {
235 otp_log(OTP_LOG_AUTH, "%s: %s: MS-CHAP-Response wrong size",
236 log_prefix, __func__);
240 if ((resp_vp->strvalue)[1] != 1) {
241 otp_log(OTP_LOG_AUTH,
242 "%s: %s: MS-CHAP-Response bad flags (LM not supported)",
243 log_prefix, __func__);
247 /* This is probably overkill. */
248 if (strlen(password) > MAX_STRING_LEN) {
249 otp_log(OTP_LOG_AUTH, "%s: %s: MS-CHAP password too long",
250 log_prefix, __func__);
256 * Start by hashing the unicode password.
257 * This is broken because unicode chars are machine-ordered,
258 * but the spec (RFC 2433) doesn't say how to prepare
259 * the password for md4 (other than by example values).
261 password_len = strlen(password);
262 for (i = 0; i < password_len; ++i) {
263 /* Set the high order 8 bits to 0 (little-endian) */
264 input[i * 2] = *password++;
265 input[i * 2 + 1] = 0;
267 (void) memset(nt_keys, 0, sizeof(nt_keys));
268 (void) MD4(input, 2 * password_len, nt_keys);
270 /* The challenge gets encrypted. */
271 (void) memcpy(input, chal_vp->strvalue, 8);
273 /* Convert the password hash to keys, and do the encryptions. */
274 for (i = 0; i < 3; ++i) {
278 otp_key_from_hash(&key, &nt_keys[i * 7]);
279 des_set_key_unchecked(&key, ks);
280 des_ecb_encrypt((des_cblock *) input,
281 (des_cblock *) &output[i * 8],
285 nmatch = memcmp(output, resp_vp->strvalue + 26, 24);
290 * Generate the MS-CHAP-MPPE-Keys attribute if needed. This is not
291 * specified anywhere -- RFC 2548, par. 2.4.1 is the authority but
292 * it has typos and omissions that make this unimplementable. The
293 * code here is based on experimental results provided by
294 * Takahiro Wagatsuma <waga@sic.shibaura-it.ac.jp>.
295 * We only support 128-bit keys derived from the NT hash; 40-bit
296 * and 56-bit keys are derived from the LM hash, which besides
297 * being deprecated, has severe security problems.
300 /* First, set some related attributes. */
301 vp = pairmake("MS-MPPE-Encryption-Policy",
302 otp_mppe_policy[inst->mschap_mppe_policy], T_OP_EQ);
303 rad_assert(vp != NULL);
305 vp = pairmake("MS-MPPE-Encryption-Types",
306 otp_mppe_types[inst->mschap_mppe_types], T_OP_EQ);
307 rad_assert(vp != NULL);
310 if (inst->mschap_mppe_policy) {
311 unsigned char mppe_keys[32];
312 /* 0x ASCII(mppe_keys) '\0' */
313 char mppe_keys_string[2 + (2 * sizeof(mppe_keys)) + 1];
315 unsigned char md5_md[MD5_DIGEST_LENGTH];
316 unsigned char encode_buf[AUTH_VECTOR_LEN + MAX_STRING_LEN];
319 /* Zero the LM-Key sub-field (and padding). */
320 (void) memset(mppe_keys, 0, sizeof(mppe_keys));
321 /* The NT-Key sub-field is MD4(MD4(unicode(password))). */
322 (void) MD4(nt_keys, 16, &mppe_keys[8]);
324 #if 0 /* encoding now handled in lib/radius.c:rad_pwencode() */
325 /* Now we must encode the key as User-Password is encoded. */
326 secretlen = strlen(request->secret);
327 (void) memcpy(encode_buf, request->secret, secretlen);
328 (void) memcpy(encode_buf + secretlen, request->packet->vector,
330 (void) MD5(encode_buf, secretlen + AUTH_VECTOR_LEN, md5_md);
331 for (i = 0; i < 16; ++i)
332 mppe_keys[i] ^= md5_md[i];
333 (void) memcpy(encode_buf + secretlen, mppe_keys, MD5_DIGEST_LENGTH);
334 (void) MD5(encode_buf, secretlen + MD5_DIGEST_LENGTH, md5_md);
335 for (i = 0; i < 16; ++i)
336 mppe_keys[i + 16] ^= md5_md[i];
339 /* Whew. Now stringify it for pairmake(). */
340 mppe_keys_string[0] = '0';
341 mppe_keys_string[1] = 'x';
342 for (i = 0; i < 32; ++i)
343 (void) sprintf(&mppe_keys_string[i*2+2], "%02X", mppe_keys[i]);
344 vp = pairmake("MS-CHAP-MPPE-Keys", mppe_keys_string, T_OP_EQ);
345 rad_assert(vp != NULL);
347 } /* if (doing mppe) */
349 } /* case PW_MS_CHAP_RESPONSE */
351 #endif /* 0 (MS_CHAP) */
353 case PW_MS_CHAP2_RESPONSE:
356 * See RFCs 2548, 2759, 3079.
357 * An MS-CHAPv2 response is
358 * (IDENT|FLAGS|PEER_CHALLENGE|RESERVED|NT_RESPONSE).
359 * octets: 1 1 16 8 24
360 * IDENT is the PPP MS-CHAPv2 Identifier, used in MS-CHAP2-Success.
361 * FLAGS is currently unused.
362 * PEER_CHALLENGE is a random number, generated by the peer.
363 * NT_RESPONSE is (DES(CHAL,K1)|DES(CHAL,K2)|DES(CHAL,K3)), where
364 * K1, K2, K3 are 7-octet pieces of MD4(unicode(password)), zero-
365 * filled to 21 octets (just as in MS-CHAP); and CHAL is
366 * MSB8(SHA(PEER_CHALLENGE|MS_CHAP_CHALLENGE|USERNAME)).
368 unsigned char nt_keys[21]; /* aka "password_md", sized for 3 DES keys */
369 unsigned char password_md_md[MD4_DIGEST_LENGTH]; /* for mutual auth */
370 unsigned char input[MAX_STRING_LEN * 2]; /* doubled for unicode */
371 unsigned char output[24];
372 unsigned password_len, i;
375 DEBUG("%s: %s: handling PW_MS_CHAP2_RESPONSE", log_prefix, __func__);
376 if (chal_vp->length != 16) {
377 otp_log(OTP_LOG_AUTH, "%s: %s: MS-CHAP-Challenge (v2) wrong size",
378 log_prefix, __func__);
382 if (resp_vp->length != 50) {
383 otp_log(OTP_LOG_AUTH, "%s: %s: MS-CHAP2-Response wrong size",
384 log_prefix, __func__);
388 /* This is probably overkill. */
389 if (strlen(password) > MAX_STRING_LEN) {
390 otp_log(OTP_LOG_AUTH, "%s: %s: MS-CHAPv2 password too long",
391 log_prefix, __func__);
397 * Start by hashing the unicode password.
398 * This is broken because unicode chars are machine-ordered,
399 * but the spec (RFC 2759) doesn't say how to prepare
400 * the password for md4 (other than by example values).
402 password_len = strlen(password);
403 for (i = 0; i < password_len; ++i) {
404 /* Set the high order 8 bits to 0 (little-endian) */
405 input[i * 2] = *password++;
406 input[i * 2 + 1] = 0;
408 (void) memset(nt_keys, 0, sizeof(nt_keys));
409 (void) MD4(input, 2 * password_len, nt_keys);
411 /* Now calculate the CHAL value from our various inputs. */
414 unsigned char md[SHA_DIGEST_LENGTH];
415 char *username = request->username->strvalue;
416 int username_len = request->username->length;
419 SHA1_Update(&ctx, resp_vp->strvalue + 2, 16);
420 SHA1_Update(&ctx, chal_vp->strvalue, 16);
421 SHA1_Update(&ctx, username, username_len);
422 SHA1_Final(md, &ctx);
424 (void) memcpy(input, md, 8);
427 /* Convert the password hash to keys, and do the encryptions. */
428 for (i = 0; i < 3; ++i) {
432 otp_key_from_hash(&key, &nt_keys[i * 7]);
433 des_set_key_unchecked(&key, ks);
434 des_ecb_encrypt((des_cblock *) input,
435 (des_cblock *) &output[i * 8],
439 nmatch = memcmp(output, resp_vp->strvalue + 26, 24);
444 * MS-CHAPv2 requires mutual authentication; we must prove
445 * that we know the secret. This is a bit circuitous: set
446 * MD1 = SHA(MD4(MD4(unicode(password)))|NT_RESPONSE|MAGIC1),
447 * MD2 = MSB8(SHA(PEER_CHALLENGE|MS_CHAP_CHALLENGE|USERNAME)),
448 * and finally use SHA(MD1|MD2|MAGIC2) as the authenticator.
449 * The authenticator is returned as the string "S=<auth>",
450 * <auth> is the authenticator expressed as [uppercase] ASCII.
455 unsigned char md1[SHA_DIGEST_LENGTH];
456 unsigned char md2[SHA_DIGEST_LENGTH];
457 unsigned char auth_md[SHA_DIGEST_LENGTH];
458 /* S= ( ASCII(auth_md) ) \0 */
459 char auth_md_string[2 + (2 * sizeof(auth_md)) + 1];
461 * ugh. The ASCII authenticator (auth_md_string) is sent
462 * along with a single (useless) binary byte (the ID).
463 * So we must "stringify" it again (for pairmake()) since the
464 * binary byte requires the attribute to be of type "octets".
466 /* 0x (ID) ( ASCII("S="ASCII(auth_md))) */
467 char auth_octet_string[2 + 2 + (2 * sizeof(auth_md_string))];
469 char *username = request->username->strvalue;
470 int username_len = request->username->length;
472 /* "Magic server to client signing constant" */
473 unsigned char magic1[39] =
474 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
475 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
476 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
477 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
478 /* "Pad to make it do more than one iteration" */
479 unsigned char magic2[41] =
480 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
481 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
482 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
483 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
487 (void) MD4(nt_keys, MD4_DIGEST_LENGTH, password_md_md);
489 SHA1_Update(&ctx, password_md_md, MD4_DIGEST_LENGTH);
490 SHA1_Update(&ctx, resp_vp->strvalue + 26, 24);
491 SHA1_Update(&ctx, magic1, sizeof(magic1));
492 SHA1_Final(md1, &ctx);
496 SHA1_Update(&ctx, resp_vp->strvalue + 2, 16);
497 SHA1_Update(&ctx, chal_vp->strvalue, 16);
498 SHA1_Update(&ctx, username, username_len);
499 SHA1_Final(md2, &ctx);
501 /* The Authenticator */
503 SHA1_Update(&ctx, md1, SHA_DIGEST_LENGTH);
504 SHA1_Update(&ctx, md2, 8);
505 SHA1_Update(&ctx, magic2, sizeof(magic2));
506 SHA1_Final(auth_md, &ctx);
508 /* String conversion. */
509 auth_md_string[0] = 'S';
510 auth_md_string[1] = '=';
511 for (i = 0; i < sizeof(auth_md); ++i)
512 (void) sprintf(&auth_md_string[i * 2 + 2], "%02X", auth_md[i]);
514 /* And then octet conversion. Ugh! */
515 auth_octet_string[0] = '0';
516 auth_octet_string[1] = 'x';
517 (void) sprintf(&auth_octet_string[2], "%02X", resp_vp->strvalue[0]);
518 for (i = 0; i < sizeof(auth_md_string) - 1; ++i)
519 (void) sprintf(&auth_octet_string[i * 2 +4], "%02X", auth_md_string[i]);
521 vp = pairmake("MS-CHAP2-Success", auth_octet_string, T_OP_EQ);
522 rad_assert(vp != NULL);
524 } /* Generate mutual auth info. */
527 * Generate the MPPE initial session key if needed, per RFC 3079.
528 * (Although, RFC 2548 leaves us guessing at how to generate this.)
529 * For MS-CHAPv2 we support all key lengths (40-, 56- and 128-bit),
530 * although MPPE via RADIUS supports only 40- and 128-bit keys.
531 * This is a bit more complicated than MS-CHAP. Start by generating
532 * a "master session key"
533 * MSB16(SHA(NTPasswordHashHash|NT_RESPONSE|MAGIC1)), where
534 * NTPasswordHashHash is MD4(MD4(unicode(password))), NT_RESPONSE
535 * is from the MS-CHAP2-Response attribute, and MAGIC1 is a
536 * constant from RFC 3079. Then, we derive asymmetric send/receive
537 * keys from the master session key. The "master send key" is
538 * MSBx(SHA(MASTERKEY|SHSPAD1|MAGIC3|SHSPAD2)),
539 * and the "master receive key" is
540 * MSBx(SHA(MASTERKEY|SHSPAD1|MAGIC2|SHSPAD2)), where
541 * MASTERKEY is the "master session key" generated above, and the
542 * other values are constants from RFC 3079. MSBx is the x-most
543 * significant bytes, where x is 5, 7, or 16 as appropriate for
544 * the desired key length. We always generate 16 byte (128-bit)
545 * keys, the NAS is required to truncate as needed.
548 /* First, set some related attributes. */
549 vp = pairmake("MS-MPPE-Encryption-Policy",
550 otp_mppe_policy[inst->mschapv2_mppe_policy], T_OP_EQ);
551 rad_assert(vp != NULL);
553 vp = pairmake("MS-MPPE-Encryption-Types",
554 otp_mppe_types[inst->mschapv2_mppe_types], T_OP_EQ);
555 rad_assert(vp != NULL);
558 if (inst->mschapv2_mppe_policy) {
559 /* These constants and key vars are named from RFC 3079. */
560 /* "This is the MPPE Master Key" */
561 unsigned char Magic1[27] =
562 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
563 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
564 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
565 /* "On the client side, this is the send key; "
566 "on the server side, it is the receive key." */
567 unsigned char Magic2[84] =
568 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
569 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
570 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
571 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
572 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
573 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
574 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
575 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
576 0x6b, 0x65, 0x79, 0x2e };
577 /* "On the client side, this is the receive key; "
578 "on the server side, it is the send key." */
579 unsigned char Magic3[84] =
580 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
581 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
582 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
583 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
584 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
585 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
586 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
587 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
588 0x6b, 0x65, 0x79, 0x2e };
589 unsigned char SHSpad1[40] =
590 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
594 unsigned char SHSpad2[40] =
595 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
596 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
597 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
598 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
599 unsigned char MasterKey[16];
600 unsigned char MasterSendKey[16];
601 unsigned char MasterReceiveKey[16];
604 unsigned char sha_md[SHA_DIGEST_LENGTH];
605 #if 0 /* salting/encoding now handled in lib/radius.c:tunnel_pwencode() */
606 unsigned char md5_md[MD5_DIGEST_LENGTH];
608 /* From RFC 2548: S R A */
609 unsigned char encode_buf[MAX_STRING_LEN + AUTH_VECTOR_LEN + 2];
612 /* A useless value required by RFC 2548. */
613 unsigned char salt[2];
614 unsigned char mppe_key[32]; /* 1 + 16 + padding */
615 /* 0x ( ASCII(salt) ) */
616 unsigned char mppe_key_string[2 + (2 * sizeof(salt)) +
617 /* ( ASCII(mppe_key) ) \0 */
618 (2 * sizeof(mppe_key)) + 1];
620 /* 0x ( ASCII(mppe_key) ) \0 */
621 unsigned char mppe_key_string[2 + (2 * sizeof(MasterKey)) + 1];
624 /* Generate the master session key. */
626 SHA1_Update(&ctx, password_md_md, MD4_DIGEST_LENGTH);
627 SHA1_Update(&ctx, resp_vp->strvalue + 26, 24);
628 SHA1_Update(&ctx, Magic1, sizeof(Magic1));
629 SHA1_Final(sha_md, &ctx);
630 (void) memcpy(MasterKey, sha_md, 16);
632 /* Generate the master send key. */
634 SHA1_Update(&ctx, MasterKey, 16);
635 SHA1_Update(&ctx, SHSpad1, 40);
636 SHA1_Update(&ctx, Magic3, sizeof(Magic3));
637 SHA1_Update(&ctx, SHSpad2, 40);
638 SHA1_Final(sha_md, &ctx);
639 (void) memcpy(MasterSendKey, sha_md, 16);
641 /* Generate the master receive key. */
643 SHA1_Update(&ctx, MasterKey, 16);
644 SHA1_Update(&ctx, SHSpad1, 40);
645 SHA1_Update(&ctx, Magic2, sizeof(Magic3));
646 SHA1_Update(&ctx, SHSpad2, 40);
647 SHA1_Final(sha_md, &ctx);
648 (void) memcpy(MasterReceiveKey, sha_md, 16);
650 /* Now, generate the MS-MPPE-Send-Key attribute. */
653 /* Setup the salt value. */
657 /* Encode the key. */
658 (void) memset(mppe_key, 0, sizeof(mppe_key));
659 mppe_key[0] = 16; /* length */
660 (void) memcpy(&mppe_key[1], MasterSendKey, 16);
661 secretlen = strlen(request->secret);
662 (void) memcpy(encode_buf, request->secret, secretlen);
663 (void) memcpy(encode_buf + secretlen, request->packet->vector,
665 (void) memcpy(encode_buf + secretlen + 16, salt, 2);
666 (void) MD5(encode_buf, secretlen + AUTH_VECTOR_LEN + 2, md5_md);
667 for (i = 0; i < 16; ++i)
668 mppe_key[i] ^= md5_md[i];
669 (void) memcpy(encode_buf + secretlen, mppe_key, 16);
670 (void) MD5(encode_buf, secretlen + 16, md5_md);
671 for (i = 0; i < 16; ++i)
672 mppe_key[i + 16] ^= md5_md[i];
674 /* Whew. Now stringify it for pairmake(). */
675 mppe_key_string[0] = '0';
676 mppe_key_string[1] = 'x';
677 (void) sprintf(&mppe_key_string[2], "%02X", salt[0]);
678 (void) sprintf(&mppe_key_string[4], "%02X", salt[1]);
679 for (i = 0; i < sizeof(mppe_key); ++i)
680 (void) sprintf(&mppe_key_string[i*2+6], "%02X", mppe_key[i]);
682 mppe_key_string[0] = '0';
683 mppe_key_string[1] = 'x';
684 for (i = 0; i < sizeof(MasterSendKey); ++i)
685 (void) sprintf(&mppe_key_string[i*2+2], "%02X", MasterSendKey[i]);
687 vp = pairmake("MS-MPPE-Send-Key", mppe_key_string, T_OP_EQ);
688 rad_assert(vp != NULL);
691 /* Generate the MS-MPPE-Recv-Key attribute. */
694 /* Setup the salt value. */
698 /* Encode the key. */
699 (void) memset(mppe_key, 0, sizeof(mppe_key));
700 mppe_key[0] = 16; /* length */
701 (void) memcpy(&mppe_key[1], MasterReceiveKey, 16);
702 secretlen = strlen(request->secret);
703 (void) memcpy(encode_buf, request->secret, secretlen);
704 (void) memcpy(encode_buf + secretlen, request->packet->vector,
706 (void) memcpy(encode_buf + secretlen + 16, salt, 2);
707 (void) MD5(encode_buf, secretlen + AUTH_VECTOR_LEN + 2, md5_md);
708 for (i = 0; i < 16; ++i)
709 mppe_key[i] ^= md5_md[i];
710 (void) memcpy(encode_buf + secretlen, mppe_key, 16);
711 (void) MD5(encode_buf, secretlen + 16, md5_md);
712 for (i = 0; i < 16; ++i)
713 mppe_key[i + 16] ^= md5_md[i];
715 /* Whew. Now stringify it for pairmake(). */
716 mppe_key_string[0] = '0';
717 mppe_key_string[1] = 'x';
718 (void) sprintf(&mppe_key_string[2], "%02X", salt[0]);
719 (void) sprintf(&mppe_key_string[4], "%02X", salt[1]);
720 for (i = 0; i < sizeof(mppe_key); ++i)
721 (void) sprintf(&mppe_key_string[i*2+6], "%02X", mppe_key[i]);
723 mppe_key_string[0] = '0';
724 mppe_key_string[1] = 'x';
725 for (i = 0; i < sizeof(MasterReceiveKey); ++i)
726 (void) sprintf(&mppe_key_string[i*2+2], "%02X", MasterReceiveKey[i]);
728 vp = pairmake("MS-MPPE-Recv-Key", mppe_key_string, T_OP_EQ);
729 rad_assert(vp != NULL);
732 } /* if (doing mppe) */
734 } /* case PW_MS_CHAP2_RESPONSE */
738 DEBUG("%s: %s: unknown password type", log_prefix, __func__);
742 } /* switch(pwattr[attr]) */
749 * #$!#@ have to convert 7 octet ranges into 8 octet keys.
750 * Implementation cribbed (and slightly modified) from
751 * rlm_mschap.c by Jay Miller <jaymiller@socket.net>.
752 * We don't bother checking/setting parity.
755 otp_key_from_hash(des_cblock *key, const unsigned char hashbytes[7])
758 unsigned char working;
759 unsigned char next = 0;
761 for (i = 0; i < 7; ++i) {
762 working = hashbytes[i];
763 (*key)[i] = (working >> i) | next;
764 next = (working << (7 - i));