2
* $Id: otp_mppe.c,v 1.1.2.2 2006/06/01 19:02:20 fcusack Exp $
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18
* Copyright 2001,2002 Google, Inc.
19
* Copyright 2005,2006 TRI-D Systems, Inc.
22
static const char rcsid[] = "$Id: otp_mppe.c,v 1.1.2.2 2006/06/01 19:02:20 fcusack Exp $";
24
/* avoid inclusion of these FR headers which conflict w/ OpenSSL */
28
#include <rad_assert.h>
34
#include <openssl/des.h>
35
#include <openssl/md4.h>
36
#include <openssl/md5.h>
37
#include <openssl/sha.h>
42
* Add MPPE attributes to a request, if required.
45
otp_mppe(REQUEST *request, otp_pwe_t pwe, const otp_option_t *opt,
48
VALUE_PAIR **avp = &request->reply->vps;
49
VALUE_PAIR *cvp, *rvp, *vp;
51
cvp = pairfind(request->packet->vps, pwattr[pwe - 1]);
52
rvp = pairfind(request->packet->vps, pwattr[pwe]);
60
/* First, set some related attributes. */
61
vp = pairmake("MS-MPPE-Encryption-Policy",
62
otp_mppe_policy[opt->mschap_mppe_policy], T_OP_EQ);
63
rad_assert(vp != NULL);
65
vp = pairmake("MS-MPPE-Encryption-Types",
66
otp_mppe_types[opt->mschap_mppe_types], T_OP_EQ);
67
rad_assert(vp != NULL);
70
/* If no MPPE, we're done. */
71
if (!opt->mschap_mppe_policy)
75
* Generate the MS-CHAP-MPPE-Keys attribute. This is not specified
76
* anywhere -- RFC 2548, par. 2.4.1 is the authority but it has
77
* typos and omissions that make this unimplementable. The
78
* code here is based on experimental results provided by
79
* Takahiro Wagatsuma <waga@sic.shibaura-it.ac.jp>.
80
* We only support 128-bit keys derived from the NT hash; 40-bit
81
* and 56-bit keys are derived from the LM hash, which besides
82
* being deprecated, has severe security problems.
85
size_t i, passcode_len;
86
unsigned char password_unicode[2 * OTP_MAX_PASSCODE_LEN];
87
unsigned char password_md[MD4_DIGEST_LENGTH];
88
unsigned char mppe_keys[32];
89
/* 0x ASCII(mppe_keys) '\0' */
90
char mppe_keys_string[2 + (2 * sizeof(mppe_keys)) + 1];
92
/* Zero the LM-Key sub-field (and padding). */
93
(void) memset(mppe_keys, 0, sizeof(mppe_keys));
96
* The NT-Key sub-field is MD4(MD4(unicode(password))).
97
* Start by hashing the unicode passcode.
98
* This is broken because unicode chars are machine-ordered,
99
* but the spec (RFC 2433) doesn't say how to prepare
100
* the password for md4 (other than by example values).
102
passcode_len = strlen(passcode);
103
for (i = 0; i < passcode_len; ++i) {
104
/* Set the high order 8 bits to 0 (little-endian) */
105
password_unicode[i * 2] = *passcode++;
106
password_unicode[i * 2 + 1] = 0;
109
(void) MD4(password_unicode, 2 * passcode_len, password_md);
111
(void) MD4(password_md, MD4_DIGEST_LENGTH, &mppe_keys[8]);
113
#if 0 /* encoding now handled in lib/radius.c:rad_pwencode() */
115
unsigned char md5_md[MD5_DIGEST_LENGTH];
116
unsigned char encode_buf[AUTH_VECTOR_LEN + MAX_STRING_LEN];
119
/* Now we must encode the key as User-Password is encoded. */
120
secretlen = strlen(request->secret);
121
(void) memcpy(encode_buf, request->secret, secretlen);
122
(void) memcpy(encode_buf + secretlen, request->packet->vector,
124
(void) MD5(encode_buf, secretlen + AUTH_VECTOR_LEN, md5_md);
125
for (i = 0; i < 16; ++i)
126
mppe_keys[i] ^= md5_md[i];
127
(void) memcpy(encode_buf + secretlen, mppe_keys, MD5_DIGEST_LENGTH);
128
(void) MD5(encode_buf, secretlen + MD5_DIGEST_LENGTH, md5_md);
129
for (i = 0; i < 16; ++i)
130
mppe_keys[i + 16] ^= md5_md[i];
134
/* Whew. Now stringify it for pairmake(). */
135
mppe_keys_string[0] = '0';
136
mppe_keys_string[1] = 'x';
137
for (i = 0; i < 32; ++i)
138
(void) sprintf(&mppe_keys_string[i*2+2], "%02X", mppe_keys[i]);
139
vp = pairmake("MS-CHAP-MPPE-Keys", mppe_keys_string, T_OP_EQ);
140
rad_assert(vp != NULL);
143
break; /* PWE_MSCHAP */
148
unsigned char password_md_md[MD4_DIGEST_LENGTH];
151
* MS-CHAPv2 requires mutual authentication; we must prove
152
* that we know the secret. This is a bit circuitous: set
153
* MD1 = SHA(MD4(MD4(unicode(password)))|NT_RESPONSE|MAGIC1),
154
* MD2 = MSB8(SHA(PEER_CHALLENGE|MS_CHAP_CHALLENGE|USERNAME)),
155
* and finally use SHA(MD1|MD2|MAGIC2) as the authenticator.
156
* The authenticator is returned as the string "S=<auth>",
157
* <auth> is the authenticator expressed as [uppercase] ASCII.
162
unsigned char password_unicode[2 * OTP_MAX_PASSCODE_LEN];
163
unsigned char password_md[MD4_DIGEST_LENGTH];
166
unsigned char md1[SHA_DIGEST_LENGTH];
167
unsigned char md2[SHA_DIGEST_LENGTH];
168
unsigned char auth_md[SHA_DIGEST_LENGTH];
169
/* S= ( ASCII(auth_md) ) \0 */
170
char auth_md_string[2 + (2 * sizeof(auth_md)) + 1];
172
* ugh. The ASCII authenticator (auth_md_string) is sent
173
* along with a single (useless) binary byte (the ID).
174
* So we must "stringify" it again (for pairmake()) since the
175
* binary byte requires the attribute to be of type "octets".
177
/* 0x (ID) ( ASCII("S="ASCII(auth_md))) */
178
char auth_octet_string[2 + 2 + (2 * sizeof(auth_md_string))];
180
char *username = request->username->strvalue;
181
int username_len = request->username->length;
183
/* "Magic server to client signing constant" */
184
unsigned char magic1[39] =
185
{ 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
186
0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
187
0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
188
0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
189
/* "Pad to make it do more than one iteration" */
190
unsigned char magic2[41] =
191
{ 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
192
0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
193
0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
194
0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
198
* Start by hashing the unicode passcode.
199
* This is broken because unicode chars are machine-ordered,
200
* but the spec (RFC 2759) doesn't say how to prepare
201
* the password for md4 (other than by example values).
203
passcode_len = strlen(passcode);
204
for (i = 0; i < passcode_len; ++i) {
205
/* Set the high order 8 bits to 0 (little-endian) */
206
password_unicode[i * 2] = *passcode++;
207
password_unicode[i * 2 + 1] = 0;
210
(void) MD4(password_unicode, 2 * passcode_len, password_md);
212
(void) MD4(password_md, MD4_DIGEST_LENGTH, password_md_md);
216
SHA1_Update(&ctx, password_md_md, MD4_DIGEST_LENGTH);
217
SHA1_Update(&ctx, rvp->strvalue + 26, 24);
218
SHA1_Update(&ctx, magic1, sizeof(magic1));
219
SHA1_Final(md1, &ctx);
223
SHA1_Update(&ctx, rvp->strvalue + 2, 16);
224
SHA1_Update(&ctx, cvp->strvalue, 16);
225
SHA1_Update(&ctx, username, username_len);
226
SHA1_Final(md2, &ctx);
228
/* The Authenticator */
230
SHA1_Update(&ctx, md1, SHA_DIGEST_LENGTH);
231
SHA1_Update(&ctx, md2, 8);
232
SHA1_Update(&ctx, magic2, sizeof(magic2));
233
SHA1_Final(auth_md, &ctx);
235
/* String conversion. */
236
auth_md_string[0] = 'S';
237
auth_md_string[1] = '=';
238
for (i = 0; i < sizeof(auth_md); ++i)
239
(void) sprintf(&auth_md_string[i * 2 + 2], "%02X", auth_md[i]);
241
/* And then octet conversion. Ugh! */
242
auth_octet_string[0] = '0';
243
auth_octet_string[1] = 'x';
244
(void) sprintf(&auth_octet_string[2], "%02X", rvp->strvalue[0]);
245
for (i = 0; i < sizeof(auth_md_string) - 1; ++i)
246
(void) sprintf(&auth_octet_string[i * 2 +4], "%02X", auth_md_string[i]);
248
vp = pairmake("MS-CHAP2-Success", auth_octet_string, T_OP_EQ);
249
rad_assert(vp != NULL);
251
} /* Generate mutual auth info. */
254
* Now, set some MPPE related attributes.
256
vp = pairmake("MS-MPPE-Encryption-Policy",
257
otp_mppe_policy[opt->mschapv2_mppe_policy], T_OP_EQ);
258
rad_assert(vp != NULL);
260
vp = pairmake("MS-MPPE-Encryption-Types",
261
otp_mppe_types[opt->mschapv2_mppe_types], T_OP_EQ);
262
rad_assert(vp != NULL);
265
/* If no MPPE, we're done. */
266
if (!opt->mschapv2_mppe_policy)
270
* Generate the MPPE initial session key, per RFC 3079.
271
* (Although, RFC 2548 leaves us guessing at how to generate this.)
272
* For MS-CHAPv2 we support all key lengths (40-, 56- and 128-bit),
273
* although MPPE via RADIUS supports only 40- and 128-bit keys.
274
* This is a bit more complicated than MS-CHAP. Start by generating
275
* a "master session key"
276
* MSB16(SHA(NTPasswordHashHash|NT_RESPONSE|MAGIC1)), where
277
* NTPasswordHashHash is MD4(MD4(unicode(password))), NT_RESPONSE
278
* is from the MS-CHAP2-Response attribute, and MAGIC1 is a
279
* constant from RFC 3079. Then, we derive asymmetric send/receive
280
* keys from the master session key. The "master send key" is
281
* MSBx(SHA(MASTERKEY|SHSPAD1|MAGIC3|SHSPAD2)),
282
* and the "master receive key" is
283
* MSBx(SHA(MASTERKEY|SHSPAD1|MAGIC2|SHSPAD2)), where
284
* MASTERKEY is the "master session key" generated above, and the
285
* other values are constants from RFC 3079. MSBx is the x-most
286
* significant bytes, where x is 5, 7, or 16 as appropriate for
287
* the desired key length. We always generate 16 byte (128-bit)
288
* keys, the NAS is required to truncate as needed.
291
/* These constants and key vars are named from RFC 3079. */
292
/* "This is the MPPE Master Key" */
293
unsigned char Magic1[27] =
294
{ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
295
0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
296
0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
297
/* "On the client side, this is the send key; "
298
"on the server side, it is the receive key." */
299
unsigned char Magic2[84] =
300
{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
301
0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
302
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
303
0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
304
0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
305
0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
306
0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
307
0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
308
0x6b, 0x65, 0x79, 0x2e };
309
/* "On the client side, this is the receive key; "
310
"on the server side, it is the send key." */
311
unsigned char Magic3[84] =
312
{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
313
0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
314
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
315
0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
316
0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
317
0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
318
0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
319
0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
320
0x6b, 0x65, 0x79, 0x2e };
321
unsigned char SHSpad1[40] =
322
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
326
unsigned char SHSpad2[40] =
327
{ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
328
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
329
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
330
0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
331
unsigned char MasterKey[16];
332
unsigned char MasterSendKey[16];
333
unsigned char MasterReceiveKey[16];
336
unsigned char sha_md[SHA_DIGEST_LENGTH];
337
#if 0 /* salting/encoding now handled in lib/radius.c:tunnel_pwencode() */
338
unsigned char md5_md[MD5_DIGEST_LENGTH];
340
/* From RFC 2548: S R A */
341
unsigned char encode_buf[MAX_STRING_LEN + AUTH_VECTOR_LEN + 2];
344
/* A useless value required by RFC 2548. */
345
unsigned char salt[2];
346
unsigned char mppe_key[32]; /* 1 + 16 + padding */
347
/* 0x ( ASCII(salt) ) */
348
unsigned char mppe_key_string[2 + (2 * sizeof(salt)) +
349
/* ( ASCII(mppe_key) ) \0 */
350
(2 * sizeof(mppe_key)) + 1];
352
/* 0x ( ASCII(mppe_key) ) \0 */
353
unsigned char mppe_key_string[2 + (2 * sizeof(MasterKey)) + 1];
356
/* Generate the master session key. */
358
SHA1_Update(&ctx, password_md_md, MD4_DIGEST_LENGTH);
359
SHA1_Update(&ctx, rvp->strvalue + 26, 24);
360
SHA1_Update(&ctx, Magic1, sizeof(Magic1));
361
SHA1_Final(sha_md, &ctx);
362
(void) memcpy(MasterKey, sha_md, 16);
364
/* Generate the master send key. */
366
SHA1_Update(&ctx, MasterKey, 16);
367
SHA1_Update(&ctx, SHSpad1, 40);
368
SHA1_Update(&ctx, Magic3, sizeof(Magic3));
369
SHA1_Update(&ctx, SHSpad2, 40);
370
SHA1_Final(sha_md, &ctx);
371
(void) memcpy(MasterSendKey, sha_md, 16);
373
/* Generate the master receive key. */
375
SHA1_Update(&ctx, MasterKey, 16);
376
SHA1_Update(&ctx, SHSpad1, 40);
377
SHA1_Update(&ctx, Magic2, sizeof(Magic3));
378
SHA1_Update(&ctx, SHSpad2, 40);
379
SHA1_Final(sha_md, &ctx);
380
(void) memcpy(MasterReceiveKey, sha_md, 16);
383
* Now, generate the MS-MPPE-Send-Key attribute.
386
/* Setup the salt value. */
390
/* Encode the key. */
391
(void) memset(mppe_key, 0, sizeof(mppe_key));
392
mppe_key[0] = 16; /* length */
393
(void) memcpy(&mppe_key[1], MasterSendKey, 16);
394
secretlen = strlen(request->secret);
395
(void) memcpy(encode_buf, request->secret, secretlen);
396
(void) memcpy(encode_buf + secretlen, request->packet->vector,
398
(void) memcpy(encode_buf + secretlen + 16, salt, 2);
399
(void) MD5(encode_buf, secretlen + AUTH_VECTOR_LEN + 2, md5_md);
400
for (i = 0; i < 16; ++i)
401
mppe_key[i] ^= md5_md[i];
402
(void) memcpy(encode_buf + secretlen, mppe_key, 16);
403
(void) MD5(encode_buf, secretlen + 16, md5_md);
404
for (i = 0; i < 16; ++i)
405
mppe_key[i + 16] ^= md5_md[i];
407
/* Whew. Now stringify it for pairmake(). */
408
mppe_key_string[0] = '0';
409
mppe_key_string[1] = 'x';
410
(void) sprintf(&mppe_key_string[2], "%02X", salt[0]);
411
(void) sprintf(&mppe_key_string[4], "%02X", salt[1]);
412
for (i = 0; i < sizeof(mppe_key); ++i)
413
(void) sprintf(&mppe_key_string[i*2+6], "%02X", mppe_key[i]);
415
mppe_key_string[0] = '0';
416
mppe_key_string[1] = 'x';
417
for (i = 0; i < sizeof(MasterSendKey); ++i)
418
(void) sprintf(&mppe_key_string[i*2+2], "%02X", MasterSendKey[i]);
420
vp = pairmake("MS-MPPE-Send-Key", mppe_key_string, T_OP_EQ);
421
rad_assert(vp != NULL);
425
* Generate the MS-MPPE-Recv-Key attribute.
428
/* Setup the salt value. */
432
/* Encode the key. */
433
(void) memset(mppe_key, 0, sizeof(mppe_key));
434
mppe_key[0] = 16; /* length */
435
(void) memcpy(&mppe_key[1], MasterReceiveKey, 16);
436
secretlen = strlen(request->secret);
437
(void) memcpy(encode_buf, request->secret, secretlen);
438
(void) memcpy(encode_buf + secretlen, request->packet->vector,
440
(void) memcpy(encode_buf + secretlen + 16, salt, 2);
441
(void) MD5(encode_buf, secretlen + AUTH_VECTOR_LEN + 2, md5_md);
442
for (i = 0; i < 16; ++i)
443
mppe_key[i] ^= md5_md[i];
444
(void) memcpy(encode_buf + secretlen, mppe_key, 16);
445
(void) MD5(encode_buf, secretlen + 16, md5_md);
446
for (i = 0; i < 16; ++i)
447
mppe_key[i + 16] ^= md5_md[i];
449
/* Whew. Now stringify it for pairmake(). */
450
mppe_key_string[0] = '0';
451
mppe_key_string[1] = 'x';
452
(void) sprintf(&mppe_key_string[2], "%02X", salt[0]);
453
(void) sprintf(&mppe_key_string[4], "%02X", salt[1]);
454
for (i = 0; i < sizeof(mppe_key); ++i)
455
(void) sprintf(&mppe_key_string[i*2+6], "%02X", mppe_key[i]);
457
mppe_key_string[0] = '0';
458
mppe_key_string[1] = 'x';
459
for (i = 0; i < sizeof(MasterReceiveKey); ++i)
460
(void) sprintf(&mppe_key_string[i*2+2], "%02X", MasterReceiveKey[i]);
462
vp = pairmake("MS-MPPE-Recv-Key", mppe_key_string, T_OP_EQ);
463
rad_assert(vp != NULL);
468
break; /* PWE_MSCHAP2 */