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