~ubuntu-branches/ubuntu/saucy/wpasupplicant/saucy

« back to all changes in this revision

Viewing changes to src/eap_server/eap_server_mschapv2.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2010-11-22 09:43:43 UTC
  • mfrom: (1.1.16 upstream)
  • Revision ID: james.westby@ubuntu.com-20101122094343-qgsxaojvmswfri77
Tags: 0.7.3-0ubuntu1
* Get wpasupplicant 0.7.3 from Debian's SVN. Leaving 0.7.3-1 as unreleased
  for now.
* Build-Depend on debhelper 8, since the packaging from Debian uses compat 8.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server
 
3
 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
 
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 version 2 as
 
7
 * published by the Free Software Foundation.
 
8
 *
 
9
 * Alternatively, this software may be distributed under the terms of BSD
 
10
 * license.
 
11
 *
 
12
 * See README and COPYING for more details.
 
13
 */
 
14
 
 
15
#include "includes.h"
 
16
 
 
17
#include "common.h"
 
18
#include "crypto/ms_funcs.h"
 
19
#include "eap_i.h"
 
20
 
 
21
 
 
22
struct eap_mschapv2_hdr {
 
23
        u8 op_code; /* MSCHAPV2_OP_* */
 
24
        u8 mschapv2_id; /* must be changed for challenges, but not for
 
25
                         * success/failure */
 
26
        u8 ms_length[2]; /* Note: misaligned; length - 5 */
 
27
        /* followed by data */
 
28
} STRUCT_PACKED;
 
29
 
 
30
#define MSCHAPV2_OP_CHALLENGE 1
 
31
#define MSCHAPV2_OP_RESPONSE 2
 
32
#define MSCHAPV2_OP_SUCCESS 3
 
33
#define MSCHAPV2_OP_FAILURE 4
 
34
#define MSCHAPV2_OP_CHANGE_PASSWORD 7
 
35
 
 
36
#define MSCHAPV2_RESP_LEN 49
 
37
 
 
38
#define ERROR_RESTRICTED_LOGON_HOURS 646
 
39
#define ERROR_ACCT_DISABLED 647
 
40
#define ERROR_PASSWD_EXPIRED 648
 
41
#define ERROR_NO_DIALIN_PERMISSION 649
 
42
#define ERROR_AUTHENTICATION_FAILURE 691
 
43
#define ERROR_CHANGING_PASSWORD 709
 
44
 
 
45
#define PASSWD_CHANGE_CHAL_LEN 16
 
46
#define MSCHAPV2_KEY_LEN 16
 
47
 
 
48
 
 
49
#define CHALLENGE_LEN 16
 
50
 
 
51
struct eap_mschapv2_data {
 
52
        u8 auth_challenge[CHALLENGE_LEN];
 
53
        int auth_challenge_from_tls;
 
54
        u8 *peer_challenge;
 
55
        u8 auth_response[20];
 
56
        enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state;
 
57
        u8 resp_mschapv2_id;
 
58
        u8 master_key[16];
 
59
        int master_key_valid;
 
60
};
 
61
 
 
62
 
 
63
static void * eap_mschapv2_init(struct eap_sm *sm)
 
64
{
 
65
        struct eap_mschapv2_data *data;
 
66
 
 
67
        data = os_zalloc(sizeof(*data));
 
68
        if (data == NULL)
 
69
                return NULL;
 
70
        data->state = CHALLENGE;
 
71
 
 
72
        if (sm->auth_challenge) {
 
73
                os_memcpy(data->auth_challenge, sm->auth_challenge,
 
74
                          CHALLENGE_LEN);
 
75
                data->auth_challenge_from_tls = 1;
 
76
        }
 
77
 
 
78
        if (sm->peer_challenge) {
 
79
                data->peer_challenge = os_malloc(CHALLENGE_LEN);
 
80
                if (data->peer_challenge == NULL) {
 
81
                        os_free(data);
 
82
                        return NULL;
 
83
                }
 
84
                os_memcpy(data->peer_challenge, sm->peer_challenge,
 
85
                          CHALLENGE_LEN);
 
86
        }
 
87
 
 
88
        return data;
 
89
}
 
90
 
 
91
 
 
92
static void eap_mschapv2_reset(struct eap_sm *sm, void *priv)
 
93
{
 
94
        struct eap_mschapv2_data *data = priv;
 
95
        if (data == NULL)
 
96
                return;
 
97
 
 
98
        os_free(data->peer_challenge);
 
99
        os_free(data);
 
100
}
 
