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 191 : void mbedtls_pem_init(mbedtls_pem_context *ctx)
39 : {
40 191 : memset(ctx, 0, sizeof(mbedtls_pem_context));
41 191 : }
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 guaranteed by mbedtls_pem_read_buffer(). */
247 : size_t pad_len = input[input_len - 1];
248 : size_t i;
249 :
250 : if (pad_len > input_len) {
251 : return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH;
252 : }
253 :
254 : *data_len = input_len - pad_len;
255 :
256 : for (i = *data_len; i < input_len; i++) {
257 : if (input[i] != pad_len) {
258 : return MBEDTLS_ERR_PEM_PASSWORD_MISMATCH;
259 : }
260 : }
261 :
262 : return 0;
263 : }
264 : #endif /* MBEDTLS_DES_C || MBEDTLS_AES_C */
265 :
266 : #endif /* PEM_RFC1421 */
267 :
268 543 : 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 : {
272 : int ret, enc;
273 : size_t len;
274 : unsigned char *buf;
275 : const unsigned char *s1, *s2, *end;
276 : #if defined(PEM_RFC1421)
277 : unsigned char pem_iv[16];
278 : mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE;
279 : #else
280 : ((void) pwd);
281 : ((void) pwdlen);
282 : #endif /* PEM_RFC1421 */
283 :
284 543 : if (ctx == NULL) {
285 0 : return MBEDTLS_ERR_PEM_BAD_INPUT_DATA;
286 : }
287 :
288 543 : s1 = (unsigned char *) strstr((const char *) data, header);
289 :
290 543 : if (s1 == NULL) {
291 362 : return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
292 : }
293 :
294 181 : s2 = (unsigned char *) strstr((const char *) data, footer);
295 :
296 181 : if (s2 == NULL || s2 <= s1) {
297 0 : return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
298 : }
299 :
300 181 : s1 += strlen(header);
301 181 : if (*s1 == ' ') {
302 0 : s1++;
303 : }
304 181 : if (*s1 == '\r') {
305 181 : s1++;
306 : }
307 181 : if (*s1 == '\n') {
308 181 : s1++;
309 : } else {
310 0 : return MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
311 : }
312 :
313 181 : end = s2;
314 181 : end += strlen(footer);
315 181 : if (*end == ' ') {
316 0 : end++;
317 : }
318 181 : if (*end == '\r') {
319 181 : end++;
320 : }
321 181 : if (*end == '\n') {
322 181 : end++;
323 : }
324 181 : *use_len = (size_t) (end - data);
325 :
326 181 : enc = 0;
327 :
328 181 : if (s2 - s1 >= 22 && memcmp(s1, "Proc-Type: 4,ENCRYPTED", 22) == 0) {
329 : #if defined(PEM_RFC1421)
330 : enc++;
331 :
332 : s1 += 22;
333 : if (*s1 == '\r') {
334 : s1++;
335 : }
336 : if (*s1 == '\n') {
337 : s1++;
338 : } else {
339 : return MBEDTLS_ERR_PEM_INVALID_DATA;
340 : }
341 :
342 :
343 : #if defined(MBEDTLS_DES_C)
344 : if (s2 - s1 >= 23 && memcmp(s1, "DEK-Info: DES-EDE3-CBC,", 23) == 0) {
345 : enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC;
346 :
347 : s1 += 23;
348 : if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) {
349 : return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
350 : }
351 :
352 : s1 += 16;
353 : } else if (s2 - s1 >= 18 && memcmp(s1, "DEK-Info: DES-CBC,", 18) == 0) {
354 : enc_alg = MBEDTLS_CIPHER_DES_CBC;
355 :
356 : s1 += 18;
357 : if (s2 - s1 < 16 || pem_get_iv(s1, pem_iv, 8) != 0) {
358 : return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
359 : }
360 :
361 : s1 += 16;
362 : }
363 : #endif /* MBEDTLS_DES_C */
364 :
365 : #if defined(MBEDTLS_AES_C)
366 : if (s2 - s1 >= 14 && memcmp(s1, "DEK-Info: AES-", 14) == 0) {
367 : if (s2 - s1 < 22) {
368 : return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG;
369 : } else if (memcmp(s1, "DEK-Info: AES-128-CBC,", 22) == 0) {
370 : enc_alg = MBEDTLS_CIPHER_AES_128_CBC;
371 : } else if (memcmp(s1, "DEK-Info: AES-192-CBC,", 22) == 0) {
372 : enc_alg = MBEDTLS_CIPHER_AES_192_CBC;
373 : } else if (memcmp(s1, "DEK-Info: AES-256-CBC,", 22) == 0) {
374 : enc_alg = MBEDTLS_CIPHER_AES_256_CBC;
375 : } else {
376 : return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG;
377 : }
378 :
379 : s1 += 22;
380 : if (s2 - s1 < 32 || pem_get_iv(s1, pem_iv, 16) != 0) {
381 : return MBEDTLS_ERR_PEM_INVALID_ENC_IV;
382 : }
383 :
384 : s1 += 32;
385 : }
386 : #endif /* MBEDTLS_AES_C */
387 :
388 : if (enc_alg == MBEDTLS_CIPHER_NONE) {
389 : return MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG;
390 : }
391 :
392 : if (*s1 == '\r') {
393 : s1++;
394 : }
395 : if (*s1 == '\n') {
396 : s1++;
397 : } else {
398 : return MBEDTLS_ERR_PEM_INVALID_DATA;
399 : }
400 : #else
401 0 : return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE;
402 : #endif /* PEM_RFC1421 */
403 : }
404 :
405 181 : if (s1 >= s2) {
406 0 : return MBEDTLS_ERR_PEM_INVALID_DATA;
407 : }
408 :
409 181 : ret = mbedtls_base64_decode(NULL, 0, &len, s1, (size_t) (s2 - s1));
410 :
411 181 : if (ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER) {
412 0 : return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PEM_INVALID_DATA, ret);
413 : }
414 :
415 181 : if (len == 0) {
416 0 : return MBEDTLS_ERR_PEM_BAD_INPUT_DATA;
417 : }
418 :
419 181 : if ((buf = mbedtls_calloc(1, len)) == NULL) {
420 0 : return MBEDTLS_ERR_PEM_ALLOC_FAILED;
421 : }
422 :
423 181 : 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 : }
427 :
428 181 : if (enc != 0) {
429 : #if defined(PEM_RFC1421)
430 : if (pwd == NULL) {
431 : mbedtls_zeroize_and_free(buf, len);
432 : return MBEDTLS_ERR_PEM_PASSWORD_REQUIRED;
433 : }
434 :
435 : ret = 0;
436 :
437 : #if defined(MBEDTLS_DES_C)
438 : if (enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC) {
439 : ret = pem_des3_decrypt(pem_iv, buf, len, pwd, pwdlen);
440 : } else if (enc_alg == MBEDTLS_CIPHER_DES_CBC) {
441 : ret = pem_des_decrypt(pem_iv, buf, len, pwd, pwdlen);
442 : }
443 : #endif /* MBEDTLS_DES_C */
444 :
445 : #if defined(MBEDTLS_AES_C)
446 : if (enc_alg == MBEDTLS_CIPHER_AES_128_CBC) {
447 : ret = pem_aes_decrypt(pem_iv, 16, buf, len, pwd, pwdlen);
448 : } else if (enc_alg == MBEDTLS_CIPHER_AES_192_CBC) {
449 : ret = pem_aes_decrypt(pem_iv, 24, buf, len, pwd, pwdlen);
450 : } else if (enc_alg == MBEDTLS_CIPHER_AES_256_CBC) {
451 : ret = pem_aes_decrypt(pem_iv, 32, buf, len, pwd, pwdlen);
452 : }
453 : #endif /* MBEDTLS_AES_C */
454 :
455 : if (ret != 0) {
456 : mbedtls_zeroize_and_free(buf, len);
457 : return ret;
458 : }
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 : size_t unpadded_len;
464 : ret = pem_check_pkcs_padding(buf, len, &unpadded_len);
465 : if (ret != 0) {
466 : mbedtls_zeroize_and_free(buf, len);
467 : return ret;
468 : }
469 : len = unpadded_len;
470 : #else
471 0 : mbedtls_zeroize_and_free(buf, len);
472 0 : return MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE;
473 : #endif /* PEM_RFC1421 */
474 : }
475 :
476 181 : ctx->buf = buf;
477 181 : ctx->buflen = len;
478 :
479 181 : return 0;
480 : }
481 :
482 191 : void mbedtls_pem_free(mbedtls_pem_context *ctx)
483 : {
484 191 : if (ctx == NULL) {
485 0 : return;
486 : }
487 :
488 191 : if (ctx->buf != NULL) {
489 181 : mbedtls_zeroize_and_free(ctx->buf, ctx->buflen);
490 : }
491 191 : mbedtls_free(ctx->info);
492 :
493 191 : mbedtls_platform_zeroize(ctx, sizeof(mbedtls_pem_context));
494 : }
495 : #endif /* MBEDTLS_PEM_PARSE_C */
496 :
497 : #if defined(MBEDTLS_PEM_WRITE_C)
498 0 : 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 : {
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 : }
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 : }
518 :
519 0 : if ((ret = mbedtls_base64_encode(encode_buf, use_len, &use_len, der_data,
520 : der_len)) != 0) {
521 0 : mbedtls_free(encode_buf);
522 0 : return ret;
523 : }
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 : }
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 : }
550 : #endif /* MBEDTLS_PEM_WRITE_C */
551 : #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */
|