3cd8d994cada7fe2ceaa0dac4685b0b088c7cc62
[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 <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 = lib->credmgr->get_shared(lib->credmgr, SHARED_NT_HASH, me, other);
618 if (shared )
619 {
620 *nt_hash = chunk_clone(shared->get_key(shared));
621 shared->destroy(shared);
622 return TRUE;
623 }
624
625 /* fallback to plaintext password */
626 shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, me, other);
627 if (shared)
628 {
629 password = ascii_to_unicode(shared->get_key(shared));
630 shared->destroy(shared);
631
632 if (NtPasswordHash(password, nt_hash) == SUCCESS)
633 {
634 chunk_clear(&password);
635 return TRUE;
636 }
637 chunk_clear(&password);
638 }
639 return FALSE;
640 }
641
642 /**
643 * Process MS-CHAPv2 Challenge Requests
644 */
645 static status_t process_peer_challenge(private_eap_mschapv2_t *this,
646 eap_payload_t *in, eap_payload_t **out)
647 {
648 rng_t *rng;
649 eap_mschapv2_header_t *eap;
650 eap_mschapv2_challenge_t *cha;
651 eap_mschapv2_response_t *res;
652 chunk_t data, peer_challenge, username, nt_hash;
653 u_int16_t len = RESPONSE_PAYLOAD_LEN;
654
655 data = in->get_data(in);
656 eap = (eap_mschapv2_header_t*)data.ptr;
657
658 /* the name MUST be at least one octet long */
659 if (data.len < CHALLENGE_PAYLOAD_LEN + 1)
660 {
661 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
662 return FAILED;
663 }
664
665 cha = (eap_mschapv2_challenge_t*)eap->data;
666
667 if (cha->value_size != CHALLENGE_LEN)
668 {
669 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
670 "invalid challenge size");
671 return FAILED;
672 }
673
674 this->mschapv2id = eap->ms_chapv2_id;
675 this->challenge = chunk_clone(chunk_create(cha->challenge, CHALLENGE_LEN));
676
677 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
678 if (!rng)
679 {
680 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no RNG");
681 return FAILED;
682 }
683 peer_challenge = chunk_alloca(CHALLENGE_LEN);
684 rng->get_bytes(rng, CHALLENGE_LEN, peer_challenge.ptr);
685 rng->destroy(rng);
686
687 if (!get_nt_hash(this, this->peer, this->server, &nt_hash))
688 {
689 DBG1(DBG_IKE, "no EAP key found for hosts '%Y' - '%Y'",
690 this->server, this->peer);
691 return NOT_FOUND;
692 }
693
694 username = extract_username(this->peer);
695 len += username.len;
696
697 if (GenerateStuff(this, this->challenge, peer_challenge,
698 username, nt_hash) != SUCCESS)
699 {
700 DBG1(DBG_IKE, "EAP-MS-CHAPv2 generating NT-Response failed");
701 chunk_clear(&nt_hash);
702 return FAILED;
703 }
704 chunk_clear(&nt_hash);
705
706 eap = alloca(len);
707 eap->code = EAP_RESPONSE;
708 eap->identifier = this->identifier;
709 eap->length = htons(len);
710 eap->type = EAP_MSCHAPV2;
711 eap->opcode = MSCHAPV2_RESPONSE;
712 eap->ms_chapv2_id = this->mschapv2id;
713 set_ms_length(eap, len);
714
715 res = (eap_mschapv2_response_t*)eap->data;
716 res->value_size = RESPONSE_LEN;
717 memset(&res->response, 0, RESPONSE_LEN);
718 memcpy(res->response.peer_challenge, peer_challenge.ptr, peer_challenge.len);
719 memcpy(res->response.nt_response, this->nt_response.ptr, this->nt_response.len);
720
721 username = this->peer->get_encoding(this->peer);
722 memcpy(res->name, username.ptr, username.len);
723
724 *out = eap_payload_create_data(chunk_create((void*) eap, len));
725 return NEED_MORE;
726 }
727
728 /**
729 * Process MS-CHAPv2 Success Requests
730 */
731 static status_t process_peer_success(private_eap_mschapv2_t *this,
732 eap_payload_t *in, eap_payload_t **out)
733 {
734 status_t status = FAILED;
735 enumerator_t *enumerator;
736 eap_mschapv2_header_t *eap;
737 chunk_t data, auth_string = chunk_empty;
738 char *message, *token, *msg = NULL;
739 int message_len;
740 u_int16_t len = SHORT_HEADER_LEN;
741
742 data = in->get_data(in);
743 eap = (eap_mschapv2_header_t*)data.ptr;
744
745 if (data.len < AUTH_RESPONSE_LEN)
746 {
747 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
748 return FAILED;
749 }
750
751 message_len = data.len - HEADER_LEN;
752 message = malloc(message_len + 1);
753 memcpy(message, eap->data, message_len);
754 message[message_len] = '\0';
755
756 /* S=<auth_string> M=<msg> */
757 enumerator = enumerator_create_token(message, " ", " ");
758 while (enumerator->enumerate(enumerator, &token))
759 {
760 if (strneq(token, "S=", 2))
761 {
762 chunk_t hex;
763 token += 2;
764 if (strlen(token) != AUTH_RESPONSE_LEN - 2)
765 {
766 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
767 "invalid auth string");
768 goto error;
769 }
770 hex = chunk_create(token, AUTH_RESPONSE_LEN - 2);
771 auth_string = chunk_from_hex(hex, NULL);
772 }
773 else if (strneq(token, "M=", 2))
774 {
775 token += 2;
776 msg = strdup(token);
777 }
778 }
779 enumerator->destroy(enumerator);
780
781 if (auth_string.ptr == NULL)
782 {
783 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
784 "auth string missing");
785 goto error;
786 }
787
788 if (!chunk_equals(this->auth_response, auth_string))
789 {
790 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed");
791 goto error;
792 }
793
794 DBG1(DBG_IKE, "EAP-MS-CHAPv2 succeeded: '%s'", sanitize(msg));
795
796 eap = alloca(len);
797 eap->code = EAP_RESPONSE;
798 eap->identifier = this->identifier;
799 eap->length = htons(len);
800 eap->type = EAP_MSCHAPV2;
801 eap->opcode = MSCHAPV2_SUCCESS;
802
803 *out = eap_payload_create_data(chunk_create((void*) eap, len));
804 status = NEED_MORE;
805
806 error:
807 chunk_free(&auth_string);
808 free(message);
809 free(msg);
810 return status;
811 }
812
813 static status_t process_peer_failure(private_eap_mschapv2_t *this,
814 eap_payload_t *in, eap_payload_t **out)
815 {
816 status_t status = FAILED;
817 enumerator_t *enumerator;
818 eap_mschapv2_header_t *eap;
819 chunk_t data;
820 char *message, *token, *msg = NULL;
821 int message_len, error = 0, retryable;
822 chunk_t challenge = chunk_empty;
823
824 data = in->get_data(in);
825 eap = (eap_mschapv2_header_t*)data.ptr;
826
827 if (data.len < 3) /* we want at least an error code: E=e */
828 {
829 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
830 return FAILED;
831 }
832
833 message_len = data.len - HEADER_LEN;
834 message = malloc(message_len + 1);
835 memcpy(message, eap->data, message_len);
836 message[message_len] = '\0';
837
838 /* E=eeeeeeeeee R=r C=cccccccccccccccccccccccccccccccc V=vvvvvvvvvv M=<msg> */
839 enumerator = enumerator_create_token(message, " ", " ");
840 while (enumerator->enumerate(enumerator, &token))
841 {
842 if (strneq(token, "E=", 2))
843 {
844 token += 2;
845 error = atoi(token);
846 }
847 else if (strneq(token, "R=", 2))
848 {
849 token += 2;
850 retryable = atoi(token);
851 }
852 else if (strneq(token, "C=", 2))
853 {
854 chunk_t hex;
855 token += 2;
856 if (strlen(token) != 2 * CHALLENGE_LEN)
857 {
858 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message:"
859 "invalid challenge");
860 goto error;
861 }
862 hex = chunk_create(token, 2 * CHALLENGE_LEN);
863 challenge = chunk_from_hex(hex, NULL);
864 }
865 else if (strneq(token, "V=", 2))
866 {
867 int version;
868 token += 2;
869 version = atoi(token);
870 }
871 else if (strneq(token, "M=", 2))
872 {
873 token += 2;
874 msg = strdup(token);
875 }
876 }
877 enumerator->destroy(enumerator);
878
879 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed with error %N: '%s'",
880 mschapv2_error_names, error, sanitize(msg));
881
882 /**
883 * at this point, if the error is retryable, we MAY retry the authentication
884 * or MAY send a Change Password packet.
885 *
886 * if the error is not retryable (or if we do neither of the above), we
887 * SHOULD send a Failure Response packet.
888 * windows clients don't do that, and since windows server 2008 r2 behaves
889 * pretty odd if we do send a Failure Response, we just don't send one
890 * either. windows 7 actually sends a delete notify (which, according to the
891 * logs, results in an error on windows server 2008 r2).
892 *
893 * btw, windows server 2008 r2 does not send non-retryable errors for e.g.
894 * a disabled account but returns the windows error code in a notify payload
895 * of type 12345.
896 */
897
898 status = FAILED;
899
900 error:
901 chunk_free(&challenge);
902 free(message);
903 free(msg);
904 return status;
905 }
906
907 /**
908 * Implementation of eap_method_t.process for the peer
909 */
910 static status_t process_peer(private_eap_mschapv2_t *this, eap_payload_t *in,
911 eap_payload_t **out)
912 {
913 chunk_t data;
914 eap_mschapv2_header_t *eap;
915
916 this->identifier = in->get_identifier(in);
917 data = in->get_data(in);
918 if (data.len < SHORT_HEADER_LEN)
919 {
920 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message");
921 return FAILED;
922 }
923
924 eap = (eap_mschapv2_header_t*)data.ptr;
925
926 switch (eap->opcode)
927 {
928 case MSCHAPV2_CHALLENGE:
929 {
930 return process_peer_challenge(this, in, out);
931 }
932 case MSCHAPV2_SUCCESS:
933 {
934 return process_peer_success(this, in, out);
935 }
936 case MSCHAPV2_FAILURE:
937 {
938 return process_peer_failure(this, in, out);
939 }
940 default:
941 {
942 DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
943 "OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
944 break;
945 }
946 }
947 return FAILED;
948 }
949
950 /**
951 * Handles retries on the server
952 */
953 static status_t process_server_retry(private_eap_mschapv2_t *this,
954 eap_payload_t **out)
955 {
956 eap_mschapv2_header_t *eap;
957 rng_t *rng;
958 chunk_t hex;
959 char msg[FAILURE_MESSAGE_LEN];
960 u_int16_t len = HEADER_LEN + FAILURE_MESSAGE_LEN - 1; /* no null byte */
961
962 if (++this->retries > MAX_RETRIES)
963 {
964 /* we MAY send a Failure Request with R=0, but windows 7 does not
965 * really like that and does not respond with a Failure Response.
966 * so, to clean up our state we just fail with an EAP-Failure.
967 * this gives an unknown error on the windows side, but is also fine
968 * with the standard. */
969 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed: "
970 "maximum number of retries reached");
971 return FAILED;
972 }
973
974 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed, retry (%d)", this->retries);
975
976 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
977 if (!rng)
978 {
979 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no RNG");
980 return FAILED;
981 }
982 rng->get_bytes(rng, CHALLENGE_LEN, this->challenge.ptr);
983 rng->destroy(rng);
984
985 chunk_free(&this->nt_response);
986 chunk_free(&this->auth_response);
987 chunk_free(&this->msk);
988
989 eap = alloca(len);
990 eap->code = EAP_REQUEST;
991 eap->identifier = ++this->identifier;
992 eap->length = htons(len);
993 eap->type = EAP_MSCHAPV2;
994 eap->opcode = MSCHAPV2_FAILURE;
995 eap->ms_chapv2_id = this->mschapv2id++; /* increase for each retry */
996 set_ms_length(eap, len);
997
998 hex = chunk_to_hex(this->challenge, NULL, TRUE);
999 snprintf(msg, FAILURE_MESSAGE_LEN, "%s%s", FAILURE_MESSAGE, hex.ptr);
1000 chunk_free(&hex);
1001 memcpy(eap->data, msg, FAILURE_MESSAGE_LEN - 1); /* no null byte */
1002 *out = eap_payload_create_data(chunk_create((void*) eap, len));
1003
1004 /* delay the response for some time to make brute-force attacks harder */
1005 sleep(RETRY_DELAY);
1006
1007 return NEED_MORE;
1008 }
1009
1010 /**
1011 * Process MS-CHAPv2 Response response packets
1012 */
1013 static status_t process_server_response(private_eap_mschapv2_t *this,
1014 eap_payload_t *in, eap_payload_t **out)
1015 {
1016 eap_mschapv2_header_t *eap;
1017 eap_mschapv2_response_t *res;
1018 chunk_t data, peer_challenge, username, nt_hash;
1019 identification_t *userid;
1020 int name_len;
1021 char buf[256];
1022
1023 data = in->get_data(in);
1024 eap = (eap_mschapv2_header_t*)data.ptr;
1025
1026 if (data.len < RESPONSE_PAYLOAD_LEN)
1027 {
1028 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
1029 return FAILED;
1030 }
1031
1032 res = (eap_mschapv2_response_t*)eap->data;
1033 peer_challenge = chunk_create(res->response.peer_challenge, CHALLENGE_LEN);
1034
1035 name_len = min(data.len - RESPONSE_PAYLOAD_LEN, 255);
1036 snprintf(buf, sizeof(buf), "%.*s", name_len, res->name);
1037 userid = identification_create_from_string(buf);
1038 DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%Y'", userid);
1039 username = extract_username(userid);
1040
1041 if (!get_nt_hash(this, this->server, userid, &nt_hash))
1042 {
1043 DBG1(DBG_IKE, "no EAP key found for hosts '%Y' - '%Y'",
1044 this->server, userid);
1045 /* FIXME: windows 7 always sends the username that is first entered in
1046 * the username box, even, if the user changes it during retries (probably
1047 * to keep consistent with the EAP-Identity).
1048 * thus, we could actually fail here, because retries do not make much
1049 * sense. on the other hand, an attacker could guess usernames, if the
1050 * error messages were different. */
1051 userid->destroy(userid);
1052 return process_server_retry(this, out);
1053 }
1054
1055 if (GenerateStuff(this, this->challenge, peer_challenge,
1056 username, nt_hash) != SUCCESS)
1057 {
1058 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed");
1059 userid->destroy(userid);
1060 chunk_clear(&nt_hash);
1061 return FAILED;
1062 }
1063 userid->destroy(userid);
1064 chunk_clear(&nt_hash);
1065
1066 if (memeq(res->response.nt_response, this->nt_response.ptr,
1067 this->nt_response.len))
1068 {
1069 chunk_t hex;
1070 char msg[AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE)];
1071 u_int16_t len = HEADER_LEN + AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE);
1072
1073 eap = alloca(len);
1074 eap->code = EAP_REQUEST;
1075 eap->identifier = ++this->identifier;
1076 eap->length = htons(len);
1077 eap->type = EAP_MSCHAPV2;
1078 eap->opcode = MSCHAPV2_SUCCESS;
1079 eap->ms_chapv2_id = this->mschapv2id;
1080 set_ms_length(eap, len);
1081
1082 hex = chunk_to_hex(this->auth_response, NULL, TRUE);
1083 snprintf(msg, AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE),
1084 "S=%s%s", hex.ptr, SUCCESS_MESSAGE);
1085 chunk_free(&hex);
1086 memcpy(eap->data, msg, AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE));
1087 *out = eap_payload_create_data(chunk_create((void*) eap, len));
1088 return NEED_MORE;
1089 }
1090
1091 return process_server_retry(this, out);
1092 }
1093
1094 /**
1095 * Implementation of eap_method_t.process for the server
1096 */
1097 static status_t process_server(private_eap_mschapv2_t *this, eap_payload_t *in,
1098 eap_payload_t **out)
1099 {
1100 eap_mschapv2_header_t *eap;
1101 chunk_t data;
1102
1103 if (this->identifier != in->get_identifier(in))
1104 {
1105 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
1106 "unexpected identifier");
1107 return FAILED;
1108 }
1109
1110 data = in->get_data(in);
1111 if (data.len < SHORT_HEADER_LEN)
1112 {
1113 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
1114 return FAILED;
1115 }
1116
1117 eap = (eap_mschapv2_header_t*)data.ptr;
1118
1119 switch (eap->opcode)
1120 {
1121 case MSCHAPV2_RESPONSE:
1122 {
1123 return process_server_response(this, in, out);
1124 }
1125 case MSCHAPV2_SUCCESS:
1126 {
1127 return SUCCESS;
1128 }
1129 case MSCHAPV2_FAILURE:
1130 {
1131 return FAILED;
1132 }
1133 default:
1134 {
1135 DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
1136 "OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
1137 break;
1138 }
1139 }
1140 return FAILED;
1141 }
1142
1143 /**
1144 * Implementation of eap_method_t.get_type.
1145 */
1146 static eap_type_t get_type(private_eap_mschapv2_t *this, u_int32_t *vendor)
1147 {
1148 *vendor = 0;
1149 return EAP_MSCHAPV2;
1150 }
1151
1152 /**
1153 * Implementation of eap_method_t.get_msk.
1154 */
1155 static status_t get_msk(private_eap_mschapv2_t *this, chunk_t *msk)
1156 {
1157 if (this->msk.ptr)
1158 {
1159 *msk = this->msk;
1160 return SUCCESS;
1161 }
1162 return FAILED;
1163 }
1164
1165 /**
1166 * Implementation of eap_method_t.is_mutual.
1167 */
1168 static bool is_mutual(private_eap_mschapv2_t *this)
1169 {
1170 return FALSE;
1171 }
1172
1173 /**
1174 * Implementation of eap_method_t.destroy.
1175 */
1176 static void destroy(private_eap_mschapv2_t *this)
1177 {
1178 this->peer->destroy(this->peer);
1179 this->server->destroy(this->server);
1180 chunk_free(&this->challenge);
1181 chunk_free(&this->nt_response);
1182 chunk_free(&this->auth_response);
1183 chunk_free(&this->msk);
1184 free(this);
1185 }
1186
1187 /**
1188 * Generic constructor
1189 */
1190 static private_eap_mschapv2_t *eap_mschapv2_create_generic(identification_t *server, identification_t *peer)
1191 {
1192 private_eap_mschapv2_t *this = malloc_thing(private_eap_mschapv2_t);
1193
1194 this->public.eap_method_interface.initiate = NULL;
1195 this->public.eap_method_interface.process = NULL;
1196 this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type;
1197 this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
1198 this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
1199 this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
1200
1201 /* private data */
1202 this->peer = peer->clone(peer);
1203 this->server = server->clone(server);
1204 this->challenge = chunk_empty;
1205 this->nt_response = chunk_empty;
1206 this->auth_response = chunk_empty;
1207 this->msk = chunk_empty;
1208 this->identifier = 0;
1209 this->mschapv2id = 0;
1210 this->retries = 0;
1211
1212 return this;
1213 }
1214
1215 /*
1216 * see header
1217 */
1218 eap_mschapv2_t *eap_mschapv2_create_server(identification_t *server, identification_t *peer)
1219 {
1220 private_eap_mschapv2_t *this = eap_mschapv2_create_generic(server, peer);
1221
1222 this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_server;
1223 this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*, eap_payload_t**))process_server;
1224
1225 /* generate a non-zero identifier */
1226 do
1227 {
1228 this->identifier = random();
1229 } while (!this->identifier);
1230
1231 this->mschapv2id = this->identifier;
1232
1233 return &this->public;
1234 }
1235
1236 /*
1237 * see header
1238 */
1239 eap_mschapv2_t *eap_mschapv2_create_peer(identification_t *server, identification_t *peer)
1240 {
1241 private_eap_mschapv2_t *this = eap_mschapv2_create_generic(server, peer);
1242
1243 this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_peer;
1244 this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*, eap_payload_t**))process_peer;
1245
1246 return &this->public;
1247 }
1248