eap-mschapv2: Report username if different from EAP-Identity (or IKE identity)
[strongswan.git] / src / libcharon / plugins / eap_mschapv2 / eap_mschapv2.c
1 /*
2 * Copyright (C) 2009 Tobias Brunner
3 * Copyright (C) 2010 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "eap_mschapv2.h"
18
19 #include <ctype.h>
20 #include <unistd.h>
21
22 #include <daemon.h>
23 #include <library.h>
24 #include <collections/enumerator.h>
25 #include <crypto/crypters/crypter.h>
26 #include <crypto/hashers/hasher.h>
27
28 typedef struct private_eap_mschapv2_t private_eap_mschapv2_t;
29
30 /**
31 * Private data of an eap_mschapv2_t object.
32 */
33 struct private_eap_mschapv2_t
34 {
35 /**
36 * Public authenticator_t interface.
37 */
38 eap_mschapv2_t public;
39
40 /**
41 * ID of the server
42 */
43 identification_t *server;
44
45 /**
46 * ID of the peer
47 */
48 identification_t *peer;
49
50 /**
51 * challenge sent by the server
52 */
53 chunk_t challenge;
54
55 /**
56 * generated NT-Response
57 */
58 chunk_t nt_response;
59
60 /**
61 * generated Authenticator Response
62 */
63 chunk_t auth_response;
64
65 /**
66 * generated MSK
67 */
68 chunk_t msk;
69
70 /**
71 * EAP message identifier
72 */
73 u_int8_t identifier;
74
75 /**
76 * MS-CHAPv2-ID (session ID, increases with each retry)
77 */
78 u_int8_t mschapv2id;
79
80 /**
81 * Number of retries
82 */
83 int retries;
84
85 /**
86 * Provide EAP-Identity
87 */
88 auth_cfg_t *auth;
89 };
90
91 /**
92 * OpCodes
93 */
94 enum mschapv2_opcode_t
95 {
96 MSCHAPV2_CHALLENGE = 1,
97 MSCHAPV2_RESPONSE = 2,
98 MSCHAPV2_SUCCESS = 3,
99 MSCHAPV2_FAILURE = 4,
100 MSCHAPV2_CHANGE_PASSWORD = 7,
101 };
102
103 /**
104 * Names for OpCodes
105 */
106 ENUM_BEGIN(mschapv2_opcode_names, MSCHAPV2_CHALLENGE, MSCHAPV2_FAILURE,
107 "CHALLENGE",
108 "RESPONSE",
109 "SUCCESS",
110 "FAILURE");
111 ENUM_NEXT(mschapv2_opcode_names, MSCHAPV2_CHANGE_PASSWORD, MSCHAPV2_CHANGE_PASSWORD, MSCHAPV2_FAILURE,
112 "CHANGE_PASSWORD");
113 ENUM_END(mschapv2_opcode_names, MSCHAPV2_CHANGE_PASSWORD);
114
115 /**
116 * Error codes
117 */
118 enum mschapv2_error_t
119 {
120 ERROR_RESTRICTED_LOGON_HOURS = 646,
121 ERROR_ACCT_DISABLED = 647,
122 ERROR_PASSWD_EXPIRED = 648,
123 ERROR_NO_DIALIN_PERMISSION = 649,
124 ERROR_AUTHENTICATION_FAILURE = 691,
125 ERROR_CHANGING_PASSWORD = 709,
126 };
127
128 /**
129 * Names for error codes
130 */
131 ENUM_BEGIN(mschapv2_error_names, ERROR_RESTRICTED_LOGON_HOURS, ERROR_NO_DIALIN_PERMISSION,
132 "ERROR_RESTRICTED_LOGON_HOURS",
133 "ERROR_ACCT_DISABLED",
134 "ERROR_PASSWD_EXPIRED",
135 "ERROR_NO_DIALIN_PERMISSION");
136 ENUM_NEXT(mschapv2_error_names, ERROR_AUTHENTICATION_FAILURE, ERROR_AUTHENTICATION_FAILURE, ERROR_NO_DIALIN_PERMISSION,
137 "ERROR_AUTHENTICATION_FAILURE");
138 ENUM_NEXT(mschapv2_error_names, ERROR_CHANGING_PASSWORD, ERROR_CHANGING_PASSWORD, ERROR_AUTHENTICATION_FAILURE,
139 "ERROR_CHANGING_PASSWORD");
140 ENUM_END(mschapv2_error_names, ERROR_CHANGING_PASSWORD);
141
142 /* Length of the challenge */
143 #define CHALLENGE_LEN 16
144 /* Length of the response (see eap_mschapv2_response_t) */
145 #define RESPONSE_LEN 49
146 /* Length of the authenticator response string ("S=<...>") */
147 #define AUTH_RESPONSE_LEN 42
148 /* Name we send as authenticator */
149 #define MSCHAPV2_HOST_NAME "strongSwan"
150 /* Message sent on success */
151 #define SUCCESS_MESSAGE " M=Welcome2strongSwan"
152 /* Message sent on failure */
153 #define FAILURE_MESSAGE "E=691 R=1 C="
154 /* Length of the complete failure message */
155 #define FAILURE_MESSAGE_LEN (sizeof(FAILURE_MESSAGE) + CHALLENGE_LEN * 2)
156
157 /* Number of seconds to delay retries */
158 #define RETRY_DELAY 2
159 /* Maximum number of retries */
160 #define MAX_RETRIES 2
161
162 typedef struct eap_mschapv2_header_t eap_mschapv2_header_t;
163 typedef struct eap_mschapv2_challenge_t eap_mschapv2_challenge_t;
164 typedef struct eap_mschapv2_response_t eap_mschapv2_response_t;
165
166 /**
167 * packed EAP-MS-CHAPv2 header struct
168 */
169 struct eap_mschapv2_header_t
170 {
171 /** EAP code (REQUEST/RESPONSE) */
172 u_int8_t code;
173 /** unique message identifier */
174 u_int8_t identifier;
175 /** length of whole message */
176 u_int16_t length;
177 /** EAP type */
178 u_int8_t type;
179 /** MS-CHAPv2 OpCode */
180 u_int8_t opcode;
181 /** MS-CHAPv2-ID (equals identifier) */
182 u_int8_t ms_chapv2_id;
183 /** MS-Length (defined as length - 5) */
184 u_int16_t ms_length;
185 /** packet data (determined by OpCode) */
186 u_int8_t data[];
187 }__attribute__((__packed__));
188
189 /**
190 * packed data for a MS-CHAPv2 Challenge packet
191 */
192 struct eap_mschapv2_challenge_t
193 {
194 /** Value-Size */
195 u_int8_t value_size;
196 /** Challenge */
197 u_int8_t challenge[CHALLENGE_LEN];
198 /** Name */
199 u_int8_t name[];
200 }__attribute__((__packed__));
201
202 /**
203 * packed data for a MS-CHAPv2 Response packet
204 */
205 struct eap_mschapv2_response_t
206 {
207 /** Value-Size */
208 u_int8_t value_size;
209 /** Response */
210 struct
211 {
212 /* Peer-Challenge*/
213 u_int8_t peer_challenge[CHALLENGE_LEN];
214 /* Reserved (=zero) */
215 u_int8_t peer_reserved[8];
216 /* NT-Response */
217 u_int8_t nt_response[24];
218 /* Flags (=zero) */
219 u_int8_t flags;
220 } response;
221 /** Name */
222 u_int8_t name[];
223 }__attribute__((__packed__));
224
225 /**
226 * Length of the MS-CHAPv2 header
227 */
228 #define HEADER_LEN (sizeof(eap_mschapv2_header_t))
229
230 /**
231 * Length of the header for MS-CHAPv2 success/failure packets (does not include
232 * MS-CHAPv2-ID and MS-Length, i.e. 3 octets)
233 */
234 #define SHORT_HEADER_LEN (HEADER_LEN - 3)
235
236 /**
237 * The minimum length of an MS-CHAPv2 Challenge packet (the name MUST be
238 * at least one octet)
239 */
240 #define CHALLENGE_PAYLOAD_LEN (HEADER_LEN + sizeof(eap_mschapv2_challenge_t))
241
242 /**
243 * The minimum length of an MS-CHAPv2 Response packet
244 */
245 #define RESPONSE_PAYLOAD_LEN (HEADER_LEN + sizeof(eap_mschapv2_response_t))
246
247
248 /**
249 * Expand a 56-bit key to a 64-bit DES key by adding parity bits (odd parity)
250 */
251 static chunk_t ExpandDESKey(chunk_t key)
252 {
253 static const u_char bitmask[] = { 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 };
254 int i;
255 u_char carry = 0;
256 chunk_t expanded;
257
258 /* expand the 7 octets to 8 octets */
259 expanded = chunk_alloc(8);
260 for (i = 0; i < 7; i++)
261 {
262 expanded.ptr[i] = ((key.ptr[i] & bitmask[i]) >> i) | (carry << (8 - i));
263 carry = key.ptr[i] & ~bitmask[i];
264 }
265 expanded.ptr[7] = carry << 1;
266
267 /* add parity bits to each octet */
268 for (i = 0; i < 8; i++)
269 {
270 u_char val = expanded.ptr[i];
271 val = (val ^ (val >> 4)) & 0x0f;
272 expanded.ptr[i] |= (0x9669 >> val) & 1;
273 }
274 return expanded;
275 }
276
277 /**
278 * Calculate the NT password hash (i.e. hash the (unicode) password with MD4)
279 */
280 static status_t NtPasswordHash(chunk_t password, chunk_t *password_hash)
281 {
282 hasher_t *hasher;
283 hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD4);
284 if (hasher == NULL)
285 {
286 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no MD4 hasher available");
287 return FAILED;
288 }
289 if (!hasher->allocate_hash(hasher, password, password_hash))
290 {
291 hasher->destroy(hasher);
292 return FAILED;
293 }
294 hasher->destroy(hasher);
295 return SUCCESS;
296 }
297
298 /**
299 * Calculate the challenge hash (i.e. hash [peer_challenge | server_challenge |
300 * username (without domain part)] with SHA1)
301 */
302 static status_t ChallengeHash(chunk_t peer_challenge, chunk_t server_challenge,
303 chunk_t username, chunk_t *challenge_hash)
304 {
305 chunk_t concat;
306 hasher_t *hasher;
307 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
308 if (hasher == NULL)
309 {
310 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, SHA1 not supported");
311 return FAILED;
312 }
313 concat = chunk_cata("ccc", peer_challenge, server_challenge, username);
314 if (!hasher->allocate_hash(hasher, concat, challenge_hash))
315 {
316 hasher->destroy(hasher);
317 return FAILED;
318 }
319 hasher->destroy(hasher);
320 /* we need only the first 8 octets */
321 challenge_hash->len = 8;
322 return SUCCESS;
323 }
324
325 /**
326 * Calculate the challenge response (i.e. expand password_hash to three DES keys
327 * and then encrypt the 8-octet challenge_hash with these keys and concatenate
328 * the results).
329 */
330 static status_t ChallengeResponse(chunk_t challenge_hash, chunk_t password_hash,
331 chunk_t *response)
332 {
333 int i;
334 crypter_t *crypter;
335 chunk_t keys[3], z_password_hash;
336 crypter = lib->crypto->create_crypter(lib->crypto, ENCR_DES_ECB, 8);
337 if (crypter == NULL)
338 {
339 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, DES-ECB not supported");
340 return FAILED;
341 }
342 /* prepare keys: first pad password_hash to 21 octets, these get then split
343 * into 7-octet chunks, which then get expanded into 8-octet DES keys */
344 z_password_hash = chunk_alloca(21);
345 memset(z_password_hash.ptr, 0, z_password_hash.len);
346 memcpy(z_password_hash.ptr, password_hash.ptr, password_hash.len);
347 chunk_split(z_password_hash, "mmm", 7, &keys[0], 7, &keys[1], 7, &keys[2]);
348
349 *response = chunk_alloc(24);
350 for (i = 0; i < 3; i++)
351 {
352 chunk_t expanded, encrypted;
353
354 expanded = ExpandDESKey(keys[i]);
355 if (!crypter->set_key(crypter, expanded) ||
356 !crypter->encrypt(crypter, challenge_hash, chunk_empty, &encrypted))
357 {
358 chunk_clear(&expanded);
359 crypter->destroy(crypter);
360 return FAILED;
361 }
362 memcpy(&response->ptr[i * 8], encrypted.ptr, encrypted.len);
363 chunk_clear(&encrypted);
364 chunk_clear(&expanded);
365 }
366 crypter->destroy(crypter);
367 return SUCCESS;
368 }
369
370 /**
371 * Computes the authenticator response
372 */
373 static status_t AuthenticatorResponse(chunk_t password_hash_hash,
374 chunk_t challenge_hash, chunk_t nt_response, chunk_t *response)
375 {
376 chunk_t magic1 = chunk_from_chars(
377 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
378 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
379 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
380 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74);
381 chunk_t magic2 = chunk_from_chars(
382 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
383 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
384 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
385 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
386 0x6E);
387 chunk_t digest = chunk_empty, concat;
388 hasher_t *hasher;
389
390 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
391 if (hasher == NULL)
392 {
393 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, SHA1 not supported");
394 return FAILED;
395 }
396
397 concat = chunk_cata("ccc", password_hash_hash, nt_response, magic1);
398 if (!hasher->allocate_hash(hasher, concat, &digest))
399 {
400 hasher->destroy(hasher);
401 return FAILED;
402 }
403 concat = chunk_cata("ccc", digest, challenge_hash, magic2);
404 if (!hasher->allocate_hash(hasher, concat, response))
405 {
406 hasher->destroy(hasher);
407 return FAILED;
408 }
409 hasher->destroy(hasher);
410 chunk_free(&digest);
411 return SUCCESS;
412 }
413
414 /**
415 * Generate the master session key according to RFC3079
416 */
417 static status_t GenerateMSK(chunk_t password_hash_hash,
418 chunk_t nt_response, chunk_t *msk)
419 {
420 chunk_t magic1 = chunk_from_chars(
421 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
422 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
423 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79);
424 chunk_t magic2 = chunk_from_chars(
425 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
426 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
427 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
428 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
429 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
430 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
431 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
432 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
433 0x6b, 0x65, 0x79, 0x2e);
434 chunk_t magic3 = chunk_from_chars(
435 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
436 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
437 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
438 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
439 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
440 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
441 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
442 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
443 0x6b, 0x65, 0x79, 0x2e);
444 chunk_t shapad1 = chunk_from_chars(
445 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
446 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
447 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
448 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
449 chunk_t shapad2 = chunk_from_chars(
450 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
451 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
452 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
453 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2);
454 chunk_t keypad = chunk_from_chars(
455 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
456 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
457 char master_key[HASH_SIZE_SHA1];
458 char master_receive_key[HASH_SIZE_SHA1], master_send_key[HASH_SIZE_SHA1];
459 chunk_t concat, master;
460 hasher_t *hasher;
461
462 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
463 if (hasher == NULL)
464 {
465 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, SHA1 not supported");
466 return FAILED;
467 }
468
469 concat = chunk_cata("ccc", password_hash_hash, nt_response, magic1);
470 if (!hasher->get_hash(hasher, concat, master_key))
471 {
472 hasher->destroy(hasher);
473 return FAILED;
474 }
475 master = chunk_create(master_key, 16);
476 concat = chunk_cata("cccc", master, shapad1, magic2, shapad2);
477 if (!hasher->get_hash(hasher, concat, master_receive_key))
478 {
479 hasher->destroy(hasher);
480 return FAILED;
481 }
482 concat = chunk_cata("cccc", master, shapad1, magic3, shapad2);
483 if (!hasher->get_hash(hasher, concat, master_send_key))
484 {
485 hasher->destroy(hasher);
486 return FAILED;
487 }
488
489 *msk = chunk_cat("cccc", chunk_create(master_receive_key, 16),
490 chunk_create(master_send_key, 16), keypad, keypad);
491
492 hasher->destroy(hasher);
493 return SUCCESS;
494 }
495
496 static status_t GenerateStuff(private_eap_mschapv2_t *this,
497 chunk_t server_challenge, chunk_t peer_challenge,
498 chunk_t username, chunk_t nt_hash)
499 {
500 status_t status = FAILED;
501 chunk_t nt_hash_hash = chunk_empty, challenge_hash = chunk_empty;
502
503 if (NtPasswordHash(nt_hash, &nt_hash_hash) != SUCCESS)
504 {
505 goto error;
506 }
507 if (ChallengeHash(peer_challenge, server_challenge, username,
508 &challenge_hash) != SUCCESS)
509 {
510 goto error;
511 }
512 if (ChallengeResponse(challenge_hash, nt_hash,
513 &this->nt_response) != SUCCESS)
514 {
515 goto error;
516 }
517 if (AuthenticatorResponse(nt_hash_hash, challenge_hash,
518 this->nt_response, &this->auth_response) != SUCCESS)
519 {
520 goto error;
521 }
522 if (GenerateMSK(nt_hash_hash, this->nt_response, &this->msk) != SUCCESS)
523 {
524 goto error;
525 }
526
527 status = SUCCESS;
528
529 error:
530 chunk_free(&nt_hash_hash);
531 chunk_free(&challenge_hash);
532 return status;
533 }
534
535 /**
536 * Converts an ASCII string into a UTF-16 (little-endian) string
537 */
538 static chunk_t ascii_to_unicode(chunk_t ascii)
539 {
540 int i;
541 chunk_t unicode = chunk_alloc(ascii.len * 2);
542 for (i = 0; i < ascii.len; i++)
543 {
544 unicode.ptr[i * 2] = ascii.ptr[i];
545 unicode.ptr[i * 2 + 1] = 0;
546 }
547 return unicode;
548 }
549
550 /**
551 * sanitize a string for printing
552 */
553 static char* sanitize(char *str)
554 {
555 char *pos = str;
556
557 while (pos && *pos)
558 {
559 if (!isprint(*pos))
560 {
561 *pos = '?';
562 }
563 pos++;
564 }
565 return str;
566 }
567
568 /**
569 * Returns a chunk of just the username part of the given user identity.
570 * Note: the chunk points to internal data of the given chunk
571 */
572 static chunk_t extract_username(chunk_t id)
573 {
574 char *has_domain;
575
576 has_domain = (char*)memchr(id.ptr, '\\', id.len);
577 if (has_domain)
578 {
579 int len;
580 has_domain++; /* skip the backslash */
581 len = id.len - ((u_char*)has_domain - id.ptr);
582 return len > 0 ? chunk_create(has_domain, len) : chunk_empty;
583 }
584 return id;
585 }
586
587 /**
588 * Set the ms_length field using aligned write
589 */
590 static void set_ms_length(eap_mschapv2_header_t *eap, u_int16_t len)
591 {
592 len = htons(len - 5);
593 memcpy(&eap->ms_length, &len, sizeof(u_int16_t));
594 }
595
596 METHOD(eap_method_t, initiate_peer, status_t,
597 private_eap_mschapv2_t *this, eap_payload_t **out)
598 {
599 /* peer never initiates */
600 return FAILED;
601 }
602
603 METHOD(eap_method_t, initiate_server, status_t,
604 private_eap_mschapv2_t *this, eap_payload_t **out)
605 {
606 rng_t *rng;
607 eap_mschapv2_header_t *eap;
608 eap_mschapv2_challenge_t *cha;
609 const char *name = MSCHAPV2_HOST_NAME;
610 u_int16_t len = CHALLENGE_PAYLOAD_LEN + sizeof(MSCHAPV2_HOST_NAME) - 1;
611
612 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
613 if (!rng || !rng->allocate_bytes(rng, CHALLENGE_LEN, &this->challenge))
614 {
615 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no challenge");
616 DESTROY_IF(rng);
617 return FAILED;
618 }
619 rng->destroy(rng);
620
621 eap = alloca(len);
622 eap->code = EAP_REQUEST;
623 eap->identifier = this->identifier;
624 eap->length = htons(len);
625 eap->type = EAP_MSCHAPV2;
626 eap->opcode = MSCHAPV2_CHALLENGE;
627 eap->ms_chapv2_id = this->mschapv2id;
628 set_ms_length(eap, len);
629
630 cha = (eap_mschapv2_challenge_t*)eap->data;
631 cha->value_size = CHALLENGE_LEN;
632 memcpy(cha->challenge, this->challenge.ptr, this->challenge.len);
633 memcpy(cha->name, name, sizeof(MSCHAPV2_HOST_NAME) - 1);
634
635 *out = eap_payload_create_data(chunk_create((void*) eap, len));
636 return NEED_MORE;
637 }
638
639 static bool get_nt_hash(private_eap_mschapv2_t *this, identification_t *me,
640 identification_t *other, chunk_t *nt_hash)
641 {
642 shared_key_t *shared;
643 chunk_t password;
644
645 /* try to find a stored NT_HASH first */
646 shared = lib->credmgr->get_shared(lib->credmgr, SHARED_NT_HASH, me, other);
647 if (shared )
648 {
649 *nt_hash = chunk_clone(shared->get_key(shared));
650 shared->destroy(shared);
651 return TRUE;
652 }
653
654 /* fallback to plaintext password */
655 shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, me, other);
656 if (shared)
657 {
658 password = ascii_to_unicode(shared->get_key(shared));
659 shared->destroy(shared);
660
661 if (NtPasswordHash(password, nt_hash) == SUCCESS)
662 {
663 chunk_clear(&password);
664 return TRUE;
665 }
666 chunk_clear(&password);
667 }
668 return FALSE;
669 }
670
671 /**
672 * Process MS-CHAPv2 Challenge Requests
673 */
674 static status_t process_peer_challenge(private_eap_mschapv2_t *this,
675 eap_payload_t *in, eap_payload_t **out)
676 {
677 rng_t *rng;
678 eap_mschapv2_header_t *eap;
679 eap_mschapv2_challenge_t *cha;
680 eap_mschapv2_response_t *res;
681 chunk_t data, peer_challenge, userid, username, nt_hash;
682 u_int16_t len = RESPONSE_PAYLOAD_LEN;
683
684 data = in->get_data(in);
685 eap = (eap_mschapv2_header_t*)data.ptr;
686
687 /* the name MUST be at least one octet long */
688 if (data.len < CHALLENGE_PAYLOAD_LEN + 1)
689 {
690 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
691 return FAILED;
692 }
693
694 cha = (eap_mschapv2_challenge_t*)eap->data;
695
696 if (cha->value_size != CHALLENGE_LEN)
697 {
698 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
699 "invalid challenge size");
700 return FAILED;
701 }
702
703 this->mschapv2id = eap->ms_chapv2_id;
704 this->challenge = chunk_clone(chunk_create(cha->challenge, CHALLENGE_LEN));
705
706 peer_challenge = chunk_alloca(CHALLENGE_LEN);
707 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
708 if (!rng || !rng->get_bytes(rng, CHALLENGE_LEN, peer_challenge.ptr))
709 {
710 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, allocating challenge failed");
711 DESTROY_IF(rng);
712 return FAILED;
713 }
714 rng->destroy(rng);
715
716 if (!get_nt_hash(this, this->peer, this->server, &nt_hash))
717 {
718 DBG1(DBG_IKE, "no EAP key found for hosts '%Y' - '%Y'",
719 this->server, this->peer);
720 return NOT_FOUND;
721 }
722
723 /* we transmit the whole user identity (including the domain part) but
724 * only use the user part when calculating the challenge hash */
725 userid = this->peer->get_encoding(this->peer);
726 len += userid.len;
727 username = extract_username(userid);
728
729 if (GenerateStuff(this, this->challenge, peer_challenge,
730 username, nt_hash) != SUCCESS)
731 {
732 DBG1(DBG_IKE, "EAP-MS-CHAPv2 generating NT-Response failed");
733 chunk_clear(&nt_hash);
734 return FAILED;
735 }
736 chunk_clear(&nt_hash);
737
738 eap = alloca(len);
739 eap->code = EAP_RESPONSE;
740 eap->identifier = this->identifier;
741 eap->length = htons(len);
742 eap->type = EAP_MSCHAPV2;
743 eap->opcode = MSCHAPV2_RESPONSE;
744 eap->ms_chapv2_id = this->mschapv2id;
745 set_ms_length(eap, len);
746
747 res = (eap_mschapv2_response_t*)eap->data;
748 res->value_size = RESPONSE_LEN;
749 memset(&res->response, 0, RESPONSE_LEN);
750 memcpy(res->response.peer_challenge, peer_challenge.ptr, peer_challenge.len);
751 memcpy(res->response.nt_response, this->nt_response.ptr, this->nt_response.len);
752 memcpy(res->name, userid.ptr, userid.len);
753
754 *out = eap_payload_create_data(chunk_create((void*) eap, len));
755 return NEED_MORE;
756 }
757
758 /**
759 * Process MS-CHAPv2 Success Requests
760 */
761 static status_t process_peer_success(private_eap_mschapv2_t *this,
762 eap_payload_t *in, eap_payload_t **out)
763 {
764 status_t status = FAILED;
765 enumerator_t *enumerator;
766 eap_mschapv2_header_t *eap;
767 chunk_t data, auth_string = chunk_empty;
768 char *message, *token, *msg = NULL;
769 int message_len;
770 u_int16_t len = SHORT_HEADER_LEN;
771
772 data = in->get_data(in);
773 eap = (eap_mschapv2_header_t*)data.ptr;
774
775 if (data.len < AUTH_RESPONSE_LEN)
776 {
777 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
778 return FAILED;
779 }
780
781 message_len = data.len - HEADER_LEN;
782 message = malloc(message_len + 1);
783 memcpy(message, eap->data, message_len);
784 message[message_len] = '\0';
785
786 /* S=<auth_string> M=<msg> */
787 enumerator = enumerator_create_token(message, " ", " ");
788 while (enumerator->enumerate(enumerator, &token))
789 {
790 if (strpfx(token, "S="))
791 {
792 chunk_t hex;
793 token += 2;
794 if (strlen(token) != AUTH_RESPONSE_LEN - 2)
795 {
796 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
797 "invalid auth string");
798 goto error;
799 }
800 chunk_free(&auth_string);
801 hex = chunk_create(token, AUTH_RESPONSE_LEN - 2);
802 auth_string = chunk_from_hex(hex, NULL);
803 }
804 else if (strpfx(token, "M="))
805 {
806 token += 2;
807 free(msg);
808 msg = strdup(token);
809 }
810 }
811 enumerator->destroy(enumerator);
812
813 if (auth_string.ptr == NULL)
814 {
815 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
816 "auth string missing");
817 goto error;
818 }
819
820 if (!chunk_equals_const(this->auth_response, auth_string))
821 {
822 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed");
823 goto error;
824 }
825
826 DBG1(DBG_IKE, "EAP-MS-CHAPv2 succeeded: '%s'", sanitize(msg));
827
828 eap = alloca(len);
829 eap->code = EAP_RESPONSE;
830 eap->identifier = this->identifier;
831 eap->length = htons(len);
832 eap->type = EAP_MSCHAPV2;
833 eap->opcode = MSCHAPV2_SUCCESS;
834
835 *out = eap_payload_create_data(chunk_create((void*) eap, len));
836 status = NEED_MORE;
837
838 error:
839 chunk_free(&auth_string);
840 free(message);
841 free(msg);
842 return status;
843 }
844
845 static status_t process_peer_failure(private_eap_mschapv2_t *this,
846 eap_payload_t *in, eap_payload_t **out)
847 {
848 status_t status = FAILED;
849 enumerator_t *enumerator;
850 eap_mschapv2_header_t *eap;
851 chunk_t data;
852 char *message, *token, *msg = NULL;
853 int message_len, error = 0;
854 chunk_t challenge = chunk_empty;
855
856 data = in->get_data(in);
857 eap = (eap_mschapv2_header_t*)data.ptr;
858
859 if (data.len < 3) /* we want at least an error code: E=e */
860 {
861 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
862 return FAILED;
863 }
864
865 message_len = data.len - HEADER_LEN;
866 message = malloc(message_len + 1);
867 memcpy(message, eap->data, message_len);
868 message[message_len] = '\0';
869
870 /* E=eeeeeeeeee R=r C=cccccccccccccccccccccccccccccccc V=vvvvvvvvvv M=<msg> */
871 enumerator = enumerator_create_token(message, " ", " ");
872 while (enumerator->enumerate(enumerator, &token))
873 {
874 if (strpfx(token, "E="))
875 {
876 token += 2;
877 error = atoi(token);
878 }
879 else if (strpfx(token, "R="))
880 {
881 /* ignore retriable */
882 }
883 else if (strpfx(token, "C="))
884 {
885 chunk_t hex;
886 token += 2;
887 if (strlen(token) != 2 * CHALLENGE_LEN)
888 {
889 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message:"
890 "invalid challenge");
891 goto error;
892 }
893 chunk_free(&challenge);
894 hex = chunk_create(token, 2 * CHALLENGE_LEN);
895 challenge = chunk_from_hex(hex, NULL);
896 }
897 else if (strpfx(token, "V="))
898 {
899 /* ignore version */
900 }
901 else if (strpfx(token, "M="))
902 {
903 token += 2;
904 free(msg);
905 msg = strdup(token);
906 }
907 }
908 enumerator->destroy(enumerator);
909
910 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed with error %N: '%s'",
911 mschapv2_error_names, error, sanitize(msg));
912
913 /**
914 * at this point, if the error is retriable, we MAY retry the authentication
915 * or MAY send a Change Password packet.
916 *
917 * if the error is not retriable (or if we do neither of the above), we
918 * SHOULD send a Failure Response packet.
919 * windows clients don't do that, and since windows server 2008 r2 behaves
920 * pretty odd if we do send a Failure Response, we just don't send one
921 * either. windows 7 actually sends a delete notify (which, according to the
922 * logs, results in an error on windows server 2008 r2).
923 *
924 * btw, windows server 2008 r2 does not send non-retriable errors for e.g.
925 * a disabled account but returns the windows error code in a notify payload
926 * of type 12345.
927 */
928
929 status = FAILED;
930
931 error:
932 chunk_free(&challenge);
933 free(message);
934 free(msg);
935 return status;
936 }
937
938 METHOD(eap_method_t, process_peer, status_t,
939 private_eap_mschapv2_t *this, eap_payload_t *in, eap_payload_t **out)
940 {
941 chunk_t data;
942 eap_mschapv2_header_t *eap;
943
944 this->identifier = in->get_identifier(in);
945 data = in->get_data(in);
946 if (data.len < SHORT_HEADER_LEN)
947 {
948 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message");
949 return FAILED;
950 }
951
952 eap = (eap_mschapv2_header_t*)data.ptr;
953
954 switch (eap->opcode)
955 {
956 case MSCHAPV2_CHALLENGE:
957 {
958 return process_peer_challenge(this, in, out);
959 }
960 case MSCHAPV2_SUCCESS:
961 {
962 return process_peer_success(this, in, out);
963 }
964 case MSCHAPV2_FAILURE:
965 {
966 return process_peer_failure(this, in, out);
967 }
968 default:
969 {
970 DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
971 "OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
972 break;
973 }
974 }
975 return FAILED;
976 }
977
978 /**
979 * Handles retries on the server
980 */
981 static status_t process_server_retry(private_eap_mschapv2_t *this,
982 eap_payload_t **out)
983 {
984 eap_mschapv2_header_t *eap;
985 rng_t *rng;
986 chunk_t hex;
987 char msg[FAILURE_MESSAGE_LEN];
988 u_int16_t len = HEADER_LEN + FAILURE_MESSAGE_LEN - 1; /* no null byte */
989
990 if (++this->retries > MAX_RETRIES)
991 {
992 /* we MAY send a Failure Request with R=0, but windows 7 does not
993 * really like that and does not respond with a Failure Response.
994 * so, to clean up our state we just fail with an EAP-Failure.
995 * this gives an unknown error on the windows side, but is also fine
996 * with the standard. */
997 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed: "
998 "maximum number of retries reached");
999 return FAILED;
1000 }
1001
1002 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed, retry (%d)", this->retries);
1003
1004 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
1005 if (!rng || !rng->get_bytes(rng, CHALLENGE_LEN, this->challenge.ptr))
1006 {
1007 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, allocating challenge failed");
1008 DESTROY_IF(rng);
1009 return FAILED;
1010 }
1011 rng->destroy(rng);
1012
1013 chunk_free(&this->nt_response);
1014 chunk_free(&this->auth_response);
1015 chunk_free(&this->msk);
1016
1017 eap = alloca(len);
1018 eap->code = EAP_REQUEST;
1019 eap->identifier = ++this->identifier;
1020 eap->length = htons(len);
1021 eap->type = EAP_MSCHAPV2;
1022 eap->opcode = MSCHAPV2_FAILURE;
1023 eap->ms_chapv2_id = this->mschapv2id++; /* increase for each retry */
1024 set_ms_length(eap, len);
1025
1026 hex = chunk_to_hex(this->challenge, NULL, TRUE);
1027 snprintf(msg, FAILURE_MESSAGE_LEN, "%s%s", FAILURE_MESSAGE, hex.ptr);
1028 chunk_free(&hex);
1029 memcpy(eap->data, msg, FAILURE_MESSAGE_LEN - 1); /* no null byte */
1030 *out = eap_payload_create_data(chunk_create((void*) eap, len));
1031
1032 /* delay the response for some time to make brute-force attacks harder */
1033 sleep(RETRY_DELAY);
1034
1035 return NEED_MORE;
1036 }
1037
1038 /**
1039 * Process MS-CHAPv2 Response response packets
1040 */
1041 static status_t process_server_response(private_eap_mschapv2_t *this,
1042 eap_payload_t *in, eap_payload_t **out)
1043 {
1044 eap_mschapv2_header_t *eap;
1045 eap_mschapv2_response_t *res;
1046 chunk_t data, peer_challenge, username, nt_hash;
1047 identification_t *userid;
1048 int name_len;
1049 char buf[256];
1050
1051 data = in->get_data(in);
1052 eap = (eap_mschapv2_header_t*)data.ptr;
1053
1054 if (data.len < RESPONSE_PAYLOAD_LEN)
1055 {
1056 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
1057 return FAILED;
1058 }
1059
1060 res = (eap_mschapv2_response_t*)eap->data;
1061 peer_challenge = chunk_create(res->response.peer_challenge, CHALLENGE_LEN);
1062
1063 name_len = min(data.len - RESPONSE_PAYLOAD_LEN, 255);
1064 snprintf(buf, sizeof(buf), "%.*s", name_len, res->name);
1065 userid = identification_create_from_string(buf);
1066 if (!userid->equals(userid, this->peer))
1067 {
1068 DBG1(DBG_IKE, "EAP-MS-CHAPv2 username: '%Y'", userid);
1069 }
1070 /* userid can only be destroyed after the last use of username */
1071 username = extract_username(userid->get_encoding(userid));
1072
1073 if (!get_nt_hash(this, this->server, userid, &nt_hash))
1074 {
1075 DBG1(DBG_IKE, "no EAP key found for hosts '%Y' - '%Y'",
1076 this->server, userid);
1077 /* FIXME: windows 7 always sends the username that is first entered in
1078 * the username box, even, if the user changes it during retries (probably
1079 * to keep consistent with the EAP-Identity).
1080 * thus, we could actually fail here, because retries do not make much
1081 * sense. on the other hand, an attacker could guess usernames, if the
1082 * error messages were different. */
1083 userid->destroy(userid);
1084 return process_server_retry(this, out);
1085 }
1086
1087 if (GenerateStuff(this, this->challenge, peer_challenge,
1088 username, nt_hash) != SUCCESS)
1089 {
1090 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed");
1091 userid->destroy(userid);
1092 chunk_clear(&nt_hash);
1093 return FAILED;
1094 }
1095 chunk_clear(&nt_hash);
1096
1097 if (memeq_const(res->response.nt_response, this->nt_response.ptr,
1098 this->nt_response.len))
1099 {
1100 chunk_t hex;
1101 char msg[AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE)];
1102 u_int16_t len = HEADER_LEN + AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE);
1103
1104 eap = alloca(len);
1105 eap->code = EAP_REQUEST;
1106 eap->identifier = ++this->identifier;
1107 eap->length = htons(len);
1108 eap->type = EAP_MSCHAPV2;
1109 eap->opcode = MSCHAPV2_SUCCESS;
1110 eap->ms_chapv2_id = this->mschapv2id;
1111 set_ms_length(eap, len);
1112
1113 hex = chunk_to_hex(this->auth_response, NULL, TRUE);
1114 snprintf(msg, AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE),
1115 "S=%s%s", hex.ptr, SUCCESS_MESSAGE);
1116 chunk_free(&hex);
1117 memcpy(eap->data, msg, AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE));
1118 *out = eap_payload_create_data(chunk_create((void*) eap, len));
1119
1120 this->auth->add(this->auth, AUTH_RULE_EAP_IDENTITY, userid);
1121 return NEED_MORE;
1122 }
1123 userid->destroy(userid);
1124 return process_server_retry(this, out);
1125 }
1126
1127 METHOD(eap_method_t, process_server, status_t,
1128 private_eap_mschapv2_t *this, eap_payload_t *in, eap_payload_t **out)
1129 {
1130 eap_mschapv2_header_t *eap;
1131 chunk_t data;
1132
1133 if (this->identifier != in->get_identifier(in))
1134 {
1135 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
1136 "unexpected identifier");
1137 return FAILED;
1138 }
1139
1140 data = in->get_data(in);
1141 if (data.len < SHORT_HEADER_LEN)
1142 {
1143 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
1144 return FAILED;
1145 }
1146
1147 eap = (eap_mschapv2_header_t*)data.ptr;
1148
1149 switch (eap->opcode)
1150 {
1151 case MSCHAPV2_RESPONSE:
1152 {
1153 return process_server_response(this, in, out);
1154 }
1155 case MSCHAPV2_SUCCESS:
1156 {
1157 return SUCCESS;
1158 }
1159 case MSCHAPV2_FAILURE:
1160 {
1161 return FAILED;
1162 }
1163 default:
1164 {
1165 DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
1166 "OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
1167 break;
1168 }
1169 }
1170 return FAILED;
1171 }
1172
1173 METHOD(eap_method_t, get_type, eap_type_t,
1174 private_eap_mschapv2_t *this, u_int32_t *vendor)
1175 {
1176 *vendor = 0;
1177 return EAP_MSCHAPV2;
1178 }
1179
1180 METHOD(eap_method_t, get_msk, status_t,
1181 private_eap_mschapv2_t *this, chunk_t *msk)
1182 {
1183 if (this->msk.ptr)
1184 {
1185 *msk = this->msk;
1186 return SUCCESS;
1187 }
1188 return FAILED;
1189 }
1190
1191 METHOD(eap_method_t, get_identifier, u_int8_t,
1192 private_eap_mschapv2_t *this)
1193 {
1194 return this->identifier;
1195 }
1196
1197 METHOD(eap_method_t, set_identifier, void,
1198 private_eap_mschapv2_t *this, u_int8_t identifier)
1199 {
1200 this->identifier = identifier;
1201 }
1202
1203 METHOD(eap_method_t, is_mutual, bool,
1204 private_eap_mschapv2_t *this)
1205 {
1206 return FALSE;
1207 }
1208
1209 METHOD(eap_method_t, get_auth, auth_cfg_t*,
1210 private_eap_mschapv2_t *this)
1211 {
1212 return this->auth;
1213 }
1214
1215 METHOD(eap_method_t, destroy, void,
1216 private_eap_mschapv2_t *this)
1217 {
1218 this->peer->destroy(this->peer);
1219 this->server->destroy(this->server);
1220 this->auth->destroy(this->auth);
1221 chunk_free(&this->challenge);
1222 chunk_free(&this->nt_response);
1223 chunk_free(&this->auth_response);
1224 chunk_free(&this->msk);
1225 free(this);
1226 }
1227
1228 /**
1229 * Generic constructor
1230 */
1231 static private_eap_mschapv2_t *eap_mschapv2_create_generic(identification_t *server, identification_t *peer)
1232 {
1233 private_eap_mschapv2_t *this;
1234
1235 INIT(this,
1236 .public = {
1237 .eap_method_interface = {
1238 .get_type = _get_type,
1239 .is_mutual = _is_mutual,
1240 .get_msk = _get_msk,
1241 .get_identifier = _get_identifier,
1242 .set_identifier = _set_identifier,
1243 .get_auth = _get_auth,
1244 .destroy = _destroy,
1245 },
1246 },
1247 .peer = peer->clone(peer),
1248 .server = server->clone(server),
1249 .auth = auth_cfg_create(),
1250 );
1251
1252 return this;
1253 }
1254
1255 /*
1256 * see header
1257 */
1258 eap_mschapv2_t *eap_mschapv2_create_server(identification_t *server, identification_t *peer)
1259 {
1260 private_eap_mschapv2_t *this = eap_mschapv2_create_generic(server, peer);
1261
1262 this->public.eap_method_interface.initiate = _initiate_server;
1263 this->public.eap_method_interface.process = _process_server;
1264
1265 /* generate a non-zero identifier */
1266 do
1267 {
1268 this->identifier = random();
1269 } while (!this->identifier);
1270
1271 this->mschapv2id = this->identifier;
1272
1273 return &this->public;
1274 }
1275
1276 /*
1277 * see header
1278 */
1279 eap_mschapv2_t *eap_mschapv2_create_peer(identification_t *server, identification_t *peer)
1280 {
1281 private_eap_mschapv2_t *this = eap_mschapv2_create_generic(server, peer);
1282
1283 this->public.eap_method_interface.initiate = _initiate_peer;
1284 this->public.eap_method_interface.process = _process_peer;
1285
1286 return &this->public;
1287 }