blob: 1305bb40e00e9f18f5160a636e9b84453ced934a [file] [log] [blame]
Paul Bakker96743fc2011-02-12 14:30:57 +00001/*
2 * Privacy Enhanced Mail (PEM) decoding
3 *
Manuel Pégourié-Gonnarda658a402015-01-23 09:45:19 +00004 * Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
Paul Bakker96743fc2011-02-12 14:30:57 +00005 *
Manuel Pégourié-Gonnardfe446432015-03-06 13:17:10 +00006 * This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakker96743fc2011-02-12 14:30:57 +00007 *
Paul Bakker96743fc2011-02-12 14:30:57 +00008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020023#if !defined(POLARSSL_CONFIG_FILE)
Paul Bakker96743fc2011-02-12 14:30:57 +000024#include "polarssl/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020025#else
26#include POLARSSL_CONFIG_FILE
27#endif
Paul Bakker96743fc2011-02-12 14:30:57 +000028
Paul Bakkercff68422013-09-15 20:43:33 +020029#if defined(POLARSSL_PEM_PARSE_C) || defined(POLARSSL_PEM_WRITE_C)
Rich Evansce2f2372015-02-06 13:57:42 +000030
Paul Bakker96743fc2011-02-12 14:30:57 +000031#include "polarssl/pem.h"
32#include "polarssl/base64.h"
33#include "polarssl/des.h"
34#include "polarssl/aes.h"
35#include "polarssl/md5.h"
36#include "polarssl/cipher.h"
37
Rich Evans00ab4702015-02-06 13:43:58 +000038#include <string.h>
39
Paul Bakker7dc4c442014-02-01 22:50:26 +010040#if defined(POLARSSL_PLATFORM_C)
41#include "polarssl/platform.h"
Paul Bakker6e339b52013-07-03 13:37:05 +020042#else
Rich Evans00ab4702015-02-06 13:43:58 +000043#include <stdlib.h>
Paul Bakker6e339b52013-07-03 13:37:05 +020044#define polarssl_malloc malloc
45#define polarssl_free free
46#endif
47
Andres AGf0a401f2016-12-07 16:08:04 +000048#if defined(POLARSSL_PEM_PARSE_C)
Paul Bakker34617722014-06-13 17:20:13 +020049/* Implementation that should never be optimized out by the compiler */
50static void polarssl_zeroize( void *v, size_t n ) {
51 volatile unsigned char *p = v; while( n-- ) *p++ = 0;
52}
53
Paul Bakker96743fc2011-02-12 14:30:57 +000054void pem_init( pem_context *ctx )
55{
56 memset( ctx, 0, sizeof( pem_context ) );
57}
58
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +020059#if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
60 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
Paul Bakker96743fc2011-02-12 14:30:57 +000061/*
62 * Read a 16-byte hex string and convert it to binary
63 */
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +020064static int pem_get_iv( const unsigned char *s, unsigned char *iv,
65 size_t iv_len )
Paul Bakker96743fc2011-02-12 14:30:57 +000066{
Paul Bakker23986e52011-04-24 08:57:21 +000067 size_t i, j, k;
Paul Bakker96743fc2011-02-12 14:30:57 +000068
69 memset( iv, 0, iv_len );
70
71 for( i = 0; i < iv_len * 2; i++, s++ )
72 {
73 if( *s >= '0' && *s <= '9' ) j = *s - '0'; else
74 if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else
75 if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else
76 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
77
78 k = ( ( i & 1 ) != 0 ) ? j : j << 4;
79
80 iv[i >> 1] = (unsigned char)( iv[i >> 1] | k );
81 }
82
83 return( 0 );
84}
85
Paul Bakker23986e52011-04-24 08:57:21 +000086static void pem_pbkdf1( unsigned char *key, size_t keylen,
Paul Bakker96743fc2011-02-12 14:30:57 +000087 unsigned char *iv,
Paul Bakker23986e52011-04-24 08:57:21 +000088 const unsigned char *pwd, size_t pwdlen )
Paul Bakker96743fc2011-02-12 14:30:57 +000089{
90 md5_context md5_ctx;
91 unsigned char md5sum[16];
Paul Bakker23986e52011-04-24 08:57:21 +000092 size_t use_len;
Paul Bakker96743fc2011-02-12 14:30:57 +000093
Paul Bakker5b4af392014-06-26 12:09:34 +020094 md5_init( &md5_ctx );
95
Paul Bakker96743fc2011-02-12 14:30:57 +000096 /*
97 * key[ 0..15] = MD5(pwd || IV)
98 */
99 md5_starts( &md5_ctx );
100 md5_update( &md5_ctx, pwd, pwdlen );
101 md5_update( &md5_ctx, iv, 8 );
102 md5_finish( &md5_ctx, md5sum );
103
104 if( keylen <= 16 )
105 {
106 memcpy( key, md5sum, keylen );
107
Paul Bakker5b4af392014-06-26 12:09:34 +0200108 md5_free( &md5_ctx );
Paul Bakker34617722014-06-13 17:20:13 +0200109 polarssl_zeroize( md5sum, 16 );
Paul Bakker96743fc2011-02-12 14:30:57 +0000110 return;
111 }
112
113 memcpy( key, md5sum, 16 );
114
115 /*
116 * key[16..23] = MD5(key[ 0..15] || pwd || IV])
117 */
118 md5_starts( &md5_ctx );
119 md5_update( &md5_ctx, md5sum, 16 );
120 md5_update( &md5_ctx, pwd, pwdlen );
121 md5_update( &md5_ctx, iv, 8 );
122 md5_finish( &md5_ctx, md5sum );
123
124 use_len = 16;
125 if( keylen < 32 )
126 use_len = keylen - 16;
127
128 memcpy( key + 16, md5sum, use_len );
129
Paul Bakker5b4af392014-06-26 12:09:34 +0200130 md5_free( &md5_ctx );
Paul Bakker34617722014-06-13 17:20:13 +0200131 polarssl_zeroize( md5sum, 16 );
Paul Bakker96743fc2011-02-12 14:30:57 +0000132}
133
134#if defined(POLARSSL_DES_C)
135/*
136 * Decrypt with DES-CBC, using PBKDF1 for key derivation
137 */
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100138static int pem_des_decrypt( unsigned char des_iv[8],
139 unsigned char *buf, size_t buflen,
140 const unsigned char *pwd, size_t pwdlen )
Paul Bakker96743fc2011-02-12 14:30:57 +0000141{
142 des_context des_ctx;
143 unsigned char des_key[8];
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100144 int ret;
Paul Bakker96743fc2011-02-12 14:30:57 +0000145
Paul Bakkerc7ea99a2014-06-18 11:12:03 +0200146 des_init( &des_ctx );
147
Paul Bakker96743fc2011-02-12 14:30:57 +0000148 pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen );
149
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100150 if( ( ret = des_setkey_dec( &des_ctx, des_key ) ) != 0 )
151 goto exit;
152 ret = des_crypt_cbc( &des_ctx, DES_DECRYPT, buflen, des_iv, buf, buf );
Paul Bakker96743fc2011-02-12 14:30:57 +0000153
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100154exit:
Paul Bakkerc7ea99a2014-06-18 11:12:03 +0200155 des_free( &des_ctx );
Paul Bakker34617722014-06-13 17:20:13 +0200156 polarssl_zeroize( des_key, 8 );
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100157
158 return( ret );
Paul Bakker96743fc2011-02-12 14:30:57 +0000159}
160
161/*
162 * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
163 */
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100164static int pem_des3_decrypt( unsigned char des3_iv[8],
165 unsigned char *buf, size_t buflen,
166 const unsigned char *pwd, size_t pwdlen )
Paul Bakker96743fc2011-02-12 14:30:57 +0000167{
168 des3_context des3_ctx;
169 unsigned char des3_key[24];
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100170 int ret;
Paul Bakker96743fc2011-02-12 14:30:57 +0000171
Paul Bakkerc7ea99a2014-06-18 11:12:03 +0200172 des3_init( &des3_ctx );
173
Paul Bakker96743fc2011-02-12 14:30:57 +0000174 pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen );
175
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100176 if( ( ret = des3_set3key_dec( &des3_ctx, des3_key ) ) != 0 )
177 goto exit;
178 ret = des3_crypt_cbc( &des3_ctx, DES_DECRYPT, buflen, des3_iv, buf, buf );
Paul Bakker96743fc2011-02-12 14:30:57 +0000179
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100180exit:
Paul Bakkerc7ea99a2014-06-18 11:12:03 +0200181 des3_free( &des3_ctx );
Paul Bakker34617722014-06-13 17:20:13 +0200182 polarssl_zeroize( des3_key, 24 );
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100183
184 return( ret );
Paul Bakker96743fc2011-02-12 14:30:57 +0000185}
186#endif /* POLARSSL_DES_C */
187
188#if defined(POLARSSL_AES_C)
189/*
190 * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
191 */
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100192static int pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen,
193 unsigned char *buf, size_t buflen,
194 const unsigned char *pwd, size_t pwdlen )
Paul Bakker96743fc2011-02-12 14:30:57 +0000195{
196 aes_context aes_ctx;
197 unsigned char aes_key[32];
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100198 int ret;
Paul Bakker96743fc2011-02-12 14:30:57 +0000199
Paul Bakkerc7ea99a2014-06-18 11:12:03 +0200200 aes_init( &aes_ctx );
201
Paul Bakker96743fc2011-02-12 14:30:57 +0000202 pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen );
203
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100204 if( ( ret = aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ) ) != 0 )
205 goto exit;
206 ret = aes_crypt_cbc( &aes_ctx, AES_DECRYPT, buflen, aes_iv, buf, buf );
Paul Bakker96743fc2011-02-12 14:30:57 +0000207
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100208exit:
Paul Bakkerc7ea99a2014-06-18 11:12:03 +0200209 aes_free( &aes_ctx );
Paul Bakker34617722014-06-13 17:20:13 +0200210 polarssl_zeroize( aes_key, keylen );
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100211
212 return( ret );
Paul Bakker96743fc2011-02-12 14:30:57 +0000213}
214#endif /* POLARSSL_AES_C */
215
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200216#endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
217 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
Paul Bakker96743fc2011-02-12 14:30:57 +0000218
Paul Bakkerb6c5d2e2013-06-25 16:25:17 +0200219int pem_read_buffer( pem_context *ctx, const char *header, const char *footer,
220 const unsigned char *data, const unsigned char *pwd,
221 size_t pwdlen, size_t *use_len )
Paul Bakker96743fc2011-02-12 14:30:57 +0000222{
Paul Bakker23986e52011-04-24 08:57:21 +0000223 int ret, enc;
224 size_t len;
Paul Bakker96743fc2011-02-12 14:30:57 +0000225 unsigned char *buf;
Paul Bakker00b28602013-06-24 13:02:41 +0200226 const unsigned char *s1, *s2, *end;
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200227#if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
228 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
Paul Bakker96743fc2011-02-12 14:30:57 +0000229 unsigned char pem_iv[16];
230 cipher_type_t enc_alg = POLARSSL_CIPHER_NONE;
231#else
232 ((void) pwd);
233 ((void) pwdlen);
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200234#endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
235 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
Paul Bakker96743fc2011-02-12 14:30:57 +0000236
237 if( ctx == NULL )
Paul Bakker00b28602013-06-24 13:02:41 +0200238 return( POLARSSL_ERR_PEM_BAD_INPUT_DATA );
Paul Bakker96743fc2011-02-12 14:30:57 +0000239
Paul Bakker3c2122f2013-06-24 19:03:14 +0200240 s1 = (unsigned char *) strstr( (const char *) data, header );
Paul Bakker96743fc2011-02-12 14:30:57 +0000241
242 if( s1 == NULL )
Paul Bakker00b28602013-06-24 13:02:41 +0200243 return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
Paul Bakker96743fc2011-02-12 14:30:57 +0000244
Paul Bakker3c2122f2013-06-24 19:03:14 +0200245 s2 = (unsigned char *) strstr( (const char *) data, footer );
Paul Bakker96743fc2011-02-12 14:30:57 +0000246
247 if( s2 == NULL || s2 <= s1 )
Paul Bakker00b28602013-06-24 13:02:41 +0200248 return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
Paul Bakker96743fc2011-02-12 14:30:57 +0000249
250 s1 += strlen( header );
Manuel Pégourié-Gonnardb5d77d32015-07-31 11:09:59 +0200251 if( *s1 == ' ' ) s1++;
Paul Bakker96743fc2011-02-12 14:30:57 +0000252 if( *s1 == '\r' ) s1++;
253 if( *s1 == '\n' ) s1++;
Paul Bakker00b28602013-06-24 13:02:41 +0200254 else return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
255
256 end = s2;
257 end += strlen( footer );
Manuel Pégourié-Gonnardb5d77d32015-07-31 11:09:59 +0200258 if( *end == ' ' ) end++;
Paul Bakker00b28602013-06-24 13:02:41 +0200259 if( *end == '\r' ) end++;
260 if( *end == '\n' ) end++;
261 *use_len = end - data;
Paul Bakker96743fc2011-02-12 14:30:57 +0000262
263 enc = 0;
264
Andres AGde6079a2016-10-24 11:23:36 +0100265 if( s2 - s1 >= 22 && memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
Paul Bakker96743fc2011-02-12 14:30:57 +0000266 {
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200267#if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
268 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
Paul Bakker96743fc2011-02-12 14:30:57 +0000269 enc++;
270
271 s1 += 22;
272 if( *s1 == '\r' ) s1++;
273 if( *s1 == '\n' ) s1++;
274 else return( POLARSSL_ERR_PEM_INVALID_DATA );
275
276
277#if defined(POLARSSL_DES_C)
Andres AGde6079a2016-10-24 11:23:36 +0100278 if( s2 - s1 >= 23 && memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 )
Paul Bakker96743fc2011-02-12 14:30:57 +0000279 {
280 enc_alg = POLARSSL_CIPHER_DES_EDE3_CBC;
281
282 s1 += 23;
Andres AGde6079a2016-10-24 11:23:36 +0100283 if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8 ) != 0 )
Paul Bakker96743fc2011-02-12 14:30:57 +0000284 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
285
286 s1 += 16;
287 }
Andres AGde6079a2016-10-24 11:23:36 +0100288 else if( s2 - s1 >= 18 && memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 )
Paul Bakker96743fc2011-02-12 14:30:57 +0000289 {
290 enc_alg = POLARSSL_CIPHER_DES_CBC;
291
292 s1 += 18;
Andres AGde6079a2016-10-24 11:23:36 +0100293 if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8) != 0 )
Paul Bakker96743fc2011-02-12 14:30:57 +0000294 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
295
296 s1 += 16;
297 }
298#endif /* POLARSSL_DES_C */
299
300#if defined(POLARSSL_AES_C)
Andres AGde6079a2016-10-24 11:23:36 +0100301 if( s2 - s1 >= 14 && memcmp( s1, "DEK-Info: AES-", 14 ) == 0 )
Paul Bakker96743fc2011-02-12 14:30:57 +0000302 {
Andres AGde6079a2016-10-24 11:23:36 +0100303 if( s2 - s1 < 22 )
304 return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG );
305 else if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 )
Paul Bakker96743fc2011-02-12 14:30:57 +0000306 enc_alg = POLARSSL_CIPHER_AES_128_CBC;
307 else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 )
308 enc_alg = POLARSSL_CIPHER_AES_192_CBC;
309 else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 )
310 enc_alg = POLARSSL_CIPHER_AES_256_CBC;
311 else
312 return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG );
313
314 s1 += 22;
Andres AGde6079a2016-10-24 11:23:36 +0100315 if( s2 - s1 < 32 || pem_get_iv( s1, pem_iv, 16 ) != 0 )
Paul Bakker96743fc2011-02-12 14:30:57 +0000316 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
317
318 s1 += 32;
319 }
320#endif /* POLARSSL_AES_C */
Paul Bakkercff68422013-09-15 20:43:33 +0200321
Paul Bakker96743fc2011-02-12 14:30:57 +0000322 if( enc_alg == POLARSSL_CIPHER_NONE )
323 return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG );
324
325 if( *s1 == '\r' ) s1++;
326 if( *s1 == '\n' ) s1++;
327 else return( POLARSSL_ERR_PEM_INVALID_DATA );
328#else
329 return( POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE );
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200330#endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
331 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
Paul Bakker96743fc2011-02-12 14:30:57 +0000332 }
333
Andres AGde6079a2016-10-24 11:23:36 +0100334 if( s1 >= s2 )
Manuel Pégourié-Gonnard9bf29be2015-09-28 18:27:15 +0200335 return( POLARSSL_ERR_PEM_INVALID_DATA );
336
Paul Bakker96743fc2011-02-12 14:30:57 +0000337 len = 0;
338 ret = base64_decode( NULL, &len, s1, s2 - s1 );
339
340 if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER )
Paul Bakker9d781402011-05-09 16:17:09 +0000341 return( POLARSSL_ERR_PEM_INVALID_DATA + ret );
Paul Bakker96743fc2011-02-12 14:30:57 +0000342
Mansour Moufidc531b4a2015-02-15 17:35:38 -0500343 if( ( buf = polarssl_malloc( len ) ) == NULL )
Paul Bakker96743fc2011-02-12 14:30:57 +0000344 return( POLARSSL_ERR_PEM_MALLOC_FAILED );
345
346 if( ( ret = base64_decode( buf, &len, s1, s2 - s1 ) ) != 0 )
347 {
Andres Amaya Garcia2d829fb2017-07-12 11:01:32 +0100348 polarssl_zeroize( buf, len );
Paul Bakker6e339b52013-07-03 13:37:05 +0200349 polarssl_free( buf );
Paul Bakker9d781402011-05-09 16:17:09 +0000350 return( POLARSSL_ERR_PEM_INVALID_DATA + ret );
Paul Bakker96743fc2011-02-12 14:30:57 +0000351 }
Paul Bakkercff68422013-09-15 20:43:33 +0200352
Paul Bakker96743fc2011-02-12 14:30:57 +0000353 if( enc != 0 )
354 {
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200355#if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
356 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
Paul Bakker96743fc2011-02-12 14:30:57 +0000357 if( pwd == NULL )
358 {
Andres Amaya Garciaf4660aa2017-07-12 10:54:06 +0100359 polarssl_zeroize( buf, len );
Paul Bakker6e339b52013-07-03 13:37:05 +0200360 polarssl_free( buf );
Paul Bakker96743fc2011-02-12 14:30:57 +0000361 return( POLARSSL_ERR_PEM_PASSWORD_REQUIRED );
362 }
363
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100364 ret = 0;
365
Paul Bakker96743fc2011-02-12 14:30:57 +0000366#if defined(POLARSSL_DES_C)
367 if( enc_alg == POLARSSL_CIPHER_DES_EDE3_CBC )
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100368 ret = pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen );
Paul Bakker96743fc2011-02-12 14:30:57 +0000369 else if( enc_alg == POLARSSL_CIPHER_DES_CBC )
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100370 ret = pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen );
Paul Bakker96743fc2011-02-12 14:30:57 +0000371#endif /* POLARSSL_DES_C */
372
373#if defined(POLARSSL_AES_C)
374 if( enc_alg == POLARSSL_CIPHER_AES_128_CBC )
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100375 ret = pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen );
Paul Bakker96743fc2011-02-12 14:30:57 +0000376 else if( enc_alg == POLARSSL_CIPHER_AES_192_CBC )
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100377 ret = pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen );
Paul Bakker96743fc2011-02-12 14:30:57 +0000378 else if( enc_alg == POLARSSL_CIPHER_AES_256_CBC )
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100379 ret = pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen );
Paul Bakker96743fc2011-02-12 14:30:57 +0000380#endif /* POLARSSL_AES_C */
381
Andres Amaya Garciaf5e753a2017-05-30 17:18:06 +0100382 if( ret != 0 )
383 {
384 polarssl_free( buf );
385 return( ret );
386 }
387
Manuel Pégourié-Gonnardf8648d52013-07-03 21:01:35 +0200388 /*
Manuel Pégourié-Gonnard7d4e5b72013-07-09 16:35:23 +0200389 * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
390 * length bytes (allow 4 to be sure) in all known use cases.
391 *
392 * Use that as heurisitic to try detecting password mismatchs.
Manuel Pégourié-Gonnardf8648d52013-07-03 21:01:35 +0200393 */
Manuel Pégourié-Gonnard7d4e5b72013-07-09 16:35:23 +0200394 if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 )
Paul Bakker96743fc2011-02-12 14:30:57 +0000395 {
Andres Amaya Garciaf4660aa2017-07-12 10:54:06 +0100396 polarssl_zeroize( buf, len );
Paul Bakker6e339b52013-07-03 13:37:05 +0200397 polarssl_free( buf );
Paul Bakker96743fc2011-02-12 14:30:57 +0000398 return( POLARSSL_ERR_PEM_PASSWORD_MISMATCH );
399 }
400#else
Andres Amaya Garciaf4660aa2017-07-12 10:54:06 +0100401 polarssl_zeroize( buf, len );
Paul Bakker6e339b52013-07-03 13:37:05 +0200402 polarssl_free( buf );
Paul Bakker96743fc2011-02-12 14:30:57 +0000403 return( POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE );
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200404#endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
405 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
Paul Bakker96743fc2011-02-12 14:30:57 +0000406 }
407
408 ctx->buf = buf;
409 ctx->buflen = len;
Paul Bakker96743fc2011-02-12 14:30:57 +0000410
411 return( 0 );
412}
413
Paul Bakkercff68422013-09-15 20:43:33 +0200414void pem_free( pem_context *ctx )
415{
Ron Eldor27ce0b52017-09-05 15:34:35 +0300416 if ( ctx->buf != NULL )
417 polarssl_zeroize( ctx->buf, ctx->buflen );
Paul Bakker14b16c62014-05-28 11:33:54 +0200418 polarssl_free( ctx->buf );
419 polarssl_free( ctx->info );
Paul Bakkercff68422013-09-15 20:43:33 +0200420
Paul Bakker34617722014-06-13 17:20:13 +0200421 polarssl_zeroize( ctx, sizeof( pem_context ) );
Paul Bakkercff68422013-09-15 20:43:33 +0200422}
423#endif /* POLARSSL_PEM_PARSE_C */
424
425#if defined(POLARSSL_PEM_WRITE_C)
Paul Bakker77e23fb2013-09-15 20:03:26 +0200426int pem_write_buffer( const char *header, const char *footer,
427 const unsigned char *der_data, size_t der_len,
428 unsigned char *buf, size_t buf_len, size_t *olen )
429{
430 int ret;
431 unsigned char *encode_buf, *c, *p = buf;
Paul Bakker16300582014-04-11 13:28:43 +0200432 size_t len = 0, use_len = 0, add_len = 0;
Paul Bakker77e23fb2013-09-15 20:03:26 +0200433
434 base64_encode( NULL, &use_len, der_data, der_len );
Paul Bakker16300582014-04-11 13:28:43 +0200435 add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1;
436
Paul Bakker77e23fb2013-09-15 20:03:26 +0200437 if( use_len + add_len > buf_len )
438 {
439 *olen = use_len + add_len;
440 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
441 }
442
443 if( ( encode_buf = polarssl_malloc( use_len ) ) == NULL )
444 return( POLARSSL_ERR_PEM_MALLOC_FAILED );
445
446 if( ( ret = base64_encode( encode_buf, &use_len, der_data,
447 der_len ) ) != 0 )
448 {
449 polarssl_free( encode_buf );
450 return( ret );
451 }
452
453 memcpy( p, header, strlen( header ) );
454 p += strlen( header );
455 c = encode_buf;
456
457 while( use_len )
458 {
459 len = ( use_len > 64 ) ? 64 : use_len;
460 memcpy( p, c, len );
461 use_len -= len;
462 p += len;
463 c += len;
464 *p++ = '\n';
465 }
466
467 memcpy( p, footer, strlen( footer ) );
468 p += strlen( footer );
469
470 *p++ = '\0';
471 *olen = p - buf;
472
473 polarssl_free( encode_buf );
474 return( 0 );
475}
Paul Bakkercff68422013-09-15 20:43:33 +0200476#endif /* POLARSSL_PEM_WRITE_C */
477#endif /* POLARSSL_PEM_PARSE_C || POLARSSL_PEM_WRITE_C */