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