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