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