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 Frank Cusack
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)
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("rlm_otp: pwe_present: password attributes %d, %d",
116 pwattr[i], pwattr[i + 1]);
117 return i + 1; /* Can't return 0 (indicates failure) */
121 DEBUG("rlm_otp: pwe_present: no password attributes present");
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)
136 const REQUEST *request = data->request;
137 const otp_option_t *inst = data->inst;
138 int attr = data->pwattr;
139 VALUE_PAIR **vps = data->returned_vps;
142 VALUE_PAIR *chal_vp, *resp_vp;
145 * A module that does this might want to verify the presence of these.
146 * This code is self contained to otp, so I know these exist.
148 chal_vp = pairfind(request->packet->vps, pwattr[attr - 1]);
149 resp_vp = pairfind(request->packet->vps, pwattr[attr]);
151 /* Prepare for failure return. */
155 /* If modular, this would actually call the authentication function. */
156 switch(pwattr[attr]) {
158 DEBUG("rlm_otp: pwe_cmp: handling PW_PASSWORD");
159 nmatch = strcmp(password, resp_vp->vp_strvalue);
162 case PW_CHAP_PASSWORD:
166 * A CHAP password is MD5(CHAP_ID|SECRET|CHAP_CHALLENGE).
167 * CHAP_ID is a value set by the authenticator (the NAS), and used
168 * in the response calculation. It is available as the first byte
169 * of the CHAP-Password attribute.
170 * SECRET is the password.
171 * CHAP_CHALLENGE is the challenge given to the peer (the user).
172 * The CHAP-Challenge Attribute may be missing, in which case the
173 * challenge is taken to be the Request Authenticator. We don't
176 /* ID password chal */
177 unsigned char input[1 + MAX_STRING_LEN + 16];
178 unsigned char output[MD5_DIGEST_LENGTH];
180 DEBUG("rlm_otp: pwe_cmp: handling PW_CHAP_PASSWORD");
181 if (1 + strlen(password) + chal_vp->length > sizeof(input)) {
182 DEBUG("rlm_otp: pwe_cmp: CHAP-Challenge/password too long");
186 if (resp_vp->length != 17) {
187 otp_log(OTP_LOG_AUTH, "pwe_cmp: CHAP-Password wrong size");
191 input[0] = *(resp_vp->vp_strvalue);
192 (void) memcpy(&input[1], password, strlen(password));
193 (void) memcpy(&input[1+strlen(password)], chal_vp->vp_strvalue,
195 (void) MD5(input, 1 + strlen(password) + chal_vp->length, output);
196 nmatch = memcmp(output, &(resp_vp->vp_strvalue)[1], MD5_DIGEST_LENGTH);
197 } /* case PW_CHAP_PASSWORD */
201 case PW_MS_CHAP_RESPONSE:
204 * See RFCs 2548, 2433, 3079.
205 * An MS-CHAP response is (IDENT|FLAGS|LM_RESPONSE|NT_RESPONSE).
207 * IDENT is not used by RADIUS (it is the PPP MS-CHAP Identifier).
208 * FLAGS is 1 to indicate the NT_RESPONSE should be preferred.
209 * LM_RESPONSE is the LAN Manager compatible response.
210 * NT_RESPONSE is the NT compatible response.
211 * Either response may be zero-filled indicating its absence.
212 * Use of the LM response has been deprecated (RFC 2433, par. 6),
213 * so we don't handle it.
215 * The NT_RESPONSE is (DES(CHAL,K1)|DES(CHAL,K2)|DES(CHAL,K3)), where
216 * CHAL is the 8-octet challenge, and K1, K2, K3 are 7-octet pieces
217 * of MD4(unicode(password)), zero-filled to 21 octets. Sigh.
219 unsigned char nt_keys[21]; /* sized for 3 DES keys */
220 unsigned char input[MAX_STRING_LEN * 2]; /* doubled for unicode */
221 unsigned char output[24];
225 DEBUG("rlm_otp: pwe_cmp: handling PW_MS_CHAP_RESPONSE");
226 if (chal_vp->length != 8) {
227 otp_log(OTP_LOG_AUTH, "pwe_cmp: MS-CHAP-Challenge wrong size");
231 if (resp_vp->length != 50) {
232 otp_log(OTP_LOG_AUTH, "pwe_cmp: MS-CHAP-Response wrong size");
236 if ((resp_vp->vp_strvalue)[1] != 1) {
237 otp_log(OTP_LOG_AUTH,
238 "pwe_cmp: MS-CHAP-Response bad flags (LM not supported)");
242 /* This is probably overkill. */
243 if (strlen(password) > MAX_STRING_LEN) {
244 otp_log(OTP_LOG_AUTH, "pwe_cmp: MS-CHAP password too long");
250 * Start by hashing the unicode password.
251 * This is broken because unicode chars are machine-ordered,
252 * but the spec (RFC 2433) doesn't say how to prepare
253 * the password for md4 (other than by example values).
255 password_len = strlen(password);
256 for (i = 0; i < password_len; ++i) {
257 /* Set the high order 8 bits to 0 (little-endian) */
258 input[i * 2] = *password++;
259 input[i * 2 + 1] = 0;
261 (void) memset(nt_keys, 0, sizeof(nt_keys));
262 (void) MD4(input, 2 * password_len, nt_keys);
264 /* The challenge gets encrypted. */
265 (void) memcpy(input, chal_vp->vp_strvalue, 8);
267 /* Convert the password hash to keys, and do the encryptions. */
268 for (i = 0; i < 3; ++i) {
272 otp_key_from_hash(&key, &nt_keys[i * 7]);
273 des_set_key_unchecked(&key, ks);
274 des_ecb_encrypt((des_cblock *) input,
275 (des_cblock *) &output[i * 8],
279 nmatch = memcmp(output, resp_vp->vp_strvalue + 26, 24);
284 * Generate the MS-CHAP-MPPE-Keys attribute if needed. This is not
285 * specified anywhere -- RFC 2548, par. 2.4.1 is the authority but
286 * it has typos and omissions that make this unimplementable. The
287 * code here is based on experimental results provided by
288 * Takahiro Wagatsuma <waga@sic.shibaura-it.ac.jp>.
289 * We only support 128-bit keys derived from the NT hash; 40-bit
290 * and 56-bit keys are derived from the LM hash, which besides
291 * being deprecated, has severe security problems.
294 /* First, set some related attributes. */
295 vp = pairmake("MS-MPPE-Encryption-Policy",
296 otp_mppe_policy[inst->mschap_mppe_policy], T_OP_EQ);
297 rad_assert(vp != NULL);
299 vp = pairmake("MS-MPPE-Encryption-Types",
300 otp_mppe_types[inst->mschap_mppe_types], T_OP_EQ);
301 rad_assert(vp != NULL);
304 if (inst->mschap_mppe_policy) {
305 unsigned char mppe_keys[32];
306 /* 0x ASCII(mppe_keys) '\0' */
307 char mppe_keys_string[2 + (2 * sizeof(mppe_keys)) + 1];
309 unsigned char md5_md[MD5_DIGEST_LENGTH];
310 unsigned char encode_buf[AUTH_VECTOR_LEN + MAX_STRING_LEN];
313 /* Zero the LM-Key sub-field (and padding). */
314 (void) memset(mppe_keys, 0, sizeof(mppe_keys));
315 /* The NT-Key sub-field is MD4(MD4(unicode(password))). */
316 (void) MD4(nt_keys, 16, &mppe_keys[8]);
318 #if 0 /* encoding now handled in lib/radius.c:rad_pwencode() */
319 /* Now we must encode the key as User-Password is encoded. */
320 secretlen = strlen(request->secret);
321 (void) memcpy(encode_buf, request->secret, secretlen);
322 (void) memcpy(encode_buf + secretlen, request->packet->vector,
324 (void) MD5(encode_buf, secretlen + AUTH_VECTOR_LEN, md5_md);
325 for (i = 0; i < 16; ++i)
326 mppe_keys[i] ^= md5_md[i];
327 (void) memcpy(encode_buf + secretlen, mppe_keys, MD5_DIGEST_LENGTH);
328 (void) MD5(encode_buf, secretlen + MD5_DIGEST_LENGTH, md5_md);
329 for (i = 0; i < 16; ++i)
330 mppe_keys[i + 16] ^= md5_md[i];
333 /* Whew. Now stringify it for pairmake(). */
334 mppe_keys_string[0] = '0';
335 mppe_keys_string[1] = 'x';
336 for (i = 0; i < 32; ++i)
337 (void) sprintf(&mppe_keys_string[i*2+2], "%02X", mppe_keys[i]);
338 vp = pairmake("MS-CHAP-MPPE-Keys", mppe_keys_string, T_OP_EQ);
339 rad_assert(vp != NULL);
341 } /* if (doing mppe) */
343 } /* case PW_MS_CHAP_RESPONSE */
345 #endif /* 0 (MS_CHAP) */
347 case PW_MS_CHAP2_RESPONSE:
350 * See RFCs 2548, 2759, 3079.
351 * An MS-CHAPv2 response is
352 * (IDENT|FLAGS|PEER_CHALLENGE|RESERVED|NT_RESPONSE).
353 * octets: 1 1 16 8 24
354 * IDENT is the PPP MS-CHAPv2 Identifier, used in MS-CHAP2-Success.
355 * FLAGS is currently unused.
356 * PEER_CHALLENGE is a random number, generated by the peer.
357 * NT_RESPONSE is (DES(CHAL,K1)|DES(CHAL,K2)|DES(CHAL,K3)), where
358 * K1, K2, K3 are 7-octet pieces of MD4(unicode(password)), zero-
359 * filled to 21 octets (just as in MS-CHAP); and CHAL is
360 * MSB8(SHA(PEER_CHALLENGE|MS_CHAP_CHALLENGE|USERNAME)).
362 unsigned char nt_keys[21]; /* aka "password_md", sized for 3 DES keys */
363 unsigned char password_md_md[MD4_DIGEST_LENGTH]; /* for mutual auth */
364 unsigned char input[MAX_STRING_LEN * 2]; /* doubled for unicode */
365 unsigned char output[24];
366 unsigned password_len, i;
369 DEBUG("rlm_otp: pwe_cmp: handling PW_MS_CHAP2_RESPONSE");
370 if (chal_vp->length != 16) {
371 otp_log(OTP_LOG_AUTH,"pwe_cmp: MS-CHAP-Challenge (v2) wrong size");
375 if (resp_vp->length != 50) {
376 otp_log(OTP_LOG_AUTH, "pwe_cmp: MS-CHAP2-Response wrong size");
380 /* This is probably overkill. */
381 if (strlen(password) > MAX_STRING_LEN) {
382 otp_log(OTP_LOG_AUTH, "pwe_cmp: MS-CHAPv2 password too long");
388 * Start by hashing the unicode password.
389 * This is broken because unicode chars are machine-ordered,
390 * but the spec (RFC 2759) doesn't say how to prepare
391 * the password for md4 (other than by example values).
393 password_len = strlen(password);
394 for (i = 0; i < password_len; ++i) {
395 /* Set the high order 8 bits to 0 (little-endian) */
396 input[i * 2] = *password++;
397 input[i * 2 + 1] = 0;
399 (void) memset(nt_keys, 0, sizeof(nt_keys));
400 (void) MD4(input, 2 * password_len, nt_keys);
402 /* Now calculate the CHAL value from our various inputs. */
405 unsigned char md[SHA_DIGEST_LENGTH];
406 char *username = request->username->vp_strvalue;
407 int username_len = request->username->length;
410 SHA1_Update(&ctx, resp_vp->vp_strvalue + 2, 16);
411 SHA1_Update(&ctx, chal_vp->vp_strvalue, 16);
412 SHA1_Update(&ctx, username, username_len);
413 SHA1_Final(md, &ctx);
415 (void) memcpy(input, md, 8);
418 /* Convert the password hash to keys, and do the encryptions. */
419 for (i = 0; i < 3; ++i) {
423 otp_key_from_hash(&key, &nt_keys[i * 7]);
424 des_set_key_unchecked(&key, ks);
425 des_ecb_encrypt((des_cblock *) input,
426 (des_cblock *) &output[i * 8],
430 nmatch = memcmp(output, resp_vp->vp_strvalue + 26, 24);
435 * MS-CHAPv2 requires mutual authentication; we must prove
436 * that we know the secret. This is a bit circuitous: set
437 * MD1 = SHA(MD4(MD4(unicode(password)))|NT_RESPONSE|MAGIC1),
438 * MD2 = MSB8(SHA(PEER_CHALLENGE|MS_CHAP_CHALLENGE|USERNAME)),
439 * and finally use SHA(MD1|MD2|MAGIC2) as the authenticator.
440 * The authenticator is returned as the string "S=<auth>",
441 * <auth> is the authenticator expressed as [uppercase] ASCII.
446 unsigned char md1[SHA_DIGEST_LENGTH];
447 unsigned char md2[SHA_DIGEST_LENGTH];
448 unsigned char auth_md[SHA_DIGEST_LENGTH];
449 /* S= ( ASCII(auth_md) ) \0 */
450 char auth_md_string[2 + (2 * sizeof(auth_md)) + 1];
452 * ugh. The ASCII authenticator (auth_md_string) is sent
453 * along with a single (useless) binary byte (the ID).
454 * So we must "stringify" it again (for pairmake()) since the
455 * binary byte requires the attribute to be of type "octets".
457 /* 0x (ID) ( ASCII("S="ASCII(auth_md))) */
458 char auth_octet_string[2 + 2 + (2 * sizeof(auth_md_string))];
460 char *username = request->username->vp_strvalue;
461 int username_len = request->username->length;
463 /* "Magic server to client signing constant" */
464 unsigned char magic1[39] =
465 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
466 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
467 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
468 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
469 /* "Pad to make it do more than one iteration" */
470 unsigned char magic2[41] =
471 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
472 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
473 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
474 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
478 (void) MD4(nt_keys, MD4_DIGEST_LENGTH, password_md_md);
480 SHA1_Update(&ctx, password_md_md, MD4_DIGEST_LENGTH);
481 SHA1_Update(&ctx, resp_vp->vp_strvalue + 26, 24);
482 SHA1_Update(&ctx, magic1, sizeof(magic1));
483 SHA1_Final(md1, &ctx);
487 SHA1_Update(&ctx, resp_vp->vp_strvalue + 2, 16);
488 SHA1_Update(&ctx, chal_vp->vp_strvalue, 16);
489 SHA1_Update(&ctx, username, username_len);
490 SHA1_Final(md2, &ctx);
492 /* The Authenticator */
494 SHA1_Update(&ctx, md1, SHA_DIGEST_LENGTH);
495 SHA1_Update(&ctx, md2, 8);
496 SHA1_Update(&ctx, magic2, sizeof(magic2));
497 SHA1_Final(auth_md, &ctx);
499 /* String conversion. */
500 auth_md_string[0] = 'S';
501 auth_md_string[1] = '=';
502 for (i = 0; i < sizeof(auth_md); ++i)
503 (void) sprintf(&auth_md_string[i * 2 + 2], "%02X", auth_md[i]);
505 /* And then octet conversion. Ugh! */
506 auth_octet_string[0] = '0';
507 auth_octet_string[1] = 'x';
508 (void) sprintf(&auth_octet_string[2], "%02X",
509 resp_vp->vp_strvalue[0]);
510 for (i = 0; i < sizeof(auth_md_string) - 1; ++i)
511 (void) sprintf(&auth_octet_string[i * 2 + 4], "%02X",
514 vp = pairmake("MS-CHAP2-Success", auth_octet_string, T_OP_EQ);
515 rad_assert(vp != NULL);
517 } /* Generate mutual auth info. */
520 * Generate the MPPE initial session key if needed, per RFC 3079.
521 * (Although, RFC 2548 leaves us guessing at how to generate this.)
522 * For MS-CHAPv2 we support all key lengths (40-, 56- and 128-bit),
523 * although MPPE via RADIUS supports only 40- and 128-bit keys.
524 * This is a bit more complicated than MS-CHAP. Start by generating
525 * a "master session key"
526 * MSB16(SHA(NTPasswordHashHash|NT_RESPONSE|MAGIC1)), where
527 * NTPasswordHashHash is MD4(MD4(unicode(password))), NT_RESPONSE
528 * is from the MS-CHAP2-Response attribute, and MAGIC1 is a
529 * constant from RFC 3079. Then, we derive asymmetric send/receive
530 * keys from the master session key. The "master send key" is
531 * MSBx(SHA(MASTERKEY|SHSPAD1|MAGIC3|SHSPAD2)),
532 * and the "master receive key" is
533 * MSBx(SHA(MASTERKEY|SHSPAD1|MAGIC2|SHSPAD2)), where
534 * MASTERKEY is the "master session key" generated above, and the
535 * other values are constants from RFC 3079. MSBx is the x-most
536 * significant bytes, where x is 5, 7, or 16 as appropriate for
537 * the desired key length. We always generate 16 byte (128-bit)
538 * keys, the NAS is required to truncate as needed.
541 /* First, set some related attributes. */
542 vp = pairmake("MS-MPPE-Encryption-Policy",
543 otp_mppe_policy[inst->mschapv2_mppe_policy], T_OP_EQ);
544 rad_assert(vp != NULL);
546 vp = pairmake("MS-MPPE-Encryption-Types",
547 otp_mppe_types[inst->mschapv2_mppe_types], T_OP_EQ);
548 rad_assert(vp != NULL);
551 if (inst->mschapv2_mppe_policy) {
552 /* These constants and key vars are named from RFC 3079. */
553 /* "This is the MPPE Master Key" */
554 unsigned char Magic1[27] =
555 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
556 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
557 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
558 /* "On the client side, this is the send key; "
559 "on the server side, it is the receive key." */
560 unsigned char Magic2[84] =
561 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
562 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
563 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
564 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
565 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
566 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
567 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
568 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
569 0x6b, 0x65, 0x79, 0x2e };
570 /* "On the client side, this is the receive key; "
571 "on the server side, it is the send key." */
572 unsigned char Magic3[84] =
573 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
574 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
575 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
576 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
577 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
578 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
579 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
580 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
581 0x6b, 0x65, 0x79, 0x2e };
582 unsigned char SHSpad1[40] =
583 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
587 unsigned char SHSpad2[40] =
588 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
589 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
590 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
591 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
592 unsigned char MasterKey[16];
593 unsigned char MasterSendKey[16];
594 unsigned char MasterReceiveKey[16];
597 unsigned char sha_md[SHA_DIGEST_LENGTH];
598 #if 0 /* salting/encoding now handled in lib/radius.c:tunnel_pwencode() */
599 unsigned char md5_md[MD5_DIGEST_LENGTH];
601 /* From RFC 2548: S R A */
602 unsigned char encode_buf[MAX_STRING_LEN + AUTH_VECTOR_LEN + 2];
605 /* A useless value required by RFC 2548. */
606 unsigned char salt[2];
607 unsigned char mppe_key[32]; /* 1 + 16 + padding */
608 /* 0x ( ASCII(salt) ) */
609 unsigned char mppe_key_string[2 + (2 * sizeof(salt)) +
610 /* ( ASCII(mppe_key) ) \0 */
611 (2 * sizeof(mppe_key)) + 1];
613 /* 0x ( ASCII(mppe_key) ) \0 */
614 unsigned char mppe_key_string[2 + (2 * sizeof(MasterKey)) + 1];
617 /* Generate the master session key. */
619 SHA1_Update(&ctx, password_md_md, MD4_DIGEST_LENGTH);
620 SHA1_Update(&ctx, resp_vp->vp_strvalue + 26, 24);
621 SHA1_Update(&ctx, Magic1, sizeof(Magic1));
622 SHA1_Final(sha_md, &ctx);
623 (void) memcpy(MasterKey, sha_md, 16);
625 /* Generate the master send key. */
627 SHA1_Update(&ctx, MasterKey, 16);
628 SHA1_Update(&ctx, SHSpad1, 40);
629 SHA1_Update(&ctx, Magic3, sizeof(Magic3));
630 SHA1_Update(&ctx, SHSpad2, 40);
631 SHA1_Final(sha_md, &ctx);
632 (void) memcpy(MasterSendKey, sha_md, 16);
634 /* Generate the master receive key. */
636 SHA1_Update(&ctx, MasterKey, 16);
637 SHA1_Update(&ctx, SHSpad1, 40);
638 SHA1_Update(&ctx, Magic2, sizeof(Magic3));
639 SHA1_Update(&ctx, SHSpad2, 40);
640 SHA1_Final(sha_md, &ctx);
641 (void) memcpy(MasterReceiveKey, sha_md, 16);
643 /* Now, generate the MS-MPPE-Send-Key attribute. */
646 /* Setup the salt value. */
650 /* Encode the key. */
651 (void) memset(mppe_key, 0, sizeof(mppe_key));
652 mppe_key[0] = 16; /* length */
653 (void) memcpy(&mppe_key[1], MasterSendKey, 16);
654 secretlen = strlen(request->secret);
655 (void) memcpy(encode_buf, request->secret, secretlen);
656 (void) memcpy(encode_buf + secretlen, request->packet->vector,
658 (void) memcpy(encode_buf + secretlen + 16, salt, 2);
659 (void) MD5(encode_buf, secretlen + AUTH_VECTOR_LEN + 2, md5_md);
660 for (i = 0; i < 16; ++i)
661 mppe_key[i] ^= md5_md[i];
662 (void) memcpy(encode_buf + secretlen, mppe_key, 16);
663 (void) MD5(encode_buf, secretlen + 16, md5_md);
664 for (i = 0; i < 16; ++i)
665 mppe_key[i + 16] ^= md5_md[i];
667 /* Whew. Now stringify it for pairmake(). */
668 mppe_key_string[0] = '0';
669 mppe_key_string[1] = 'x';
670 (void) sprintf(&mppe_key_string[2], "%02X", salt[0]);
671 (void) sprintf(&mppe_key_string[4], "%02X", salt[1]);
672 for (i = 0; i < sizeof(mppe_key); ++i)
673 (void) sprintf(&mppe_key_string[i*2+6], "%02X", mppe_key[i]);
675 mppe_key_string[0] = '0';
676 mppe_key_string[1] = 'x';
677 for (i = 0; i < sizeof(MasterSendKey); ++i)
678 (void) sprintf(&mppe_key_string[i*2+2], "%02X",
681 vp = pairmake("MS-MPPE-Send-Key", mppe_key_string, T_OP_EQ);
682 rad_assert(vp != NULL);
685 /* Generate the MS-MPPE-Recv-Key attribute. */
688 /* Setup the salt value. */
692 /* Encode the key. */
693 (void) memset(mppe_key, 0, sizeof(mppe_key));
694 mppe_key[0] = 16; /* length */
695 (void) memcpy(&mppe_key[1], MasterReceiveKey, 16);
696 secretlen = strlen(request->secret);
697 (void) memcpy(encode_buf, request->secret, secretlen);
698 (void) memcpy(encode_buf + secretlen, request->packet->vector,
700 (void) memcpy(encode_buf + secretlen + 16, salt, 2);
701 (void) MD5(encode_buf, secretlen + AUTH_VECTOR_LEN + 2, md5_md);
702 for (i = 0; i < 16; ++i)
703 mppe_key[i] ^= md5_md[i];
704 (void) memcpy(encode_buf + secretlen, mppe_key, 16);
705 (void) MD5(encode_buf, secretlen + 16, md5_md);
706 for (i = 0; i < 16; ++i)
707 mppe_key[i + 16] ^= md5_md[i];
709 /* Whew. Now stringify it for pairmake(). */
710 mppe_key_string[0] = '0';
711 mppe_key_string[1] = 'x';
712 (void) sprintf(&mppe_key_string[2], "%02X", salt[0]);
713 (void) sprintf(&mppe_key_string[4], "%02X", salt[1]);
714 for (i = 0; i < sizeof(mppe_key); ++i)
715 (void) sprintf(&mppe_key_string[i*2+6], "%02X", mppe_key[i]);
717 mppe_key_string[0] = '0';
718 mppe_key_string[1] = 'x';
719 for (i = 0; i < sizeof(MasterReceiveKey); ++i)
720 (void) sprintf(&mppe_key_string[i*2+2], "%02X",
721 MasterReceiveKey[i]);
723 vp = pairmake("MS-MPPE-Recv-Key", mppe_key_string, T_OP_EQ);
724 rad_assert(vp != NULL);
727 } /* if (doing mppe) */
729 } /* case PW_MS_CHAP2_RESPONSE */
733 DEBUG("rlm_otp: pwe_cmp: unknown password type");
737 } /* switch(pwattr[attr]) */
744 * #$!#@ have to convert 7 octet ranges into 8 octet keys.
745 * Implementation cribbed (and slightly modified) from
746 * rlm_mschap.c by Jay Miller <jaymiller@socket.net>.
747 * We don't bother checking/setting parity.
750 otp_key_from_hash(des_cblock *key, const unsigned char hashbytes[7])
753 unsigned char working;
754 unsigned char next = 0;
756 for (i = 0; i < 7; ++i) {
757 working = hashbytes[i];
758 (*key)[i] = (working >> i) | next;
759 next = (working << (7 - i));