101
 
 
102
 
 
103
static struct wpabuf * eap_mschapv2_build_challenge(
 
104
        struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
 
105
{
 
106
        struct wpabuf *req;
 
107
        struct eap_mschapv2_hdr *ms;
 
108
        char *name = "hostapd"; /* TODO: make this configurable */
 
109
        size_t ms_len;
 
110
 
 
111
        if (!data->auth_challenge_from_tls &&
 
112
            os_get_random(data->auth_challenge, CHALLENGE_LEN)) {
 
113
                wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
 
114
                           "data");
 
115
                data->state = FAILURE;
 
116
                return NULL;
 
117
        }
 
118
 
 
119
        ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + os_strlen(name);
 
120
        req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
 
121
                            EAP_CODE_REQUEST, id);
 
122
        if (req == NULL) {
 
123
                wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
 
124
                           " for request");
 
125
                data->state = FAILURE;
 
126
                return NULL;
 
127
        }
 
128
 
 
129
        ms = wpabuf_put(req, sizeof(*ms));
 
130
        ms->op_code = MSCHAPV2_OP_CHALLENGE;
 
131
        ms->mschapv2_id = id;
 
132
        WPA_PUT_BE16(ms->ms_length, ms_len);
 
133
 
 
134
        wpabuf_put_u8(req, CHALLENGE_LEN);
 
135
        if (!data->auth_challenge_from_tls)
 
136
                wpabuf_put_data(req, data->auth_challenge, CHALLENGE_LEN);
 
137
        else
 
138
                wpabuf_put(req, CHALLENGE_LEN);
 
139
        wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge",
 
140
                    data->auth_challenge, CHALLENGE_LEN);
 
141
        wpabuf_put_data(req, name, os_strlen(name));
 
142
 
 
143
        return req;
 
144
}
 
145
 
 
146
 
 
147
static struct wpabuf * eap_mschapv2_build_success_req(
 
148
        struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
 
149
{
 
150
        struct wpabuf *req;
 
151
        struct eap_mschapv2_hdr *ms;
 
152
        u8 *msg;
 
153
        char *message = "OK";
 
154
        size_t ms_len;
 
155
 
 
156
        ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 +
 
157
                os_strlen(message);
 
158
        req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
 
159
                            EAP_CODE_REQUEST, id);
 
160
        if (req == NULL) {
 
161
                wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
 
162
                           " for request");
 
163
                data->state = FAILURE;
 
164
                return NULL;
 
165
        }
 
166
 
 
167
        ms = wpabuf_put(req, sizeof(*ms));
 
168
        ms->op_code = MSCHAPV2_OP_SUCCESS;
 
169
        ms->mschapv2_id = data->resp_mschapv2_id;
 
170
        WPA_PUT_BE16(ms->ms_length, ms_len);
 
171
        msg = (u8 *) (ms + 1);
 
172
 
 
173
        wpabuf_put_u8(req, 'S');
 
174
        wpabuf_put_u8(req, '=');
 
175
        wpa_snprintf_hex_uppercase(
 
176
                wpabuf_put(req, sizeof(data->auth_response) * 2),
 
177
                sizeof(data->auth_response) * 2 + 1,
 
178
                data->auth_response, sizeof(data->auth_response));
 
179
        wpabuf_put_u8(req, ' ');
 
180
        wpabuf_put_u8(req, 'M');
 
181
        wpabuf_put_u8(req, '=');
 
182
        wpabuf_put_data(req, message, os_strlen(message));
 
183
 
 
184
        wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message",
 
185
                          msg, ms_len - sizeof(*ms));
 
186
 
 
187
        return req;
 
188
}
 
189
 
 
190
 
 
191
static struct wpabuf * eap_mschapv2_build_failure_req(
 
192
        struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id)
 
193
{
 
194
        struct wpabuf *req;
 
195
        struct eap_mschapv2_hdr *ms;
 
196
        char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 "
 
197
                "M=FAILED";
 
198
        size_t ms_len;
 
199
 
 
200
        ms_len = sizeof(*ms) + os_strlen(message);
 
201
        req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
 
202
                            EAP_CODE_REQUEST, id);
 
203
        if (req == NULL) {
 
204
                wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
 
205
                           " for request");
 
206
                data->state = FAILURE;
 
207
                return NULL;
 
208
        }
 
209
 
 
210
        ms = wpabuf_put(req, sizeof(*ms));
 
