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