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