]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/crypto/ms_funcs.c
Update hostapd/wpa_supplicant to 2.8 to fix multiple vulnerabilities.
[FreeBSD/FreeBSD.git] / contrib / wpa / src / crypto / ms_funcs.c
1 /*
2  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
3  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "sha1.h"
13 #include "ms_funcs.h"
14 #include "crypto.h"
15
16 /**
17  * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
18  * @utf8_string: UTF-8 string (IN)
19  * @utf8_string_len: Length of utf8_string (IN)
20  * @ucs2_buffer: UCS-2 buffer (OUT)
21  * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
22  * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
23  * Returns: 0 on success, -1 on failure
24  */
25 static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
26                         u8 *ucs2_buffer, size_t ucs2_buffer_size,
27                         size_t *ucs2_string_size)
28 {
29         size_t i, j;
30
31         for (i = 0, j = 0; i < utf8_string_len; i++) {
32                 u8 c = utf8_string[i];
33                 if (j >= ucs2_buffer_size) {
34                         /* input too long */
35                         return -1;
36                 }
37                 if (c <= 0x7F) {
38                         WPA_PUT_LE16(ucs2_buffer + j, c);
39                         j += 2;
40                 } else if (i == utf8_string_len - 1 ||
41                            j >= ucs2_buffer_size - 1) {
42                         /* incomplete surrogate */
43                         return -1;
44                 } else {
45                         u8 c2 = utf8_string[++i];
46                         if ((c & 0xE0) == 0xC0) {
47                                 /* two-byte encoding */
48                                 WPA_PUT_LE16(ucs2_buffer + j,
49                                              ((c & 0x1F) << 6) | (c2 & 0x3F));
50                                 j += 2;
51                         } else if (i == utf8_string_len - 1 ||
52                                    j >= ucs2_buffer_size - 1) {
53                                 /* incomplete surrogate */
54                                 return -1;
55                         } else {
56                                 /* three-byte encoding */
57                                 u8 c3 = utf8_string[++i];
58                                 WPA_PUT_LE16(ucs2_buffer + j,
59                                              ((c & 0xF) << 12) |
60                                              ((c2 & 0x3F) << 6) | (c3 & 0x3F));
61                                 j += 2;
62                         }
63                 }
64         }
65
66         if (ucs2_string_size)
67                 *ucs2_string_size = j / 2;
68         return 0;
69 }
70
71
72 /**
73  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
74  * @peer_challenge: 16-octet PeerChallenge (IN)
75  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
76  * @username: 0-to-256-char UserName (IN)
77  * @username_len: Length of username
78  * @challenge: 8-octet Challenge (OUT)
79  * Returns: 0 on success, -1 on failure
80  */
81 int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
82                    const u8 *username, size_t username_len, u8 *challenge)
83 {
84         u8 hash[SHA1_MAC_LEN];
85         const unsigned char *addr[3];
86         size_t len[3];
87
88         addr[0] = peer_challenge;
89         len[0] = 16;
90         addr[1] = auth_challenge;
91         len[1] = 16;
92         addr[2] = username;
93         len[2] = username_len;
94
95         if (sha1_vector(3, addr, len, hash))
96                 return -1;
97         os_memcpy(challenge, hash, 8);
98         return 0;
99 }
100
101
102 /**
103  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
104  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
105  * @password_len: Length of password
106  * @password_hash: 16-octet PasswordHash (OUT)
107  * Returns: 0 on success, -1 on failure
108  */
109 int nt_password_hash(const u8 *password, size_t password_len,
110                       u8 *password_hash)
111 {
112         u8 buf[512], *pos;
113         size_t len, max_len;
114
115         max_len = sizeof(buf);
116         if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
117                 return -1;
118
119         len *= 2;
120         pos = buf;
121         return md4_vector(1, (const u8 **) &pos, &len, password_hash);
122 }
123
124
125 /**
126  * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
127  * @password_hash: 16-octet PasswordHash (IN)
128  * @password_hash_hash: 16-octet PasswordHashHash (OUT)
129  * Returns: 0 on success, -1 on failure
130  */
131 int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
132 {
133         size_t len = 16;
134         return md4_vector(1, &password_hash, &len, password_hash_hash);
135 }
136
137
138 /**
139  * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
140  * @challenge: 8-octet Challenge (IN)
141  * @password_hash: 16-octet PasswordHash (IN)
142  * @response: 24-octet Response (OUT)
143  * Returns: 0 on success, -1 on failure
144  */
145 int challenge_response(const u8 *challenge, const u8 *password_hash,
146                        u8 *response)
147 {
148         u8 zpwd[7];
149
150         if (des_encrypt(challenge, password_hash, response) < 0 ||
151             des_encrypt(challenge, password_hash + 7, response + 8) < 0)
152                 return -1;
153         zpwd[0] = password_hash[14];
154         zpwd[1] = password_hash[15];
155         os_memset(zpwd + 2, 0, 5);
156         return des_encrypt(challenge, zpwd, response + 16);
157 }
158
159
160 /**
161  * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
162  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
163  * @peer_challenge: 16-octet PeerChallenge (IN)
164  * @username: 0-to-256-char UserName (IN)
165  * @username_len: Length of username
166  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
167  * @password_len: Length of password
168  * @response: 24-octet Response (OUT)
169  * Returns: 0 on success, -1 on failure
170  */
171 int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
172                          const u8 *username, size_t username_len,
173                          const u8 *password, size_t password_len,
174                          u8 *response)
175 {
176         u8 challenge[8];
177         u8 password_hash[16];
178
179         if (challenge_hash(peer_challenge, auth_challenge, username,
180                            username_len, challenge) ||
181             nt_password_hash(password, password_len, password_hash) ||
182             challenge_response(challenge, password_hash, response))
183                 return -1;
184         return 0;
185 }
186
187
188 /**
189  * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
190  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
191  * @peer_challenge: 16-octet PeerChallenge (IN)
192  * @username: 0-to-256-char UserName (IN)
193  * @username_len: Length of username
194  * @password_hash: 16-octet PasswordHash (IN)
195  * @response: 24-octet Response (OUT)
196  * Returns: 0 on success, -1 on failure
197  */
198 int generate_nt_response_pwhash(const u8 *auth_challenge,
199                                 const u8 *peer_challenge,
200                                 const u8 *username, size_t username_len,
201                                 const u8 *password_hash,
202                                 u8 *response)
203 {
204         u8 challenge[8];
205
206         if (challenge_hash(peer_challenge, auth_challenge,
207                            username, username_len,
208                            challenge) ||
209             challenge_response(challenge, password_hash, response))
210                 return -1;
211         return 0;
212 }
213
214
215 /**
216  * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
217  * @password_hash: 16-octet PasswordHash (IN)
218  * @nt_response: 24-octet NT-Response (IN)
219  * @peer_challenge: 16-octet PeerChallenge (IN)
220  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
221  * @username: 0-to-256-char UserName (IN)
222  * @username_len: Length of username
223  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
224  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
225  * Returns: 0 on success, -1 on failure
226  */
227 int generate_authenticator_response_pwhash(
228         const u8 *password_hash,
229         const u8 *peer_challenge, const u8 *auth_challenge,
230         const u8 *username, size_t username_len,
231         const u8 *nt_response, u8 *response)
232 {
233         static const u8 magic1[39] = {
234                 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
235                 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
236                 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
237                 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
238         };
239         static const u8 magic2[41] = {
240                 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
241                 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
242                 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
243                 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
244                 0x6E
245         };
246
247         u8 password_hash_hash[16], challenge[8];
248         const unsigned char *addr1[3];
249         const size_t len1[3] = { 16, 24, sizeof(magic1) };
250         const unsigned char *addr2[3];
251         const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
252
253         addr1[0] = password_hash_hash;
254         addr1[1] = nt_response;
255         addr1[2] = magic1;
256
257         addr2[0] = response;
258         addr2[1] = challenge;
259         addr2[2] = magic2;
260
261         if (hash_nt_password_hash(password_hash, password_hash_hash) ||
262             sha1_vector(3, addr1, len1, response) ||
263             challenge_hash(peer_challenge, auth_challenge, username,
264                            username_len, challenge))
265                 return -1;
266         return sha1_vector(3, addr2, len2, response);
267 }
268
269
270 /**
271  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
272  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
273  * @password_len: Length of password
274  * @nt_response: 24-octet NT-Response (IN)
275  * @peer_challenge: 16-octet PeerChallenge (IN)
276  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
277  * @username: 0-to-256-char UserName (IN)
278  * @username_len: Length of username
279  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
280  * encoded as a 42-octet ASCII string (S=hexdump_of_response)
281  * Returns: 0 on success, -1 on failure
282  */
283 int generate_authenticator_response(const u8 *password, size_t password_len,
284                                     const u8 *peer_challenge,
285                                     const u8 *auth_challenge,
286                                     const u8 *username, size_t username_len,
287                                     const u8 *nt_response, u8 *response)
288 {
289         u8 password_hash[16];
290         if (nt_password_hash(password, password_len, password_hash))
291                 return -1;
292         return generate_authenticator_response_pwhash(
293                 password_hash, peer_challenge, auth_challenge,
294                 username, username_len, nt_response, response);
295 }
296
297
298 /**
299  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
300  * @challenge: 8-octet Challenge (IN)
301  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
302  * @password_len: Length of password
303  * @response: 24-octet Response (OUT)
304  * Returns: 0 on success, -1 on failure
305  */
306 int nt_challenge_response(const u8 *challenge, const u8 *password,
307                           size_t password_len, u8 *response)
308 {
309         u8 password_hash[16];
310
311         if (nt_password_hash(password, password_len, password_hash) ||
312             challenge_response(challenge, password_hash, response))
313                 return -1;
314         return 0;
315 }
316
317
318 /**
319  * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
320  * @password_hash_hash: 16-octet PasswordHashHash (IN)
321  * @nt_response: 24-octet NTResponse (IN)
322  * @master_key: 16-octet MasterKey (OUT)
323  * Returns: 0 on success, -1 on failure
324  */
325 int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
326                    u8 *master_key)
327 {
328         static const u8 magic1[27] = {
329                 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
330                 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
331                 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
332         };
333         const unsigned char *addr[3];
334         const size_t len[3] = { 16, 24, sizeof(magic1) };
335         u8 hash[SHA1_MAC_LEN];
336
337         addr[0] = password_hash_hash;
338         addr[1] = nt_response;
339         addr[2] = magic1;
340
341         if (sha1_vector(3, addr, len, hash))
342                 return -1;
343         os_memcpy(master_key, hash, 16);
344         return 0;
345 }
346
347
348 /**
349  * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
350  * @master_key: 16-octet MasterKey (IN)
351  * @session_key: 8-to-16 octet SessionKey (OUT)
352  * @session_key_len: SessionKeyLength (Length of session_key) (IN)
353  * @is_send: IsSend (IN, BOOLEAN)
354  * @is_server: IsServer (IN, BOOLEAN)
355  * Returns: 0 on success, -1 on failure
356  */
357 int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
358                             size_t session_key_len, int is_send,
359                             int is_server)
360 {
361         static const u8 magic2[84] = {
362                 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
363                 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
364                 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
365                 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
366                 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
367                 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
368                 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
369                 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
370                 0x6b, 0x65, 0x79, 0x2e
371         };
372         static const u8 magic3[84] = {
373                 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
374                 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
375                 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
376                 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
377                 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
378                 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
379                 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
380                 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
381                 0x6b, 0x65, 0x79, 0x2e
382         };
383         static const u8 shs_pad1[40] = {
384                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
388         };
389
390         static const u8 shs_pad2[40] = {
391                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
392                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
393                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
394                 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
395         };
396         u8 digest[SHA1_MAC_LEN];
397         const unsigned char *addr[4];
398         const size_t len[4] = { 16, 40, 84, 40 };
399
400         addr[0] = master_key;
401         addr[1] = shs_pad1;
402         if (is_send) {
403                 addr[2] = is_server ? magic3 : magic2;
404         } else {
405                 addr[2] = is_server ? magic2 : magic3;
406         }
407         addr[3] = shs_pad2;
408
409         if (sha1_vector(4, addr, len, digest))
410                 return -1;
411
412         if (session_key_len > SHA1_MAC_LEN)
413                 session_key_len = SHA1_MAC_LEN;
414         os_memcpy(session_key, digest, session_key_len);
415         return 0;
416 }
417
418
419 #ifndef CONFIG_NO_RC4
420
421 #define PWBLOCK_LEN 516
422
423 /**
424  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
425  * @password: 0-to-256-unicode-char Password (IN; UTF-8)
426  * @password_len: Length of password
427  * @password_hash: 16-octet PasswordHash (IN)
428  * @pw_block: 516-byte PwBlock (OUT)
429  * Returns: 0 on success, -1 on failure
430  */
431 int encrypt_pw_block_with_password_hash(
432         const u8 *password, size_t password_len,
433         const u8 *password_hash, u8 *pw_block)
434 {
435         size_t ucs2_len, offset;
436         u8 *pos;
437
438         os_memset(pw_block, 0, PWBLOCK_LEN);
439
440         if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
441             || ucs2_len > 256)
442                 return -1;
443
444         offset = (256 - ucs2_len) * 2;
445         if (offset != 0) {
446                 os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
447                 if (os_get_random(pw_block, offset) < 0)
448                         return -1;
449         }
450         /*
451          * PasswordLength is 4 octets, but since the maximum password length is
452          * 256, only first two (in little endian byte order) can be non-zero.
453          */
454         pos = &pw_block[2 * 256];
455         WPA_PUT_LE16(pos, password_len * 2);
456         rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
457         return 0;
458 }
459
460
461 /**
462  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
463  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
464  * @new_password_len: Length of new_password
465  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
466  * @old_password_len: Length of old_password
467  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
468  * Returns: 0 on success, -1 on failure
469  */
470 int new_password_encrypted_with_old_nt_password_hash(
471         const u8 *new_password, size_t new_password_len,
472         const u8 *old_password, size_t old_password_len,
473         u8 *encrypted_pw_block)
474 {
475         u8 password_hash[16];
476
477         if (nt_password_hash(old_password, old_password_len, password_hash))
478                 return -1;
479         if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
480                                                 password_hash,
481                                                 encrypted_pw_block))
482                 return -1;
483         return 0;
484 }
485
486 #endif /* CONFIG_NO_RC4 */
487
488
489 /**
490  * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
491  * @password_hash: 16-octer PasswordHash (IN)
492  * @block: 16-octet Block (IN)
493  * @cypher: 16-octer Cypher (OUT)
494  * Returns: 0 on success, -1 on failure
495  */
496 int nt_password_hash_encrypted_with_block(const u8 *password_hash,
497                                           const u8 *block, u8 *cypher)
498 {
499         if (des_encrypt(password_hash, block, cypher) < 0 ||
500             des_encrypt(password_hash + 8, block + 7, cypher + 8) < 0)
501                 return -1;
502         return 0;
503 }
504
505
506 /**
507  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
508  * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
509  * @new_password_len: Length of new_password
510  * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
511  * @old_password_len: Length of old_password
512  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
513  * Returns: 0 on success, -1 on failure
514  */
515 int old_nt_password_hash_encrypted_with_new_nt_password_hash(
516         const u8 *new_password, size_t new_password_len,
517         const u8 *old_password, size_t old_password_len,
518         u8 *encrypted_password_hash)
519 {
520         u8 old_password_hash[16], new_password_hash[16];
521
522         if (nt_password_hash(old_password, old_password_len,
523                              old_password_hash) ||
524             nt_password_hash(new_password, new_password_len,
525                              new_password_hash) ||
526             nt_password_hash_encrypted_with_block(old_password_hash,
527                                                   new_password_hash,
528                                                   encrypted_password_hash))
529                 return -1;
530         return 0;
531 }