211
        ms->op_code = MSCHAPV2_OP_FAILURE;
 
212
        ms->mschapv2_id = data->resp_mschapv2_id;
 
213
        WPA_PUT_BE16(ms->ms_length, ms_len);
 
214
 
 
215
        wpabuf_put_data(req, message, os_strlen(message));
 
216
 
 
217
        wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message",
 
218
                          (u8 *) message, os_strlen(message));
 
219
 
 
220
        return req;
 
221
}
 
222
 
 
223
 
 
224
static struct wpabuf * eap_mschapv2_buildReq(struct eap_sm *sm, void *priv,
 
225
                                             u8 id)
 
226
{
 
227
        struct eap_mschapv2_data *data = priv;
 
228
 
 
229
        switch (data->state) {
 
230
        case CHALLENGE:
 
231
                return eap_mschapv2_build_challenge(sm, data, id);
 
232
        case SUCCESS_REQ:
 
233
                return eap_mschapv2_build_success_req(sm, data, id);
 
234
        case FAILURE_REQ:
 
235
                return eap_mschapv2_build_failure_req(sm, data, id);
 
236
        default:
 
237
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
 
238
                           "buildReq", data->state);
 
239
                break;
 
240
        }
 
241
        return NULL;
 
242
}
 
243
 
 
244
 
 
245
static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
 
246
                                  struct wpabuf *respData)
 
247
{
 
248
        struct eap_mschapv2_data *data = priv;
 
249
        struct eap_mschapv2_hdr *resp;
 
250
        const u8 *pos;
 
251
        size_t len;
 
252
 
 
253
        pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
 
254
                               &len);
 
255
        if (pos == NULL || len < 1) {
 
256
                wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
 
257
                return TRUE;
 
258
        }
 
259
 
 
260
        resp = (struct eap_mschapv2_hdr *) pos;
 
261
        if (data->state == CHALLENGE &&
 
262
            resp->op_code != MSCHAPV2_OP_RESPONSE) {
 
263
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - "
 
264
                           "ignore op %d", resp->op_code);
 
265
                return TRUE;
 
266
        }
 
267
 
 
268
        if (data->state == SUCCESS_REQ &&
 
269
            resp->op_code != MSCHAPV2_OP_SUCCESS &&
 
270
            resp->op_code != MSCHAPV2_OP_FAILURE) {
 
271
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or "
 
272
                           "Failure - ignore op %d", resp->op_code);
 
273
                return TRUE;
 
274
        }
 
275
 
 
276
        if (data->state == FAILURE_REQ &&
 
277
            resp->op_code != MSCHAPV2_OP_FAILURE) {
 
278
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure "
 
279
                           "- ignore op %d", resp->op_code);
 
280
                return TRUE;
 
281
        }
 
282
 
 
283
        return FALSE;
 
284
}
 
285
 
 
286
 
 
287
static void eap_mschapv2_process_response(struct eap_sm *sm,
 
288
                                          struct eap_mschapv2_data *data,
 
289
                                          struct wpabuf *respData)
 
290
{
 
291
        struct eap_mschapv2_hdr *resp;
 
292
        const u8 *pos, *end, *peer_challenge, *nt_response, *name;
 
293
        u8 flags;
 
294
        size_t len, name_len, i;
 
295
        u8 expected[24];
 
296
        const u8 *username, *user;
 
297
        size_t username_len, user_len;
 
298
        int res;
 
299
 
 
300
        pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
 
301
                               &len);
 
302
        if (pos == NULL || len < 1)
 
303
                return; /* Should not happen - frame already validated */
 
304
 
 
305
        end = pos + len;
 
306
        resp = (struct eap_mschapv2_hdr *) pos;
 
307
        pos = (u8 *) (resp + 1);
 
308
 
 
309
        if (len < sizeof(*resp) + 1 + 49 ||
 
310
            resp->op_code != MSCHAPV2_OP_RESPONSE ||
 
311
            pos[0] != 49) {
 
312
                wpa_hexdump_buf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response",
 
313
                                respData);
 
314
                data->state = FAILURE;
 
315
                return;
 
316
        }
 
317
        data->resp_mschapv2_id = resp->mschapv2_id;
 
318
        pos++;
 
319
        peer_challenge = pos;
 
320
        pos += 16 + 8;
 
321
        nt_response = pos;
 
322
        pos += 24;
 
323
        flags = *pos++;
 
324
        name = pos;
 
