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"
41 #if defined(MBEDTLS_PLATFORM_C)
42 #include "mbedtls/platform.h"
45 #define mbedtls_calloc calloc
46 #define mbedtls_free free
49 /* Implementation that should never be optimized out by the compiler */
50 static void mbedtls_zeroize( void *v
, size_t n
) {
51 volatile unsigned char *p
= v
; while( n
-- ) *p
++ = 0;
54 #if defined(MBEDTLS_PEM_PARSE_C)
55 void mbedtls_pem_init( mbedtls_pem_context
*ctx
)
57 memset( ctx
, 0, sizeof( mbedtls_pem_context
) );
60 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
61 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
63 * Read a 16-byte hex string and convert it to binary
65 static int pem_get_iv( const unsigned char *s
, unsigned char *iv
,
70 memset( iv
, 0, iv_len
);
72 for( i
= 0; i
< iv_len
* 2; i
++, s
++ )
74 if( *s
>= '0' && *s
<= '9' ) j
= *s
- '0'; else
75 if( *s
>= 'A' && *s
<= 'F' ) j
= *s
- '7'; else
76 if( *s
>= 'a' && *s
<= 'f' ) j
= *s
- 'W'; else
77 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV
);
79 k
= ( ( i
& 1 ) != 0 ) ? j
: j
<< 4;
81 iv
[i
>> 1] = (unsigned char)( iv
[i
>> 1] | k
);
87 static void pem_pbkdf1( unsigned char *key
, size_t keylen
,
89 const unsigned char *pwd
, size_t pwdlen
)
91 mbedtls_md5_context md5_ctx
;
92 unsigned char md5sum
[16];
95 mbedtls_md5_init( &md5_ctx
);
98 * key[ 0..15] = MD5(pwd || IV)
100 mbedtls_md5_starts( &md5_ctx
);
101 mbedtls_md5_update( &md5_ctx
, pwd
, pwdlen
);
102 mbedtls_md5_update( &md5_ctx
, iv
, 8 );
103 mbedtls_md5_finish( &md5_ctx
, md5sum
);
107 memcpy( key
, md5sum
, keylen
);
109 mbedtls_md5_free( &md5_ctx
);
110 mbedtls_zeroize( md5sum
, 16 );
114 memcpy( key
, md5sum
, 16 );
117 * key[16..23] = MD5(key[ 0..15] || pwd || IV])
119 mbedtls_md5_starts( &md5_ctx
);
120 mbedtls_md5_update( &md5_ctx
, md5sum
, 16 );
121 mbedtls_md5_update( &md5_ctx
, pwd
, pwdlen
);
122 mbedtls_md5_update( &md5_ctx
, iv
, 8 );
123 mbedtls_md5_finish( &md5_ctx
, md5sum
);
127 use_len
= keylen
- 16;
129 memcpy( key
+ 16, md5sum
, use_len
);
131 mbedtls_md5_free( &md5_ctx
);
132 mbedtls_zeroize( md5sum
, 16 );
135 #if defined(MBEDTLS_DES_C)
137 * Decrypt with DES-CBC, using PBKDF1 for key derivation
139 static void pem_des_decrypt( unsigned char des_iv
[8],
140 unsigned char *buf
, size_t buflen
,
141 const unsigned char *pwd
, size_t pwdlen
)
143 mbedtls_des_context des_ctx
;
144 unsigned char des_key
[8];
146 mbedtls_des_init( &des_ctx
);
148 pem_pbkdf1( des_key
, 8, des_iv
, pwd
, pwdlen
);
150 mbedtls_des_setkey_dec( &des_ctx
, des_key
);
151 mbedtls_des_crypt_cbc( &des_ctx
, MBEDTLS_DES_DECRYPT
, buflen
,
154 mbedtls_des_free( &des_ctx
);
155 mbedtls_zeroize( des_key
, 8 );
159 * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
161 static void pem_des3_decrypt( unsigned char des3_iv
[8],
162 unsigned char *buf
, size_t buflen
,
163 const unsigned char *pwd
, size_t pwdlen
)
165 mbedtls_des3_context des3_ctx
;
166 unsigned char des3_key
[24];
168 mbedtls_des3_init( &des3_ctx
);
170 pem_pbkdf1( des3_key
, 24, des3_iv
, pwd
, pwdlen
);
172 mbedtls_des3_set3key_dec( &des3_ctx
, des3_key
);
173 mbedtls_des3_crypt_cbc( &des3_ctx
, MBEDTLS_DES_DECRYPT
, buflen
,
176 mbedtls_des3_free( &des3_ctx
);
177 mbedtls_zeroize( des3_key
, 24 );
179 #endif /* MBEDTLS_DES_C */
181 #if defined(MBEDTLS_AES_C)
183 * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
185 static void pem_aes_decrypt( unsigned char aes_iv
[16], unsigned int keylen
,
186 unsigned char *buf
, size_t buflen
,
187 const unsigned char *pwd
, size_t pwdlen
)
189 mbedtls_aes_context aes_ctx
;
190 unsigned char aes_key
[32];
192 mbedtls_aes_init( &aes_ctx
);
194 pem_pbkdf1( aes_key
, keylen
, aes_iv
, pwd
, pwdlen
);
196 mbedtls_aes_setkey_dec( &aes_ctx
, aes_key
, keylen
* 8 );
197 mbedtls_aes_crypt_cbc( &aes_ctx
, MBEDTLS_AES_DECRYPT
, buflen
,
200 mbedtls_aes_free( &aes_ctx
);
201 mbedtls_zeroize( aes_key
, keylen
);
203 #endif /* MBEDTLS_AES_C */
205 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
206 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
208 int mbedtls_pem_read_buffer( mbedtls_pem_context
*ctx
, const char *header
, const char *footer
,
209 const unsigned char *data
, const unsigned char *pwd
,
210 size_t pwdlen
, size_t *use_len
)
215 const unsigned char *s1
, *s2
, *end
;
216 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
217 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
218 unsigned char pem_iv
[16];
219 mbedtls_cipher_type_t enc_alg
= MBEDTLS_CIPHER_NONE
;
223 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
224 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
227 return( MBEDTLS_ERR_PEM_BAD_INPUT_DATA
);
229 s1
= (unsigned char *) strstr( (const char *) data
, header
);
232 return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT
);
234 s2
= (unsigned char *) strstr( (const char *) data
, footer
);
236 if( s2
== NULL
|| s2
<= s1
)
237 return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT
);
239 s1
+= strlen( header
);
240 if( *s1
== ' ' ) s1
++;
241 if( *s1
== '\r' ) s1
++;
242 if( *s1
== '\n' ) s1
++;
243 else return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT
);
246 end
+= strlen( footer
);
247 if( *end
== ' ' ) end
++;
248 if( *end
== '\r' ) end
++;
249 if( *end
== '\n' ) end
++;
250 *use_len
= end
- data
;
254 if( memcmp( s1
, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
256 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
257 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
261 if( *s1
== '\r' ) s1
++;
262 if( *s1
== '\n' ) s1
++;
263 else return( MBEDTLS_ERR_PEM_INVALID_DATA
);
266 #if defined(MBEDTLS_DES_C)
267 if( memcmp( s1
, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 )
269 enc_alg
= MBEDTLS_CIPHER_DES_EDE3_CBC
;
272 if( pem_get_iv( s1
, pem_iv
, 8 ) != 0 )
273 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV
);
277 else if( memcmp( s1
, "DEK-Info: DES-CBC,", 18 ) == 0 )
279 enc_alg
= MBEDTLS_CIPHER_DES_CBC
;
282 if( pem_get_iv( s1
, pem_iv
, 8) != 0 )
283 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV
);
287 #endif /* MBEDTLS_DES_C */
289 #if defined(MBEDTLS_AES_C)
290 if( memcmp( s1
, "DEK-Info: AES-", 14 ) == 0 )
292 if( memcmp( s1
, "DEK-Info: AES-128-CBC,", 22 ) == 0 )
293 enc_alg
= MBEDTLS_CIPHER_AES_128_CBC
;
294 else if( memcmp( s1
, "DEK-Info: AES-192-CBC,", 22 ) == 0 )
295 enc_alg
= MBEDTLS_CIPHER_AES_192_CBC
;
296 else if( memcmp( s1
, "DEK-Info: AES-256-CBC,", 22 ) == 0 )
297 enc_alg
= MBEDTLS_CIPHER_AES_256_CBC
;
299 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG
);
302 if( pem_get_iv( s1
, pem_iv
, 16 ) != 0 )
303 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV
);
307 #endif /* MBEDTLS_AES_C */
309 if( enc_alg
== MBEDTLS_CIPHER_NONE
)
310 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG
);
312 if( *s1
== '\r' ) s1
++;
313 if( *s1
== '\n' ) s1
++;
314 else return( MBEDTLS_ERR_PEM_INVALID_DATA
);
316 return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE
);
317 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
318 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
322 return( MBEDTLS_ERR_PEM_INVALID_DATA
);
324 ret
= mbedtls_base64_decode( NULL
, 0, &len
, s1
, s2
- s1
);
326 if( ret
== MBEDTLS_ERR_BASE64_INVALID_CHARACTER
)
327 return( MBEDTLS_ERR_PEM_INVALID_DATA
+ ret
);
329 if( ( buf
= mbedtls_calloc( 1, len
) ) == NULL
)
330 return( MBEDTLS_ERR_PEM_ALLOC_FAILED
);
332 if( ( ret
= mbedtls_base64_decode( buf
, len
, &len
, s1
, s2
- s1
) ) != 0 )
335 return( MBEDTLS_ERR_PEM_INVALID_DATA
+ ret
);
340 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \
341 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
345 return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED
);
348 #if defined(MBEDTLS_DES_C)
349 if( enc_alg
== MBEDTLS_CIPHER_DES_EDE3_CBC
)
350 pem_des3_decrypt( pem_iv
, buf
, len
, pwd
, pwdlen
);
351 else if( enc_alg
== MBEDTLS_CIPHER_DES_CBC
)
352 pem_des_decrypt( pem_iv
, buf
, len
, pwd
, pwdlen
);
353 #endif /* MBEDTLS_DES_C */
355 #if defined(MBEDTLS_AES_C)
356 if( enc_alg
== MBEDTLS_CIPHER_AES_128_CBC
)
357 pem_aes_decrypt( pem_iv
, 16, buf
, len
, pwd
, pwdlen
);
358 else if( enc_alg
== MBEDTLS_CIPHER_AES_192_CBC
)
359 pem_aes_decrypt( pem_iv
, 24, buf
, len
, pwd
, pwdlen
);
360 else if( enc_alg
== MBEDTLS_CIPHER_AES_256_CBC
)
361 pem_aes_decrypt( pem_iv
, 32, buf
, len
, pwd
, pwdlen
);
362 #endif /* MBEDTLS_AES_C */
365 * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
366 * length bytes (allow 4 to be sure) in all known use cases.
368 * Use that as heurisitic to try detecting password mismatchs.
370 if( len
<= 2 || buf
[0] != 0x30 || buf
[1] > 0x83 )
373 return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH
);
377 return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE
);
378 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
379 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
388 void mbedtls_pem_free( mbedtls_pem_context
*ctx
)
390 mbedtls_free( ctx
->buf
);
391 mbedtls_free( ctx
->info
);
393 mbedtls_zeroize( ctx
, sizeof( mbedtls_pem_context
) );
395 #endif /* MBEDTLS_PEM_PARSE_C */
397 #if defined(MBEDTLS_PEM_WRITE_C)
398 int mbedtls_pem_write_buffer( const char *header
, const char *footer
,
399 const unsigned char *der_data
, size_t der_len
,
400 unsigned char *buf
, size_t buf_len
, size_t *olen
)
403 unsigned char *encode_buf
, *c
, *p
= buf
;
404 size_t len
= 0, use_len
, add_len
= 0;
406 mbedtls_base64_encode( NULL
, 0, &use_len
, der_data
, der_len
);
407 add_len
= strlen( header
) + strlen( footer
) + ( use_len
/ 64 ) + 1;
409 if( use_len
+ add_len
> buf_len
)
411 *olen
= use_len
+ add_len
;
412 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL
);
415 if( ( encode_buf
= mbedtls_calloc( 1, use_len
) ) == NULL
)
416 return( MBEDTLS_ERR_PEM_ALLOC_FAILED
);
418 if( ( ret
= mbedtls_base64_encode( encode_buf
, use_len
, &use_len
, der_data
,
421 mbedtls_free( encode_buf
);
425 memcpy( p
, header
, strlen( header
) );
426 p
+= strlen( header
);
431 len
= ( use_len
> 64 ) ? 64 : use_len
;
439 memcpy( p
, footer
, strlen( footer
) );
440 p
+= strlen( footer
);
445 mbedtls_free( encode_buf
);
448 #endif /* MBEDTLS_PEM_WRITE_C */
449 #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */