adding plugin for EAP-MS-CHAPv2
[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, 64);
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(&expanded);
343 }
344 crypter->destroy(crypter);
345 return SUCCESS;
346 }
347
348 /**
349 * Computes the authenticator response
350 */
351 static status_t AuthenticatorResponse(chunk_t password_hash_hash,
352 chunk_t challenge_hash, chunk_t nt_response, chunk_t *response)
353 {
354 static u_int8_t magic1_data[] =
355 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
356 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
357 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
358 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
359 static u_int8_t magic2_data[] =
360 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
361 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
362 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
363 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
364 0x6E };
365 static const chunk_t magic1 = chunk_from_buf(magic1_data);
366 static const chunk_t magic2 = chunk_from_buf(magic2_data);
367
368 status_t status = FAILED;
369 chunk_t digest = chunk_empty, concat;
370 hasher_t *hasher;
371
372 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
373 if (hasher == NULL)
374 {
375 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, SHA1 not supported");
376 return FAILED;
377 }
378
379 concat = chunk_cata("ccc", password_hash_hash, nt_response, magic1);
380 hasher->allocate_hash(hasher, concat, &digest);
381 concat = chunk_cata("ccc", digest, challenge_hash, magic2);
382 hasher->allocate_hash(hasher, concat, response);
383
384 hasher->destroy(hasher);
385 chunk_free(&digest);
386 return SUCCESS;
387 }
388
389 /**
390 * Generate the master session key according to RFC3079
391 */
392 static status_t GenerateMSK(chunk_t password_hash_hash,
393 chunk_t nt_response, chunk_t *msk)
394 {
395 static u_int8_t magic1_data[] =
396 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
397 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
398 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
399 static u_int8_t magic2_data[] =
400 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
401 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
402 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
403 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
404 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
405 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
406 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
407 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
408 0x6b, 0x65, 0x79, 0x2e };
409 static u_int8_t magic3_data[] =
410 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
411 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
412 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
413 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
414 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
415 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
416 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
417 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
418 0x6b, 0x65, 0x79, 0x2e };
419 static u_int8_t shapad1_data[] =
420 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 static u_int8_t shapad2_data[] =
425 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
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 static const chunk_t magic1 = chunk_from_buf(magic1_data);
430 static const chunk_t magic2 = chunk_from_buf(magic2_data);
431 static const chunk_t magic3 = chunk_from_buf(magic3_data);
432 static const chunk_t shapad1 = chunk_from_buf(shapad1_data);
433 static const chunk_t shapad2 = chunk_from_buf(shapad2_data);
434 static const chunk_t keypad = { shapad1_data, 16 };
435
436 chunk_t concat, master_key, master_receive_key, master_send_key;
437 hasher_t *hasher;
438
439 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
440 if (hasher == NULL)
441 {
442 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, SHA1 not supported");
443 return FAILED;
444 }
445
446 concat = chunk_cata("ccc", password_hash_hash, nt_response, magic1);
447 hasher->allocate_hash(hasher, concat, &master_key);
448 master_key.len = 16;
449
450 concat = chunk_cata("cccc", master_key, shapad1, magic2, shapad2);
451 hasher->allocate_hash(hasher, concat, &master_receive_key);
452 master_receive_key.len = 16;
453
454 concat = chunk_cata("cccc", master_key, shapad1, magic3, shapad2);
455 hasher->allocate_hash(hasher, concat, &master_send_key);
456 master_send_key.len = 16;
457
458 *msk = chunk_cat("cccc", master_receive_key, keypad, master_send_key, keypad);
459
460 hasher->destroy(hasher);
461 chunk_free(&master_key);
462 chunk_free(&master_receive_key);
463 chunk_free(&master_send_key);
464 return SUCCESS;
465 }
466
467 static status_t GenerateStuff(private_eap_mschapv2_t *this,
468 chunk_t server_challenge, chunk_t peer_challenge,
469 chunk_t username, chunk_t password)
470 {
471 status_t status = FAILED;
472 chunk_t password_hash = chunk_empty, password_hash_hash = chunk_empty,
473 challenge_hash = chunk_empty;
474
475 if (NtPasswordHash(password, &password_hash) != SUCCESS)
476 {
477 goto error;
478 }
479 if (NtPasswordHash(password_hash, &password_hash_hash) != SUCCESS)
480 {
481 goto error;
482 }
483 if (ChallengeHash(peer_challenge, server_challenge, username,
484 &challenge_hash) != SUCCESS)
485 {
486 goto error;
487 }
488
489 if (ChallengeResponse(challenge_hash, password_hash,
490 &this->nt_response) != SUCCESS)
491 {
492 goto error;
493 }
494 if (AuthenticatorResponse(password_hash_hash, challenge_hash,
495 this->nt_response, &this->auth_response) != SUCCESS)
496 {
497 goto error;
498 }
499 if (GenerateMSK(password_hash_hash, this->nt_response, &this->msk) != SUCCESS)
500 {
501 goto error;
502 }
503
504 status = SUCCESS;
505
506 error:
507 chunk_free(&password_hash);
508 chunk_free(&password_hash_hash);
509 chunk_free(&challenge_hash);
510 return status;
511 }
512
513 /**
514 * Converts an ASCII string into a UTF-16 (little-endian) string
515 */
516 static chunk_t ascii_to_unicode(chunk_t ascii)
517 {
518 int i;
519 chunk_t unicode = chunk_alloc(ascii.len * 2);
520 for (i = 0; i < ascii.len; i++)
521 {
522 unicode.ptr[i * 2] = ascii.ptr[i];
523 unicode.ptr[i * 2 + 1] = 0;
524 }
525 return unicode;
526 }
527
528 /**
529 * Returns a chunk of just the username part of the given user identity.
530 * Note: the chunk points to internal data of the identification.
531 */
532 static chunk_t extract_username(identification_t* identification)
533 {
534 char *has_domain;
535 chunk_t id;
536 id = identification->get_encoding(identification);
537 has_domain = (char*)memrchr(id.ptr, '\\', id.len);
538 if (has_domain)
539 {
540 int len;
541 has_domain++; /* skip the backslash */
542 len = id.len - ((u_char*)has_domain - id.ptr);
543 return len > 0 ? chunk_create(has_domain, len) : chunk_empty;
544 }
545 return id;
546 }
547
548
549 /**
550 * Implementation of eap_method_t.initiate for the peer
551 */
552 static status_t initiate_peer(private_eap_mschapv2_t *this, eap_payload_t **out)
553 {
554 /* peer never initiates */
555 return FAILED;
556 }
557
558 /**
559 * Implementation of eap_method_t.initiate for the server
560 */
561 static status_t initiate_server(private_eap_mschapv2_t *this, eap_payload_t **out)
562 {
563 rng_t *rng;
564 eap_mschapv2_header_t *eap;
565 eap_mschapv2_challenge_t *cha;
566 const char *name = MSCHAPV2_HOST_NAME;
567 u_int16_t len = CHALLENGE_PAYLOAD_LEN + sizeof(MSCHAPV2_HOST_NAME) - 1;
568
569 DBG1(DBG_IKE, "initiating EAP-MS-CHAPv2");
570
571 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
572 if (!rng)
573 {
574 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no RNG");
575 return FAILED;
576 }
577 rng->allocate_bytes(rng, CHALLENGE_LEN, &this->challenge);
578 rng->destroy(rng);
579
580 eap = alloca(len);
581 eap->code = EAP_REQUEST;
582 eap->identifier = this->identifier;
583 eap->length = htons(len);
584 eap->type = EAP_MSCHAPV2;
585 eap->opcode = MSCHAPV2_CHALLENGE;
586 eap->ms_chapv2_id = this->mschapv2id;
587 eap->ms_length = htons(len - 5);
588
589 cha = (eap_mschapv2_challenge_t*)eap->data;
590 cha->value_size = CHALLENGE_LEN;
591 memcpy(cha->challenge, this->challenge.ptr, this->challenge.len);
592 memcpy(cha->name, name, sizeof(MSCHAPV2_HOST_NAME) - 1);
593
594 *out = eap_payload_create_data(chunk_create((void*) eap, len));
595 return NEED_MORE;
596 }
597
598
599 /**
600 * Process MS-CHAPv2 Challenge Requests
601 */
602 static status_t process_peer_challenge(private_eap_mschapv2_t *this,
603 eap_payload_t *in, eap_payload_t **out)
604 {
605 rng_t *rng;
606 eap_mschapv2_header_t *eap;
607 eap_mschapv2_challenge_t *cha;
608 eap_mschapv2_response_t *res;
609 shared_key_t *shared;
610 chunk_t data, peer_challenge, username, password;
611 u_int16_t len = RESPONSE_PAYLOAD_LEN;
612
613 data = in->get_data(in);
614 eap = (eap_mschapv2_header_t*)data.ptr;
615
616 /* the name MUST be at least one octet long */
617 if (data.len < CHALLENGE_PAYLOAD_LEN + 1)
618 {
619 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
620 return FAILED;
621 }
622
623 cha = (eap_mschapv2_challenge_t*)eap->data;
624
625 if (cha->value_size != CHALLENGE_LEN)
626 {
627 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: invalid challenge size");
628 return FAILED;
629 }
630
631 this->mschapv2id = eap->ms_chapv2_id;
632 this->challenge = chunk_clone(chunk_create(cha->challenge, CHALLENGE_LEN));
633
634 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
635 if (!rng)
636 {
637 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no RNG");
638 return FAILED;
639 }
640 peer_challenge = chunk_alloca(CHALLENGE_LEN);
641 rng->get_bytes(rng, CHALLENGE_LEN, peer_challenge.ptr);
642 rng->destroy(rng);
643
644 shared = charon->credentials->get_shared(charon->credentials,
645 SHARED_EAP, this->server, this->peer);
646 if (shared == NULL)
647 {
648 DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'",
649 this->server, this->peer);
650 return NOT_FOUND;
651 }
652
653 password = ascii_to_unicode(shared->get_key(shared));
654 shared->destroy(shared);
655
656 username = extract_username(this->peer);
657 len += username.len;
658
659 if (GenerateStuff(this, this->challenge, peer_challenge, username, password) != SUCCESS)
660 {
661 DBG1(DBG_IKE, "EAP-MS-CHAPv2 generating NT-Response failed");
662 chunk_clear(&password);
663 return FAILED;
664 }
665 chunk_clear(&password);
666
667 eap = alloca(len);
668 eap->code = EAP_RESPONSE;
669 eap->identifier = this->identifier;
670 eap->length = htons(len);
671 eap->type = EAP_MSCHAPV2;
672 eap->opcode = MSCHAPV2_RESPONSE;
673 eap->ms_chapv2_id = this->mschapv2id;
674 eap->ms_length = htons(len - 5);
675
676 res = (eap_mschapv2_response_t*)eap->data;
677 res->value_size = RESPONSE_LEN;
678 memset(&res->response, 0, RESPONSE_LEN);
679 memcpy(res->response.peer_challenge, peer_challenge.ptr, peer_challenge.len);
680 memcpy(res->response.nt_response, this->nt_response.ptr, this->nt_response.len);
681
682 username = this->peer->get_encoding(this->peer);
683 memcpy(res->name, username.ptr, username.len);
684
685 *out = eap_payload_create_data(chunk_create((void*) eap, len));
686 return NEED_MORE;
687 }
688
689 /**
690 * Process MS-CHAPv2 Success Requests
691 */
692 static status_t process_peer_success(private_eap_mschapv2_t *this,
693 eap_payload_t *in, eap_payload_t **out)
694 {
695 status_t status = FAILED;
696 enumerator_t *enumerator;
697 eap_mschapv2_header_t *eap;
698 chunk_t data, auth_string = chunk_empty;
699 char *message, *token, *msg = NULL;
700 int message_len;
701 u_int16_t len = SHORT_HEADER_LEN;
702
703 data = in->get_data(in);
704 eap = (eap_mschapv2_header_t*)data.ptr;
705
706 if (data.len < AUTH_RESPONSE_LEN)
707 {
708 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
709 return FAILED;
710 }
711
712 message_len = data.len - HEADER_LEN + 1; /* + null byte */
713 message = malloc(message_len);
714 memcpy(message, eap->data, message_len - 1);
715 message[message_len] = '\0';
716
717 /* S=<auth_string> M=<msg> */
718 enumerator = enumerator_create_token(message, " ", " ");
719 while (enumerator->enumerate(enumerator, &token))
720 {
721 if (strneq(token, "S=", 2))
722 {
723 chunk_t hex;
724 token += 2;
725 if (strlen(token) != AUTH_RESPONSE_LEN - 2)
726 {
727 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: invalid auth string");
728 goto error;
729 }
730 hex = chunk_create(token, AUTH_RESPONSE_LEN - 2);
731 auth_string = chunk_from_hex(hex, NULL);
732 }
733 else if (strneq(token, "M=", 2))
734 {
735 token += 2;
736 msg = strdup(token);
737 }
738 }
739 enumerator->destroy(enumerator);
740
741 if (auth_string.ptr == NULL)
742 {
743 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: auth string missing");
744 goto error;
745 }
746
747 if (!chunk_equals(this->auth_response, auth_string))
748 {
749 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed");
750 goto error;
751 }
752
753 DBG1(DBG_IKE, "EAP-MS-CHAPv2 succeeded: '%s'", msg);
754
755 eap = alloca(len);
756 eap->code = EAP_RESPONSE;
757 eap->identifier = this->identifier;
758 eap->length = htons(len);
759 eap->type = EAP_MSCHAPV2;
760 eap->opcode = MSCHAPV2_SUCCESS;
761
762 *out = eap_payload_create_data(chunk_create((void*) eap, len));
763 status = NEED_MORE;
764
765 error:
766 chunk_free(&auth_string);
767 free(message);
768 free(msg);
769 return status;
770 }
771
772 static status_t process_peer_failure(private_eap_mschapv2_t *this,
773 eap_payload_t *in, eap_payload_t **out)
774 {
775 status_t status = FAILED;
776 enumerator_t *enumerator;
777 eap_mschapv2_header_t *eap;
778 chunk_t data;
779 char *message, *token, *msg = NULL;
780 int message_len, error, retryable;
781 chunk_t challenge = chunk_empty;
782 u_int16_t len = SHORT_HEADER_LEN;
783
784 data = in->get_data(in);
785 eap = (eap_mschapv2_header_t*)data.ptr;
786
787 if (data.len < 3) /* we want at least an error code: E=e */
788 {
789 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
790 return FAILED;
791 }
792
793 message_len = data.len - HEADER_LEN;
794 message = malloc(message_len + 1);
795 memcpy(message, eap->data, message_len);
796 message[message_len] = '\0';
797
798 /* E=eeeeeeeeee R=r C=cccccccccccccccccccccccccccccccc V=vvvvvvvvvv M=<msg> */
799 enumerator = enumerator_create_token(message, " ", " ");
800 while (enumerator->enumerate(enumerator, &token))
801 {
802 if (strneq(token, "E=", 2))
803 {
804 token += 2;
805 error = atoi(token);
806 }
807 else if (strneq(token, "R=", 2))
808 {
809 token += 2;
810 retryable = atoi(token);
811 }
812 else if (strneq(token, "C=", 2))
813 {
814 chunk_t hex;
815 token += 2;
816 if (strlen(token) != 2 * CHALLENGE_LEN)
817 {
818 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: invalid challenge");
819 goto error;
820 }
821 hex = chunk_create(token, 2 * CHALLENGE_LEN);
822 challenge = chunk_from_hex(hex, NULL);
823 }
824 else if (strneq(token, "V=", 2))
825 {
826 int version;
827 token += 2;
828 version = atoi(token);
829 }
830 else if (strneq(token, "M=", 2))
831 {
832 token += 2;
833 msg = strdup(token);
834 }
835 }
836 enumerator->destroy(enumerator);
837
838 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed with error %N: '%s'", mschapv2_error_names, error, msg);
839
840 /**
841 * at this point, if the error is retryable, we MAY retry the
842 * authentication or MAY send a Change Password packet.
843 *
844 * if the error is not retryable (or if we do neither of the
845 * above), we SHOULD send a Failure Response packet.
846 * windows clients don't do that, and since windows server 2008 r2
847 * behaves pretty odd if we do send a Failure Response, we just
848 * don't send one either.
849 *
850 * btw, windows server 2008 r2 does not send non-retryable errors
851 * for e.g. a disabled account but returns the windows error code in
852 * a notify payload of type 12345.
853 */
854
855 status = FAILED;
856
857 error:
858 chunk_free(&challenge);
859 free(message);
860 free(msg);
861 return status;
862 }
863
864 /**
865 * Implementation of eap_method_t.process for the peer
866 */
867 static status_t process_peer(private_eap_mschapv2_t *this, eap_payload_t *in,
868 eap_payload_t **out)
869 {
870 chunk_t data;
871 eap_mschapv2_header_t *eap;
872
873 this->identifier = in->get_identifier(in);
874 data = in->get_data(in);
875 if (data.len < SHORT_HEADER_LEN)
876 {
877 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message");
878 return FAILED;
879 }
880
881 eap = (eap_mschapv2_header_t*)data.ptr;
882
883 switch (eap->opcode)
884 {
885 case MSCHAPV2_CHALLENGE:
886 {
887 return process_peer_challenge(this, in, out);
888 }
889 case MSCHAPV2_SUCCESS:
890 {
891 return process_peer_success(this, in, out);
892 }
893 case MSCHAPV2_FAILURE:
894 {
895 return process_peer_failure(this, in, out);
896 }
897 default:
898 {
899 DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported OpCode (%N)!",
900 mschapv2_opcode_names, eap->opcode);
901 break;
902 }
903 }
904 return FAILED;
905 }
906
907 /**
908 * Handles retries on the server
909 */
910 static status_t process_server_retry(private_eap_mschapv2_t *this,
911 eap_payload_t **out)
912 {
913 eap_mschapv2_header_t *eap;
914 rng_t *rng;
915 chunk_t hex;
916 char msg[FAILURE_MESSAGE_LEN];
917 u_int16_t len = HEADER_LEN + FAILURE_MESSAGE_LEN - 1;
918
919 if (++this->retries > MAX_RETRIES)
920 {
921 /* we MAY send a Failure Request with R=0, but windows 7 does not
922 * really like that and does not respond with a Failure Response.
923 * so, to clean up our state we just fail with an EAP-Failure.
924 * this gives an unknown error on the windows side, but is also fine
925 * with the standard. */
926 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed: maximum number of retries reached");
927 return FAILED;
928 }
929
930 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed, retry (%d)", this->retries);
931
932 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
933 if (!rng)
934 {
935 DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no RNG");
936 return FAILED;
937 }
938 rng->get_bytes(rng, CHALLENGE_LEN, this->challenge.ptr);
939 rng->destroy(rng);
940
941 eap = alloca(len);
942 eap->code = EAP_REQUEST;
943 eap->identifier = ++this->identifier;
944 eap->length = htons(len);
945 eap->type = EAP_MSCHAPV2;
946 eap->opcode = MSCHAPV2_FAILURE;
947 eap->ms_chapv2_id = this->mschapv2id++; /* increase for each retry */
948 eap->ms_length = htons(len - 5);
949
950 hex = chunk_to_hex(this->challenge, NULL, TRUE);
951 snprintf(msg, FAILURE_MESSAGE_LEN, "%s%s", FAILURE_MESSAGE, hex.ptr);
952 chunk_free(&hex);
953 memcpy(eap->data, msg, FAILURE_MESSAGE_LEN - 1);
954 *out = eap_payload_create_data(chunk_create((void*) eap, len));
955
956 /* delay the response for some time to make brute-force attacks harder */
957 sleep(RETRY_DELAY);
958
959 return NEED_MORE;
960 }
961
962 /**
963 * Process MS-CHAPv2 Response response packets
964 */
965 static status_t process_server_response(private_eap_mschapv2_t *this,
966 eap_payload_t *in, eap_payload_t **out)
967 {
968 eap_mschapv2_header_t *eap;
969 eap_mschapv2_response_t *res;
970 chunk_t data, peer_challenge, username, password;
971 identification_t *userid;
972 shared_key_t *shared;
973 int name_len;
974
975 data = in->get_data(in);
976 eap = (eap_mschapv2_header_t*)data.ptr;
977
978 if (data.len < RESPONSE_PAYLOAD_LEN)
979 {
980 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
981 return FAILED;
982 }
983
984 res = (eap_mschapv2_response_t*)eap->data;
985 peer_challenge = chunk_create(res->response.peer_challenge, CHALLENGE_LEN);
986
987 name_len = min(data.len - RESPONSE_PAYLOAD_LEN, 255);
988 userid = identification_create_from_encoding(ID_EAP,
989 chunk_create(res->name, name_len));
990 username = extract_username(userid);
991 DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%.*s'", name_len, res->name);
992
993 shared = charon->credentials->get_shared(charon->credentials,
994 SHARED_EAP, this->server, userid);
995 if (shared == NULL)
996 {
997 DBG1(DBG_IKE, "no EAP key found for hosts '%D' - '%D'",
998 this->server, userid);
999 /* FIXME: windows 7 always sends the username that is first entered in
1000 * the username box, even, if the user changes it during retries (probably
1001 * to keep consistent with the EAP-Identity).
1002 * thus, we could actually fail here, because retries do not make much
1003 * sense. on the other hand, an attacker could guess usernames, if the
1004 * error messages were different. */
1005 return process_server_retry(this, out);
1006 }
1007
1008 password = ascii_to_unicode(shared->get_key(shared));
1009 shared->destroy(shared);
1010
1011 if (GenerateStuff(this, this->challenge, peer_challenge, username, password) != SUCCESS)
1012 {
1013 DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed");
1014 chunk_clear(&password);
1015 return FAILED;
1016 }
1017 chunk_clear(&password);
1018
1019 if (memeq(res->response.nt_response, this->nt_response.ptr, this->nt_response.len))
1020 {
1021 chunk_t hex;
1022 char msg[AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE)];
1023 u_int16_t len = HEADER_LEN + AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE);
1024
1025 eap = alloca(len);
1026 eap->code = EAP_REQUEST;
1027 eap->identifier = ++this->identifier;
1028 eap->length = htons(len);
1029 eap->type = EAP_MSCHAPV2;
1030 eap->opcode = MSCHAPV2_SUCCESS;
1031 eap->ms_chapv2_id = this->mschapv2id;
1032 eap->ms_length = htons(len - 5);
1033
1034 hex = chunk_to_hex(this->auth_response, NULL, TRUE);
1035 snprintf(msg, AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE),
1036 "S=%s%s", hex.ptr, SUCCESS_MESSAGE);
1037 chunk_free(&hex);
1038 memcpy(eap->data, msg, AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE));
1039 *out = eap_payload_create_data(chunk_create((void*) eap, len));
1040 return NEED_MORE;
1041 }
1042
1043 return process_server_retry(this, out);
1044 }
1045
1046 /**
1047 * Implementation of eap_method_t.process for the server
1048 */
1049 static status_t process_server(private_eap_mschapv2_t *this, eap_payload_t *in,
1050 eap_payload_t **out)
1051 {
1052 eap_mschapv2_header_t *eap;
1053 chunk_t data;
1054
1055 if (this->identifier != in->get_identifier(in))
1056 {
1057 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: unexpected identifier");
1058 return FAILED;
1059 }
1060
1061 data = in->get_data(in);
1062 if (data.len < SHORT_HEADER_LEN)
1063 {
1064 DBG1(DBG_IKE, "received invalid EAP-MS-CHAPv2 message: too short");
1065 return FAILED;
1066 }
1067
1068 eap = (eap_mschapv2_header_t*)data.ptr;
1069
1070 switch (eap->opcode)
1071 {
1072 case MSCHAPV2_RESPONSE:
1073 {
1074 return process_server_response(this, in, out);
1075 }
1076 case MSCHAPV2_SUCCESS:
1077 {
1078 return SUCCESS;
1079 }
1080 case MSCHAPV2_FAILURE:
1081 {
1082 return FAILED;
1083 }
1084 default:
1085 {
1086 DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported OpCode (%N)!",
1087 mschapv2_opcode_names, eap->opcode);
1088 break;
1089 }
1090 }
1091 return FAILED;
1092 }
1093
1094 /**
1095 * Implementation of eap_method_t.get_type.
1096 */
1097 static eap_type_t get_type(private_eap_mschapv2_t *this, u_int32_t *vendor)
1098 {
1099 *vendor = 0;
1100 return EAP_MSCHAPV2;
1101 }
1102
1103 /**
1104 * Implementation of eap_method_t.get_msk.
1105 */
1106 static status_t get_msk(private_eap_mschapv2_t *this, chunk_t *msk)
1107 {
1108 if (this->msk.ptr)
1109 {
1110 *msk = this->msk;
1111 return SUCCESS;
1112 }
1113 return FAILED;
1114 }
1115
1116 /**
1117 * Implementation of eap_method_t.is_mutual.
1118 */
1119 static bool is_mutual(private_eap_mschapv2_t *this)
1120 {
1121 return TRUE;
1122 }
1123
1124 /**
1125 * Implementation of eap_method_t.destroy.
1126 */
1127 static void destroy(private_eap_mschapv2_t *this)
1128 {
1129 this->peer->destroy(this->peer);
1130 this->server->destroy(this->server);
1131 chunk_free(&this->challenge);
1132 chunk_free(&this->nt_response);
1133 chunk_free(&this->auth_response);
1134 chunk_free(&this->msk);
1135 free(this);
1136 }
1137
1138 /**
1139 * Generic constructor
1140 */
1141 static private_eap_mschapv2_t *eap_mschapv2_create_generic(identification_t *server, identification_t *peer)
1142 {
1143 private_eap_mschapv2_t *this = malloc_thing(private_eap_mschapv2_t);
1144
1145 this->public.eap_method_interface.initiate = NULL;
1146 this->public.eap_method_interface.process = NULL;
1147 this->public.eap_method_interface.get_type = (eap_type_t(*)(eap_method_t*,u_int32_t*))get_type;
1148 this->public.eap_method_interface.is_mutual = (bool(*)(eap_method_t*))is_mutual;
1149 this->public.eap_method_interface.get_msk = (status_t(*)(eap_method_t*,chunk_t*))get_msk;
1150 this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
1151
1152 /* private data */
1153 this->peer = peer->clone(peer);
1154 this->server = server->clone(server);
1155 this->challenge = chunk_empty;
1156 this->nt_response = chunk_empty;
1157 this->auth_response = chunk_empty;
1158 this->msk = chunk_empty;
1159 this->identifier = 0;
1160 this->mschapv2id = 0;
1161 this->retries = 0;
1162
1163 return this;
1164 }
1165
1166 /*
1167 * see header
1168 */
1169 eap_mschapv2_t *eap_mschapv2_create_server(identification_t *server, identification_t *peer)
1170 {
1171 private_eap_mschapv2_t *this = eap_mschapv2_create_generic(server, peer);
1172
1173 this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_server;
1174 this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*, eap_payload_t**))process_server;
1175
1176 /* generate a non-zero identifier */
1177 do
1178 {
1179 this->identifier = random();
1180 } while (!this->identifier);
1181
1182 this->mschapv2id = this->identifier;
1183
1184 return &this->public;
1185 }
1186
1187 /*
1188 * see header
1189 */
1190 eap_mschapv2_t *eap_mschapv2_create_peer(identification_t *server, identification_t *peer)
1191 {
1192 private_eap_mschapv2_t *this = eap_mschapv2_create_generic(server, peer);
1193
1194 this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_peer;
1195 this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*, eap_payload_t**))process_peer;
1196
1197 return &this->public;
1198 }
1199