~ubuntu-branches/ubuntu/hardy/freeradius/hardy-proposed

« back to all changes in this revision

Viewing changes to src/modules/rlm_otp/otp_mppe.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2006-12-16 20:45:11 UTC
  • mfrom: (3.1.10 feisty)
  • Revision ID: james.westby@ubuntu.com-20061216204511-3pbbsu4s8jtehsor
Tags: 1.1.3-3
Fix POSIX compliance problem in init script.  Closes: #403384. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: otp_mppe.c,v 1.1.2.2 2006/06/01 19:02:20 fcusack Exp $
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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
 
17
 *
 
18
 * Copyright 2001,2002  Google, Inc.
 
19
 * Copyright 2005,2006 TRI-D Systems, Inc.
 
20
 */
 
21
 
 
22
static const char rcsid[] = "$Id: otp_mppe.c,v 1.1.2.2 2006/06/01 19:02:20 fcusack Exp $";
 
23
 
 
24
/* avoid inclusion of these FR headers which conflict w/ OpenSSL */
 
25
#define _LRAD_MD4_H
 
26
#define _LRAD_SHA1_H
 
27
 
 
28
#include <rad_assert.h>
 
29
 
 
30
#include "extern.h"
 
31
#include "otp.h"
 
32
#include "otp_mppe.h"
 
33
 
 
34
#include <openssl/des.h>
 
35
#include <openssl/md4.h>
 
36
#include <openssl/md5.h>
 
37
#include <openssl/sha.h>
 
38
 
 
39
#include <string.h>
 
40
 
 
41
/*
 
42
 * Add MPPE attributes to a request, if required.
 
43
 */
 
44
void
 
45
otp_mppe(REQUEST *request, otp_pwe_t pwe, const otp_option_t *opt,
 
46
         const char *passcode)
 
47
{
 
48
  VALUE_PAIR **avp = &request->reply->vps;
 
49
  VALUE_PAIR *cvp, *rvp, *vp;
 
50
 
 
51
  cvp = pairfind(request->packet->vps, pwattr[pwe - 1]);
 
52
  rvp = pairfind(request->packet->vps, pwattr[pwe]);
 
53
 
 
54
  switch (pwe) {
 
55
  case PWE_PAP:
 
56
  case PWE_CHAP:
 
57
    return;
 
58
 
 
59
  case PWE_MSCHAP:
 
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);
 
64
    pairadd(avp, vp);
 
65
    vp = pairmake("MS-MPPE-Encryption-Types",
 
66
                  otp_mppe_types[opt->mschap_mppe_types], T_OP_EQ);
 
67
    rad_assert(vp != NULL);
 
68
    pairadd(avp, vp);
 
69
 
 
70
    /* If no MPPE, we're done. */
 
71
    if (!opt->mschap_mppe_policy)
 
72
      return;
 
73
 
 
74
    /*
 
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.
 
83
     */
 
84
    {
 
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];
 
91
 
 
92
      /* Zero the LM-Key sub-field (and padding). */
 
93
      (void) memset(mppe_keys, 0, sizeof(mppe_keys));
 
94
 
 
95
      /*
 
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).
 
101
       */
 
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;
 
107
      }
 
108
      /* first md4 */
 
109
      (void) MD4(password_unicode, 2 * passcode_len, password_md);
 
110
      /* second md4 */
 
111
      (void) MD4(password_md, MD4_DIGEST_LENGTH, &mppe_keys[8]);
 
112
 
 
113
#if 0 /* encoding now handled in lib/radius.c:rad_pwencode() */
 
114
      {
 
115
        unsigned char md5_md[MD5_DIGEST_LENGTH];
 
116
        unsigned char encode_buf[AUTH_VECTOR_LEN + MAX_STRING_LEN];
 
117
        int secretlen;
 
118
 
 
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,
 
123
                      AUTH_VECTOR_LEN);
 
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];
 
131
      }
 
132
#endif /* 0 */
 
133
 
 
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);
 
141
      pairadd(avp, vp);
 
142
    } /* (doing mppe) */
 
143
  break; /* PWE_MSCHAP */
 
144
 
 
145
  case PWE_MSCHAP2:
 
146
  {
 
147
    size_t i;
 
148
    unsigned char password_md_md[MD4_DIGEST_LENGTH];
 
149
 
 
150
    /*
 
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.
 
158
     * See RFC 2759.
 
159
     */
 
160
    {
 
161
      size_t passcode_len;
 
162
      unsigned char password_unicode[2 * OTP_MAX_PASSCODE_LEN];
 
163
      unsigned char password_md[MD4_DIGEST_LENGTH];
 
164
 
 
165
      SHA_CTX ctx;
 
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];
 
171
      /*
 
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".
 
176
       */
 
177
      /*                    0x  (ID) ( ASCII("S="ASCII(auth_md))) */
 
178
      char auth_octet_string[2 + 2 + (2 * sizeof(auth_md_string))];
 
179
 
 
180
      char *username = request->username->strvalue;
 
181
      int username_len = request->username->length;
 
182
 
 
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,
 
195
          0x6E };
 