325
        name_len = end - name;
 
326
 
 
327
        if (data->peer_challenge) {
 
328
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured "
 
329
                           "Peer-Challenge");
 
330
                peer_challenge = data->peer_challenge;
 
331
        }
 
332
        wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge",
 
333
                    peer_challenge, 16);
 
334
        wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24);
 
335
        wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags);
 
336
        wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len);
 
337
 
 
338
        /* MSCHAPv2 does not include optional domain name in the
 
339
         * challenge-response calculation, so remove domain prefix
 
340
         * (if present). */
 
341
        username = sm->identity;
 
342
        username_len = sm->identity_len;
 
343
        for (i = 0; i < username_len; i++) {
 
344
                if (username[i] == '\\') {
 
345
                        username_len -= i + 1;
 
346
                        username += i + 1;
 
347
                        break;
 
348
                }
 
349
        }
 
350
 
 
351
        user = name;
 
352
        user_len = name_len;
 
353
        for (i = 0; i < user_len; i++) {
 
354
                if (user[i] == '\\') {
 
355
                        user_len -= i + 1;
 
356
                        user += i + 1;
 
357
                        break;
 
358
                }
 
359
        }
 
360
 
 
361
        if (username_len != user_len ||
 
362
            os_memcmp(username, user, username_len) != 0) {
 
363
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names");
 
364
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user "
 
365
                                  "name", username, username_len);
 
366
                wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user "
 
367
                                  "name", user, user_len);
 
368
                data->state = FAILURE;
 
369
                return;
 
370
        }
 
371
 
 
372
        wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name",
 
373
                          username, username_len);
 
374
 
 
375
        if (sm->user->password_hash) {
 
376
                res = generate_nt_response_pwhash(data->auth_challenge,
 
377
                                                  peer_challenge,
 
378
                                                  username, username_len,
 
379
                                                  sm->user->password,
 
380
                                                  expected);
 
381
        } else {
 
382
                res = generate_nt_response(data->auth_challenge,
 
383
                                           peer_challenge,
 
384
                                           username, username_len,
 
385
                                           sm->user->password,
 
386
                                           sm->user->password_len,
 
387
                                           expected);
 
388
        }
 
389
        if (res) {
 
390
                data->state = FAILURE;
 
391
                return;
 
392
        }
 
393
 
 
394
        if (os_memcmp(nt_response, expected, 24) == 0) {
 
395
                const u8 *pw_hash;
 
396
                u8 pw_hash_buf[16], pw_hash_hash[16];
 
397
 
 
398
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response");
 
399
                data->state = SUCCESS_REQ;
 
400
 
 
401
                /* Authenticator response is not really needed yet, but
 
402
                 * calculate it here so that peer_challenge and username need
 
403
                 * not be saved. */
 
404
                if (sm->user->password_hash) {
 
405
                        pw_hash = sm->user->password;
 
406
                } else {
 
407
                        nt_password_hash(sm->user->password,
 
408
                                         sm->user->password_len,
 
409
                                         pw_hash_buf);
 
410
                        pw_hash = pw_hash_buf;
 
411
                }
 
412
                generate_authenticator_response_pwhash(
 
413
                        pw_hash, peer_challenge, data->auth_challenge,
 
414
                        username, username_len, nt_response,
 
415
                        data->auth_response);
 
416
 
 
417
                hash_nt_password_hash(pw_hash, pw_hash_hash);
 
418
                get_master_key(pw_hash_hash, nt_response, data->master_key);
 
419
                data->master_key_valid = 1;
 
420
                wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
 
421
                                data->master_key, MSCHAPV2_KEY_LEN);
 
422
        } else {
 
423
                wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response",
 
424
                            expected, 24);
 
425
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid NT-Response");
 
426
                data->state = FAILURE_REQ;
 
427
        }
 
428
}
 
429
 
 
430
 
 
431
static void eap_mschapv2_process_success_resp(struct eap_sm *sm,
 
432
                                              struct eap_mschapv2_data *data,
 
433
                                              struct wpabuf *respData)
 
434
{
 
435
        struct eap_mschapv2_hdr *resp;
 
436
        const u8 *pos;
 
437
        size_t len;
 
438
 
 
439
        pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
 
440
                               &len);
 
441
        if (pos == NULL || len < 1)
 
442
                return; /* Should not happen - frame already validated */
 
443
 
 
444
        resp = (struct eap_mschapv2_hdr *) pos;
 
445
 
 
446
        if (resp->op_code == MSCHAPV2_OP_SUCCESS) {
 
447
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response"
 
448
                           " - authentication completed successfully");
 
449
                data->state = SUCCESS;
 
450
        } else {
 
451
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Success "
 
452
                           "Response - peer rejected authentication");
 
453
                data->state = FAILURE;
 
454
        }
 
455
}
 
456
 
 
457
 
 
458
static void eap_mschapv2_process_failure_resp(struct eap_sm *sm,
 
459
                                              struct eap_mschapv2_data *data,
 
460
                                              struct wpabuf *respData)
 
461
{
 
462
        struct eap_mschapv2_hdr *resp;
 
463
        const u8 *pos;
 
464
        size_t len;
 
465
 
 
466
        pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData,
 
467
                               &len);
 
468
        if (pos == NULL || len < 1)
 
469
                return; /* Should not happen - frame already validated */
 
470
 
 
471
        resp = (struct eap_mschapv2_hdr *) pos;
 
472
 
 
473
        if (resp->op_code == MSCHAPV2_OP_FAILURE) {
 
474
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response"
 
475
                           " - authentication failed");
 
476
        } else {
 
477
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Failure "
 
478
                           "Response - authentication failed");
 
479
        }
 
480
 
 
481
        data->state = FAILURE;
 
482
}
 
483
 
 
484
 
 
485
static void eap_mschapv2_process(struct eap_sm *sm, void *priv,
 
486
                                 struct wpabuf *respData)
 
487
{
 
488
        struct eap_mschapv2_data *data = priv;
 
489
 
 
490
        if (sm->user == NULL || sm->user->password == NULL) {
 
491
                wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
 
492
                data->state = FAILURE;
 
493
                return;
 
494
        }
 
495
 
 
496
        switch (data->state) {
 
497
        case CHALLENGE:
 
498
                eap_mschapv2_process_response(sm, data, respData);
 
499
                break;
 
500
        case SUCCESS_REQ:
 
501
                eap_mschapv2_process_success_resp(sm, data, respData);
 
502
                break;
 
503
        case FAILURE_REQ:
 
504
                eap_mschapv2_process_failure_resp(sm, data, respData);
 
505
                break;
 
506
        default:
 
507
                wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in "
 
508
                           "process", data->state);
 
509
                break;
 
510
        }
 
511
}
 
512
 
 
513
 
 
514
static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
 
515
{
 
516
        struct eap_mschapv2_data *data = priv;
 
517
        return data->state == SUCCESS || data->state == FAILURE;
 
518
}
 
519
 
 
520
 
 
521
static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
 
522
{
 
523
        struct eap_mschapv2_data *data = priv;
 
524
        u8 *key;
 
525
 
 
526
        if (data->state != SUCCESS || !data->master_key_valid)
 
527
                return NULL;
 
528
 
 
529
        *len = 2 * MSCHAPV2_KEY_LEN;
 
530
        key = os_malloc(*len);
 
531
        if (key == NULL)
 
532
                return NULL;
 
533
        /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */
 
534
        get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1);
 
535
        get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
 
536
                                MSCHAPV2_KEY_LEN, 1, 1);
 
537
        wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
 
538
 
 
539
        return key;
 
540
}
 
541
 
 
542
 
 
543
static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
 
544
{
 
545
        struct eap_mschapv2_data *data = priv;
 
546
        return data->state == SUCCESS;
 
547
}
 
548
 
 
549
 
 
550
int eap_server_mschapv2_register(void)
 
551
{
 
552
        struct eap_method *eap;
 
553
        int ret;
 
554
 
 
555
        eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
 
556
                                      EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
 
557
                                      "MSCHAPV2");
 
558
        if (eap == NULL)
 
559
                return -1;
 
560
 
 
561
        eap->init = eap_mschapv2_init;
 
562
        eap->reset = eap_mschapv2_reset;
 
563
        eap->buildReq = eap_mschapv2_buildReq;
 
564
        eap->check = eap_mschapv2_check;
 
565
        eap->process = eap_mschapv2_process;
 
566
        eap->isDone = eap_mschapv2_isDone;
 
567
        eap->getKey = eap_mschapv2_getKey;
 
568
        eap->isSuccess = eap_mschapv2_isSuccess;
 
569
 
 
570
        ret = eap_server_method_register(eap);
 
571
        if (ret)
 
572
                eap_server_method_free(eap);
 
573
        return ret;
 
574
}