/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 OR GPL-2.0-or-later |
6 | | */ |
7 | | |
8 | | #include "common.h" |
9 | | |
10 | | #if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) |
11 | | |
12 | | #include "mbedtls/pem.h" |
13 | | #include "mbedtls/base64.h" |
14 | | #include "mbedtls/des.h" |
15 | | #include "mbedtls/aes.h" |
16 | | #include "mbedtls/md.h" |
17 | | #include "mbedtls/cipher.h" |
18 | | #include "mbedtls/platform_util.h" |
19 | | #include "mbedtls/error.h" |
20 | | |
21 | | #include <string.h> |
22 | | |
23 | | #include "mbedtls/platform.h" |
24 | | |
25 | | #if defined(MBEDTLS_USE_PSA_CRYPTO) |
26 | | #include "psa/crypto.h" |
27 | | #endif |
28 | | |
29 | | #if defined(MBEDTLS_MD_CAN_MD5) && \ |
30 | | defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
31 | | (defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C)) |
32 | | #define PEM_RFC1421 |
33 | | #endif /* MBEDTLS_MD_CAN_MD5 && |
34 | | MBEDTLS_CIPHER_MODE_CBC && |
35 | | ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ |
36 | | |
37 | | #if defined(MBEDTLS_PEM_PARSE_C) |
38 | | void mbedtls_pem_init(mbedtls_pem_context *ctx) |
39 | 59.1k | { |
40 | 59.1k | memset(ctx, 0, sizeof(mbedtls_pem_context)); |
41 | 59.1k | } |
42 | | |
43 | | #if defined(PEM_RFC1421) |
44 | | /* |
45 | | * Read a 16-byte hex string and convert it to binary |
46 | | */ |
47 | | static int pem_get_iv(const unsigned char *s, unsigned char *iv, |
48 | | size_t iv_len) |
49 | 1.73k | { |
50 | 1.73k | size_t i, j, k; |
51 | | |
52 | 1.73k | memset(iv, 0, iv_len); |
53 | | |
54 | 28.0k | for (i = 0; i < iv_len * 2; i++, s++) { |
55 | 27.0k | if (*s >= '0' && *s <= '9') { |
56 | 11.1k | j = *s - '0'; |
57 | 11.1k | } else |
58 | 15.8k | if (*s >= 'A' && *s <= 'F') { |
59 | 6.30k | j = *s - '7'; |
60 | 6.30k | } else |
61 | 9.57k | if (*s >= 'a' && *s <= 'f') { |
62 | 8.87k | j = *s - 'W'; |
63 | 8.87k | } else { |
64 | 695 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
65 | 695 | } |
66 | | |
67 | 26.3k | k = ((i & 1) != 0) ? j : j << 4; |
68 | | |
69 | 26.3k | iv[i >> 1] = (unsigned char) (iv[i >> 1] | k); |
70 | 26.3k | } |
71 | | |
72 | 1.04k | return 0; |
73 | 1.73k | } |
74 | | |
75 | | static int pem_pbkdf1(unsigned char *key, size_t keylen, |
76 | | unsigned char *iv, |
77 | | const unsigned char *pwd, size_t pwdlen) |
78 | 0 | { |
79 | 0 | mbedtls_md_context_t md5_ctx; |
80 | 0 | const mbedtls_md_info_t *md5_info; |
81 | 0 | unsigned char md5sum[16]; |
82 | 0 | size_t use_len; |
83 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
84 | |
|
85 | 0 | mbedtls_md_init(&md5_ctx); |
86 | | |
87 | | /* Prepare the context. (setup() errors gracefully on NULL info.) */ |
88 | 0 | md5_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); |
89 | 0 | if ((ret = mbedtls_md_setup(&md5_ctx, md5_info, 0)) != 0) { |
90 | 0 | goto exit; |
91 | 0 | } |
92 | | |
93 | | /* |
94 | | * key[ 0..15] = MD5(pwd || IV) |
95 | | */ |
96 | 0 | if ((ret = mbedtls_md_starts(&md5_ctx)) != 0) { |
97 | 0 | goto exit; |
98 | 0 | } |
99 | 0 | if ((ret = mbedtls_md_update(&md5_ctx, pwd, pwdlen)) != 0) { |
100 | 0 | goto exit; |
101 | 0 | } |
102 | 0 | if ((ret = mbedtls_md_update(&md5_ctx, iv, 8)) != 0) { |
103 | 0 | goto exit; |
104 | 0 | } |
105 | 0 | if ((ret = mbedtls_md_finish(&md5_ctx, md5sum)) != 0) { |
106 | 0 | goto exit; |
107 | 0 | } |
108 | | |
109 | 0 | if (keylen <= 16) { |
110 | 0 | memcpy(key, md5sum, keylen); |
111 | 0 | goto exit; |
112 | 0 | } |
113 | | |
114 | 0 | memcpy(key, md5sum, 16); |
115 | | |
116 | | /* |
117 | | * key[16..23] = MD5(key[ 0..15] || pwd || IV]) |
118 | | */ |
119 | 0 | if ((ret = mbedtls_md_starts(&md5_ctx)) != 0) { |
120 | 0 | goto exit; |
121 | 0 | } |
122 | 0 | if ((ret = mbedtls_md_update(&md5_ctx, md5sum, 16)) != 0) { |
123 | 0 | goto exit; |
124 | 0 | } |
125 | 0 | if ((ret = mbedtls_md_update(&md5_ctx, pwd, pwdlen)) != 0) { |
126 | 0 | goto exit; |
127 | 0 | } |
128 | 0 | if ((ret = mbedtls_md_update(&md5_ctx, iv, 8)) != 0) { |
129 | 0 | goto exit; |
130 | 0 | } |
131 | 0 | if ((ret = mbedtls_md_finish(&md5_ctx, md5sum)) != 0) { |
132 | 0 | goto exit; |
133 | 0 | } |
134 | | |
135 | 0 | use_len = 16; |
136 | 0 | if (keylen < 32) { |
137 | 0 | use_len = keylen - 16; |
138 | 0 | } |
139 | |
|
140 | 0 | memcpy(key + 16, md5sum, use_len); |
141 | |
|
142 | 0 | exit: |
143 | 0 | mbedtls_md_free(&md5_ctx); |
144 | 0 | mbedtls_platform_zeroize(md5sum, 16); |
145 | |
|
146 | 0 | return ret; |
147 | 0 | } |
148 | | |
149 | | #if defined(MBEDTLS_DES_C) |
150 | | /* |
151 | | * Decrypt with DES-CBC, using PBKDF1 for key derivation |
152 | | */ |
153 | | static int pem_des_decrypt(unsigned char des_iv[8], |
154 | | unsigned char *buf, size_t buflen, |
155 | | const unsigned char *pwd, size_t pwdlen) |
156 | 0 | { |
157 | 0 | mbedtls_des_context des_ctx; |
158 | 0 | unsigned char des_key[8]; |
159 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
160 | |
|
161 | 0 | mbedtls_des_init(&des_ctx); |
162 | |
|
163 | 0 | if ((ret = pem_pbkdf1(des_key, 8, des_iv, pwd, pwdlen)) != 0) { |
164 | 0 | goto exit; |
165 | 0 | } |
166 | | |
167 | 0 | if ((ret = mbedtls_des_setkey_dec(&des_ctx, des_key)) != 0) { |
168 | 0 | goto exit; |
169 | 0 | } |
170 | 0 | ret = mbedtls_des_crypt_cbc(&des_ctx, MBEDTLS_DES_DECRYPT, buflen, |
171 | 0 | des_iv, buf, buf); |
172 | |
|
173 | 0 | exit: |
174 | 0 | mbedtls_des_free(&des_ctx); |
175 | 0 | mbedtls_platform_zeroize(des_key, 8); |
176 | |
|
177 | 0 | return ret; |
178 | 0 | } |
179 | | |
180 | | /* |
181 | | * Decrypt with 3DES-CBC, using PBKDF1 for key derivation |
182 | | */ |
183 | | static int pem_des3_decrypt(unsigned char des3_iv[8], |
184 | | unsigned char *buf, size_t buflen, |
185 | | const unsigned char *pwd, size_t pwdlen) |
186 | 0 | { |
187 | 0 | mbedtls_des3_context des3_ctx; |
188 | 0 | unsigned char des3_key[24]; |
189 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
190 | |
|
191 | 0 | mbedtls_des3_init(&des3_ctx); |
192 | |
|
193 | 0 | if ((ret = pem_pbkdf1(des3_key, 24, des3_iv, pwd, pwdlen)) != 0) { |
194 | 0 | goto exit; |
195 | 0 | } |
196 | | |
197 | 0 | if ((ret = mbedtls_des3_set3key_dec(&des3_ctx, des3_key)) != 0) { |
198 | 0 | goto exit; |
199 | 0 | } |
200 | 0 | ret = mbedtls_des3_crypt_cbc(&des3_ctx, MBEDTLS_DES_DECRYPT, buflen, |
201 | 0 | des3_iv, buf, buf); |
202 | |
|
203 | 0 | exit: |
204 | 0 | mbedtls_des3_free(&des3_ctx); |
205 | 0 | mbedtls_platform_zeroize(des3_key, 24); |
206 | |
|
207 | 0 | return ret; |
208 | 0 | } |
209 | | #endif /* MBEDTLS_DES_C */ |
210 | | |
211 | | #if defined(MBEDTLS_AES_C) |
212 | | /* |
213 | | * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation |
214 | | */ |
215 | | static int pem_aes_decrypt(unsigned char aes_iv[16], unsigned int keylen, |
216 | | unsigned char *buf, size_t buflen, |
217 | | const unsigned char *pwd, size_t pwdlen) |
218 | 0 | { |
219 | 0 | mbedtls_aes_context aes_ctx; |
220 | 0 | unsigned char aes_key[32]; |
221 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
222 | |
|
223 | 0 | mbedtls_aes_init(&aes_ctx); |
224 | |
|
225 | 0 | if ((ret = pem_pbkdf1(aes_key, keylen, aes_iv, pwd, pwdlen)) != 0) { |
226 | 0 | goto exit; |
227 | 0 | } |
228 | | |
229 | 0 | if ((ret = mbedtls_aes_setkey_dec(&aes_ctx, aes_key, keylen * 8)) != 0) { |
230 | 0 | goto exit; |
231 | 0 | } |
232 | 0 | ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, buflen, |
233 | 0 | aes_iv, buf, buf); |
234 | |
|
235 | 0 | exit: |
236 | 0 | mbedtls_aes_free(&aes_ctx); |
237 | 0 | mbedtls_platform_zeroize(aes_key, keylen); |
238 | |
|
239 | 0 | return ret; |
240 | 0 | } |
241 | | #endif /* MBEDTLS_AES_C */ |
242 | | |
243 | | #if defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) |
244 | | static int pem_check_pkcs_padding(unsigned char *input, size_t input_len, size_t *data_len) |
245 | 0 | { |
246 | | /* input_len > 0 is guaranteed by mbedtls_pem_read_buffer(). */ |
247 | 0 | size_t pad_len = input[input_len - 1]; |
248 | 0 | size_t i; |
249 | |
|
250 | 0 | if (pad_len > input_len) { |
251 | 0 | return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH; |
252 | 0 | } |
253 | | |
254 | 0 | *data_len = input_len - pad_len; |
255 | |
|
256 | 0 | for (i = *data_len; i < input_len; i++) { |
257 | 0 | if (input[i] != pad_len) { |
258 | 0 | return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH; |
259 | 0 | } |
260 | 0 | } |
261 | | |
262 | 0 | return 0; |
263 | 0 | } |
264 | | #endif /* MBEDTLS_DES_C || MBEDTLS_AES_C */ |
265 | | |
266 | | #endif /* PEM_RFC1421 */ |
267 | | |
268 | | int mbedtls_pem_read_buffer(mbedtls_pem_context *ctx, const char *header, const char *footer, |
269 | | const unsigned char *data, const unsigned char *pwd, |
270 | | size_t pwdlen, size_t *use_len) |
271 | 59.1k | { |
272 | 59.1k | int ret, enc; |
273 | 59.1k | size_t len; |
274 | 59.1k | unsigned char *buf; |
275 | 59.1k | const unsigned char *s1, *s2, *end; |
276 | 59.1k | #if defined(PEM_RFC1421) |
277 | 59.1k | unsigned char pem_iv[16]; |
278 | 59.1k | mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE; |
279 | | #else |
280 | | ((void) pwd); |
281 | | ((void) pwdlen); |
282 | | #endif /* PEM_RFC1421 */ |
283 | | |
284 | 59.1k | if (ctx == NULL) { |
285 | 0 | return MBEDTLS_ERR_PEM_BAD_INPUT_DATA; |
286 | 0 | } |
287 | | |
288 | 59.1k | s1 = (unsigned char *) strstr((const char *) data, header); |
289 | | |
290 | 59.1k | if (s1 == NULL) { |
291 | 924 | return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; |
292 | 924 | } |
293 | | |
294 | 58.2k | s2 = (unsigned char *) strstr((const char *) data, footer); |
295 | | |
296 | 58.2k | if (s2 == NULL || s2 <= s1) { |
297 | 145 | return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; |
298 | 145 | } |
299 | | |
300 | 58.1k | s1 += strlen(header); |
301 | 58.1k | if (*s1 == ' ') { |
302 | 289 | s1++; |
303 | 289 | } |
304 | 58.1k | if (*s1 == '\r') { |
305 | 194 | s1++; |
306 | 194 | } |
307 | 58.1k | if (*s1 == '\n') { |
308 | 58.0k | s1++; |
309 | 58.0k | } else { |
310 | 39 | return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; |
311 | 39 | } |
312 | | |
313 | 58.0k | end = s2; |
314 | 58.0k | end += strlen(footer); |
315 | 58.0k | if (*end == ' ') { |
316 | 240 | end++; |
317 | 240 | } |
318 | 58.0k | if (*end == '\r') { |
319 | 324 | end++; |
320 | 324 | } |
321 | 58.0k | if (*end == '\n') { |
322 | 1.45k | end++; |
323 | 1.45k | } |
324 | 58.0k | *use_len = (size_t) (end - data); |
325 | | |
326 | 58.0k | enc = 0; |
327 | | |
328 | 58.0k | if (s2 - s1 >= 22 && memcmp(s1, "Proc-Type: 4,ENCRYPTED", 22) == 0) { |
329 | 4.17k | #if defined(PEM_RFC1421) |
330 | 4.17k | enc++; |
331 | | |
332 | 4.17k | s1 += 22; |
333 | 4.17k | if (*s1 == '\r') { |
334 | 276 | s1++; |
335 | 276 | } |
336 | 4.17k | if (*s1 == '\n') { |
337 | 3.77k | s1++; |
338 | 3.77k | } else { |
339 | 406 | return MBEDTLS_ERR_PEM_INVALID_DATA; |
340 | 406 | } |
341 | | |
342 | | |
343 | 3.77k | #if defined(MBEDTLS_DES_C) |
344 | 3.77k | if (s2 - s1 >= 23 && memcmp(s1, "DEK-Info: DES-EDE3-CBC,", 23) == 0) { |
345 | 625 | enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC; |
346 | | |
347 | 625 | s1 += 23; |
348 | 625 | if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) { |
349 | 404 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
350 | 404 | } |
351 | | |
352 | 221 | s1 += 16; |
353 | 3.14k | } else if (s2 - s1 >= 18 && memcmp(s1, "DEK-Info: DES-CBC,", 18) == 0) { |
354 | 832 | enc_alg = MBEDTLS_CIPHER_DES_CBC; |
355 | | |
356 | 832 | s1 += 18; |
357 | 832 | if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) { |
358 | 427 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
359 | 427 | } |
360 | | |
361 | 405 | s1 += 16; |
362 | 405 | } |
363 | 2.93k | #endif /* MBEDTLS_DES_C */ |
364 | | |
365 | 2.93k | #if defined(MBEDTLS_AES_C) |
366 | 2.93k | if (s2 - s1 >= 14 && memcmp(s1, "DEK-Info: AES-", 14) == 0) { |
367 | 1.81k | if (s2 - s1 < 22) { |
368 | 213 | return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG; |
369 | 1.60k | } else if (memcmp(s1, "DEK-Info: AES-128-CBC,", 22) == 0) { |
370 | 362 | enc_alg = MBEDTLS_CIPHER_AES_128_CBC; |
371 | 1.24k | } else if (memcmp(s1, "DEK-Info: AES-192-CBC,", 22) == 0) { |
372 | 709 | enc_alg = MBEDTLS_CIPHER_AES_192_CBC; |
373 | 709 | } else if (memcmp(s1, "DEK-Info: AES-256-CBC,", 22) == 0) { |
374 | 301 | enc_alg = MBEDTLS_CIPHER_AES_256_CBC; |
375 | 301 | } else { |
376 | 234 | return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG; |
377 | 234 | } |
378 | | |
379 | 1.37k | s1 += 22; |
380 | 1.37k | if (s2 - s1 < 32 || pem_get_iv(s1, pem_iv, 16) != 0) { |
381 | 955 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
382 | 955 | } |
383 | | |
384 | 417 | s1 += 32; |
385 | 417 | } |
386 | 1.53k | #endif /* MBEDTLS_AES_C */ |
387 | | |
388 | 1.53k | if (enc_alg == MBEDTLS_CIPHER_NONE) { |
389 | 598 | return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG; |
390 | 598 | } |
391 | | |
392 | 939 | if (*s1 == '\r') { |
393 | 261 | s1++; |
394 | 261 | } |
395 | 939 | if (*s1 == '\n') { |
396 | 392 | s1++; |
397 | 547 | } else { |
398 | 547 | return MBEDTLS_ERR_PEM_INVALID_DATA; |
399 | 547 | } |
400 | | #else |
401 | | return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE; |
402 | | #endif /* PEM_RFC1421 */ |
403 | 939 | } |
404 | | |
405 | 54.2k | if (s1 >= s2) { |
406 | 1.74k | return MBEDTLS_ERR_PEM_INVALID_DATA; |
407 | 1.74k | } |
408 | | |
409 | 52.5k | ret = mbedtls_base64_decode(NULL, 0, &len, s1, (size_t) (s2 - s1)); |
410 | | |
411 | 52.5k | if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) { |
412 | 2.80k | return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret); |
413 | 2.80k | } |
414 | | |
415 | 49.7k | if (len == 0) { |
416 | 10 | return MBEDTLS_ERR_PEM_BAD_INPUT_DATA; |
417 | 10 | } |
418 | | |
419 | 49.7k | if ((buf = mbedtls_calloc(1, len)) == NULL) { |
420 | 0 | return MBEDTLS_ERR_PEM_ALLOC_FAILED; |
421 | 0 | } |
422 | | |
423 | 49.7k | if ((ret = mbedtls_base64_decode(buf, len, &len, s1, (size_t) (s2 - s1))) != 0) { |
424 | 0 | mbedtls_zeroize_and_free(buf, len); |
425 | 0 | return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret); |
426 | 0 | } |
427 | | |
428 | 49.7k | if (enc != 0) { |
429 | 195 | #if defined(PEM_RFC1421) |
430 | 195 | if (pwd == NULL) { |
431 | 195 | mbedtls_zeroize_and_free(buf, len); |
432 | 195 | return MBEDTLS_ERR_PEM_PASSWORD_REQUIRED; |
433 | 195 | } |
434 | | |
435 | 0 | ret = 0; |
436 | |
|
437 | 0 | #if defined(MBEDTLS_DES_C) |
438 | 0 | if (enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC) { |
439 | 0 | ret = pem_des3_decrypt(pem_iv, buf, len, pwd, pwdlen); |
440 | 0 | } else if (enc_alg == MBEDTLS_CIPHER_DES_CBC) { |
441 | 0 | ret = pem_des_decrypt(pem_iv, buf, len, pwd, pwdlen); |
442 | 0 | } |
443 | 0 | #endif /* MBEDTLS_DES_C */ |
444 | |
|
445 | 0 | #if defined(MBEDTLS_AES_C) |
446 | 0 | if (enc_alg == MBEDTLS_CIPHER_AES_128_CBC) { |
447 | 0 | ret = pem_aes_decrypt(pem_iv, 16, buf, len, pwd, pwdlen); |
448 | 0 | } else if (enc_alg == MBEDTLS_CIPHER_AES_192_CBC) { |
449 | 0 | ret = pem_aes_decrypt(pem_iv, 24, buf, len, pwd, pwdlen); |
450 | 0 | } else if (enc_alg == MBEDTLS_CIPHER_AES_256_CBC) { |
451 | 0 | ret = pem_aes_decrypt(pem_iv, 32, buf, len, pwd, pwdlen); |
452 | 0 | } |
453 | 0 | #endif /* MBEDTLS_AES_C */ |
454 | |
|
455 | 0 | if (ret != 0) { |
456 | 0 | mbedtls_zeroize_and_free(buf, len); |
457 | 0 | return ret; |
458 | 0 | } |
459 | | |
460 | | /* Check PKCS padding and update data length based on padding info. |
461 | | * This can be used to detect invalid padding data and password |
462 | | * mismatches. */ |
463 | 0 | size_t unpadded_len; |
464 | 0 | ret = pem_check_pkcs_padding(buf, len, &unpadded_len); |
465 | 0 | if (ret != 0) { |
466 | 0 | mbedtls_zeroize_and_free(buf, len); |
467 | 0 | return ret; |
468 | 0 | } |
469 | 0 | len = unpadded_len; |
470 | | #else |
471 | | mbedtls_zeroize_and_free(buf, len); |
472 | | return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE; |
473 | | #endif /* PEM_RFC1421 */ |
474 | 0 | } |
475 | | |
476 | 49.5k | ctx->buf = buf; |
477 | 49.5k | ctx->buflen = len; |
478 | | |
479 | 49.5k | return 0; |
480 | 49.7k | } |
481 | | |
482 | | void mbedtls_pem_free(mbedtls_pem_context *ctx) |
483 | 58.0k | { |
484 | 58.0k | if (ctx == NULL) { |
485 | 0 | return; |
486 | 0 | } |
487 | | |
488 | 58.0k | if (ctx->buf != NULL) { |
489 | 49.5k | mbedtls_zeroize_and_free(ctx->buf, ctx->buflen); |
490 | 49.5k | } |
491 | 58.0k | mbedtls_free(ctx->info); |
492 | | |
493 | 58.0k | mbedtls_platform_zeroize(ctx, sizeof(mbedtls_pem_context)); |
494 | 58.0k | } |
495 | | #endif /* MBEDTLS_PEM_PARSE_C */ |
496 | | |
497 | | #if defined(MBEDTLS_PEM_WRITE_C) |
498 | | int mbedtls_pem_write_buffer(const char *header, const char *footer, |
499 | | const unsigned char *der_data, size_t der_len, |
500 | | unsigned char *buf, size_t buf_len, size_t *olen) |
501 | 0 | { |
502 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
503 | 0 | unsigned char *encode_buf = NULL, *c, *p = buf; |
504 | 0 | size_t len = 0, use_len, add_len = 0; |
505 | |
|
506 | 0 | mbedtls_base64_encode(NULL, 0, &use_len, der_data, der_len); |
507 | 0 | add_len = strlen(header) + strlen(footer) + (((use_len > 2) ? (use_len - 2) : 0) / 64) + 1; |
508 | |
|
509 | 0 | if (use_len + add_len > buf_len) { |
510 | 0 | *olen = use_len + add_len; |
511 | 0 | return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL; |
512 | 0 | } |
513 | | |
514 | 0 | if (use_len != 0 && |
515 | 0 | ((encode_buf = mbedtls_calloc(1, use_len)) == NULL)) { |
516 | 0 | return MBEDTLS_ERR_PEM_ALLOC_FAILED; |
517 | 0 | } |
518 | | |
519 | 0 | if ((ret = mbedtls_base64_encode(encode_buf, use_len, &use_len, der_data, |
520 | 0 | der_len)) != 0) { |
521 | 0 | mbedtls_free(encode_buf); |
522 | 0 | return ret; |
523 | 0 | } |
524 | | |
525 | 0 | memcpy(p, header, strlen(header)); |
526 | 0 | p += strlen(header); |
527 | 0 | c = encode_buf; |
528 | |
|
529 | 0 | while (use_len) { |
530 | 0 | len = (use_len > 64) ? 64 : use_len; |
531 | 0 | memcpy(p, c, len); |
532 | 0 | use_len -= len; |
533 | 0 | p += len; |
534 | 0 | c += len; |
535 | 0 | *p++ = '\n'; |
536 | 0 | } |
537 | |
|
538 | 0 | memcpy(p, footer, strlen(footer)); |
539 | 0 | p += strlen(footer); |
540 | |
|
541 | 0 | *p++ = '\0'; |
542 | 0 | *olen = (size_t) (p - buf); |
543 | | |
544 | | /* Clean any remaining data previously written to the buffer */ |
545 | 0 | memset(buf + *olen, 0, buf_len - *olen); |
546 | |
|
547 | 0 | mbedtls_free(encode_buf); |
548 | 0 | return 0; |
549 | 0 | } |
550 | | #endif /* MBEDTLS_PEM_WRITE_C */ |
551 | | #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ |