dd6f56fd92f3d091feb3f88c283b8e3b28d36994
[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
341 expanded = ExpandDESKey(keys[i]);
342 if (!crypter->set_key(crypter, expanded) ||
343 !crypter->encrypt(crypter, challenge_hash, chunk_empty, &encrypted))
344 {
345 chunk_clear(&expanded);
346 crypter->destroy(crypter);
347 return FAILED;
348 }
349 memcpy(&response->ptr[i * 8], encrypted.ptr, encrypted.len);
350 chunk_clear(&encrypted);
351 chunk_clear(&expanded);
352 }
353 crypter->destroy(crypter);
354 return SUCCESS;
355 }
356
357 /**
358 * Computes the authenticator response
359 */
360 static status_t AuthenticatorResponse(chunk_t password_hash_hash,
361 chunk_t challenge_hash, chunk_t nt_response, chunk_t *response)
362 {
363 chunk_t magic1 = chunk_from_chars(
364 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
365 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
366 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
367 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74);
368 chunk_t magic2 = chunk_from_chars(
369 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
370 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
371 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
372 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
373 0x6E);
374 chunk_t digest = chunk_empty, concat;
375 hasher_t *hasher;
376
377 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
378 if (hasher == NULL)
379 {
380 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, SHA1 not supported");
381 return FAILED;
382 }
383
384 concat = chunk_cata("ccc", password_hash_hash, nt_response, magic1);
385 hasher->allocate_hash(hasher, concat, &digest);
386 concat = chunk_cata("ccc", digest, challenge_hash, magic2);
387 hasher->allocate_hash(hasher, concat, response);
388
389 hasher->destroy(hasher);
390 chunk_free(&digest);
391 return SUCCESS;
392 }
393
394 /**
395 * Generate the master session key according to RFC3079
396 */
397 static status_t GenerateMSK(chunk_t password_hash_hash,
398 chunk_t nt_response, chunk_t *msk)
399 {
400 chunk_t magic1 = chunk_from_chars(
401 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
402 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
403 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79);
404 chunk_t magic2 = chunk_from_chars(
405 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
406 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
407 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
408 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
409 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
410 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
411 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
412 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
413 0x6b, 0x65, 0x79, 0x2e);
414 chunk_t magic3 = chunk_from_chars(
415 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
416 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
417 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
418 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
419 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
420 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
421 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
422 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
423 0x6b, 0x65, 0x79, 0x2e);
424 chunk_t shapad1 = chunk_from_chars(
425 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
426 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
427 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
428 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
429 chunk_t shapad2 = chunk_from_chars(
430 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
431 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
432 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
433 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2);
434 chunk_t keypad = chunk_from_chars(
435 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
436 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
437 chunk_t concat, master_key, master_receive_key, master_send_key;
438 hasher_t *hasher;
439
440 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
441 if (hasher == NULL)
442 {
443 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, SHA1 not supported");
444 return FAILED;
445 }
446
447 concat = chunk_cata("ccc", password_hash_hash, nt_response, magic1);
448 hasher->allocate_hash(hasher, concat, &master_key);
449 master_key.len = 16;
450
451 concat = chunk_cata("cccc", master_key, shapad1, magic2, shapad2);
452 hasher->allocate_hash(hasher, concat, &master_receive_key);
453 master_receive_key.len = 16;
454
455 concat = chunk_cata("cccc", master_key, shapad1, magic3, shapad2);
456 hasher->allocate_hash(hasher, concat, &master_send_key);
457 master_send_key.len = 16;
458
459 *msk = chunk_cat("cccc", master_receive_key, master_send_key, keypad, keypad);
460
461 hasher->destroy(hasher);
462 chunk_free(&master_key);
463 chunk_free(&master_receive_key);
464 chunk_free(&master_send_key);
465 return SUCCESS;
466 }
467
468 static status_t GenerateStuff(private_eap_mschapv2_t *this,
469 chunk_t server_challenge, chunk_t peer_challenge,
470 chunk_t username, chunk_t nt_hash)
471 {
472 status_t status = FAILED;
473 chunk_t nt_hash_hash = chunk_empty, challenge_hash = chunk_empty;
474
475 if (NtPasswordHash(nt_hash, &nt_hash_hash) != SUCCESS)
476 {
477 goto error;
478 }
479 if (ChallengeHash(peer_challenge, server_challenge, username,
480 &challenge_hash) != SUCCESS)
481 {
482 goto error;
483 }
484 if (ChallengeResponse(challenge_hash, nt_hash,
485 &this->nt_response) != SUCCESS)
486 {
487 goto error;
488 }
489 if (AuthenticatorResponse(nt_hash_hash, challenge_hash,
490 this->nt_response, &this->auth_response) != SUCCESS)
491 {
492 goto error;
493 }
494 if (GenerateMSK(nt_hash_hash, this->nt_response, &this->msk) != SUCCESS)
495 {
496 goto error;
497 }
498
499 status = SUCCESS;
500
501 error:
502 chunk_free(&nt_hash_hash);
503 chunk_free(&challenge_hash);
504 return status;
505 }
506
507 /**
508 * Converts an ASCII string into a UTF-16 (little-endian) string
509 */
510 static chunk_t ascii_to_unicode(chunk_t ascii)
511 {
512 int i;
513 chunk_t unicode = chunk_alloc(ascii.len * 2);
514 for (i = 0; i < ascii.len; i++)
515 {
516 unicode.ptr[i * 2] = ascii.ptr[i];
517 unicode.ptr[i * 2 + 1] = 0;
518 }
519 return unicode;
520 }
521
522 /**
523 * sanitize a string for printing
524 */
525 static char* sanitize(char *str)
526 {
527 char *pos = str;
528
529 while (pos && *pos)
530 {
531 if (!isprint(*pos))
532 {
533 *pos = '?';
534 }
535 pos++;
536 }
537 return str;
538 }
539
540 /**
541 * Returns a chunk of just the username part of the given user identity.
542 * Note: the chunk points to internal data of the identification.
543 */
544 static chunk_t extract_username(identification_t* identification)
545 {
546 char *has_domain;
547 chunk_t id;
548 id = identification->get_encoding(identification);
549 has_domain = (char*)memchr(id.ptr, '\\', id.len);
550 if (has_domain)
551 {
552 int len;
553 has_domain++; /* skip the backslash */
554 len = id.len - ((u_char*)has_domain - id.ptr);
555 return len > 0 ? chunk_create(has_domain, len) : chunk_empty;
556 }
557 return id;
558 }
559
560 /**
561 * Set the ms_length field using aligned write
562 */
563 static void set_ms_length(eap_mschapv2_header_t *eap, u_int16_t len)
564 {
565 len = htons(len - 5);
566 memcpy(&eap->ms_length, &len, sizeof(u_int16_t));
567 }
568
569 METHOD(eap_method_t, initiate_peer, status_t,
570 private_eap_mschapv2_t *this, eap_payload_t **out)
571 {
572 /* peer never initiates */
573 return FAILED;
574 }
575
576 METHOD(eap_method_t, initiate_server, status_t,
577 private_eap_mschapv2_t *this, eap_payload_t **out)
578 {
579 rng_t *rng;
580 eap_mschapv2_header_t *eap;
581 eap_mschapv2_challenge_t *cha;
582 const char *name = MSCHAPV2_HOST_NAME;
583 u_int16_t len = CHALLENGE_PAYLOAD_LEN + sizeof(MSCHAPV2_HOST_NAME) - 1;
584
585 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
586 if (!rng || !rng->allocate_bytes(rng, CHALLENGE_LEN, &this->challenge))
587 {
588 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no challenge");
589 DESTROY_IF(rng);
590 return FAILED;
591 }
592 rng->destroy(rng);
593
594 eap = alloca(len);
595 eap->code = EAP_REQUEST;
596 eap->identifier = this->identifier;
597 eap->length = htons(len);
598 eap->type = EAP_MSCHAPV2;
599 eap->opcode = MSCHAPV2_CHALLENGE;
600 eap->ms_chapv2_id = this->mschapv2id;
601 set_ms_length(eap, len);
602
603 cha = (eap_mschapv2_challenge_t*)eap->data;
604 cha->value_size = CHALLENGE_LEN;
605 memcpy(cha->challenge, this->challenge.ptr, this->challenge.len);
606 memcpy(cha->name, name, sizeof(MSCHAPV2_HOST_NAME) - 1);
607
608 *out = eap_payload_create_data(chunk_create((void*) eap, len));
609 return NEED_MORE;
610 }
611
612 static bool get_nt_hash(private_eap_mschapv2_t *this, identification_t *me,
613 identification_t *other, chunk_t *nt_hash)
614 {
615 shared_key_t *shared;
616 chunk_t password;
617
618 /* try to find a stored NT_HASH first */
619 shared = lib->credmgr->get_shared(lib->credmgr, SHARED_NT_HASH, me, other);
620 if (shared )
621 {
622 *nt_hash = chunk_clone(shared->get_key(shared));
623 shared->destroy(shared);
624 return TRUE;
625 }
626
627 /* fallback to plaintext password */
628 shared = lib->credmgr->get_shared(lib->credmgr, 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 peer_challenge = chunk_alloca(CHALLENGE_LEN);
680 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
681 if (!rng || !rng->get_bytes(rng, CHALLENGE_LEN, peer_challenge.ptr))
682 {
683 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, allocating challenge failed");
684 DESTROY_IF(rng);
685 return FAILED;
686 }
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 = 0;
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 /* ignore retriable */
852 }
853 else if (strneq(token, "C=", 2))
854 {
855 chunk_t hex;
856 token += 2;
857 if (strlen(token) != 2 * CHALLENGE_LEN)
858 {
859 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message:"
860 "invalid challenge");
861 goto error;
862 }
863 hex = chunk_create(token, 2 * CHALLENGE_LEN);
864 challenge = chunk_from_hex(hex, NULL);
865 }
866 else if (strneq(token, "V=", 2))
867 {
868 /* ignore version */
869 }
870 else if (strneq(token, "M=", 2))
871 {
872 token += 2;
873 msg = strdup(token);
874 }
875 }
876 enumerator->destroy(enumerator);
877
878 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed with error %N: '%s'",
879 mschapv2_error_names, error, sanitize(msg));
880
881 /**
882 * at this point, if the error is retriable, we MAY retry the authentication
883 * or MAY send a Change Password packet.
884 *
885 * if the error is not retriable (or if we do neither of the above), we
886 * SHOULD send a Failure Response packet.
887 * windows clients don't do that, and since windows server 2008 r2 behaves
888 * pretty odd if we do send a Failure Response, we just don't send one
889 * either. windows 7 actually sends a delete notify (which, according to the
890 * logs, results in an error on windows server 2008 r2).
891 *
892 * btw, windows server 2008 r2 does not send non-retriable errors for e.g.
893 * a disabled account but returns the windows error code in a notify payload
894 * of type 12345.
895 */
896
897 status = FAILED;
898
899 error:
900 chunk_free(&challenge);
901 free(message);
902 free(msg);
903 return status;
904 }
905
906 METHOD(eap_method_t, process_peer, status_t,
907 private_eap_mschapv2_t *this, eap_payload_t *in, eap_payload_t **out)
908 {
909 chunk_t data;
910 eap_mschapv2_header_t *eap;
911
912 this->identifier = in->get_identifier(in);
913 data = in->get_data(in);
914 if (data.len < SHORT_HEADER_LEN)
915 {
916 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message");
917 return FAILED;
918 }
919
920 eap = (eap_mschapv2_header_t*)data.ptr;
921
922 switch (eap->opcode)
923 {
924 case MSCHAPV2_CHALLENGE:
925 {
926 return process_peer_challenge(this, in, out);
927 }
928 case MSCHAPV2_SUCCESS:
929 {
930 return process_peer_success(this, in, out);
931 }
932 case MSCHAPV2_FAILURE:
933 {
934 return process_peer_failure(this, in, out);
935 }
936 default:
937 {
938 DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
939 "OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
940 break;
941 }
942 }
943 return FAILED;
944 }
945
946 /**
947 * Handles retries on the server
948 */
949 static status_t process_server_retry(private_eap_mschapv2_t *this,
950 eap_payload_t **out)
951 {
952 eap_mschapv2_header_t *eap;
953 rng_t *rng;
954 chunk_t hex;
955 char msg[FAILURE_MESSAGE_LEN];
956 u_int16_t len = HEADER_LEN + FAILURE_MESSAGE_LEN - 1; /* no null byte */
957
958 if (++this->retries > MAX_RETRIES)
959 {
960 /* we MAY send a Failure Request with R=0, but windows 7 does not
961 * really like that and does not respond with a Failure Response.
962 * so, to clean up our state we just fail with an EAP-Failure.
963 * this gives an unknown error on the windows side, but is also fine
964 * with the standard. */
965 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed: "
966 "maximum number of retries reached");
967 return FAILED;
968 }
969
970 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed, retry (%d)", this->retries);
971
972 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
973 if (!rng || !rng->get_bytes(rng, CHALLENGE_LEN, this->challenge.ptr))
974 {
975 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, allocating challenge failed");
976 DESTROY_IF(rng);
977 return FAILED;
978 }
979 rng->destroy(rng);
980
981 chunk_free(&this->nt_response);
982 chunk_free(&this->auth_response);
983 chunk_free(&this->msk);
984
985 eap = alloca(len);
986 eap->code = EAP_REQUEST;
987 eap->identifier = ++this->identifier;
988 eap->length = htons(len);
989 eap->type = EAP_MSCHAPV2;
990 eap->opcode = MSCHAPV2_FAILURE;
991 eap->ms_chapv2_id = this->mschapv2id++; /* increase for each retry */
992 set_ms_length(eap, len);
993
994 hex = chunk_to_hex(this->challenge, NULL, TRUE);
995 snprintf(msg, FAILURE_MESSAGE_LEN, "%s%s", FAILURE_MESSAGE, hex.ptr);
996 chunk_free(&hex);
997 memcpy(eap->data, msg, FAILURE_MESSAGE_LEN - 1); /* no null byte */
998 *out = eap_payload_create_data(chunk_create((void*) eap, len));
999
1000 /* delay the response for some time to make brute-force attacks harder */
1001 sleep(RETRY_DELAY);
1002
1003 return NEED_MORE;
1004 }
1005
1006 /**
1007 * Process MS-CHAPv2 Response response packets
1008 */
1009 static status_t process_server_response(private_eap_mschapv2_t *this,
1010 eap_payload_t *in, eap_payload_t **out)
1011 {
1012 eap_mschapv2_header_t *eap;
1013 eap_mschapv2_response_t *res;
1014 chunk_t data, peer_challenge, username, nt_hash;
1015 identification_t *userid;
1016 int name_len;
1017 char buf[256];
1018
1019 data = in->get_data(in);
1020 eap = (eap_mschapv2_header_t*)data.ptr;
1021
1022 if (data.len < RESPONSE_PAYLOAD_LEN)
1023 {
1024 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
1025 return FAILED;
1026 }
1027
1028 res = (eap_mschapv2_response_t*)eap->data;
1029 peer_challenge = chunk_create(res->response.peer_challenge, CHALLENGE_LEN);
1030
1031 name_len = min(data.len - RESPONSE_PAYLOAD_LEN, 255);
1032 snprintf(buf, sizeof(buf), "%.*s", name_len, res->name);
1033 userid = identification_create_from_string(buf);
1034 DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%Y'", userid);
1035 username = extract_username(userid);
1036
1037 if (!get_nt_hash(this, this->server, userid, &nt_hash))
1038 {
1039 DBG1(DBG_IKE, "no EAP key found for hosts '%Y' - '%Y'",
1040 this->server, userid);
1041 /* FIXME: windows 7 always sends the username that is first entered in
1042 * the username box, even, if the user changes it during retries (probably
1043 * to keep consistent with the EAP-Identity).
1044 * thus, we could actually fail here, because retries do not make much
1045 * sense. on the other hand, an attacker could guess usernames, if the
1046 * error messages were different. */
1047 userid->destroy(userid);
1048 return process_server_retry(this, out);
1049 }
1050
1051 if (GenerateStuff(this, this->challenge, peer_challenge,
1052 username, nt_hash) != SUCCESS)
1053 {
1054 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed");
1055 userid->destroy(userid);
1056 chunk_clear(&nt_hash);
1057 return FAILED;
1058 }
1059 userid->destroy(userid);
1060 chunk_clear(&nt_hash);
1061
1062 if (memeq(res->response.nt_response, this->nt_response.ptr,
1063 this->nt_response.len))
1064 {
1065 chunk_t hex;
1066 char msg[AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE)];
1067 u_int16_t len = HEADER_LEN + AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE);
1068
1069 eap = alloca(len);
1070 eap->code = EAP_REQUEST;
1071 eap->identifier = ++this->identifier;
1072 eap->length = htons(len);
1073 eap->type = EAP_MSCHAPV2;
1074 eap->opcode = MSCHAPV2_SUCCESS;
1075 eap->ms_chapv2_id = this->mschapv2id;
1076 set_ms_length(eap, len);
1077
1078 hex = chunk_to_hex(this->auth_response, NULL, TRUE);
1079 snprintf(msg, AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE),
1080 "S=%s%s", hex.ptr, SUCCESS_MESSAGE);
1081 chunk_free(&hex);
1082 memcpy(eap->data, msg, AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE));
1083 *out = eap_payload_create_data(chunk_create((void*) eap, len));
1084 return NEED_MORE;
1085 }
1086
1087 return process_server_retry(this, out);
1088 }
1089
1090 METHOD(eap_method_t, process_server, status_t,
1091 private_eap_mschapv2_t *this, eap_payload_t *in, eap_payload_t **out)
1092 {
1093 eap_mschapv2_header_t *eap;
1094 chunk_t data;
1095
1096 if (this->identifier != in->get_identifier(in))
1097 {
1098 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: "
1099 "unexpected identifier");
1100 return FAILED;
1101 }
1102
1103 data = in->get_data(in);
1104 if (data.len < SHORT_HEADER_LEN)
1105 {
1106 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
1107 return FAILED;
1108 }
1109
1110 eap = (eap_mschapv2_header_t*)data.ptr;
1111
1112 switch (eap->opcode)
1113 {
1114 case MSCHAPV2_RESPONSE:
1115 {
1116 return process_server_response(this, in, out);
1117 }
1118 case MSCHAPV2_SUCCESS:
1119 {
1120 return SUCCESS;
1121 }
1122 case MSCHAPV2_FAILURE:
1123 {
1124 return FAILED;
1125 }
1126 default:
1127 {
1128 DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
1129 "OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
1130 break;
1131 }
1132 }
1133 return FAILED;
1134 }
1135
1136 METHOD(eap_method_t, get_type, eap_type_t,
1137 private_eap_mschapv2_t *this, u_int32_t *vendor)
1138 {
1139 *vendor = 0;
1140 return EAP_MSCHAPV2;
1141 }
1142
1143 METHOD(eap_method_t, get_msk, status_t,
1144 private_eap_mschapv2_t *this, chunk_t *msk)
1145 {
1146 if (this->msk.ptr)
1147 {
1148 *msk = this->msk;
1149 return SUCCESS;
1150 }
1151 return FAILED;
1152 }
1153
1154 METHOD(eap_method_t, get_identifier, u_int8_t,
1155 private_eap_mschapv2_t *this)
1156 {
1157 return this->identifier;
1158 }
1159
1160 METHOD(eap_method_t, set_identifier, void,
1161 private_eap_mschapv2_t *this, u_int8_t identifier)
1162 {
1163 this->identifier = identifier;
1164 }
1165
1166 METHOD(eap_method_t, is_mutual, bool,
1167 private_eap_mschapv2_t *this)
1168 {
1169 return FALSE;
1170 }
1171
1172 METHOD(eap_method_t, destroy, void,
1173 private_eap_mschapv2_t *this)
1174 {
1175 this->peer->destroy(this->peer);
1176 this->server->destroy(this->server);
1177 chunk_free(&this->challenge);
1178 chunk_free(&this->nt_response);
1179 chunk_free(&this->auth_response);
1180 chunk_free(&this->msk);
1181 free(this);
1182 }
1183
1184 /**
1185 * Generic constructor
1186 */
1187 static private_eap_mschapv2_t *eap_mschapv2_create_generic(identification_t *server, identification_t *peer)
1188 {
1189 private_eap_mschapv2_t *this;
1190
1191 INIT(this,
1192 .public = {
1193 .eap_method_interface = {
1194 .get_type = _get_type,
1195 .is_mutual = _is_mutual,
1196 .get_msk = _get_msk,
1197 .get_identifier = _get_identifier,
1198 .set_identifier = _set_identifier,
1199 .destroy = _destroy,
1200 },
1201 },
1202 .peer = peer->clone(peer),
1203 .server = server->clone(server),
1204 );
1205
1206 return this;
1207 }
1208
1209 /*
1210 * see header
1211 */
1212 eap_mschapv2_t *eap_mschapv2_create_server(identification_t *server, identification_t *peer)
1213 {
1214 private_eap_mschapv2_t *this = eap_mschapv2_create_generic(server, peer);
1215
1216 this->public.eap_method_interface.initiate = _initiate_server;
1217 this->public.eap_method_interface.process = _process_server;
1218
1219 /* generate a non-zero identifier */
1220 do
1221 {
1222 this->identifier = random();
1223 } while (!this->identifier);
1224
1225 this->mschapv2id = this->identifier;
1226
1227 return &this->public;
1228 }
1229
1230 /*
1231 * see header
1232 */
1233 eap_mschapv2_t *eap_mschapv2_create_peer(identification_t *server, identification_t *peer)
1234 {
1235 private_eap_mschapv2_t *this = eap_mschapv2_create_generic(server, peer);
1236
1237 this->public.eap_method_interface.initiate = _initiate_peer;
1238 this->public.eap_method_interface.process = _process_peer;
1239
1240 return &this->public;
1241 }
1242