196
 
 
197
      /*
 
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).
 
202
       */
 
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;
 
208
      }
 
209
      /* first md4 */
 
210
      (void) MD4(password_unicode, 2 * passcode_len, password_md);
 
211
      /* second md4 */
 
212
      (void) MD4(password_md, MD4_DIGEST_LENGTH, password_md_md);
 
213
 
 
214
      /* MD1 */
 
215
      SHA1_Init(&ctx);
 
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);
 
220
 
 
221
      /* MD2 */
 
222
      SHA1_Init(&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);
 
227
 
 
228
      /* The Authenticator */
 
229
      SHA1_Init(&ctx);
 
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);
 
234
 
 
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]);
 
240
 
 
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]);
 
247
 
 
248
      vp = pairmake("MS-CHAP2-Success", auth_octet_string, T_OP_EQ);
 
249
      rad_assert(vp != NULL);
 
250
      pairadd(avp, vp);
 
251
    } /* Generate mutual auth info. */
 
252
 
 
253
    /*
 
254
     * Now, set some MPPE related attributes.
 
255
     */
 
256
    vp = pairmake("MS-MPPE-Encryption-Policy",
 
257
                  otp_mppe_policy[opt->mschapv2_mppe_policy], T_OP_EQ);
 
258
    rad_assert(vp != NULL);
 
259
    pairadd(avp, vp);
 
260
    vp = pairmake("MS-MPPE-Encryption-Types",
 
261
                  otp_mppe_types[opt->mschapv2_mppe_types], T_OP_EQ);
 
262
    rad_assert(vp != NULL);
 
263
    pairadd(avp, vp);
 
264
 
 
265
    /* If no MPPE, we're done. */
 
266
    if (!opt->mschapv2_mppe_policy)
 
267
      return;
 
268
 
 
269
    /*
 
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.
 
289
     */
 
290
    {
 
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];
 
334
 
 
335
      SHA_CTX ctx;
 
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];
 
339
 
 
340
      /*   From RFC 2548:           S                 R           A */
 
341
      unsigned char encode_buf[MAX_STRING_LEN + AUTH_VECTOR_LEN + 2];
 
342
      int secretlen;
 
343
 
 
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];
 
351
#else /* 0 */
 
352
      /*                           0x   (   ASCII(mppe_key)   )  \0 */
 
353
      unsigned char mppe_key_string[2 + (2 * sizeof(MasterKey)) + 1];
 
354
#endif /* else !0 */
 
355
 
 
356
      /* Generate the master session key. */
 
357
      SHA1_Init(&ctx);
 
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);
 
363
 
 
364
      /* Generate the master send key. */
 
365
      SHA1_Init(&ctx);
 
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);
 
372
 
 
373
      /* Generate the master receive key. */
 
374
      SHA1_Init(&ctx);
 
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);
 
381
 
 
382
      /*
 
383
       * Now, generate the MS-MPPE-Send-Key attribute.
 
384
       */
 
385
#if 0
 
386
      /* Setup the salt value. */
 
387
      salt[0] = 0x80;
 
388
      salt[1] = 0x01;
 
389
 
 
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,
 
397
                    AUTH_VECTOR_LEN);
 
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];
 
406
 
 
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]);
 
414
#else /* 0 */
 
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]);
 
419
#endif /* else !0 */
 
420
      vp = pairmake("MS-MPPE-Send-Key", mppe_key_string, T_OP_EQ);
 
421
      rad_assert(vp != NULL);
 
422
      pairadd(avp, vp);
 
423
 
 
424
      /*
 
425
       * Generate the MS-MPPE-Recv-Key attribute.
 
426
       */
 
427
#if 0
 
428
      /* Setup the salt value. */
 
429
      salt[0] = 0x80;
 
430
      salt[1] = 0x02;
 
431
 
 
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,
 
439
                    AUTH_VECTOR_LEN);
 
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];
 
448
 
 
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]);
 
456
#else /* 0 */
 
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]);
 
461
#endif /* else !0 */
 
462
      vp = pairmake("MS-MPPE-Recv-Key", mppe_key_string, T_OP_EQ);
 
463
      rad_assert(vp != NULL);
 
464
      pairadd(avp, vp);
 
465
 
 
466
    } /* (doing mppe) */
 
467
  } /* PWE_MSCHAP2 */
 
468
  break; /* PWE_MSCHAP2 */
 
469
 
 
470
  } /* switch (pwe) */
 
471
 
 
472
  return;
 
473
}