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