2 * Privacy Enhanced Mail (PEM) decoding
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5 * SPDX-License-Identifier: GPL-2.0
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * This file is part of mbed TLS (https://tls.mbed.org)
24 #if !defined(MBEDTLS_CONFIG_FILE)
25 #include "mbedtls/config.h"
27 #include MBEDTLS_CONFIG_FILE
30 #if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C)
32 #include "mbedtls/pem.h"
33 #include "mbedtls/base64.h"
34 #include "mbedtls/des.h"
35 #include "mbedtls/aes.h"
36 #include "mbedtls/md5.h"
37 #include "mbedtls/cipher.h"
38 #include "mbedtls/platform_util.h"
42 #if defined(MBEDTLS_PLATFORM_C)
43 #include "mbedtls/platform.h"
46 #define mbedtls_calloc calloc
47 #define mbedtls_free free
50 #if defined(MBEDTLS_PEM_PARSE_C)
51 void mbedtls_pem_init( mbedtls_pem_context
*ctx
)
53 memset( ctx
, 0, sizeof( mbedtls_pem_context
) );
56 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
57 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
59 * Read a 16-byte hex string and convert it to binary
61 static int pem_get_iv( const unsigned char *s
, unsigned char *iv
,
66 memset( iv
, 0, iv_len
);
68 for( i
= 0; i
< iv_len
* 2; i
++, s
++ )
70 if( *s
>= '0' && *s
<= '9' ) j
= *s
- '0'; else
71 if( *s
>= 'A' && *s
<= 'F' ) j
= *s
- '7'; else
72 if( *s
>= 'a' && *s
<= 'f' ) j
= *s
- 'W'; else
73 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV
);
75 k
= ( ( i
& 1 ) != 0 ) ? j
: j
<< 4;
77 iv
[i
>> 1] = (unsigned char)( iv
[i
>> 1] | k
);
83 static int pem_pbkdf1( unsigned char *key
, size_t keylen
,
85 const unsigned char *pwd
, size_t pwdlen
)
87 mbedtls_md5_context md5_ctx
;
88 unsigned char md5sum
[16];
92 mbedtls_md5_init( &md5_ctx
);
95 * key[ 0..15] = MD5(pwd || IV)
97 if( ( ret
= mbedtls_md5_starts_ret( &md5_ctx
) ) != 0 )
99 if( ( ret
= mbedtls_md5_update_ret( &md5_ctx
, pwd
, pwdlen
) ) != 0 )
101 if( ( ret
= mbedtls_md5_update_ret( &md5_ctx
, iv
, 8 ) ) != 0 )
103 if( ( ret
= mbedtls_md5_finish_ret( &md5_ctx
, md5sum
) ) != 0 )
108 memcpy( key
, md5sum
, keylen
);
112 memcpy( key
, md5sum
, 16 );
115 * key[16..23] = MD5(key[ 0..15] || pwd || IV])
117 if( ( ret
= mbedtls_md5_starts_ret( &md5_ctx
) ) != 0 )
119 if( ( ret
= mbedtls_md5_update_ret( &md5_ctx
, md5sum
, 16 ) ) != 0 )
121 if( ( ret
= mbedtls_md5_update_ret( &md5_ctx
, pwd
, pwdlen
) ) != 0 )
123 if( ( ret
= mbedtls_md5_update_ret( &md5_ctx
, iv
, 8 ) ) != 0 )
125 if( ( ret
= mbedtls_md5_finish_ret( &md5_ctx
, md5sum
) ) != 0 )
130 use_len
= keylen
- 16;
132 memcpy( key
+ 16, md5sum
, use_len
);
135 mbedtls_md5_free( &md5_ctx
);
136 mbedtls_platform_zeroize( md5sum
, 16 );
141 #if defined(MBEDTLS_DES_C)
143 * Decrypt with DES-CBC, using PBKDF1 for key derivation
145 static int pem_des_decrypt( unsigned char des_iv
[8],
146 unsigned char *buf
, size_t buflen
,
147 const unsigned char *pwd
, size_t pwdlen
)
149 mbedtls_des_context des_ctx
;
150 unsigned char des_key
[8];
153 mbedtls_des_init( &des_ctx
);
155 if( ( ret
= pem_pbkdf1( des_key
, 8, des_iv
, pwd
, pwdlen
) ) != 0 )
158 if( ( ret
= mbedtls_des_setkey_dec( &des_ctx
, des_key
) ) != 0 )
160 ret
= mbedtls_des_crypt_cbc( &des_ctx
, MBEDTLS_DES_DECRYPT
, buflen
,
164 mbedtls_des_free( &des_ctx
);
165 mbedtls_platform_zeroize( des_key
, 8 );
171 * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
173 static int pem_des3_decrypt( unsigned char des3_iv
[8],
174 unsigned char *buf
, size_t buflen
,
175 const unsigned char *pwd
, size_t pwdlen
)
177 mbedtls_des3_context des3_ctx
;
178 unsigned char des3_key
[24];
181 mbedtls_des3_init( &des3_ctx
);
183 if( ( ret
= pem_pbkdf1( des3_key
, 24, des3_iv
, pwd
, pwdlen
) ) != 0 )
186 if( ( ret
= mbedtls_des3_set3key_dec( &des3_ctx
, des3_key
) ) != 0 )
188 ret
= mbedtls_des3_crypt_cbc( &des3_ctx
, MBEDTLS_DES_DECRYPT
, buflen
,
192 mbedtls_des3_free( &des3_ctx
);
193 mbedtls_platform_zeroize( des3_key
, 24 );
197 #endif /* MBEDTLS_DES_C */
199 #if defined(MBEDTLS_AES_C)
201 * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
203 static int pem_aes_decrypt( unsigned char aes_iv
[16], unsigned int keylen
,
204 unsigned char *buf
, size_t buflen
,
205 const unsigned char *pwd
, size_t pwdlen
)
207 mbedtls_aes_context aes_ctx
;
208 unsigned char aes_key
[32];
211 mbedtls_aes_init( &aes_ctx
);
213 if( ( ret
= pem_pbkdf1( aes_key
, keylen
, aes_iv
, pwd
, pwdlen
) ) != 0 )
216 if( ( ret
= mbedtls_aes_setkey_dec( &aes_ctx
, aes_key
, keylen
* 8 ) ) != 0 )
218 ret
= mbedtls_aes_crypt_cbc( &aes_ctx
, MBEDTLS_AES_DECRYPT
, buflen
,
222 mbedtls_aes_free( &aes_ctx
);
223 mbedtls_platform_zeroize( aes_key
, keylen
);
227 #endif /* MBEDTLS_AES_C */
229 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
230 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
232 int mbedtls_pem_read_buffer( mbedtls_pem_context
*ctx
, const char *header
, const char *footer
,
233 const unsigned char *data
, const unsigned char *pwd
,
234 size_t pwdlen
, size_t *use_len
)
239 const unsigned char *s1
, *s2
, *end
;
240 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
241 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
242 unsigned char pem_iv
[16];
243 mbedtls_cipher_type_t enc_alg
= MBEDTLS_CIPHER_NONE
;
247 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
248 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
251 return( MBEDTLS_ERR_PEM_BAD_INPUT_DATA
);
253 s1
= (unsigned char *) strstr( (const char *) data
, header
);
256 return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT
);
258 s2
= (unsigned char *) strstr( (const char *) data
, footer
);
260 if( s2
== NULL
|| s2
<= s1
)
261 return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT
);
263 s1
+= strlen( header
);
264 if( *s1
== ' ' ) s1
++;
265 if( *s1
== '\r' ) s1
++;
266 if( *s1
== '\n' ) s1
++;
267 else return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT
);
270 end
+= strlen( footer
);
271 if( *end
== ' ' ) end
++;
272 if( *end
== '\r' ) end
++;
273 if( *end
== '\n' ) end
++;
274 *use_len
= end
- data
;
278 if( s2
- s1
>= 22 && memcmp( s1
, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
280 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
281 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
285 if( *s1
== '\r' ) s1
++;
286 if( *s1
== '\n' ) s1
++;
287 else return( MBEDTLS_ERR_PEM_INVALID_DATA
);
290 #if defined(MBEDTLS_DES_C)
291 if( s2
- s1
>= 23 && memcmp( s1
, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 )
293 enc_alg
= MBEDTLS_CIPHER_DES_EDE3_CBC
;
296 if( s2
- s1
< 16 || pem_get_iv( s1
, pem_iv
, 8 ) != 0 )
297 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV
);
301 else if( s2
- s1
>= 18 && memcmp( s1
, "DEK-Info: DES-CBC,", 18 ) == 0 )
303 enc_alg
= MBEDTLS_CIPHER_DES_CBC
;
306 if( s2
- s1
< 16 || pem_get_iv( s1
, pem_iv
, 8) != 0 )
307 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV
);
311 #endif /* MBEDTLS_DES_C */
313 #if defined(MBEDTLS_AES_C)
314 if( s2
- s1
>= 14 && memcmp( s1
, "DEK-Info: AES-", 14 ) == 0 )
317 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG
);
318 else if( memcmp( s1
, "DEK-Info: AES-128-CBC,", 22 ) == 0 )
319 enc_alg
= MBEDTLS_CIPHER_AES_128_CBC
;
320 else if( memcmp( s1
, "DEK-Info: AES-192-CBC,", 22 ) == 0 )
321 enc_alg
= MBEDTLS_CIPHER_AES_192_CBC
;
322 else if( memcmp( s1
, "DEK-Info: AES-256-CBC,", 22 ) == 0 )
323 enc_alg
= MBEDTLS_CIPHER_AES_256_CBC
;
325 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG
);
328 if( s2
- s1
< 32 || pem_get_iv( s1
, pem_iv
, 16 ) != 0 )
329 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV
);
333 #endif /* MBEDTLS_AES_C */
335 if( enc_alg
== MBEDTLS_CIPHER_NONE
)
336 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG
);
338 if( *s1
== '\r' ) s1
++;
339 if( *s1
== '\n' ) s1
++;
340 else return( MBEDTLS_ERR_PEM_INVALID_DATA
);
342 return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE
);
343 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
344 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
348 return( MBEDTLS_ERR_PEM_INVALID_DATA
);
350 ret
= mbedtls_base64_decode( NULL
, 0, &len
, s1
, s2
- s1
);
352 if( ret
== MBEDTLS_ERR_BASE64_INVALID_CHARACTER
)
353 return( MBEDTLS_ERR_PEM_INVALID_DATA
+ ret
);
355 if( ( buf
= mbedtls_calloc( 1, len
) ) == NULL
)
356 return( MBEDTLS_ERR_PEM_ALLOC_FAILED
);
358 if( ( ret
= mbedtls_base64_decode( buf
, len
, &len
, s1
, s2
- s1
) ) != 0 )
360 mbedtls_platform_zeroize( buf
, len
);
362 return( MBEDTLS_ERR_PEM_INVALID_DATA
+ ret
);
367 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
368 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
371 mbedtls_platform_zeroize( buf
, len
);
373 return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED
);
378 #if defined(MBEDTLS_DES_C)
379 if( enc_alg
== MBEDTLS_CIPHER_DES_EDE3_CBC
)
380 ret
= pem_des3_decrypt( pem_iv
, buf
, len
, pwd
, pwdlen
);
381 else if( enc_alg
== MBEDTLS_CIPHER_DES_CBC
)
382 ret
= pem_des_decrypt( pem_iv
, buf
, len
, pwd
, pwdlen
);
383 #endif /* MBEDTLS_DES_C */
385 #if defined(MBEDTLS_AES_C)
386 if( enc_alg
== MBEDTLS_CIPHER_AES_128_CBC
)
387 ret
= pem_aes_decrypt( pem_iv
, 16, buf
, len
, pwd
, pwdlen
);
388 else if( enc_alg
== MBEDTLS_CIPHER_AES_192_CBC
)
389 ret
= pem_aes_decrypt( pem_iv
, 24, buf
, len
, pwd
, pwdlen
);
390 else if( enc_alg
== MBEDTLS_CIPHER_AES_256_CBC
)
391 ret
= pem_aes_decrypt( pem_iv
, 32, buf
, len
, pwd
, pwdlen
);
392 #endif /* MBEDTLS_AES_C */
401 * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
402 * length bytes (allow 4 to be sure) in all known use cases.
404 * Use that as a heuristic to try to detect password mismatches.
406 if( len
<= 2 || buf
[0] != 0x30 || buf
[1] > 0x83 )
408 mbedtls_platform_zeroize( buf
, len
);
410 return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH
);
413 mbedtls_platform_zeroize( buf
, len
);
415 return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE
);
416 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
417 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
426 void mbedtls_pem_free( mbedtls_pem_context
*ctx
)
428 if( ctx
->buf
!= NULL
)
429 mbedtls_platform_zeroize( ctx
->buf
, ctx
->buflen
);
430 mbedtls_free( ctx
->buf
);
431 mbedtls_free( ctx
->info
);
433 mbedtls_platform_zeroize( ctx
, sizeof( mbedtls_pem_context
) );
435 #endif /* MBEDTLS_PEM_PARSE_C */
437 #if defined(MBEDTLS_PEM_WRITE_C)
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
)
443 unsigned char *encode_buf
= NULL
, *c
, *p
= buf
;
444 size_t len
= 0, use_len
, add_len
= 0;
446 mbedtls_base64_encode( NULL
, 0, &use_len
, der_data
, der_len
);
447 add_len
= strlen( header
) + strlen( footer
) + ( use_len
/ 64 ) + 1;
449 if( use_len
+ add_len
> buf_len
)
451 *olen
= use_len
+ add_len
;
452 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL
);
456 ( ( encode_buf
= mbedtls_calloc( 1, use_len
) ) == NULL
) )
457 return( MBEDTLS_ERR_PEM_ALLOC_FAILED
);
459 if( ( ret
= mbedtls_base64_encode( encode_buf
, use_len
, &use_len
, der_data
,
462 mbedtls_free( encode_buf
);
466 memcpy( p
, header
, strlen( header
) );
467 p
+= strlen( header
);
472 len
= ( use_len
> 64 ) ? 64 : use_len
;
480 memcpy( p
, footer
, strlen( footer
) );
481 p
+= strlen( footer
);
486 mbedtls_free( encode_buf
);
489 #endif /* MBEDTLS_PEM_WRITE_C */
490 #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */