missed a s/strvalue/vp_strvalue/
[freeradius.git] / src / modules / rlm_otp / otp_pwe.c
1 /*
2  * otp_pwe.c
3  * $Id$
4  *
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.
9  *
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.
14  *
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
18  *
19  * Copyright 2001,2002  Google, Inc.
20  * Copyright 2005 Frank Cusack
21  */
22
23 /*
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.
27  */
28
29 #ifdef FREERADIUS
30 #define _LRAD_MD4_H
31 #define _LRAD_SHA1_H
32 #include "rad_assert.h"
33 #endif
34 #include "otp.h"
35 #include "otp_pwe.h"
36
37 #include <openssl/des.h>
38 #include <openssl/md4.h>
39 #include <openssl/md5.h>
40 #include <openssl/sha.h>
41
42 #include <string.h>
43
44 static const char rcsid[] = "$Id$";
45
46
47 /* Attribute IDs for supported password encodings. */
48 static int pwattr[8];
49
50
51 /* Initialize the pwattr array for supported password encodings. */
52 void
53 otp_pwe_init(void)
54 {
55     DICT_ATTR *da;
56     int i = 0;
57
58     /*
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)
62      */
63     (void) memset(pwattr, 0, sizeof(pwattr));
64
65     /* PAP */
66     if ((da = dict_attrbyname("User-Password")) != NULL) {
67         pwattr[i++] = da->attr;
68         pwattr[i++] = da->attr;
69     }
70
71     /* CHAP */
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;
76         else
77             pwattr[--i] = 0;
78     }
79
80 #if 0
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;
86         else
87             pwattr[--i] = 0;
88     }
89 #endif /* 0 */
90
91     /* MS-CHAPv2 */
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;
96         else
97             pwattr[--i] = 0;
98     }
99 }
100
101
102 /*
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().
106  */
107 int
108 otp_pwe_present(const REQUEST *request)
109 {
110     unsigned i;
111
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) */
118         }
119     }
120
121     DEBUG("rlm_otp: pwe_present: no password attributes present");
122     return 0;
123 }
124
125
126 /*
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.
132  */
133 int
134 otp_pwe_cmp(struct otp_pwe_cmp_t *data, const char *password)
135 {
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;
140
141     int nmatch = -1;
142     VALUE_PAIR *chal_vp, *resp_vp;
143
144     /*
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.
147      */
148     chal_vp = pairfind(request->packet->vps, pwattr[attr - 1]);
149     resp_vp = pairfind(request->packet->vps, pwattr[attr]);
150
151     /* Prepare for failure return. */
152     if (vps)
153         *vps = NULL;
154
155     /* If modular, this would actually call the authentication function. */
156     switch(pwattr[attr]) {
157     case PW_PASSWORD:
158         DEBUG("rlm_otp: pwe_cmp: handling PW_PASSWORD");
159         nmatch = strcmp(password, resp_vp->vp_strvalue);
160         break;
161
162     case PW_CHAP_PASSWORD:
163     {
164         /*
165          * See RFC 1994.
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
174          * handle this case.
175          */
176         /*                 ID       password    chal */
177         unsigned char input[1 + MAX_STRING_LEN + 16];
178         unsigned char output[MD5_DIGEST_LENGTH];
179
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");
183             nmatch = -1;
184             break;
185         }
186         if (resp_vp->length != 17) {
187             otp_log(OTP_LOG_AUTH, "pwe_cmp: CHAP-Password wrong size");
188             nmatch = -1;
189             break;
190         }
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,
194                       chal_vp->length);
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 */
198     break;
199
200 #if 0
201     case PW_MS_CHAP_RESPONSE:
202     {
203         /*
204          * See RFCs 2548, 2433, 3079.
205          * An MS-CHAP response is (IDENT|FLAGS|LM_RESPONSE|NT_RESPONSE).
206          *                 octets:   1     1       24           24
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.
214          *
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.
218          */
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];
222         int password_len, i;
223         VALUE_PAIR *vp;
224
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");
228             nmatch = -1;
229             break;
230         }
231         if (resp_vp->length != 50) {
232             otp_log(OTP_LOG_AUTH, "pwe_cmp: MS-CHAP-Response wrong size");
233             nmatch = -1;
234             break;
235         }
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)");
239             nmatch = -1;
240             break;
241         }
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");
245             nmatch = -1;
246             break;
247         }
248
249         /*
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).
254          */
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;
260         }
261         (void) memset(nt_keys, 0, sizeof(nt_keys));
262         (void) MD4(input, 2 * password_len, nt_keys);
263
264         /* The challenge gets encrypted. */
265         (void) memcpy(input, chal_vp->vp_strvalue, 8);
266
267         /* Convert the password hash to keys, and do the encryptions. */
268         for (i = 0; i < 3; ++i) {
269             des_cblock key;
270             des_key_schedule ks;
271
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],
276                             ks, DES_ENCRYPT);
277         }
278
279         nmatch = memcmp(output, resp_vp->vp_strvalue + 26, 24);
280         if (nmatch || !vps)
281             break;
282
283         /*
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.
292          */
293
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);
298         pairadd(vps, vp);
299         vp = pairmake("MS-MPPE-Encryption-Types",
300                       otp_mppe_types[inst->mschap_mppe_types], T_OP_EQ);
301         rad_assert(vp != NULL);
302         pairadd(vps, vp);
303
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];
308
309             unsigned char md5_md[MD5_DIGEST_LENGTH];
310             unsigned char encode_buf[AUTH_VECTOR_LEN + MAX_STRING_LEN];
311             int secretlen;
312
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]);
317
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,
323                           AUTH_VECTOR_LEN);
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];
331 #endif /* 0 */
332
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);
340             pairadd(vps, vp);
341         } /* if (doing mppe) */
342
343     } /* case PW_MS_CHAP_RESPONSE */
344     break;
345 #endif /* 0 (MS_CHAP) */
346
347     case PW_MS_CHAP2_RESPONSE:
348     {
349         /*
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)).
361          */
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;
367         VALUE_PAIR *vp;
368
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");
372             nmatch = -1;
373             break;
374         }
375         if (resp_vp->length != 50) {
376             otp_log(OTP_LOG_AUTH, "pwe_cmp: MS-CHAP2-Response wrong size");
377             nmatch = -1;
378             break;
379         }
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");
383             nmatch = -1;
384             break;
385         }
386
387         /*
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).
392          */
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;
398         }
399         (void) memset(nt_keys, 0, sizeof(nt_keys));
400         (void) MD4(input, 2 * password_len, nt_keys);
401
402         /* Now calculate the CHAL value from our various inputs. */
403         {
404             SHA_CTX ctx;
405             unsigned char md[SHA_DIGEST_LENGTH];
406             char *username = request->username->vp_strvalue;
407             int username_len = request->username->length;
408
409             SHA1_Init(&ctx);
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);
414
415             (void) memcpy(input, md, 8);
416         }
417
418         /* Convert the password hash to keys, and do the encryptions. */
419         for (i = 0; i < 3; ++i) {
420             des_cblock key;
421             des_key_schedule ks;
422
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],
427                             ks, DES_ENCRYPT);
428         }
429
430         nmatch = memcmp(output, resp_vp->vp_strvalue + 26, 24);
431         if (nmatch || !vps)
432             break;
433
434         /*
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.
442          * See RFC 2759.
443          */
444         {
445             SHA_CTX ctx;
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];
451             /*
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".
456              */
457             /*                    0x  (ID) ( ASCII("S="ASCII(auth_md))) */
458             char auth_octet_string[2 + 2 + (2 * sizeof(auth_md_string))];
459
460             char *username = request->username->vp_strvalue;
461             int username_len = request->username->length;
462
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,
475               0x6E };
476
477             /* MD1 */
478             (void) MD4(nt_keys, MD4_DIGEST_LENGTH, password_md_md);
479             SHA1_Init(&ctx);
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);
484
485             /* MD2 */
486             SHA1_Init(&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);
491
492             /* The Authenticator */
493             SHA1_Init(&ctx);
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);
498
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]);
504
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",
512                                auth_md_string[i]);
513
514             vp = pairmake("MS-CHAP2-Success", auth_octet_string, T_OP_EQ);
515             rad_assert(vp != NULL);
516             pairadd(vps, vp);
517         } /* Generate mutual auth info. */
518
519         /*
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.
539          */
540
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);
545         pairadd(vps, vp);
546         vp = pairmake("MS-MPPE-Encryption-Types",
547                       otp_mppe_types[inst->mschapv2_mppe_types], T_OP_EQ);
548         rad_assert(vp != NULL);
549         pairadd(vps, vp);
550
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];
595
596             SHA_CTX ctx;
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];
600
601             /*   From RFC 2548:           S                 R           A */
602             unsigned char encode_buf[MAX_STRING_LEN + AUTH_VECTOR_LEN + 2];
603             int secretlen;
604
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];
612 #else /* 0 */
613             /*                           0x   (   ASCII(mppe_key)   )  \0 */
614             unsigned char mppe_key_string[2 + (2 * sizeof(MasterKey)) + 1];
615 #endif /* 0 */
616
617             /* Generate the master session key. */
618             SHA1_Init(&ctx);
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);
624
625             /* Generate the master send key. */
626             SHA1_Init(&ctx);
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);
633
634             /* Generate the master receive key. */
635             SHA1_Init(&ctx);
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);
642
643             /* Now, generate the MS-MPPE-Send-Key attribute. */
644
645 #if 0
646             /* Setup the salt value. */
647             salt[0] = 0x80;
648             salt[1] = 0x01;
649
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,
657                           AUTH_VECTOR_LEN);
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];
666
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]);
674 #else /* 0 */
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",
679                                MasterSendKey[i]);
680 #endif /* 0 */
681             vp = pairmake("MS-MPPE-Send-Key", mppe_key_string, T_OP_EQ);
682             rad_assert(vp != NULL);
683             pairadd(vps, vp);
684
685             /* Generate the MS-MPPE-Recv-Key attribute. */
686
687 #if 0
688             /* Setup the salt value. */
689             salt[0] = 0x80;
690             salt[1] = 0x02;
691
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,
699                           AUTH_VECTOR_LEN);
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];
708
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]);
716 #else /* 0 */
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]);
722 #endif /* 0 */
723             vp = pairmake("MS-MPPE-Recv-Key", mppe_key_string, T_OP_EQ);
724             rad_assert(vp != NULL);
725             pairadd(vps, vp);
726
727         } /* if (doing mppe) */
728
729     } /* case PW_MS_CHAP2_RESPONSE */
730     break;
731
732     default:
733         DEBUG("rlm_otp: pwe_cmp: unknown password type");
734         nmatch = -1;
735         break;
736
737     } /* switch(pwattr[attr]) */
738
739     return nmatch;
740 }
741
742
743 /*
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.
748  */
749 static void
750 otp_key_from_hash(des_cblock *key, const unsigned char hashbytes[7])
751 {
752     int i;
753     unsigned char working;
754     unsigned char next = 0;
755
756     for (i = 0; i < 7; ++i) {
757         working = hashbytes[i];
758         (*key)[i] = (working >> i) | next;
759         next = (working << (7 - i));
760     }
761     (*key)[i] = next;
762 }
763