/src/mbedtls/library/pem.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Privacy Enhanced Mail (PEM) decoding |
3 | | * |
4 | | * Copyright The Mbed TLS Contributors |
5 | | * SPDX-License-Identifier: Apache-2.0 |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
8 | | * not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
15 | | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include "common.h" |
21 | | |
22 | | #if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) |
23 | | |
24 | | #include "mbedtls/pem.h" |
25 | | #include "mbedtls/base64.h" |
26 | | #include "mbedtls/des.h" |
27 | | #include "mbedtls/aes.h" |
28 | | #include "mbedtls/md5.h" |
29 | | #include "mbedtls/cipher.h" |
30 | | #include "mbedtls/platform_util.h" |
31 | | #include "mbedtls/error.h" |
32 | | #include "hash_info.h" |
33 | | |
34 | | #include <string.h> |
35 | | |
36 | | #include "mbedtls/platform.h" |
37 | | |
38 | | #if defined(MBEDTLS_USE_PSA_CRYPTO) |
39 | | #include "psa/crypto.h" |
40 | | #endif |
41 | | |
42 | | #include "mbedtls/legacy_or_psa.h" |
43 | | |
44 | | #if defined(MBEDTLS_HAS_ALG_MD5_VIA_MD_OR_PSA_BASED_ON_USE_PSA) && \ |
45 | | defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
46 | | (defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C)) |
47 | | #define PEM_RFC1421 |
48 | | #endif /* MBEDTLS_HAS_ALG_MD5_VIA_MD_OR_PSA_BASED_ON_USE_PSA && |
49 | | MBEDTLS_CIPHER_MODE_CBC && |
50 | | ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ |
51 | | |
52 | | #if defined(MBEDTLS_PEM_PARSE_C) |
53 | | void mbedtls_pem_init(mbedtls_pem_context *ctx) |
54 | 4.35k | { |
55 | 4.35k | memset(ctx, 0, sizeof(mbedtls_pem_context)); |
56 | 4.35k | } |
57 | | |
58 | | #if defined(PEM_RFC1421) |
59 | | /* |
60 | | * Read a 16-byte hex string and convert it to binary |
61 | | */ |
62 | | static int pem_get_iv(const unsigned char *s, unsigned char *iv, |
63 | | size_t iv_len) |
64 | 0 | { |
65 | 0 | size_t i, j, k; |
66 | |
|
67 | 0 | memset(iv, 0, iv_len); |
68 | |
|
69 | 0 | for (i = 0; i < iv_len * 2; i++, s++) { |
70 | 0 | if (*s >= '0' && *s <= '9') { |
71 | 0 | j = *s - '0'; |
72 | 0 | } else |
73 | 0 | if (*s >= 'A' && *s <= 'F') { |
74 | 0 | j = *s - '7'; |
75 | 0 | } else |
76 | 0 | if (*s >= 'a' && *s <= 'f') { |
77 | 0 | j = *s - 'W'; |
78 | 0 | } else { |
79 | 0 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
80 | 0 | } |
81 | | |
82 | 0 | k = ((i & 1) != 0) ? j : j << 4; |
83 | |
|
84 | 0 | iv[i >> 1] = (unsigned char) (iv[i >> 1] | k); |
85 | 0 | } |
86 | | |
87 | 0 | return 0; |
88 | 0 | } |
89 | | |
90 | | #if defined(MBEDTLS_MD5_C) |
91 | | static int pem_pbkdf1(unsigned char *key, size_t keylen, |
92 | | unsigned char *iv, |
93 | | const unsigned char *pwd, size_t pwdlen) |
94 | 0 | { |
95 | 0 | mbedtls_md5_context md5_ctx; |
96 | 0 | unsigned char md5sum[16]; |
97 | 0 | size_t use_len; |
98 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
99 | |
|
100 | 0 | mbedtls_md5_init(&md5_ctx); |
101 | | |
102 | | /* |
103 | | * key[ 0..15] = MD5(pwd || IV) |
104 | | */ |
105 | 0 | if ((ret = mbedtls_md5_starts(&md5_ctx)) != 0) { |
106 | 0 | goto exit; |
107 | 0 | } |
108 | 0 | if ((ret = mbedtls_md5_update(&md5_ctx, pwd, pwdlen)) != 0) { |
109 | 0 | goto exit; |
110 | 0 | } |
111 | 0 | if ((ret = mbedtls_md5_update(&md5_ctx, iv, 8)) != 0) { |
112 | 0 | goto exit; |
113 | 0 | } |
114 | 0 | if ((ret = mbedtls_md5_finish(&md5_ctx, md5sum)) != 0) { |
115 | 0 | goto exit; |
116 | 0 | } |
117 | | |
118 | 0 | if (keylen <= 16) { |
119 | 0 | memcpy(key, md5sum, keylen); |
120 | 0 | goto exit; |
121 | 0 | } |
122 | | |
123 | 0 | memcpy(key, md5sum, 16); |
124 | | |
125 | | /* |
126 | | * key[16..23] = MD5(key[ 0..15] || pwd || IV]) |
127 | | */ |
128 | 0 | if ((ret = mbedtls_md5_starts(&md5_ctx)) != 0) { |
129 | 0 | goto exit; |
130 | 0 | } |
131 | 0 | if ((ret = mbedtls_md5_update(&md5_ctx, md5sum, 16)) != 0) { |
132 | 0 | goto exit; |
133 | 0 | } |
134 | 0 | if ((ret = mbedtls_md5_update(&md5_ctx, pwd, pwdlen)) != 0) { |
135 | 0 | goto exit; |
136 | 0 | } |
137 | 0 | if ((ret = mbedtls_md5_update(&md5_ctx, iv, 8)) != 0) { |
138 | 0 | goto exit; |
139 | 0 | } |
140 | 0 | if ((ret = mbedtls_md5_finish(&md5_ctx, md5sum)) != 0) { |
141 | 0 | goto exit; |
142 | 0 | } |
143 | | |
144 | 0 | use_len = 16; |
145 | 0 | if (keylen < 32) { |
146 | 0 | use_len = keylen - 16; |
147 | 0 | } |
148 | |
|
149 | 0 | memcpy(key + 16, md5sum, use_len); |
150 | |
|
151 | 0 | exit: |
152 | 0 | mbedtls_md5_free(&md5_ctx); |
153 | 0 | mbedtls_platform_zeroize(md5sum, 16); |
154 | |
|
155 | 0 | return ret; |
156 | 0 | } |
157 | | #else |
158 | | static int pem_pbkdf1(unsigned char *key, size_t keylen, |
159 | | unsigned char *iv, |
160 | | const unsigned char *pwd, size_t pwdlen) |
161 | | { |
162 | | unsigned char md5sum[16]; |
163 | | psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; |
164 | | size_t output_length = 0; |
165 | | psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; |
166 | | |
167 | | |
168 | | if ((status = psa_hash_setup(&operation, PSA_ALG_MD5)) != PSA_SUCCESS) { |
169 | | goto exit; |
170 | | } |
171 | | |
172 | | if ((status = psa_hash_update(&operation, pwd, pwdlen)) != PSA_SUCCESS) { |
173 | | goto exit; |
174 | | } |
175 | | |
176 | | if ((status = psa_hash_update(&operation, iv, 8)) != PSA_SUCCESS) { |
177 | | goto exit; |
178 | | } |
179 | | |
180 | | if ((status = psa_hash_finish(&operation, md5sum, |
181 | | PSA_HASH_LENGTH(PSA_ALG_MD5), |
182 | | &output_length)) != PSA_SUCCESS) { |
183 | | goto exit; |
184 | | } |
185 | | |
186 | | if ((status = psa_hash_abort(&operation)) != PSA_SUCCESS) { |
187 | | goto exit; |
188 | | } |
189 | | |
190 | | /* |
191 | | * key[ 0..15] = MD5(pwd || IV) |
192 | | */ |
193 | | if (keylen <= 16) { |
194 | | memcpy(key, md5sum, keylen); |
195 | | goto exit; |
196 | | } |
197 | | |
198 | | memcpy(key, md5sum, 16); |
199 | | |
200 | | /* |
201 | | * key[16..23] = MD5(key[ 0..15] || pwd || IV]) |
202 | | */ |
203 | | if ((status = psa_hash_setup(&operation, PSA_ALG_MD5)) != PSA_SUCCESS) { |
204 | | goto exit; |
205 | | } |
206 | | |
207 | | if ((status = psa_hash_update(&operation, md5sum, 16)) != PSA_SUCCESS) { |
208 | | goto exit; |
209 | | } |
210 | | |
211 | | if ((status = psa_hash_update(&operation, pwd, pwdlen)) != PSA_SUCCESS) { |
212 | | goto exit; |
213 | | } |
214 | | |
215 | | if ((status = psa_hash_update(&operation, iv, 8)) != PSA_SUCCESS) { |
216 | | goto exit; |
217 | | } |
218 | | |
219 | | if ((status = psa_hash_finish(&operation, md5sum, |
220 | | PSA_HASH_LENGTH(PSA_ALG_MD5), |
221 | | &output_length)) != PSA_SUCCESS) { |
222 | | goto exit; |
223 | | } |
224 | | |
225 | | if ((status = psa_hash_abort(&operation)) != PSA_SUCCESS) { |
226 | | goto exit; |
227 | | } |
228 | | |
229 | | size_t use_len = 16; |
230 | | if (keylen < 32) { |
231 | | use_len = keylen - 16; |
232 | | } |
233 | | |
234 | | memcpy(key + 16, md5sum, use_len); |
235 | | |
236 | | exit: |
237 | | mbedtls_platform_zeroize(md5sum, 16); |
238 | | |
239 | | return mbedtls_md_error_from_psa(status); |
240 | | } |
241 | | #endif /* MBEDTLS_MD5_C */ |
242 | | |
243 | | #if defined(MBEDTLS_DES_C) |
244 | | /* |
245 | | * Decrypt with DES-CBC, using PBKDF1 for key derivation |
246 | | */ |
247 | | static int pem_des_decrypt(unsigned char des_iv[8], |
248 | | unsigned char *buf, size_t buflen, |
249 | | const unsigned char *pwd, size_t pwdlen) |
250 | 0 | { |
251 | 0 | mbedtls_des_context des_ctx; |
252 | 0 | unsigned char des_key[8]; |
253 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
254 | |
|
255 | 0 | mbedtls_des_init(&des_ctx); |
256 | |
|
257 | 0 | if ((ret = pem_pbkdf1(des_key, 8, des_iv, pwd, pwdlen)) != 0) { |
258 | 0 | goto exit; |
259 | 0 | } |
260 | | |
261 | 0 | if ((ret = mbedtls_des_setkey_dec(&des_ctx, des_key)) != 0) { |
262 | 0 | goto exit; |
263 | 0 | } |
264 | 0 | ret = mbedtls_des_crypt_cbc(&des_ctx, MBEDTLS_DES_DECRYPT, buflen, |
265 | 0 | des_iv, buf, buf); |
266 | |
|
267 | 0 | exit: |
268 | 0 | mbedtls_des_free(&des_ctx); |
269 | 0 | mbedtls_platform_zeroize(des_key, 8); |
270 | |
|
271 | 0 | return ret; |
272 | 0 | } |
273 | | |
274 | | /* |
275 | | * Decrypt with 3DES-CBC, using PBKDF1 for key derivation |
276 | | */ |
277 | | static int pem_des3_decrypt(unsigned char des3_iv[8], |
278 | | unsigned char *buf, size_t buflen, |
279 | | const unsigned char *pwd, size_t pwdlen) |
280 | 0 | { |
281 | 0 | mbedtls_des3_context des3_ctx; |
282 | 0 | unsigned char des3_key[24]; |
283 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
284 | |
|
285 | 0 | mbedtls_des3_init(&des3_ctx); |
286 | |
|
287 | 0 | if ((ret = pem_pbkdf1(des3_key, 24, des3_iv, pwd, pwdlen)) != 0) { |
288 | 0 | goto exit; |
289 | 0 | } |
290 | | |
291 | 0 | if ((ret = mbedtls_des3_set3key_dec(&des3_ctx, des3_key)) != 0) { |
292 | 0 | goto exit; |
293 | 0 | } |
294 | 0 | ret = mbedtls_des3_crypt_cbc(&des3_ctx, MBEDTLS_DES_DECRYPT, buflen, |
295 | 0 | des3_iv, buf, buf); |
296 | |
|
297 | 0 | exit: |
298 | 0 | mbedtls_des3_free(&des3_ctx); |
299 | 0 | mbedtls_platform_zeroize(des3_key, 24); |
300 | |
|
301 | 0 | return ret; |
302 | 0 | } |
303 | | #endif /* MBEDTLS_DES_C */ |
304 | | |
305 | | #if defined(MBEDTLS_AES_C) |
306 | | /* |
307 | | * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation |
308 | | */ |
309 | | static int pem_aes_decrypt(unsigned char aes_iv[16], unsigned int keylen, |
310 | | unsigned char *buf, size_t buflen, |
311 | | const unsigned char *pwd, size_t pwdlen) |
312 | 0 | { |
313 | 0 | mbedtls_aes_context aes_ctx; |
314 | 0 | unsigned char aes_key[32]; |
315 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
316 | |
|
317 | 0 | mbedtls_aes_init(&aes_ctx); |
318 | |
|
319 | 0 | if ((ret = pem_pbkdf1(aes_key, keylen, aes_iv, pwd, pwdlen)) != 0) { |
320 | 0 | goto exit; |
321 | 0 | } |
322 | | |
323 | 0 | if ((ret = mbedtls_aes_setkey_dec(&aes_ctx, aes_key, keylen * 8)) != 0) { |
324 | 0 | goto exit; |
325 | 0 | } |
326 | 0 | ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, buflen, |
327 | 0 | aes_iv, buf, buf); |
328 | |
|
329 | 0 | exit: |
330 | 0 | mbedtls_aes_free(&aes_ctx); |
331 | 0 | mbedtls_platform_zeroize(aes_key, keylen); |
332 | |
|
333 | 0 | return ret; |
334 | 0 | } |
335 | | #endif /* MBEDTLS_AES_C */ |
336 | | |
337 | | #endif /* PEM_RFC1421 */ |
338 | | |
339 | | int mbedtls_pem_read_buffer(mbedtls_pem_context *ctx, const char *header, const char *footer, |
340 | | const unsigned char *data, const unsigned char *pwd, |
341 | | size_t pwdlen, size_t *use_len) |
342 | 4.35k | { |
343 | 4.35k | int ret, enc; |
344 | 4.35k | size_t len; |
345 | 4.35k | unsigned char *buf; |
346 | 4.35k | const unsigned char *s1, *s2, *end; |
347 | 4.35k | #if defined(PEM_RFC1421) |
348 | 4.35k | unsigned char pem_iv[16]; |
349 | 4.35k | mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE; |
350 | | #else |
351 | | ((void) pwd); |
352 | | ((void) pwdlen); |
353 | | #endif /* PEM_RFC1421 */ |
354 | | |
355 | 4.35k | if (ctx == NULL) { |
356 | 0 | return MBEDTLS_ERR_PEM_BAD_INPUT_DATA; |
357 | 0 | } |
358 | | |
359 | 4.35k | s1 = (unsigned char *) strstr((const char *) data, header); |
360 | | |
361 | 4.35k | if (s1 == NULL) { |
362 | 0 | return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; |
363 | 0 | } |
364 | | |
365 | 4.35k | s2 = (unsigned char *) strstr((const char *) data, footer); |
366 | | |
367 | 4.35k | if (s2 == NULL || s2 <= s1) { |
368 | 0 | return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; |
369 | 0 | } |
370 | | |
371 | 4.35k | s1 += strlen(header); |
372 | 4.35k | if (*s1 == ' ') { |
373 | 0 | s1++; |
374 | 0 | } |
375 | 4.35k | if (*s1 == '\r') { |
376 | 4.35k | s1++; |
377 | 4.35k | } |
378 | 4.35k | if (*s1 == '\n') { |
379 | 4.35k | s1++; |
380 | 4.35k | } else { |
381 | 0 | return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; |
382 | 0 | } |
383 | | |
384 | 4.35k | end = s2; |
385 | 4.35k | end += strlen(footer); |
386 | 4.35k | if (*end == ' ') { |
387 | 0 | end++; |
388 | 0 | } |
389 | 4.35k | if (*end == '\r') { |
390 | 4.35k | end++; |
391 | 4.35k | } |
392 | 4.35k | if (*end == '\n') { |
393 | 4.35k | end++; |
394 | 4.35k | } |
395 | 4.35k | *use_len = end - data; |
396 | | |
397 | 4.35k | enc = 0; |
398 | | |
399 | 4.35k | if (s2 - s1 >= 22 && memcmp(s1, "Proc-Type: 4,ENCRYPTED", 22) == 0) { |
400 | 0 | #if defined(PEM_RFC1421) |
401 | 0 | enc++; |
402 | |
|
403 | 0 | s1 += 22; |
404 | 0 | if (*s1 == '\r') { |
405 | 0 | s1++; |
406 | 0 | } |
407 | 0 | if (*s1 == '\n') { |
408 | 0 | s1++; |
409 | 0 | } else { |
410 | 0 | return MBEDTLS_ERR_PEM_INVALID_DATA; |
411 | 0 | } |
412 | | |
413 | | |
414 | 0 | #if defined(MBEDTLS_DES_C) |
415 | 0 | if (s2 - s1 >= 23 && memcmp(s1, "DEK-Info: DES-EDE3-CBC,", 23) == 0) { |
416 | 0 | enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC; |
417 | |
|
418 | 0 | s1 += 23; |
419 | 0 | if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) { |
420 | 0 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
421 | 0 | } |
422 | | |
423 | 0 | s1 += 16; |
424 | 0 | } else if (s2 - s1 >= 18 && memcmp(s1, "DEK-Info: DES-CBC,", 18) == 0) { |
425 | 0 | enc_alg = MBEDTLS_CIPHER_DES_CBC; |
426 | |
|
427 | 0 | s1 += 18; |
428 | 0 | if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) { |
429 | 0 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
430 | 0 | } |
431 | | |
432 | 0 | s1 += 16; |
433 | 0 | } |
434 | 0 | #endif /* MBEDTLS_DES_C */ |
435 | | |
436 | 0 | #if defined(MBEDTLS_AES_C) |
437 | 0 | if (s2 - s1 >= 14 && memcmp(s1, "DEK-Info: AES-", 14) == 0) { |
438 | 0 | if (s2 - s1 < 22) { |
439 | 0 | return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG; |
440 | 0 | } else if (memcmp(s1, "DEK-Info: AES-128-CBC,", 22) == 0) { |
441 | 0 | enc_alg = MBEDTLS_CIPHER_AES_128_CBC; |
442 | 0 | } else if (memcmp(s1, "DEK-Info: AES-192-CBC,", 22) == 0) { |
443 | 0 | enc_alg = MBEDTLS_CIPHER_AES_192_CBC; |
444 | 0 | } else if (memcmp(s1, "DEK-Info: AES-256-CBC,", 22) == 0) { |
445 | 0 | enc_alg = MBEDTLS_CIPHER_AES_256_CBC; |
446 | 0 | } else { |
447 | 0 | return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG; |
448 | 0 | } |
449 | | |
450 | 0 | s1 += 22; |
451 | 0 | if (s2 - s1 < 32 || pem_get_iv(s1, pem_iv, 16) != 0) { |
452 | 0 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
453 | 0 | } |
454 | | |
455 | 0 | s1 += 32; |
456 | 0 | } |
457 | 0 | #endif /* MBEDTLS_AES_C */ |
458 | | |
459 | 0 | if (enc_alg == MBEDTLS_CIPHER_NONE) { |
460 | 0 | return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG; |
461 | 0 | } |
462 | | |
463 | 0 | if (*s1 == '\r') { |
464 | 0 | s1++; |
465 | 0 | } |
466 | 0 | if (*s1 == '\n') { |
467 | 0 | s1++; |
468 | 0 | } else { |
469 | 0 | return MBEDTLS_ERR_PEM_INVALID_DATA; |
470 | 0 | } |
471 | | #else |
472 | | return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE; |
473 | | #endif /* PEM_RFC1421 */ |
474 | 0 | } |
475 | | |
476 | 4.35k | if (s1 >= s2) { |
477 | 0 | return MBEDTLS_ERR_PEM_INVALID_DATA; |
478 | 0 | } |
479 | | |
480 | 4.35k | ret = mbedtls_base64_decode(NULL, 0, &len, s1, s2 - s1); |
481 | | |
482 | 4.35k | if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) { |
483 | 0 | return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret); |
484 | 0 | } |
485 | | |
486 | 4.35k | if ((buf = mbedtls_calloc(1, len)) == NULL) { |
487 | 0 | return MBEDTLS_ERR_PEM_ALLOC_FAILED; |
488 | 0 | } |
489 | | |
490 | 4.35k | if ((ret = mbedtls_base64_decode(buf, len, &len, s1, s2 - s1)) != 0) { |
491 | 0 | mbedtls_platform_zeroize(buf, len); |
492 | 0 | mbedtls_free(buf); |
493 | 0 | return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret); |
494 | 0 | } |
495 | | |
496 | 4.35k | if (enc != 0) { |
497 | 0 | #if defined(PEM_RFC1421) |
498 | 0 | if (pwd == NULL) { |
499 | 0 | mbedtls_platform_zeroize(buf, len); |
500 | 0 | mbedtls_free(buf); |
501 | 0 | return MBEDTLS_ERR_PEM_PASSWORD_REQUIRED; |
502 | 0 | } |
503 | | |
504 | 0 | ret = 0; |
505 | |
|
506 | 0 | #if defined(MBEDTLS_DES_C) |
507 | 0 | if (enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC) { |
508 | 0 | ret = pem_des3_decrypt(pem_iv, buf, len, pwd, pwdlen); |
509 | 0 | } else if (enc_alg == MBEDTLS_CIPHER_DES_CBC) { |
510 | 0 | ret = pem_des_decrypt(pem_iv, buf, len, pwd, pwdlen); |
511 | 0 | } |
512 | 0 | #endif /* MBEDTLS_DES_C */ |
513 | |
|
514 | 0 | #if defined(MBEDTLS_AES_C) |
515 | 0 | if (enc_alg == MBEDTLS_CIPHER_AES_128_CBC) { |
516 | 0 | ret = pem_aes_decrypt(pem_iv, 16, buf, len, pwd, pwdlen); |
517 | 0 | } else if (enc_alg == MBEDTLS_CIPHER_AES_192_CBC) { |
518 | 0 | ret = pem_aes_decrypt(pem_iv, 24, buf, len, pwd, pwdlen); |
519 | 0 | } else if (enc_alg == MBEDTLS_CIPHER_AES_256_CBC) { |
520 | 0 | ret = pem_aes_decrypt(pem_iv, 32, buf, len, pwd, pwdlen); |
521 | 0 | } |
522 | 0 | #endif /* MBEDTLS_AES_C */ |
523 | |
|
524 | 0 | if (ret != 0) { |
525 | 0 | mbedtls_free(buf); |
526 | 0 | return ret; |
527 | 0 | } |
528 | | |
529 | | /* |
530 | | * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3 |
531 | | * length bytes (allow 4 to be sure) in all known use cases. |
532 | | * |
533 | | * Use that as a heuristic to try to detect password mismatches. |
534 | | */ |
535 | 0 | if (len <= 2 || buf[0] != 0x30 || buf[1] > 0x83) { |
536 | 0 | mbedtls_platform_zeroize(buf, len); |
537 | 0 | mbedtls_free(buf); |
538 | 0 | return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH; |
539 | 0 | } |
540 | | #else |
541 | | mbedtls_platform_zeroize(buf, len); |
542 | | mbedtls_free(buf); |
543 | | return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE; |
544 | | #endif /* PEM_RFC1421 */ |
545 | 0 | } |
546 | | |
547 | 4.35k | ctx->buf = buf; |
548 | 4.35k | ctx->buflen = len; |
549 | | |
550 | 4.35k | return 0; |
551 | 4.35k | } |
552 | | |
553 | | void mbedtls_pem_free(mbedtls_pem_context *ctx) |
554 | 4.35k | { |
555 | 4.35k | if (ctx->buf != NULL) { |
556 | 4.35k | mbedtls_platform_zeroize(ctx->buf, ctx->buflen); |
557 | 4.35k | mbedtls_free(ctx->buf); |
558 | 4.35k | } |
559 | 4.35k | mbedtls_free(ctx->info); |
560 | | |
561 | 4.35k | mbedtls_platform_zeroize(ctx, sizeof(mbedtls_pem_context)); |
562 | 4.35k | } |
563 | | #endif /* MBEDTLS_PEM_PARSE_C */ |
564 | | |
565 | | #if defined(MBEDTLS_PEM_WRITE_C) |
566 | | int mbedtls_pem_write_buffer(const char *header, const char *footer, |
567 | | const unsigned char *der_data, size_t der_len, |
568 | | unsigned char *buf, size_t buf_len, size_t *olen) |
569 | 0 | { |
570 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
571 | 0 | unsigned char *encode_buf = NULL, *c, *p = buf; |
572 | 0 | size_t len = 0, use_len, add_len = 0; |
573 | |
|
574 | 0 | mbedtls_base64_encode(NULL, 0, &use_len, der_data, der_len); |
575 | 0 | add_len = strlen(header) + strlen(footer) + (use_len / 64) + 1; |
576 | |
|
577 | 0 | if (use_len + add_len > buf_len) { |
578 | 0 | *olen = use_len + add_len; |
579 | 0 | return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL; |
580 | 0 | } |
581 | | |
582 | 0 | if (use_len != 0 && |
583 | 0 | ((encode_buf = mbedtls_calloc(1, use_len)) == NULL)) { |
584 | 0 | return MBEDTLS_ERR_PEM_ALLOC_FAILED; |
585 | 0 | } |
586 | | |
587 | 0 | if ((ret = mbedtls_base64_encode(encode_buf, use_len, &use_len, der_data, |
588 | 0 | der_len)) != 0) { |
589 | 0 | mbedtls_free(encode_buf); |
590 | 0 | return ret; |
591 | 0 | } |
592 | | |
593 | 0 | memcpy(p, header, strlen(header)); |
594 | 0 | p += strlen(header); |
595 | 0 | c = encode_buf; |
596 | |
|
597 | 0 | while (use_len) { |
598 | 0 | len = (use_len > 64) ? 64 : use_len; |
599 | 0 | memcpy(p, c, len); |
600 | 0 | use_len -= len; |
601 | 0 | p += len; |
602 | 0 | c += len; |
603 | 0 | *p++ = '\n'; |
604 | 0 | } |
605 | |
|
606 | 0 | memcpy(p, footer, strlen(footer)); |
607 | 0 | p += strlen(footer); |
608 | |
|
609 | 0 | *p++ = '\0'; |
610 | 0 | *olen = p - buf; |
611 | | |
612 | | /* Clean any remaining data previously written to the buffer */ |
613 | 0 | memset(buf + *olen, 0, buf_len - *olen); |
614 | |
|
615 | 0 | mbedtls_free(encode_buf); |
616 | 0 | return 0; |
617 | 0 | } |
618 | | #endif /* MBEDTLS_PEM_WRITE_C */ |
619 | | #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ |