/work/mbedtls-2.28.8/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/md5.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_PEM_PARSE_C) |
26 | | void mbedtls_pem_init(mbedtls_pem_context *ctx) |
27 | 0 | { |
28 | 0 | memset(ctx, 0, sizeof(mbedtls_pem_context)); |
29 | 0 | } |
30 | | |
31 | | #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
32 | | (defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C)) |
33 | | /* |
34 | | * Read a 16-byte hex string and convert it to binary |
35 | | */ |
36 | | static int pem_get_iv(const unsigned char *s, unsigned char *iv, |
37 | | size_t iv_len) |
38 | 0 | { |
39 | 0 | size_t i, j, k; |
40 | |
|
41 | 0 | memset(iv, 0, iv_len); |
42 | |
|
43 | 0 | for (i = 0; i < iv_len * 2; i++, s++) { |
44 | 0 | if (*s >= '0' && *s <= '9') { |
45 | 0 | j = *s - '0'; |
46 | 0 | } else |
47 | 0 | if (*s >= 'A' && *s <= 'F') { |
48 | 0 | j = *s - '7'; |
49 | 0 | } else |
50 | 0 | if (*s >= 'a' && *s <= 'f') { |
51 | 0 | j = *s - 'W'; |
52 | 0 | } else { |
53 | 0 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
54 | 0 | } |
55 | | |
56 | 0 | k = ((i & 1) != 0) ? j : j << 4; |
57 | |
|
58 | 0 | iv[i >> 1] = (unsigned char) (iv[i >> 1] | k); |
59 | 0 | } |
60 | | |
61 | 0 | return 0; |
62 | 0 | } |
63 | | |
64 | | static int pem_pbkdf1(unsigned char *key, size_t keylen, |
65 | | unsigned char *iv, |
66 | | const unsigned char *pwd, size_t pwdlen) |
67 | 0 | { |
68 | 0 | mbedtls_md5_context md5_ctx; |
69 | 0 | unsigned char md5sum[16]; |
70 | 0 | size_t use_len; |
71 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
72 | |
|
73 | 0 | mbedtls_md5_init(&md5_ctx); |
74 | | |
75 | | /* |
76 | | * key[ 0..15] = MD5(pwd || IV) |
77 | | */ |
78 | 0 | if ((ret = mbedtls_md5_starts_ret(&md5_ctx)) != 0) { |
79 | 0 | goto exit; |
80 | 0 | } |
81 | 0 | if ((ret = mbedtls_md5_update_ret(&md5_ctx, pwd, pwdlen)) != 0) { |
82 | 0 | goto exit; |
83 | 0 | } |
84 | 0 | if ((ret = mbedtls_md5_update_ret(&md5_ctx, iv, 8)) != 0) { |
85 | 0 | goto exit; |
86 | 0 | } |
87 | 0 | if ((ret = mbedtls_md5_finish_ret(&md5_ctx, md5sum)) != 0) { |
88 | 0 | goto exit; |
89 | 0 | } |
90 | | |
91 | 0 | if (keylen <= 16) { |
92 | 0 | memcpy(key, md5sum, keylen); |
93 | 0 | goto exit; |
94 | 0 | } |
95 | | |
96 | 0 | memcpy(key, md5sum, 16); |
97 | | |
98 | | /* |
99 | | * key[16..23] = MD5(key[ 0..15] || pwd || IV]) |
100 | | */ |
101 | 0 | if ((ret = mbedtls_md5_starts_ret(&md5_ctx)) != 0) { |
102 | 0 | goto exit; |
103 | 0 | } |
104 | 0 | if ((ret = mbedtls_md5_update_ret(&md5_ctx, md5sum, 16)) != 0) { |
105 | 0 | goto exit; |
106 | 0 | } |
107 | 0 | if ((ret = mbedtls_md5_update_ret(&md5_ctx, pwd, pwdlen)) != 0) { |
108 | 0 | goto exit; |
109 | 0 | } |
110 | 0 | if ((ret = mbedtls_md5_update_ret(&md5_ctx, iv, 8)) != 0) { |
111 | 0 | goto exit; |
112 | 0 | } |
113 | 0 | if ((ret = mbedtls_md5_finish_ret(&md5_ctx, md5sum)) != 0) { |
114 | 0 | goto exit; |
115 | 0 | } |
116 | | |
117 | 0 | use_len = 16; |
118 | 0 | if (keylen < 32) { |
119 | 0 | use_len = keylen - 16; |
120 | 0 | } |
121 | |
|
122 | 0 | memcpy(key + 16, md5sum, use_len); |
123 | |
|
124 | 0 | exit: |
125 | 0 | mbedtls_md5_free(&md5_ctx); |
126 | 0 | mbedtls_platform_zeroize(md5sum, 16); |
127 | |
|
128 | 0 | return ret; |
129 | 0 | } |
130 | | |
131 | | #if defined(MBEDTLS_DES_C) |
132 | | /* |
133 | | * Decrypt with DES-CBC, using PBKDF1 for key derivation |
134 | | */ |
135 | | static int pem_des_decrypt(unsigned char des_iv[8], |
136 | | unsigned char *buf, size_t buflen, |
137 | | const unsigned char *pwd, size_t pwdlen) |
138 | 0 | { |
139 | 0 | mbedtls_des_context des_ctx; |
140 | 0 | unsigned char des_key[8]; |
141 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
142 | |
|
143 | 0 | mbedtls_des_init(&des_ctx); |
144 | |
|
145 | 0 | if ((ret = pem_pbkdf1(des_key, 8, des_iv, pwd, pwdlen)) != 0) { |
146 | 0 | goto exit; |
147 | 0 | } |
148 | | |
149 | 0 | if ((ret = mbedtls_des_setkey_dec(&des_ctx, des_key)) != 0) { |
150 | 0 | goto exit; |
151 | 0 | } |
152 | 0 | ret = mbedtls_des_crypt_cbc(&des_ctx, MBEDTLS_DES_DECRYPT, buflen, |
153 | 0 | des_iv, buf, buf); |
154 | |
|
155 | 0 | exit: |
156 | 0 | mbedtls_des_free(&des_ctx); |
157 | 0 | mbedtls_platform_zeroize(des_key, 8); |
158 | |
|
159 | 0 | return ret; |
160 | 0 | } |
161 | | |
162 | | /* |
163 | | * Decrypt with 3DES-CBC, using PBKDF1 for key derivation |
164 | | */ |
165 | | static int pem_des3_decrypt(unsigned char des3_iv[8], |
166 | | unsigned char *buf, size_t buflen, |
167 | | const unsigned char *pwd, size_t pwdlen) |
168 | 0 | { |
169 | 0 | mbedtls_des3_context des3_ctx; |
170 | 0 | unsigned char des3_key[24]; |
171 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
172 | |
|
173 | 0 | mbedtls_des3_init(&des3_ctx); |
174 | |
|
175 | 0 | if ((ret = pem_pbkdf1(des3_key, 24, des3_iv, pwd, pwdlen)) != 0) { |
176 | 0 | goto exit; |
177 | 0 | } |
178 | | |
179 | 0 | if ((ret = mbedtls_des3_set3key_dec(&des3_ctx, des3_key)) != 0) { |
180 | 0 | goto exit; |
181 | 0 | } |
182 | 0 | ret = mbedtls_des3_crypt_cbc(&des3_ctx, MBEDTLS_DES_DECRYPT, buflen, |
183 | 0 | des3_iv, buf, buf); |
184 | |
|
185 | 0 | exit: |
186 | 0 | mbedtls_des3_free(&des3_ctx); |
187 | 0 | mbedtls_platform_zeroize(des3_key, 24); |
188 | |
|
189 | 0 | return ret; |
190 | 0 | } |
191 | | #endif /* MBEDTLS_DES_C */ |
192 | | |
193 | | #if defined(MBEDTLS_AES_C) |
194 | | /* |
195 | | * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation |
196 | | */ |
197 | | static int pem_aes_decrypt(unsigned char aes_iv[16], unsigned int keylen, |
198 | | unsigned char *buf, size_t buflen, |
199 | | const unsigned char *pwd, size_t pwdlen) |
200 | 0 | { |
201 | 0 | mbedtls_aes_context aes_ctx; |
202 | 0 | unsigned char aes_key[32]; |
203 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
204 | |
|
205 | 0 | mbedtls_aes_init(&aes_ctx); |
206 | |
|
207 | 0 | if ((ret = pem_pbkdf1(aes_key, keylen, aes_iv, pwd, pwdlen)) != 0) { |
208 | 0 | goto exit; |
209 | 0 | } |
210 | | |
211 | 0 | if ((ret = mbedtls_aes_setkey_dec(&aes_ctx, aes_key, keylen * 8)) != 0) { |
212 | 0 | goto exit; |
213 | 0 | } |
214 | 0 | ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, buflen, |
215 | 0 | aes_iv, buf, buf); |
216 | |
|
217 | 0 | exit: |
218 | 0 | mbedtls_aes_free(&aes_ctx); |
219 | 0 | mbedtls_platform_zeroize(aes_key, keylen); |
220 | |
|
221 | 0 | return ret; |
222 | 0 | } |
223 | | #endif /* MBEDTLS_AES_C */ |
224 | | |
225 | | #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && |
226 | | ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ |
227 | | |
228 | | int mbedtls_pem_read_buffer(mbedtls_pem_context *ctx, const char *header, const char *footer, |
229 | | const unsigned char *data, const unsigned char *pwd, |
230 | | size_t pwdlen, size_t *use_len) |
231 | 0 | { |
232 | 0 | int ret, enc; |
233 | 0 | size_t len; |
234 | 0 | unsigned char *buf; |
235 | 0 | const unsigned char *s1, *s2, *end; |
236 | 0 | #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
237 | 0 | (defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C)) |
238 | 0 | unsigned char pem_iv[16]; |
239 | 0 | mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE; |
240 | | #else |
241 | | ((void) pwd); |
242 | | ((void) pwdlen); |
243 | | #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && |
244 | | ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ |
245 | |
|
246 | 0 | if (ctx == NULL) { |
247 | 0 | return MBEDTLS_ERR_PEM_BAD_INPUT_DATA; |
248 | 0 | } |
249 | | |
250 | 0 | s1 = (unsigned char *) strstr((const char *) data, header); |
251 | |
|
252 | 0 | if (s1 == NULL) { |
253 | 0 | return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; |
254 | 0 | } |
255 | | |
256 | 0 | s2 = (unsigned char *) strstr((const char *) data, footer); |
257 | |
|
258 | 0 | if (s2 == NULL || s2 <= s1) { |
259 | 0 | return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; |
260 | 0 | } |
261 | | |
262 | 0 | s1 += strlen(header); |
263 | 0 | if (*s1 == ' ') { |
264 | 0 | s1++; |
265 | 0 | } |
266 | 0 | if (*s1 == '\r') { |
267 | 0 | s1++; |
268 | 0 | } |
269 | 0 | if (*s1 == '\n') { |
270 | 0 | s1++; |
271 | 0 | } else { |
272 | 0 | return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; |
273 | 0 | } |
274 | | |
275 | 0 | end = s2; |
276 | 0 | end += strlen(footer); |
277 | 0 | if (*end == ' ') { |
278 | 0 | end++; |
279 | 0 | } |
280 | 0 | if (*end == '\r') { |
281 | 0 | end++; |
282 | 0 | } |
283 | 0 | if (*end == '\n') { |
284 | 0 | end++; |
285 | 0 | } |
286 | 0 | *use_len = end - data; |
287 | |
|
288 | 0 | enc = 0; |
289 | |
|
290 | 0 | if (s2 - s1 >= 22 && memcmp(s1, "Proc-Type: 4,ENCRYPTED", 22) == 0) { |
291 | 0 | #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
292 | 0 | (defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C)) |
293 | 0 | enc++; |
294 | |
|
295 | 0 | s1 += 22; |
296 | 0 | if (*s1 == '\r') { |
297 | 0 | s1++; |
298 | 0 | } |
299 | 0 | if (*s1 == '\n') { |
300 | 0 | s1++; |
301 | 0 | } else { |
302 | 0 | return MBEDTLS_ERR_PEM_INVALID_DATA; |
303 | 0 | } |
304 | | |
305 | | |
306 | 0 | #if defined(MBEDTLS_DES_C) |
307 | 0 | if (s2 - s1 >= 23 && memcmp(s1, "DEK-Info: DES-EDE3-CBC,", 23) == 0) { |
308 | 0 | enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC; |
309 | |
|
310 | 0 | s1 += 23; |
311 | 0 | if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) { |
312 | 0 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
313 | 0 | } |
314 | | |
315 | 0 | s1 += 16; |
316 | 0 | } else if (s2 - s1 >= 18 && memcmp(s1, "DEK-Info: DES-CBC,", 18) == 0) { |
317 | 0 | enc_alg = MBEDTLS_CIPHER_DES_CBC; |
318 | |
|
319 | 0 | s1 += 18; |
320 | 0 | if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) { |
321 | 0 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
322 | 0 | } |
323 | | |
324 | 0 | s1 += 16; |
325 | 0 | } |
326 | 0 | #endif /* MBEDTLS_DES_C */ |
327 | | |
328 | 0 | #if defined(MBEDTLS_AES_C) |
329 | 0 | if (s2 - s1 >= 14 && memcmp(s1, "DEK-Info: AES-", 14) == 0) { |
330 | 0 | if (s2 - s1 < 22) { |
331 | 0 | return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG; |
332 | 0 | } else if (memcmp(s1, "DEK-Info: AES-128-CBC,", 22) == 0) { |
333 | 0 | enc_alg = MBEDTLS_CIPHER_AES_128_CBC; |
334 | 0 | } else if (memcmp(s1, "DEK-Info: AES-192-CBC,", 22) == 0) { |
335 | 0 | enc_alg = MBEDTLS_CIPHER_AES_192_CBC; |
336 | 0 | } else if (memcmp(s1, "DEK-Info: AES-256-CBC,", 22) == 0) { |
337 | 0 | enc_alg = MBEDTLS_CIPHER_AES_256_CBC; |
338 | 0 | } else { |
339 | 0 | return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG; |
340 | 0 | } |
341 | | |
342 | 0 | s1 += 22; |
343 | 0 | if (s2 - s1 < 32 || pem_get_iv(s1, pem_iv, 16) != 0) { |
344 | 0 | return MBEDTLS_ERR_PEM_INVALID_ENC_IV; |
345 | 0 | } |
346 | | |
347 | 0 | s1 += 32; |
348 | 0 | } |
349 | 0 | #endif /* MBEDTLS_AES_C */ |
350 | | |
351 | 0 | if (enc_alg == MBEDTLS_CIPHER_NONE) { |
352 | 0 | return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG; |
353 | 0 | } |
354 | | |
355 | 0 | if (*s1 == '\r') { |
356 | 0 | s1++; |
357 | 0 | } |
358 | 0 | if (*s1 == '\n') { |
359 | 0 | s1++; |
360 | 0 | } else { |
361 | 0 | return MBEDTLS_ERR_PEM_INVALID_DATA; |
362 | 0 | } |
363 | | #else |
364 | | return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE; |
365 | | #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && |
366 | | ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ |
367 | 0 | } |
368 | | |
369 | 0 | if (s1 >= s2) { |
370 | 0 | return MBEDTLS_ERR_PEM_INVALID_DATA; |
371 | 0 | } |
372 | | |
373 | 0 | ret = mbedtls_base64_decode(NULL, 0, &len, s1, s2 - s1); |
374 | |
|
375 | 0 | if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) { |
376 | 0 | return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret); |
377 | 0 | } |
378 | | |
379 | 0 | if ((buf = mbedtls_calloc(1, len)) == NULL) { |
380 | 0 | return MBEDTLS_ERR_PEM_ALLOC_FAILED; |
381 | 0 | } |
382 | | |
383 | 0 | if ((ret = mbedtls_base64_decode(buf, len, &len, s1, s2 - s1)) != 0) { |
384 | 0 | mbedtls_platform_zeroize(buf, len); |
385 | 0 | mbedtls_free(buf); |
386 | 0 | return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret); |
387 | 0 | } |
388 | | |
389 | 0 | if (enc != 0) { |
390 | 0 | #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ |
391 | 0 | (defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C)) |
392 | 0 | if (pwd == NULL) { |
393 | 0 | mbedtls_platform_zeroize(buf, len); |
394 | 0 | mbedtls_free(buf); |
395 | 0 | return MBEDTLS_ERR_PEM_PASSWORD_REQUIRED; |
396 | 0 | } |
397 | | |
398 | 0 | ret = 0; |
399 | |
|
400 | 0 | #if defined(MBEDTLS_DES_C) |
401 | 0 | if (enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC) { |
402 | 0 | ret = pem_des3_decrypt(pem_iv, buf, len, pwd, pwdlen); |
403 | 0 | } else if (enc_alg == MBEDTLS_CIPHER_DES_CBC) { |
404 | 0 | ret = pem_des_decrypt(pem_iv, buf, len, pwd, pwdlen); |
405 | 0 | } |
406 | 0 | #endif /* MBEDTLS_DES_C */ |
407 | |
|
408 | 0 | #if defined(MBEDTLS_AES_C) |
409 | 0 | if (enc_alg == MBEDTLS_CIPHER_AES_128_CBC) { |
410 | 0 | ret = pem_aes_decrypt(pem_iv, 16, buf, len, pwd, pwdlen); |
411 | 0 | } else if (enc_alg == MBEDTLS_CIPHER_AES_192_CBC) { |
412 | 0 | ret = pem_aes_decrypt(pem_iv, 24, buf, len, pwd, pwdlen); |
413 | 0 | } else if (enc_alg == MBEDTLS_CIPHER_AES_256_CBC) { |
414 | 0 | ret = pem_aes_decrypt(pem_iv, 32, buf, len, pwd, pwdlen); |
415 | 0 | } |
416 | 0 | #endif /* MBEDTLS_AES_C */ |
417 | |
|
418 | 0 | if (ret != 0) { |
419 | 0 | mbedtls_free(buf); |
420 | 0 | return ret; |
421 | 0 | } |
422 | | |
423 | | /* |
424 | | * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3 |
425 | | * length bytes (allow 4 to be sure) in all known use cases. |
426 | | * |
427 | | * Use that as a heuristic to try to detect password mismatches. |
428 | | */ |
429 | 0 | if (len <= 2 || buf[0] != 0x30 || buf[1] > 0x83) { |
430 | 0 | mbedtls_platform_zeroize(buf, len); |
431 | 0 | mbedtls_free(buf); |
432 | 0 | return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH; |
433 | 0 | } |
434 | | #else |
435 | | mbedtls_platform_zeroize(buf, len); |
436 | | mbedtls_free(buf); |
437 | | return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE; |
438 | | #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && |
439 | | ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ |
440 | 0 | } |
441 | | |
442 | 0 | ctx->buf = buf; |
443 | 0 | ctx->buflen = len; |
444 | |
|
445 | 0 | return 0; |
446 | 0 | } |
447 | | |
448 | | void mbedtls_pem_free(mbedtls_pem_context *ctx) |
449 | 0 | { |
450 | 0 | if (ctx->buf != NULL) { |
451 | 0 | mbedtls_platform_zeroize(ctx->buf, ctx->buflen); |
452 | 0 | mbedtls_free(ctx->buf); |
453 | 0 | } |
454 | 0 | mbedtls_free(ctx->info); |
455 | |
|
456 | 0 | mbedtls_platform_zeroize(ctx, sizeof(mbedtls_pem_context)); |
457 | 0 | } |
458 | | #endif /* MBEDTLS_PEM_PARSE_C */ |
459 | | |
460 | | #if defined(MBEDTLS_PEM_WRITE_C) |
461 | | int mbedtls_pem_write_buffer(const char *header, const char *footer, |
462 | | const unsigned char *der_data, size_t der_len, |
463 | | unsigned char *buf, size_t buf_len, size_t *olen) |
464 | 0 | { |
465 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
466 | 0 | unsigned char *encode_buf = NULL, *c, *p = buf; |
467 | 0 | size_t len = 0, use_len, add_len = 0; |
468 | |
|
469 | 0 | mbedtls_base64_encode(NULL, 0, &use_len, der_data, der_len); |
470 | 0 | add_len = strlen(header) + strlen(footer) + (use_len / 64) + 1; |
471 | |
|
472 | 0 | if (use_len + add_len > buf_len) { |
473 | 0 | *olen = use_len + add_len; |
474 | 0 | return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL; |
475 | 0 | } |
476 | | |
477 | 0 | if (use_len != 0 && |
478 | 0 | ((encode_buf = mbedtls_calloc(1, use_len)) == NULL)) { |
479 | 0 | return MBEDTLS_ERR_PEM_ALLOC_FAILED; |
480 | 0 | } |
481 | | |
482 | 0 | if ((ret = mbedtls_base64_encode(encode_buf, use_len, &use_len, der_data, |
483 | 0 | der_len)) != 0) { |
484 | 0 | mbedtls_free(encode_buf); |
485 | 0 | return ret; |
486 | 0 | } |
487 | | |
488 | 0 | memcpy(p, header, strlen(header)); |
489 | 0 | p += strlen(header); |
490 | 0 | c = encode_buf; |
491 | |
|
492 | 0 | while (use_len) { |
493 | 0 | len = (use_len > 64) ? 64 : use_len; |
494 | 0 | memcpy(p, c, len); |
495 | 0 | use_len -= len; |
496 | 0 | p += len; |
497 | 0 | c += len; |
498 | 0 | *p++ = '\n'; |
499 | 0 | } |
500 | |
|
501 | 0 | memcpy(p, footer, strlen(footer)); |
502 | 0 | p += strlen(footer); |
503 | |
|
504 | 0 | *p++ = '\0'; |
505 | 0 | *olen = p - buf; |
506 | | |
507 | | /* Clean any remaining data previously written to the buffer */ |
508 | 0 | memset(buf + *olen, 0, buf_len - *olen); |
509 | |
|
510 | 0 | mbedtls_free(encode_buf); |
511 | 0 | return 0; |
512 | 0 | } |
513 | | #endif /* MBEDTLS_PEM_WRITE_C */ |
514 | | #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ |