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