blob: 2f639d04f03ff7c88b90917033c9ef3f28a6643e [file] [log] [blame]
Paul Bakker96743fc2011-02-12 14:30:57 +00001/*
2 * Privacy Enhanced Mail (PEM) decoding
3 *
Paul Bakker7dc4c442014-02-01 22:50:26 +01004 * Copyright (C) 2006-2014, Brainspark B.V.
Paul Bakker96743fc2011-02-12 14:30:57 +00005 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020026#if !defined(POLARSSL_CONFIG_FILE)
Paul Bakker96743fc2011-02-12 14:30:57 +000027#include "polarssl/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020028#else
29#include POLARSSL_CONFIG_FILE
30#endif
Paul Bakker96743fc2011-02-12 14:30:57 +000031
Paul Bakkercff68422013-09-15 20:43:33 +020032#if defined(POLARSSL_PEM_PARSE_C) || defined(POLARSSL_PEM_WRITE_C)
Paul Bakker96743fc2011-02-12 14:30:57 +000033#include "polarssl/pem.h"
34#include "polarssl/base64.h"
35#include "polarssl/des.h"
36#include "polarssl/aes.h"
37#include "polarssl/md5.h"
38#include "polarssl/cipher.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
43#define polarssl_malloc malloc
44#define polarssl_free free
45#endif
46
Paul Bakker96743fc2011-02-12 14:30:57 +000047#include <stdlib.h>
Paul Bakker96743fc2011-02-12 14:30:57 +000048
Paul Bakkercff68422013-09-15 20:43:33 +020049#if defined(POLARSSL_PEM_PARSE_C)
Paul Bakker96743fc2011-02-12 14:30:57 +000050void pem_init( pem_context *ctx )
51{
52 memset( ctx, 0, sizeof( pem_context ) );
53}
54
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +020055#if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
56 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
Paul Bakker96743fc2011-02-12 14:30:57 +000057/*
58 * Read a 16-byte hex string and convert it to binary
59 */
Paul Bakker23986e52011-04-24 08:57:21 +000060static int pem_get_iv( const unsigned char *s, unsigned char *iv, size_t iv_len )
Paul Bakker96743fc2011-02-12 14:30:57 +000061{
Paul Bakker23986e52011-04-24 08:57:21 +000062 size_t i, j, k;
Paul Bakker96743fc2011-02-12 14:30:57 +000063
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( POLARSSL_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
Paul Bakker23986e52011-04-24 08:57:21 +000081static void pem_pbkdf1( unsigned char *key, size_t keylen,
Paul Bakker96743fc2011-02-12 14:30:57 +000082 unsigned char *iv,
Paul Bakker23986e52011-04-24 08:57:21 +000083 const unsigned char *pwd, size_t pwdlen )
Paul Bakker96743fc2011-02-12 14:30:57 +000084{
85 md5_context md5_ctx;
86 unsigned char md5sum[16];
Paul Bakker23986e52011-04-24 08:57:21 +000087 size_t use_len;
Paul Bakker96743fc2011-02-12 14:30:57 +000088
89 /*
90 * key[ 0..15] = MD5(pwd || IV)
91 */
92 md5_starts( &md5_ctx );
93 md5_update( &md5_ctx, pwd, pwdlen );
94 md5_update( &md5_ctx, iv, 8 );
95 md5_finish( &md5_ctx, md5sum );
96
97 if( keylen <= 16 )
98 {
99 memcpy( key, md5sum, keylen );
100
101 memset( &md5_ctx, 0, sizeof( md5_ctx ) );
102 memset( md5sum, 0, 16 );
103 return;
104 }
105
106 memcpy( key, md5sum, 16 );
107
108 /*
109 * key[16..23] = MD5(key[ 0..15] || pwd || IV])
110 */
111 md5_starts( &md5_ctx );
112 md5_update( &md5_ctx, md5sum, 16 );
113 md5_update( &md5_ctx, pwd, pwdlen );
114 md5_update( &md5_ctx, iv, 8 );
115 md5_finish( &md5_ctx, md5sum );
116
117 use_len = 16;
118 if( keylen < 32 )
119 use_len = keylen - 16;
120
121 memcpy( key + 16, md5sum, use_len );
122
123 memset( &md5_ctx, 0, sizeof( md5_ctx ) );
124 memset( md5sum, 0, 16 );
125}
126
127#if defined(POLARSSL_DES_C)
128/*
129 * Decrypt with DES-CBC, using PBKDF1 for key derivation
130 */
131static void pem_des_decrypt( unsigned char des_iv[8],
Paul Bakker23986e52011-04-24 08:57:21 +0000132 unsigned char *buf, size_t buflen,
133 const unsigned char *pwd, size_t pwdlen )
Paul Bakker96743fc2011-02-12 14:30:57 +0000134{
135 des_context des_ctx;
136 unsigned char des_key[8];
137
138 pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen );
139
140 des_setkey_dec( &des_ctx, des_key );
141 des_crypt_cbc( &des_ctx, DES_DECRYPT, buflen,
142 des_iv, buf, buf );
143
144 memset( &des_ctx, 0, sizeof( des_ctx ) );
145 memset( des_key, 0, 8 );
146}
147
148/*
149 * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
150 */
151static void pem_des3_decrypt( unsigned char des3_iv[8],
Paul Bakker23986e52011-04-24 08:57:21 +0000152 unsigned char *buf, size_t buflen,
153 const unsigned char *pwd, size_t pwdlen )
Paul Bakker96743fc2011-02-12 14:30:57 +0000154{
155 des3_context des3_ctx;
156 unsigned char des3_key[24];
157
158 pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen );
159
160 des3_set3key_dec( &des3_ctx, des3_key );
161 des3_crypt_cbc( &des3_ctx, DES_DECRYPT, buflen,
162 des3_iv, buf, buf );
163
164 memset( &des3_ctx, 0, sizeof( des3_ctx ) );
165 memset( des3_key, 0, 24 );
166}
167#endif /* POLARSSL_DES_C */
168
169#if defined(POLARSSL_AES_C)
170/*
171 * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
172 */
Paul Bakker23986e52011-04-24 08:57:21 +0000173static void pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen,
174 unsigned char *buf, size_t buflen,
175 const unsigned char *pwd, size_t pwdlen )
Paul Bakker96743fc2011-02-12 14:30:57 +0000176{
177 aes_context aes_ctx;
178 unsigned char aes_key[32];
179
180 pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen );
181
182 aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 );
183 aes_crypt_cbc( &aes_ctx, AES_DECRYPT, buflen,
184 aes_iv, buf, buf );
185
186 memset( &aes_ctx, 0, sizeof( aes_ctx ) );
187 memset( aes_key, 0, keylen );
188}
189#endif /* POLARSSL_AES_C */
190
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200191#endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
192 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
Paul Bakker96743fc2011-02-12 14:30:57 +0000193
Paul Bakkerb6c5d2e2013-06-25 16:25:17 +0200194int pem_read_buffer( pem_context *ctx, const char *header, const char *footer,
195 const unsigned char *data, const unsigned char *pwd,
196 size_t pwdlen, size_t *use_len )
Paul Bakker96743fc2011-02-12 14:30:57 +0000197{
Paul Bakker23986e52011-04-24 08:57:21 +0000198 int ret, enc;
199 size_t len;
Paul Bakker96743fc2011-02-12 14:30:57 +0000200 unsigned char *buf;
Paul Bakker00b28602013-06-24 13:02:41 +0200201 const unsigned char *s1, *s2, *end;
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200202#if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
203 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
Paul Bakker96743fc2011-02-12 14:30:57 +0000204 unsigned char pem_iv[16];
205 cipher_type_t enc_alg = POLARSSL_CIPHER_NONE;
206#else
207 ((void) pwd);
208 ((void) pwdlen);
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200209#endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
210 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
Paul Bakker96743fc2011-02-12 14:30:57 +0000211
212 if( ctx == NULL )
Paul Bakker00b28602013-06-24 13:02:41 +0200213 return( POLARSSL_ERR_PEM_BAD_INPUT_DATA );
Paul Bakker96743fc2011-02-12 14:30:57 +0000214
Paul Bakker3c2122f2013-06-24 19:03:14 +0200215 s1 = (unsigned char *) strstr( (const char *) data, header );
Paul Bakker96743fc2011-02-12 14:30:57 +0000216
217 if( s1 == NULL )
Paul Bakker00b28602013-06-24 13:02:41 +0200218 return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
Paul Bakker96743fc2011-02-12 14:30:57 +0000219
Paul Bakker3c2122f2013-06-24 19:03:14 +0200220 s2 = (unsigned char *) strstr( (const char *) data, footer );
Paul Bakker96743fc2011-02-12 14:30:57 +0000221
222 if( s2 == NULL || s2 <= s1 )
Paul Bakker00b28602013-06-24 13:02:41 +0200223 return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
Paul Bakker96743fc2011-02-12 14:30:57 +0000224
225 s1 += strlen( header );
226 if( *s1 == '\r' ) s1++;
227 if( *s1 == '\n' ) s1++;
Paul Bakker00b28602013-06-24 13:02:41 +0200228 else return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
229
230 end = s2;
231 end += strlen( footer );
232 if( *end == '\r' ) end++;
233 if( *end == '\n' ) end++;
234 *use_len = end - data;
Paul Bakker96743fc2011-02-12 14:30:57 +0000235
236 enc = 0;
237
238 if( memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
239 {
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200240#if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
241 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
Paul Bakker96743fc2011-02-12 14:30:57 +0000242 enc++;
243
244 s1 += 22;
245 if( *s1 == '\r' ) s1++;
246 if( *s1 == '\n' ) s1++;
247 else return( POLARSSL_ERR_PEM_INVALID_DATA );
248
249
250#if defined(POLARSSL_DES_C)
251 if( memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 )
252 {
253 enc_alg = POLARSSL_CIPHER_DES_EDE3_CBC;
254
255 s1 += 23;
256 if( pem_get_iv( s1, pem_iv, 8 ) != 0 )
257 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
258
259 s1 += 16;
260 }
261 else if( memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 )
262 {
263 enc_alg = POLARSSL_CIPHER_DES_CBC;
264
265 s1 += 18;
266 if( pem_get_iv( s1, pem_iv, 8) != 0 )
267 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
268
269 s1 += 16;
270 }
271#endif /* POLARSSL_DES_C */
272
273#if defined(POLARSSL_AES_C)
274 if( memcmp( s1, "DEK-Info: AES-", 14 ) == 0 )
275 {
276 if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 )
277 enc_alg = POLARSSL_CIPHER_AES_128_CBC;
278 else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 )
279 enc_alg = POLARSSL_CIPHER_AES_192_CBC;
280 else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 )
281 enc_alg = POLARSSL_CIPHER_AES_256_CBC;
282 else
283 return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG );
284
285 s1 += 22;
286 if( pem_get_iv( s1, pem_iv, 16 ) != 0 )
287 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
288
289 s1 += 32;
290 }
291#endif /* POLARSSL_AES_C */
Paul Bakkercff68422013-09-15 20:43:33 +0200292
Paul Bakker96743fc2011-02-12 14:30:57 +0000293 if( enc_alg == POLARSSL_CIPHER_NONE )
294 return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG );
295
296 if( *s1 == '\r' ) s1++;
297 if( *s1 == '\n' ) s1++;
298 else return( POLARSSL_ERR_PEM_INVALID_DATA );
299#else
300 return( POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE );
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200301#endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
302 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
Paul Bakker96743fc2011-02-12 14:30:57 +0000303 }
304
305 len = 0;
306 ret = base64_decode( NULL, &len, s1, s2 - s1 );
307
308 if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER )
Paul Bakker9d781402011-05-09 16:17:09 +0000309 return( POLARSSL_ERR_PEM_INVALID_DATA + ret );
Paul Bakker96743fc2011-02-12 14:30:57 +0000310
Paul Bakker6e339b52013-07-03 13:37:05 +0200311 if( ( buf = (unsigned char *) polarssl_malloc( len ) ) == NULL )
Paul Bakker96743fc2011-02-12 14:30:57 +0000312 return( POLARSSL_ERR_PEM_MALLOC_FAILED );
313
314 if( ( ret = base64_decode( buf, &len, s1, s2 - s1 ) ) != 0 )
315 {
Paul Bakker6e339b52013-07-03 13:37:05 +0200316 polarssl_free( buf );
Paul Bakker9d781402011-05-09 16:17:09 +0000317 return( POLARSSL_ERR_PEM_INVALID_DATA + ret );
Paul Bakker96743fc2011-02-12 14:30:57 +0000318 }
Paul Bakkercff68422013-09-15 20:43:33 +0200319
Paul Bakker96743fc2011-02-12 14:30:57 +0000320 if( enc != 0 )
321 {
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200322#if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
323 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
Paul Bakker96743fc2011-02-12 14:30:57 +0000324 if( pwd == NULL )
325 {
Paul Bakker6e339b52013-07-03 13:37:05 +0200326 polarssl_free( buf );
Paul Bakker96743fc2011-02-12 14:30:57 +0000327 return( POLARSSL_ERR_PEM_PASSWORD_REQUIRED );
328 }
329
330#if defined(POLARSSL_DES_C)
331 if( enc_alg == POLARSSL_CIPHER_DES_EDE3_CBC )
332 pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen );
333 else if( enc_alg == POLARSSL_CIPHER_DES_CBC )
334 pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen );
335#endif /* POLARSSL_DES_C */
336
337#if defined(POLARSSL_AES_C)
338 if( enc_alg == POLARSSL_CIPHER_AES_128_CBC )
339 pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen );
340 else if( enc_alg == POLARSSL_CIPHER_AES_192_CBC )
341 pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen );
342 else if( enc_alg == POLARSSL_CIPHER_AES_256_CBC )
343 pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen );
344#endif /* POLARSSL_AES_C */
345
Manuel Pégourié-Gonnardf8648d52013-07-03 21:01:35 +0200346 /*
Manuel Pégourié-Gonnard7d4e5b72013-07-09 16:35:23 +0200347 * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
348 * length bytes (allow 4 to be sure) in all known use cases.
349 *
350 * Use that as heurisitic to try detecting password mismatchs.
Manuel Pégourié-Gonnardf8648d52013-07-03 21:01:35 +0200351 */
Manuel Pégourié-Gonnard7d4e5b72013-07-09 16:35:23 +0200352 if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 )
Paul Bakker96743fc2011-02-12 14:30:57 +0000353 {
Paul Bakker6e339b52013-07-03 13:37:05 +0200354 polarssl_free( buf );
Paul Bakker96743fc2011-02-12 14:30:57 +0000355 return( POLARSSL_ERR_PEM_PASSWORD_MISMATCH );
356 }
357#else
Paul Bakker6e339b52013-07-03 13:37:05 +0200358 polarssl_free( buf );
Paul Bakker96743fc2011-02-12 14:30:57 +0000359 return( POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE );
Manuel Pégourié-Gonnard92cb1d32013-09-13 16:24:20 +0200360#endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
361 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
Paul Bakker96743fc2011-02-12 14:30:57 +0000362 }
363
364 ctx->buf = buf;
365 ctx->buflen = len;
Paul Bakker96743fc2011-02-12 14:30:57 +0000366
367 return( 0 );
368}
369
Paul Bakkercff68422013-09-15 20:43:33 +0200370void pem_free( pem_context *ctx )
371{
372 if( ctx->buf )
373 polarssl_free( ctx->buf );
374
375 if( ctx->info )
376 polarssl_free( ctx->info );
377
378 memset( ctx, 0, sizeof( pem_context ) );
379}
380#endif /* POLARSSL_PEM_PARSE_C */
381
382#if defined(POLARSSL_PEM_WRITE_C)
Paul Bakker77e23fb2013-09-15 20:03:26 +0200383int pem_write_buffer( const char *header, const char *footer,
384 const unsigned char *der_data, size_t der_len,
385 unsigned char *buf, size_t buf_len, size_t *olen )
386{
387 int ret;
388 unsigned char *encode_buf, *c, *p = buf;
Paul Bakker16300582014-04-11 13:28:43 +0200389 size_t len = 0, use_len = 0, add_len = 0;
Paul Bakker77e23fb2013-09-15 20:03:26 +0200390
391 base64_encode( NULL, &use_len, der_data, der_len );
Paul Bakker16300582014-04-11 13:28:43 +0200392 add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1;
393
Paul Bakker77e23fb2013-09-15 20:03:26 +0200394 if( use_len + add_len > buf_len )
395 {
396 *olen = use_len + add_len;
397 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
398 }
399
400 if( ( encode_buf = polarssl_malloc( use_len ) ) == NULL )
401 return( POLARSSL_ERR_PEM_MALLOC_FAILED );
402
403 if( ( ret = base64_encode( encode_buf, &use_len, der_data,
404 der_len ) ) != 0 )
405 {
406 polarssl_free( encode_buf );
407 return( ret );
408 }
409
410 memcpy( p, header, strlen( header ) );
411 p += strlen( header );
412 c = encode_buf;
413
414 while( use_len )
415 {
416 len = ( use_len > 64 ) ? 64 : use_len;
417 memcpy( p, c, len );
418 use_len -= len;
419 p += len;
420 c += len;
421 *p++ = '\n';
422 }
423
424 memcpy( p, footer, strlen( footer ) );
425 p += strlen( footer );
426
427 *p++ = '\0';
428 *olen = p - buf;
429
430 polarssl_free( encode_buf );
431 return( 0 );
432}
Paul Bakkercff68422013-09-15 20:43:33 +0200433#endif /* POLARSSL_PEM_WRITE_C */
434#endif /* POLARSSL_PEM_PARSE_C || POLARSSL_PEM_WRITE_C */