/src/hostap/src/tls/pkcs5.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * PKCS #5 (Password-based Encryption) |
3 | | * Copyright (c) 2009-2015, 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 "crypto/crypto.h" |
13 | | #include "crypto/md5.h" |
14 | | #include "crypto/sha1.h" |
15 | | #include "asn1.h" |
16 | | #include "pkcs5.h" |
17 | | |
18 | | |
19 | | struct pkcs5_params { |
20 | | enum pkcs5_alg { |
21 | | PKCS5_ALG_UNKNOWN, |
22 | | PKCS5_ALG_MD5_DES_CBC, |
23 | | PKCS5_ALG_PBES2, |
24 | | PKCS5_ALG_SHA1_3DES_CBC, |
25 | | } alg; |
26 | | u8 salt[64]; |
27 | | size_t salt_len; |
28 | | unsigned int iter_count; |
29 | | enum pbes2_enc_alg { |
30 | | PBES2_ENC_ALG_UNKNOWN, |
31 | | PBES2_ENC_ALG_DES_EDE3_CBC, |
32 | | } enc_alg; |
33 | | u8 iv[8]; |
34 | | size_t iv_len; |
35 | | }; |
36 | | |
37 | | |
38 | | static int oid_is_rsadsi(struct asn1_oid *oid) |
39 | 0 | { |
40 | 0 | return oid->len >= 4 && |
41 | 0 | oid->oid[0] == 1 /* iso */ && |
42 | 0 | oid->oid[1] == 2 /* member-body */ && |
43 | 0 | oid->oid[2] == 840 /* us */ && |
44 | 0 | oid->oid[3] == 113549 /* rsadsi */; |
45 | 0 | } |
46 | | |
47 | | |
48 | | static int pkcs5_is_oid(struct asn1_oid *oid, unsigned long alg) |
49 | 0 | { |
50 | 0 | return oid->len == 7 && |
51 | 0 | oid_is_rsadsi(oid) && |
52 | 0 | oid->oid[4] == 1 /* pkcs */ && |
53 | 0 | oid->oid[5] == 5 /* pkcs-5 */ && |
54 | 0 | oid->oid[6] == alg; |
55 | 0 | } |
56 | | |
57 | | |
58 | | static int enc_alg_is_oid(struct asn1_oid *oid, unsigned long alg) |
59 | 0 | { |
60 | 0 | return oid->len == 6 && |
61 | 0 | oid_is_rsadsi(oid) && |
62 | 0 | oid->oid[4] == 3 /* encryptionAlgorithm */ && |
63 | 0 | oid->oid[5] == alg; |
64 | 0 | } |
65 | | |
66 | | |
67 | | static int pkcs12_is_pbe_oid(struct asn1_oid *oid, unsigned long alg) |
68 | 0 | { |
69 | 0 | return oid->len == 8 && |
70 | 0 | oid_is_rsadsi(oid) && |
71 | 0 | oid->oid[4] == 1 /* pkcs */ && |
72 | 0 | oid->oid[5] == 12 /* pkcs-12 */ && |
73 | 0 | oid->oid[6] == 1 /* pkcs-12PbeIds */ && |
74 | 0 | oid->oid[7] == alg; |
75 | 0 | } |
76 | | |
77 | | |
78 | | static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid) |
79 | 0 | { |
80 | 0 | if (pkcs5_is_oid(oid, 3)) /* pbeWithMD5AndDES-CBC (PBES1) */ |
81 | 0 | return PKCS5_ALG_MD5_DES_CBC; |
82 | 0 | if (pkcs12_is_pbe_oid(oid, 3)) /* pbeWithSHAAnd3-KeyTripleDES-CBC */ |
83 | 0 | return PKCS5_ALG_SHA1_3DES_CBC; |
84 | 0 | if (pkcs5_is_oid(oid, 13)) /* id-PBES2 (PBES2) */ |
85 | 0 | return PKCS5_ALG_PBES2; |
86 | 0 | return PKCS5_ALG_UNKNOWN; |
87 | 0 | } |
88 | | |
89 | | |
90 | | static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos, |
91 | | const u8 *enc_alg_end) |
92 | 0 | { |
93 | 0 | struct asn1_hdr hdr; |
94 | 0 | const u8 *end, *kdf_end; |
95 | 0 | struct asn1_oid oid; |
96 | 0 | char obuf[80]; |
97 | | |
98 | | /* |
99 | | * RFC 2898, Ch. A.4 |
100 | | * |
101 | | * PBES2-params ::= SEQUENCE { |
102 | | * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, |
103 | | * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } |
104 | | * |
105 | | * PBES2-KDFs ALGORITHM-IDENTIFIER ::= |
106 | | * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } |
107 | | */ |
108 | |
|
109 | 0 | if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || |
110 | 0 | !asn1_is_sequence(&hdr)) { |
111 | 0 | asn1_unexpected(&hdr, |
112 | 0 | "PKCS #5: Expected SEQUENCE (PBES2-params)"); |
113 | 0 | return -1; |
114 | 0 | } |
115 | 0 | pos = hdr.payload; |
116 | 0 | end = hdr.payload + hdr.length; |
117 | |
|
118 | 0 | if (asn1_get_next(pos, end - pos, &hdr) < 0 || |
119 | 0 | !asn1_is_sequence(&hdr)) { |
120 | 0 | asn1_unexpected(&hdr, |
121 | 0 | "PKCS #5: Expected SEQUENCE (keyDerivationFunc)"); |
122 | 0 | return -1; |
123 | 0 | } |
124 | | |
125 | 0 | pos = hdr.payload; |
126 | 0 | kdf_end = end = hdr.payload + hdr.length; |
127 | |
|
128 | 0 | if (asn1_get_oid(pos, end - pos, &oid, &pos)) { |
129 | 0 | wpa_printf(MSG_DEBUG, |
130 | 0 | "PKCS #5: Failed to parse OID (keyDerivationFunc algorithm)"); |
131 | 0 | return -1; |
132 | 0 | } |
133 | | |
134 | 0 | asn1_oid_to_str(&oid, obuf, sizeof(obuf)); |
135 | 0 | wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 keyDerivationFunc algorithm %s", |
136 | 0 | obuf); |
137 | 0 | if (!pkcs5_is_oid(&oid, 12)) /* id-PBKDF2 */ { |
138 | 0 | wpa_printf(MSG_DEBUG, |
139 | 0 | "PKCS #5: Unsupported PBES2 keyDerivationFunc algorithm %s", |
140 | 0 | obuf); |
141 | 0 | return -1; |
142 | 0 | } |
143 | | |
144 | | /* |
145 | | * RFC 2898, C. |
146 | | * |
147 | | * PBKDF2-params ::= SEQUENCE { |
148 | | * salt CHOICE { |
149 | | * specified OCTET STRING, |
150 | | * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} |
151 | | * }, |
152 | | * iterationCount INTEGER (1..MAX), |
153 | | * keyLength INTEGER (1..MAX) OPTIONAL, |
154 | | * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT |
155 | | * algid-hmacWithSHA1 |
156 | | * } |
157 | | */ |
158 | | |
159 | 0 | if (asn1_get_next(pos, end - pos, &hdr) < 0 || |
160 | 0 | !asn1_is_sequence(&hdr)) { |
161 | 0 | asn1_unexpected(&hdr, |
162 | 0 | "PKCS #5: Expected SEQUENCE (PBKDF2-params)"); |
163 | 0 | return -1; |
164 | 0 | } |
165 | | |
166 | 0 | pos = hdr.payload; |
167 | 0 | end = hdr.payload + hdr.length; |
168 | | |
169 | | /* For now, only support the salt CHOICE specified (OCTET STRING) */ |
170 | 0 | if (asn1_get_next(pos, end - pos, &hdr) < 0 || |
171 | 0 | !asn1_is_octetstring(&hdr) || |
172 | 0 | hdr.length > sizeof(params->salt)) { |
173 | 0 | asn1_unexpected(&hdr, |
174 | 0 | "PKCS #5: Expected OCTET STRING (salt.specified)"); |
175 | 0 | return -1; |
176 | 0 | } |
177 | 0 | pos = hdr.payload + hdr.length; |
178 | 0 | os_memcpy(params->salt, hdr.payload, hdr.length); |
179 | 0 | params->salt_len = hdr.length; |
180 | 0 | wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", params->salt, params->salt_len); |
181 | | |
182 | | /* iterationCount INTEGER */ |
183 | 0 | if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) { |
184 | 0 | asn1_unexpected(&hdr, "PKCS #5: Expected INTEGER"); |
185 | 0 | return -1; |
186 | 0 | } |
187 | 0 | if (hdr.length == 1) { |
188 | 0 | params->iter_count = *hdr.payload; |
189 | 0 | } else if (hdr.length == 2) { |
190 | 0 | params->iter_count = WPA_GET_BE16(hdr.payload); |
191 | 0 | } else if (hdr.length == 4) { |
192 | 0 | params->iter_count = WPA_GET_BE32(hdr.payload); |
193 | 0 | } else { |
194 | 0 | wpa_hexdump(MSG_DEBUG, |
195 | 0 | "PKCS #5: Unsupported INTEGER value (iterationCount)", |
196 | 0 | hdr.payload, hdr.length); |
197 | 0 | return -1; |
198 | 0 | } |
199 | 0 | wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x", |
200 | 0 | params->iter_count); |
201 | 0 | if (params->iter_count == 0 || params->iter_count > 0xffff) { |
202 | 0 | wpa_printf(MSG_INFO, "PKCS #5: Unsupported iterationCount=0x%x", |
203 | 0 | params->iter_count); |
204 | 0 | return -1; |
205 | 0 | } |
206 | | |
207 | | /* For now, ignore optional keyLength and prf */ |
208 | | |
209 | 0 | pos = kdf_end; |
210 | | |
211 | | /* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} */ |
212 | |
|
213 | 0 | if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || |
214 | 0 | !asn1_is_sequence(&hdr)) { |
215 | 0 | asn1_unexpected(&hdr, |
216 | 0 | "PKCS #5: Expected SEQUENCE (encryptionScheme)"); |
217 | 0 | return -1; |
218 | 0 | } |
219 | | |
220 | 0 | pos = hdr.payload; |
221 | 0 | end = hdr.payload + hdr.length; |
222 | |
|
223 | 0 | if (asn1_get_oid(pos, end - pos, &oid, &pos)) { |
224 | 0 | wpa_printf(MSG_DEBUG, |
225 | 0 | "PKCS #5: Failed to parse OID (encryptionScheme algorithm)"); |
226 | 0 | return -1; |
227 | 0 | } |
228 | | |
229 | 0 | asn1_oid_to_str(&oid, obuf, sizeof(obuf)); |
230 | 0 | wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 encryptionScheme algorithm %s", |
231 | 0 | obuf); |
232 | 0 | if (enc_alg_is_oid(&oid, 7)) { |
233 | 0 | params->enc_alg = PBES2_ENC_ALG_DES_EDE3_CBC; |
234 | 0 | } else { |
235 | 0 | wpa_printf(MSG_DEBUG, |
236 | 0 | "PKCS #5: Unsupported PBES2 encryptionScheme algorithm %s", |
237 | 0 | obuf); |
238 | 0 | return -1; |
239 | 0 | } |
240 | | |
241 | | /* |
242 | | * RFC 2898, B.2.2: |
243 | | * The parameters field associated with this OID in an |
244 | | * AlgorithmIdentifier shall have type OCTET STRING (SIZE(8)), |
245 | | * specifying the initialization vector for CBC mode. |
246 | | */ |
247 | 0 | if (asn1_get_next(pos, end - pos, &hdr) < 0 || |
248 | 0 | !asn1_is_octetstring(&hdr) || hdr.length != 8) { |
249 | 0 | asn1_unexpected(&hdr, |
250 | 0 | "PKCS #5: Expected OCTET STRING (SIZE(8)) (IV)"); |
251 | 0 | return -1; |
252 | 0 | } |
253 | 0 | os_memcpy(params->iv, hdr.payload, hdr.length); |
254 | 0 | params->iv_len = hdr.length; |
255 | 0 | wpa_hexdump(MSG_DEBUG, "PKCS #5: IV", params->iv, params->iv_len); |
256 | |
|
257 | 0 | return 0; |
258 | 0 | } |
259 | | |
260 | | |
261 | | static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len, |
262 | | struct pkcs5_params *params) |
263 | 0 | { |
264 | 0 | struct asn1_hdr hdr; |
265 | 0 | const u8 *enc_alg_end, *pos, *end; |
266 | 0 | struct asn1_oid oid; |
267 | 0 | char obuf[80]; |
268 | | |
269 | | /* AlgorithmIdentifier */ |
270 | |
|
271 | 0 | enc_alg_end = enc_alg + enc_alg_len; |
272 | |
|
273 | 0 | os_memset(params, 0, sizeof(*params)); |
274 | |
|
275 | 0 | if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) { |
276 | 0 | wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID " |
277 | 0 | "(algorithm)"); |
278 | 0 | return -1; |
279 | 0 | } |
280 | | |
281 | 0 | asn1_oid_to_str(&oid, obuf, sizeof(obuf)); |
282 | 0 | wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf); |
283 | 0 | params->alg = pkcs5_get_alg(&oid); |
284 | 0 | if (params->alg == PKCS5_ALG_UNKNOWN) { |
285 | 0 | wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption " |
286 | 0 | "algorithm %s", obuf); |
287 | 0 | return -1; |
288 | 0 | } |
289 | | |
290 | 0 | if (params->alg == PKCS5_ALG_PBES2) |
291 | 0 | return pkcs5_get_params_pbes2(params, pos, enc_alg_end); |
292 | | |
293 | | /* PBES1 */ |
294 | | |
295 | | /* |
296 | | * PKCS#5, Section 8 |
297 | | * PBEParameter ::= SEQUENCE { |
298 | | * salt OCTET STRING SIZE(8), |
299 | | * iterationCount INTEGER } |
300 | | * |
301 | | * Note: The same implementation can be used to parse the PKCS #12 |
302 | | * version described in RFC 7292, C: |
303 | | * pkcs-12PbeParams ::= SEQUENCE { |
304 | | * salt OCTET STRING, |
305 | | * iterations INTEGER |
306 | | * } |
307 | | */ |
308 | | |
309 | 0 | if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || |
310 | 0 | !asn1_is_sequence(&hdr)) { |
311 | 0 | asn1_unexpected(&hdr, |
312 | 0 | "PKCS #5: Expected SEQUENCE (PBEParameter)"); |
313 | 0 | return -1; |
314 | 0 | } |
315 | 0 | pos = hdr.payload; |
316 | 0 | end = hdr.payload + hdr.length; |
317 | | |
318 | | /* salt OCTET STRING SIZE(8) (PKCS #5) or OCTET STRING (PKCS #12) */ |
319 | 0 | if (asn1_get_next(pos, end - pos, &hdr) < 0 || |
320 | 0 | !asn1_is_octetstring(&hdr) || hdr.length > sizeof(params->salt)) { |
321 | 0 | asn1_unexpected(&hdr, |
322 | 0 | "PKCS #5: Expected OCTETSTRING SIZE(8) (salt)"); |
323 | 0 | return -1; |
324 | 0 | } |
325 | 0 | pos = hdr.payload + hdr.length; |
326 | 0 | os_memcpy(params->salt, hdr.payload, hdr.length); |
327 | 0 | params->salt_len = hdr.length; |
328 | 0 | wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", |
329 | 0 | params->salt, params->salt_len); |
330 | | |
331 | | /* iterationCount INTEGER */ |
332 | 0 | if (asn1_get_next(pos, end - pos, &hdr) < 0 || |
333 | 0 | !asn1_is_integer(&hdr)) { |
334 | 0 | asn1_unexpected(&hdr, "PKCS #5: Expected INTEGER"); |
335 | 0 | return -1; |
336 | 0 | } |
337 | 0 | if (hdr.length == 1) |
338 | 0 | params->iter_count = *hdr.payload; |
339 | 0 | else if (hdr.length == 2) |
340 | 0 | params->iter_count = WPA_GET_BE16(hdr.payload); |
341 | 0 | else if (hdr.length == 4) |
342 | 0 | params->iter_count = WPA_GET_BE32(hdr.payload); |
343 | 0 | else { |
344 | 0 | wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value " |
345 | 0 | " (iterationCount)", |
346 | 0 | hdr.payload, hdr.length); |
347 | 0 | return -1; |
348 | 0 | } |
349 | 0 | wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x", |
350 | 0 | params->iter_count); |
351 | 0 | if (params->iter_count == 0 || params->iter_count > 0xffff) { |
352 | 0 | wpa_printf(MSG_INFO, "PKCS #5: Unsupported " |
353 | 0 | "iterationCount=0x%x", params->iter_count); |
354 | 0 | return -1; |
355 | 0 | } |
356 | | |
357 | 0 | return 0; |
358 | 0 | } |
359 | | |
360 | | |
361 | | static struct crypto_cipher * |
362 | | pkcs5_crypto_init_pbes2(struct pkcs5_params *params, const char *passwd) |
363 | 0 | { |
364 | 0 | u8 key[24]; |
365 | |
|
366 | 0 | if (params->enc_alg != PBES2_ENC_ALG_DES_EDE3_CBC || |
367 | 0 | params->iv_len != 8) |
368 | 0 | return NULL; |
369 | | |
370 | 0 | wpa_hexdump_ascii_key(MSG_DEBUG, "PKCS #5: PBES2 password for PBKDF2", |
371 | 0 | passwd, os_strlen(passwd)); |
372 | 0 | wpa_hexdump(MSG_DEBUG, "PKCS #5: PBES2 salt for PBKDF2", |
373 | 0 | params->salt, params->salt_len); |
374 | 0 | wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 PBKDF2 iterations: %u", |
375 | 0 | params->iter_count); |
376 | 0 | if (pbkdf2_sha1(passwd, params->salt, params->salt_len, |
377 | 0 | params->iter_count, key, sizeof(key)) < 0) |
378 | 0 | return NULL; |
379 | 0 | wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES EDE3 key", key, sizeof(key)); |
380 | 0 | wpa_hexdump(MSG_DEBUG, "PKCS #5: DES IV", params->iv, params->iv_len); |
381 | |
|
382 | 0 | return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, params->iv, |
383 | 0 | key, sizeof(key)); |
384 | 0 | } |
385 | | |
386 | | |
387 | | static void add_byte_array_mod(u8 *a, const u8 *b, size_t len) |
388 | 0 | { |
389 | 0 | size_t i; |
390 | 0 | unsigned int carry = 0; |
391 | |
|
392 | 0 | for (i = len - 1; i < len; i--) { |
393 | 0 | carry = carry + a[i] + b[i]; |
394 | 0 | a[i] = carry & 0xff; |
395 | 0 | carry >>= 8; |
396 | 0 | } |
397 | 0 | } |
398 | | |
399 | | |
400 | | static int pkcs12_key_gen(const u8 *pw, size_t pw_len, const u8 *salt, |
401 | | size_t salt_len, u8 id, unsigned int iter, |
402 | | size_t out_len, u8 *out) |
403 | 0 | { |
404 | 0 | unsigned int u, v, S_len, P_len, i; |
405 | 0 | u8 *D = NULL, *I = NULL, *B = NULL, *pos; |
406 | 0 | int res = -1; |
407 | | |
408 | | /* RFC 7292, B.2 */ |
409 | 0 | u = SHA1_MAC_LEN; |
410 | 0 | v = 64; |
411 | | |
412 | | /* D = copies of ID */ |
413 | 0 | D = os_malloc(v); |
414 | 0 | if (!D) |
415 | 0 | goto done; |
416 | 0 | os_memset(D, id, v); |
417 | | |
418 | | /* S = copies of salt; P = copies of password, I = S || P */ |
419 | 0 | S_len = v * ((salt_len + v - 1) / v); |
420 | 0 | P_len = v * ((pw_len + v - 1) / v); |
421 | 0 | I = os_malloc(S_len + P_len); |
422 | 0 | if (!I) |
423 | 0 | goto done; |
424 | 0 | pos = I; |
425 | 0 | if (salt_len) { |
426 | 0 | for (i = 0; i < S_len; i++) |
427 | 0 | *pos++ = salt[i % salt_len]; |
428 | 0 | } |
429 | 0 | if (pw_len) { |
430 | 0 | for (i = 0; i < P_len; i++) |
431 | 0 | *pos++ = pw[i % pw_len]; |
432 | 0 | } |
433 | |
|
434 | 0 | B = os_malloc(v); |
435 | 0 | if (!B) |
436 | 0 | goto done; |
437 | | |
438 | 0 | for (;;) { |
439 | 0 | u8 hash[SHA1_MAC_LEN]; |
440 | 0 | const u8 *addr[2]; |
441 | 0 | size_t len[2]; |
442 | |
|
443 | 0 | addr[0] = D; |
444 | 0 | len[0] = v; |
445 | 0 | addr[1] = I; |
446 | 0 | len[1] = S_len + P_len; |
447 | 0 | if (sha1_vector(2, addr, len, hash) < 0) |
448 | 0 | goto done; |
449 | | |
450 | 0 | addr[0] = hash; |
451 | 0 | len[0] = SHA1_MAC_LEN; |
452 | 0 | for (i = 1; i < iter; i++) { |
453 | 0 | if (sha1_vector(1, addr, len, hash) < 0) |
454 | 0 | goto done; |
455 | 0 | } |
456 | | |
457 | 0 | if (out_len <= u) { |
458 | 0 | os_memcpy(out, hash, out_len); |
459 | 0 | res = 0; |
460 | 0 | goto done; |
461 | 0 | } |
462 | | |
463 | 0 | os_memcpy(out, hash, u); |
464 | 0 | out += u; |
465 | 0 | out_len -= u; |
466 | | |
467 | | /* I_j = (I_j + B + 1) mod 2^(v*8) */ |
468 | | /* B = copies of Ai (final hash value) */ |
469 | 0 | for (i = 0; i < v; i++) |
470 | 0 | B[i] = hash[i % u]; |
471 | 0 | inc_byte_array(B, v); |
472 | 0 | for (i = 0; i < S_len + P_len; i += v) |
473 | 0 | add_byte_array_mod(&I[i], B, v); |
474 | 0 | } |
475 | | |
476 | 0 | done: |
477 | 0 | os_free(B); |
478 | 0 | os_free(I); |
479 | 0 | os_free(D); |
480 | 0 | return res; |
481 | 0 | } |
482 | | |
483 | | |
484 | 0 | #define PKCS12_ID_ENC 1 |
485 | 0 | #define PKCS12_ID_IV 2 |
486 | | #define PKCS12_ID_MAC 3 |
487 | | |
488 | | static struct crypto_cipher * |
489 | | pkcs12_crypto_init_sha1(struct pkcs5_params *params, const char *passwd) |
490 | 0 | { |
491 | 0 | unsigned int i; |
492 | 0 | u8 *pw; |
493 | 0 | size_t pw_len; |
494 | 0 | u8 key[24]; |
495 | 0 | u8 iv[8]; |
496 | |
|
497 | 0 | if (params->alg != PKCS5_ALG_SHA1_3DES_CBC) |
498 | 0 | return NULL; |
499 | | |
500 | 0 | pw_len = passwd ? os_strlen(passwd) : 0; |
501 | 0 | pw = os_malloc(2 * (pw_len + 1)); |
502 | 0 | if (!pw) |
503 | 0 | return NULL; |
504 | 0 | if (pw_len) { |
505 | 0 | for (i = 0; i <= pw_len; i++) |
506 | 0 | WPA_PUT_BE16(&pw[2 * i], passwd[i]); |
507 | 0 | pw_len = 2 * (pw_len + 1); |
508 | 0 | } |
509 | |
|
510 | 0 | if (pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len, |
511 | 0 | PKCS12_ID_ENC, params->iter_count, |
512 | 0 | sizeof(key), key) < 0 || |
513 | 0 | pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len, |
514 | 0 | PKCS12_ID_IV, params->iter_count, |
515 | 0 | sizeof(iv), iv) < 0) { |
516 | 0 | os_free(pw); |
517 | 0 | return NULL; |
518 | 0 | } |
519 | | |
520 | 0 | os_free(pw); |
521 | |
|
522 | 0 | wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES key", key, sizeof(key)); |
523 | 0 | wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES IV", iv, sizeof(iv)); |
524 | |
|
525 | 0 | return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, iv, key, sizeof(key)); |
526 | 0 | } |
527 | | |
528 | | |
529 | | static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params, |
530 | | const char *passwd) |
531 | 0 | { |
532 | 0 | unsigned int i; |
533 | 0 | u8 hash[MD5_MAC_LEN]; |
534 | 0 | const u8 *addr[2]; |
535 | 0 | size_t len[2]; |
536 | |
|
537 | 0 | if (params->alg == PKCS5_ALG_PBES2) |
538 | 0 | return pkcs5_crypto_init_pbes2(params, passwd); |
539 | | |
540 | 0 | if (params->alg == PKCS5_ALG_SHA1_3DES_CBC) |
541 | 0 | return pkcs12_crypto_init_sha1(params, passwd); |
542 | | |
543 | 0 | if (params->alg != PKCS5_ALG_MD5_DES_CBC) |
544 | 0 | return NULL; |
545 | | |
546 | 0 | addr[0] = (const u8 *) passwd; |
547 | 0 | len[0] = os_strlen(passwd); |
548 | 0 | addr[1] = params->salt; |
549 | 0 | len[1] = params->salt_len; |
550 | 0 | if (md5_vector(2, addr, len, hash) < 0) |
551 | 0 | return NULL; |
552 | 0 | addr[0] = hash; |
553 | 0 | len[0] = MD5_MAC_LEN; |
554 | 0 | for (i = 1; i < params->iter_count; i++) { |
555 | 0 | if (md5_vector(1, addr, len, hash) < 0) |
556 | 0 | return NULL; |
557 | 0 | } |
558 | | /* TODO: DES key parity bits(?) */ |
559 | 0 | wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8); |
560 | 0 | wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8); |
561 | |
|
562 | 0 | return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); |
563 | 0 | } |
564 | | |
565 | | |
566 | | u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, |
567 | | const u8 *enc_data, size_t enc_data_len, |
568 | | const char *passwd, size_t *data_len) |
569 | 0 | { |
570 | 0 | struct crypto_cipher *ctx; |
571 | 0 | u8 *eb, pad; |
572 | 0 | struct pkcs5_params params; |
573 | 0 | unsigned int i; |
574 | |
|
575 | 0 | if (pkcs5_get_params(enc_alg, enc_alg_len, ¶ms) < 0) { |
576 | 0 | wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters"); |
577 | 0 | return NULL; |
578 | 0 | } |
579 | | |
580 | 0 | ctx = pkcs5_crypto_init(¶ms, passwd); |
581 | 0 | if (ctx == NULL) { |
582 | 0 | wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto"); |
583 | 0 | return NULL; |
584 | 0 | } |
585 | | |
586 | | /* PKCS #5, Section 7 - Decryption process */ |
587 | 0 | if (enc_data_len < 16 || enc_data_len % 8) { |
588 | 0 | wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext " |
589 | 0 | "%d", (int) enc_data_len); |
590 | 0 | crypto_cipher_deinit(ctx); |
591 | 0 | return NULL; |
592 | 0 | } |
593 | | |
594 | 0 | eb = os_malloc(enc_data_len); |
595 | 0 | if (eb == NULL) { |
596 | 0 | crypto_cipher_deinit(ctx); |
597 | 0 | return NULL; |
598 | 0 | } |
599 | | |
600 | 0 | if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { |
601 | 0 | wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); |
602 | 0 | crypto_cipher_deinit(ctx); |
603 | 0 | os_free(eb); |
604 | 0 | return NULL; |
605 | 0 | } |
606 | 0 | crypto_cipher_deinit(ctx); |
607 | |
|
608 | 0 | pad = eb[enc_data_len - 1]; |
609 | 0 | if (pad > 8) { |
610 | 0 | wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad); |
611 | 0 | os_free(eb); |
612 | 0 | return NULL; |
613 | 0 | } |
614 | 0 | for (i = enc_data_len - pad; i < enc_data_len; i++) { |
615 | 0 | if (eb[i] != pad) { |
616 | 0 | wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS", |
617 | 0 | eb + enc_data_len - pad, pad); |
618 | 0 | os_free(eb); |
619 | 0 | return NULL; |
620 | 0 | } |
621 | 0 | } |
622 | | |
623 | 0 | wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)", |
624 | 0 | eb, enc_data_len - pad); |
625 | |
|
626 | 0 | *data_len = enc_data_len - pad; |
627 | 0 | return eb; |
628 | 0 | } |