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