mbed TLS library

Dependents:   HTTPClient-SSL WS_SERVER

Committer:
ansond
Date:
Thu Jun 11 03:27:03 2015 +0000
Revision:
0:137634ff4186
initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ansond 0:137634ff4186 1 /*
ansond 0:137634ff4186 2 * Privacy Enhanced Mail (PEM) decoding
ansond 0:137634ff4186 3 *
ansond 0:137634ff4186 4 * Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
ansond 0:137634ff4186 5 *
ansond 0:137634ff4186 6 * This file is part of mbed TLS (https://tls.mbed.org)
ansond 0:137634ff4186 7 *
ansond 0:137634ff4186 8 * This program is free software; you can redistribute it and/or modify
ansond 0:137634ff4186 9 * it under the terms of the GNU General Public License as published by
ansond 0:137634ff4186 10 * the Free Software Foundation; either version 2 of the License, or
ansond 0:137634ff4186 11 * (at your option) any later version.
ansond 0:137634ff4186 12 *
ansond 0:137634ff4186 13 * This program is distributed in the hope that it will be useful,
ansond 0:137634ff4186 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ansond 0:137634ff4186 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
ansond 0:137634ff4186 16 * GNU General Public License for more details.
ansond 0:137634ff4186 17 *
ansond 0:137634ff4186 18 * You should have received a copy of the GNU General Public License along
ansond 0:137634ff4186 19 * with this program; if not, write to the Free Software Foundation, Inc.,
ansond 0:137634ff4186 20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
ansond 0:137634ff4186 21 */
ansond 0:137634ff4186 22
ansond 0:137634ff4186 23 #if !defined(POLARSSL_CONFIG_FILE)
ansond 0:137634ff4186 24 #include "polarssl/config.h"
ansond 0:137634ff4186 25 #else
ansond 0:137634ff4186 26 #include POLARSSL_CONFIG_FILE
ansond 0:137634ff4186 27 #endif
ansond 0:137634ff4186 28
ansond 0:137634ff4186 29 #if defined(POLARSSL_PEM_PARSE_C) || defined(POLARSSL_PEM_WRITE_C)
ansond 0:137634ff4186 30
ansond 0:137634ff4186 31 #include "polarssl/pem.h"
ansond 0:137634ff4186 32 #include "polarssl/base64.h"
ansond 0:137634ff4186 33 #include "polarssl/des.h"
ansond 0:137634ff4186 34 #include "polarssl/aes.h"
ansond 0:137634ff4186 35 #include "polarssl/md5.h"
ansond 0:137634ff4186 36 #include "polarssl/cipher.h"
ansond 0:137634ff4186 37
ansond 0:137634ff4186 38 #include <string.h>
ansond 0:137634ff4186 39
ansond 0:137634ff4186 40 #if defined(POLARSSL_PLATFORM_C)
ansond 0:137634ff4186 41 #include "polarssl/platform.h"
ansond 0:137634ff4186 42 #else
ansond 0:137634ff4186 43 #include <stdlib.h>
ansond 0:137634ff4186 44 #define polarssl_malloc malloc
ansond 0:137634ff4186 45 #define polarssl_free free
ansond 0:137634ff4186 46 #endif
ansond 0:137634ff4186 47
ansond 0:137634ff4186 48 /* Implementation that should never be optimized out by the compiler */
ansond 0:137634ff4186 49 static void polarssl_zeroize( void *v, size_t n ) {
ansond 0:137634ff4186 50 volatile unsigned char *p = v; while( n-- ) *p++ = 0;
ansond 0:137634ff4186 51 }
ansond 0:137634ff4186 52
ansond 0:137634ff4186 53 #if defined(POLARSSL_PEM_PARSE_C)
ansond 0:137634ff4186 54 void pem_init( pem_context *ctx )
ansond 0:137634ff4186 55 {
ansond 0:137634ff4186 56 memset( ctx, 0, sizeof( pem_context ) );
ansond 0:137634ff4186 57 }
ansond 0:137634ff4186 58
ansond 0:137634ff4186 59 #if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
ansond 0:137634ff4186 60 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
ansond 0:137634ff4186 61 /*
ansond 0:137634ff4186 62 * Read a 16-byte hex string and convert it to binary
ansond 0:137634ff4186 63 */
ansond 0:137634ff4186 64 static int pem_get_iv( const unsigned char *s, unsigned char *iv,
ansond 0:137634ff4186 65 size_t iv_len )
ansond 0:137634ff4186 66 {
ansond 0:137634ff4186 67 size_t i, j, k;
ansond 0:137634ff4186 68
ansond 0:137634ff4186 69 memset( iv, 0, iv_len );
ansond 0:137634ff4186 70
ansond 0:137634ff4186 71 for( i = 0; i < iv_len * 2; i++, s++ )
ansond 0:137634ff4186 72 {
ansond 0:137634ff4186 73 if( *s >= '0' && *s <= '9' ) j = *s - '0'; else
ansond 0:137634ff4186 74 if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else
ansond 0:137634ff4186 75 if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else
ansond 0:137634ff4186 76 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
ansond 0:137634ff4186 77
ansond 0:137634ff4186 78 k = ( ( i & 1 ) != 0 ) ? j : j << 4;
ansond 0:137634ff4186 79
ansond 0:137634ff4186 80 iv[i >> 1] = (unsigned char)( iv[i >> 1] | k );
ansond 0:137634ff4186 81 }
ansond 0:137634ff4186 82
ansond 0:137634ff4186 83 return( 0 );
ansond 0:137634ff4186 84 }
ansond 0:137634ff4186 85
ansond 0:137634ff4186 86 static void pem_pbkdf1( unsigned char *key, size_t keylen,
ansond 0:137634ff4186 87 unsigned char *iv,
ansond 0:137634ff4186 88 const unsigned char *pwd, size_t pwdlen )
ansond 0:137634ff4186 89 {
ansond 0:137634ff4186 90 md5_context md5_ctx;
ansond 0:137634ff4186 91 unsigned char md5sum[16];
ansond 0:137634ff4186 92 size_t use_len;
ansond 0:137634ff4186 93
ansond 0:137634ff4186 94 md5_init( &md5_ctx );
ansond 0:137634ff4186 95
ansond 0:137634ff4186 96 /*
ansond 0:137634ff4186 97 * key[ 0..15] = MD5(pwd || IV)
ansond 0:137634ff4186 98 */
ansond 0:137634ff4186 99 md5_starts( &md5_ctx );
ansond 0:137634ff4186 100 md5_update( &md5_ctx, pwd, pwdlen );
ansond 0:137634ff4186 101 md5_update( &md5_ctx, iv, 8 );
ansond 0:137634ff4186 102 md5_finish( &md5_ctx, md5sum );
ansond 0:137634ff4186 103
ansond 0:137634ff4186 104 if( keylen <= 16 )
ansond 0:137634ff4186 105 {
ansond 0:137634ff4186 106 memcpy( key, md5sum, keylen );
ansond 0:137634ff4186 107
ansond 0:137634ff4186 108 md5_free( &md5_ctx );
ansond 0:137634ff4186 109 polarssl_zeroize( md5sum, 16 );
ansond 0:137634ff4186 110 return;
ansond 0:137634ff4186 111 }
ansond 0:137634ff4186 112
ansond 0:137634ff4186 113 memcpy( key, md5sum, 16 );
ansond 0:137634ff4186 114
ansond 0:137634ff4186 115 /*
ansond 0:137634ff4186 116 * key[16..23] = MD5(key[ 0..15] || pwd || IV])
ansond 0:137634ff4186 117 */
ansond 0:137634ff4186 118 md5_starts( &md5_ctx );
ansond 0:137634ff4186 119 md5_update( &md5_ctx, md5sum, 16 );
ansond 0:137634ff4186 120 md5_update( &md5_ctx, pwd, pwdlen );
ansond 0:137634ff4186 121 md5_update( &md5_ctx, iv, 8 );
ansond 0:137634ff4186 122 md5_finish( &md5_ctx, md5sum );
ansond 0:137634ff4186 123
ansond 0:137634ff4186 124 use_len = 16;
ansond 0:137634ff4186 125 if( keylen < 32 )
ansond 0:137634ff4186 126 use_len = keylen - 16;
ansond 0:137634ff4186 127
ansond 0:137634ff4186 128 memcpy( key + 16, md5sum, use_len );
ansond 0:137634ff4186 129
ansond 0:137634ff4186 130 md5_free( &md5_ctx );
ansond 0:137634ff4186 131 polarssl_zeroize( md5sum, 16 );
ansond 0:137634ff4186 132 }
ansond 0:137634ff4186 133
ansond 0:137634ff4186 134 #if defined(POLARSSL_DES_C)
ansond 0:137634ff4186 135 /*
ansond 0:137634ff4186 136 * Decrypt with DES-CBC, using PBKDF1 for key derivation
ansond 0:137634ff4186 137 */
ansond 0:137634ff4186 138 static void pem_des_decrypt( unsigned char des_iv[8],
ansond 0:137634ff4186 139 unsigned char *buf, size_t buflen,
ansond 0:137634ff4186 140 const unsigned char *pwd, size_t pwdlen )
ansond 0:137634ff4186 141 {
ansond 0:137634ff4186 142 des_context des_ctx;
ansond 0:137634ff4186 143 unsigned char des_key[8];
ansond 0:137634ff4186 144
ansond 0:137634ff4186 145 des_init( &des_ctx );
ansond 0:137634ff4186 146
ansond 0:137634ff4186 147 pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen );
ansond 0:137634ff4186 148
ansond 0:137634ff4186 149 des_setkey_dec( &des_ctx, des_key );
ansond 0:137634ff4186 150 des_crypt_cbc( &des_ctx, DES_DECRYPT, buflen,
ansond 0:137634ff4186 151 des_iv, buf, buf );
ansond 0:137634ff4186 152
ansond 0:137634ff4186 153 des_free( &des_ctx );
ansond 0:137634ff4186 154 polarssl_zeroize( des_key, 8 );
ansond 0:137634ff4186 155 }
ansond 0:137634ff4186 156
ansond 0:137634ff4186 157 /*
ansond 0:137634ff4186 158 * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
ansond 0:137634ff4186 159 */
ansond 0:137634ff4186 160 static void pem_des3_decrypt( unsigned char des3_iv[8],
ansond 0:137634ff4186 161 unsigned char *buf, size_t buflen,
ansond 0:137634ff4186 162 const unsigned char *pwd, size_t pwdlen )
ansond 0:137634ff4186 163 {
ansond 0:137634ff4186 164 des3_context des3_ctx;
ansond 0:137634ff4186 165 unsigned char des3_key[24];
ansond 0:137634ff4186 166
ansond 0:137634ff4186 167 des3_init( &des3_ctx );
ansond 0:137634ff4186 168
ansond 0:137634ff4186 169 pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen );
ansond 0:137634ff4186 170
ansond 0:137634ff4186 171 des3_set3key_dec( &des3_ctx, des3_key );
ansond 0:137634ff4186 172 des3_crypt_cbc( &des3_ctx, DES_DECRYPT, buflen,
ansond 0:137634ff4186 173 des3_iv, buf, buf );
ansond 0:137634ff4186 174
ansond 0:137634ff4186 175 des3_free( &des3_ctx );
ansond 0:137634ff4186 176 polarssl_zeroize( des3_key, 24 );
ansond 0:137634ff4186 177 }
ansond 0:137634ff4186 178 #endif /* POLARSSL_DES_C */
ansond 0:137634ff4186 179
ansond 0:137634ff4186 180 #if defined(POLARSSL_AES_C)
ansond 0:137634ff4186 181 /*
ansond 0:137634ff4186 182 * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
ansond 0:137634ff4186 183 */
ansond 0:137634ff4186 184 static void pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen,
ansond 0:137634ff4186 185 unsigned char *buf, size_t buflen,
ansond 0:137634ff4186 186 const unsigned char *pwd, size_t pwdlen )
ansond 0:137634ff4186 187 {
ansond 0:137634ff4186 188 aes_context aes_ctx;
ansond 0:137634ff4186 189 unsigned char aes_key[32];
ansond 0:137634ff4186 190
ansond 0:137634ff4186 191 aes_init( &aes_ctx );
ansond 0:137634ff4186 192
ansond 0:137634ff4186 193 pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen );
ansond 0:137634ff4186 194
ansond 0:137634ff4186 195 aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 );
ansond 0:137634ff4186 196 aes_crypt_cbc( &aes_ctx, AES_DECRYPT, buflen,
ansond 0:137634ff4186 197 aes_iv, buf, buf );
ansond 0:137634ff4186 198
ansond 0:137634ff4186 199 aes_free( &aes_ctx );
ansond 0:137634ff4186 200 polarssl_zeroize( aes_key, keylen );
ansond 0:137634ff4186 201 }
ansond 0:137634ff4186 202 #endif /* POLARSSL_AES_C */
ansond 0:137634ff4186 203
ansond 0:137634ff4186 204 #endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
ansond 0:137634ff4186 205 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
ansond 0:137634ff4186 206
ansond 0:137634ff4186 207 int pem_read_buffer( pem_context *ctx, const char *header, const char *footer,
ansond 0:137634ff4186 208 const unsigned char *data, const unsigned char *pwd,
ansond 0:137634ff4186 209 size_t pwdlen, size_t *use_len )
ansond 0:137634ff4186 210 {
ansond 0:137634ff4186 211 int ret, enc;
ansond 0:137634ff4186 212 size_t len;
ansond 0:137634ff4186 213 unsigned char *buf;
ansond 0:137634ff4186 214 const unsigned char *s1, *s2, *end;
ansond 0:137634ff4186 215 #if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
ansond 0:137634ff4186 216 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
ansond 0:137634ff4186 217 unsigned char pem_iv[16];
ansond 0:137634ff4186 218 cipher_type_t enc_alg = POLARSSL_CIPHER_NONE;
ansond 0:137634ff4186 219 #else
ansond 0:137634ff4186 220 ((void) pwd);
ansond 0:137634ff4186 221 ((void) pwdlen);
ansond 0:137634ff4186 222 #endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
ansond 0:137634ff4186 223 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
ansond 0:137634ff4186 224
ansond 0:137634ff4186 225 if( ctx == NULL )
ansond 0:137634ff4186 226 return( POLARSSL_ERR_PEM_BAD_INPUT_DATA );
ansond 0:137634ff4186 227
ansond 0:137634ff4186 228 s1 = (unsigned char *) strstr( (const char *) data, header );
ansond 0:137634ff4186 229
ansond 0:137634ff4186 230 if( s1 == NULL )
ansond 0:137634ff4186 231 return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
ansond 0:137634ff4186 232
ansond 0:137634ff4186 233 s2 = (unsigned char *) strstr( (const char *) data, footer );
ansond 0:137634ff4186 234
ansond 0:137634ff4186 235 if( s2 == NULL || s2 <= s1 )
ansond 0:137634ff4186 236 return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
ansond 0:137634ff4186 237
ansond 0:137634ff4186 238 s1 += strlen( header );
ansond 0:137634ff4186 239 if( *s1 == '\r' ) s1++;
ansond 0:137634ff4186 240 if( *s1 == '\n' ) s1++;
ansond 0:137634ff4186 241 else return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
ansond 0:137634ff4186 242
ansond 0:137634ff4186 243 end = s2;
ansond 0:137634ff4186 244 end += strlen( footer );
ansond 0:137634ff4186 245 if( *end == '\r' ) end++;
ansond 0:137634ff4186 246 if( *end == '\n' ) end++;
ansond 0:137634ff4186 247 *use_len = end - data;
ansond 0:137634ff4186 248
ansond 0:137634ff4186 249 enc = 0;
ansond 0:137634ff4186 250
ansond 0:137634ff4186 251 if( memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
ansond 0:137634ff4186 252 {
ansond 0:137634ff4186 253 #if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
ansond 0:137634ff4186 254 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
ansond 0:137634ff4186 255 enc++;
ansond 0:137634ff4186 256
ansond 0:137634ff4186 257 s1 += 22;
ansond 0:137634ff4186 258 if( *s1 == '\r' ) s1++;
ansond 0:137634ff4186 259 if( *s1 == '\n' ) s1++;
ansond 0:137634ff4186 260 else return( POLARSSL_ERR_PEM_INVALID_DATA );
ansond 0:137634ff4186 261
ansond 0:137634ff4186 262
ansond 0:137634ff4186 263 #if defined(POLARSSL_DES_C)
ansond 0:137634ff4186 264 if( memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 )
ansond 0:137634ff4186 265 {
ansond 0:137634ff4186 266 enc_alg = POLARSSL_CIPHER_DES_EDE3_CBC;
ansond 0:137634ff4186 267
ansond 0:137634ff4186 268 s1 += 23;
ansond 0:137634ff4186 269 if( pem_get_iv( s1, pem_iv, 8 ) != 0 )
ansond 0:137634ff4186 270 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
ansond 0:137634ff4186 271
ansond 0:137634ff4186 272 s1 += 16;
ansond 0:137634ff4186 273 }
ansond 0:137634ff4186 274 else if( memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 )
ansond 0:137634ff4186 275 {
ansond 0:137634ff4186 276 enc_alg = POLARSSL_CIPHER_DES_CBC;
ansond 0:137634ff4186 277
ansond 0:137634ff4186 278 s1 += 18;
ansond 0:137634ff4186 279 if( pem_get_iv( s1, pem_iv, 8) != 0 )
ansond 0:137634ff4186 280 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
ansond 0:137634ff4186 281
ansond 0:137634ff4186 282 s1 += 16;
ansond 0:137634ff4186 283 }
ansond 0:137634ff4186 284 #endif /* POLARSSL_DES_C */
ansond 0:137634ff4186 285
ansond 0:137634ff4186 286 #if defined(POLARSSL_AES_C)
ansond 0:137634ff4186 287 if( memcmp( s1, "DEK-Info: AES-", 14 ) == 0 )
ansond 0:137634ff4186 288 {
ansond 0:137634ff4186 289 if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 )
ansond 0:137634ff4186 290 enc_alg = POLARSSL_CIPHER_AES_128_CBC;
ansond 0:137634ff4186 291 else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 )
ansond 0:137634ff4186 292 enc_alg = POLARSSL_CIPHER_AES_192_CBC;
ansond 0:137634ff4186 293 else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 )
ansond 0:137634ff4186 294 enc_alg = POLARSSL_CIPHER_AES_256_CBC;
ansond 0:137634ff4186 295 else
ansond 0:137634ff4186 296 return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG );
ansond 0:137634ff4186 297
ansond 0:137634ff4186 298 s1 += 22;
ansond 0:137634ff4186 299 if( pem_get_iv( s1, pem_iv, 16 ) != 0 )
ansond 0:137634ff4186 300 return( POLARSSL_ERR_PEM_INVALID_ENC_IV );
ansond 0:137634ff4186 301
ansond 0:137634ff4186 302 s1 += 32;
ansond 0:137634ff4186 303 }
ansond 0:137634ff4186 304 #endif /* POLARSSL_AES_C */
ansond 0:137634ff4186 305
ansond 0:137634ff4186 306 if( enc_alg == POLARSSL_CIPHER_NONE )
ansond 0:137634ff4186 307 return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG );
ansond 0:137634ff4186 308
ansond 0:137634ff4186 309 if( *s1 == '\r' ) s1++;
ansond 0:137634ff4186 310 if( *s1 == '\n' ) s1++;
ansond 0:137634ff4186 311 else return( POLARSSL_ERR_PEM_INVALID_DATA );
ansond 0:137634ff4186 312 #else
ansond 0:137634ff4186 313 return( POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE );
ansond 0:137634ff4186 314 #endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
ansond 0:137634ff4186 315 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
ansond 0:137634ff4186 316 }
ansond 0:137634ff4186 317
ansond 0:137634ff4186 318 len = 0;
ansond 0:137634ff4186 319 ret = base64_decode( NULL, &len, s1, s2 - s1 );
ansond 0:137634ff4186 320
ansond 0:137634ff4186 321 if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER )
ansond 0:137634ff4186 322 return( POLARSSL_ERR_PEM_INVALID_DATA + ret );
ansond 0:137634ff4186 323
ansond 0:137634ff4186 324 if( ( buf = polarssl_malloc( len ) ) == NULL )
ansond 0:137634ff4186 325 return( POLARSSL_ERR_PEM_MALLOC_FAILED );
ansond 0:137634ff4186 326
ansond 0:137634ff4186 327 if( ( ret = base64_decode( buf, &len, s1, s2 - s1 ) ) != 0 )
ansond 0:137634ff4186 328 {
ansond 0:137634ff4186 329 polarssl_free( buf );
ansond 0:137634ff4186 330 return( POLARSSL_ERR_PEM_INVALID_DATA + ret );
ansond 0:137634ff4186 331 }
ansond 0:137634ff4186 332
ansond 0:137634ff4186 333 if( enc != 0 )
ansond 0:137634ff4186 334 {
ansond 0:137634ff4186 335 #if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
ansond 0:137634ff4186 336 ( defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C) )
ansond 0:137634ff4186 337 if( pwd == NULL )
ansond 0:137634ff4186 338 {
ansond 0:137634ff4186 339 polarssl_free( buf );
ansond 0:137634ff4186 340 return( POLARSSL_ERR_PEM_PASSWORD_REQUIRED );
ansond 0:137634ff4186 341 }
ansond 0:137634ff4186 342
ansond 0:137634ff4186 343 #if defined(POLARSSL_DES_C)
ansond 0:137634ff4186 344 if( enc_alg == POLARSSL_CIPHER_DES_EDE3_CBC )
ansond 0:137634ff4186 345 pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen );
ansond 0:137634ff4186 346 else if( enc_alg == POLARSSL_CIPHER_DES_CBC )
ansond 0:137634ff4186 347 pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen );
ansond 0:137634ff4186 348 #endif /* POLARSSL_DES_C */
ansond 0:137634ff4186 349
ansond 0:137634ff4186 350 #if defined(POLARSSL_AES_C)
ansond 0:137634ff4186 351 if( enc_alg == POLARSSL_CIPHER_AES_128_CBC )
ansond 0:137634ff4186 352 pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen );
ansond 0:137634ff4186 353 else if( enc_alg == POLARSSL_CIPHER_AES_192_CBC )
ansond 0:137634ff4186 354 pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen );
ansond 0:137634ff4186 355 else if( enc_alg == POLARSSL_CIPHER_AES_256_CBC )
ansond 0:137634ff4186 356 pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen );
ansond 0:137634ff4186 357 #endif /* POLARSSL_AES_C */
ansond 0:137634ff4186 358
ansond 0:137634ff4186 359 /*
ansond 0:137634ff4186 360 * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
ansond 0:137634ff4186 361 * length bytes (allow 4 to be sure) in all known use cases.
ansond 0:137634ff4186 362 *
ansond 0:137634ff4186 363 * Use that as heurisitic to try detecting password mismatchs.
ansond 0:137634ff4186 364 */
ansond 0:137634ff4186 365 if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 )
ansond 0:137634ff4186 366 {
ansond 0:137634ff4186 367 polarssl_free( buf );
ansond 0:137634ff4186 368 return( POLARSSL_ERR_PEM_PASSWORD_MISMATCH );
ansond 0:137634ff4186 369 }
ansond 0:137634ff4186 370 #else
ansond 0:137634ff4186 371 polarssl_free( buf );
ansond 0:137634ff4186 372 return( POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE );
ansond 0:137634ff4186 373 #endif /* POLARSSL_MD5_C && POLARSSL_CIPHER_MODE_CBC &&
ansond 0:137634ff4186 374 ( POLARSSL_AES_C || POLARSSL_DES_C ) */
ansond 0:137634ff4186 375 }
ansond 0:137634ff4186 376
ansond 0:137634ff4186 377 ctx->buf = buf;
ansond 0:137634ff4186 378 ctx->buflen = len;
ansond 0:137634ff4186 379
ansond 0:137634ff4186 380 return( 0 );
ansond 0:137634ff4186 381 }
ansond 0:137634ff4186 382
ansond 0:137634ff4186 383 void pem_free( pem_context *ctx )
ansond 0:137634ff4186 384 {
ansond 0:137634ff4186 385 polarssl_free( ctx->buf );
ansond 0:137634ff4186 386 polarssl_free( ctx->info );
ansond 0:137634ff4186 387
ansond 0:137634ff4186 388 polarssl_zeroize( ctx, sizeof( pem_context ) );
ansond 0:137634ff4186 389 }
ansond 0:137634ff4186 390 #endif /* POLARSSL_PEM_PARSE_C */
ansond 0:137634ff4186 391
ansond 0:137634ff4186 392 #if defined(POLARSSL_PEM_WRITE_C)
ansond 0:137634ff4186 393 int pem_write_buffer( const char *header, const char *footer,
ansond 0:137634ff4186 394 const unsigned char *der_data, size_t der_len,
ansond 0:137634ff4186 395 unsigned char *buf, size_t buf_len, size_t *olen )
ansond 0:137634ff4186 396 {
ansond 0:137634ff4186 397 int ret;
ansond 0:137634ff4186 398 unsigned char *encode_buf, *c, *p = buf;
ansond 0:137634ff4186 399 size_t len = 0, use_len = 0, add_len = 0;
ansond 0:137634ff4186 400
ansond 0:137634ff4186 401 base64_encode( NULL, &use_len, der_data, der_len );
ansond 0:137634ff4186 402 add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1;
ansond 0:137634ff4186 403
ansond 0:137634ff4186 404 if( use_len + add_len > buf_len )
ansond 0:137634ff4186 405 {
ansond 0:137634ff4186 406 *olen = use_len + add_len;
ansond 0:137634ff4186 407 return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
ansond 0:137634ff4186 408 }
ansond 0:137634ff4186 409
ansond 0:137634ff4186 410 if( ( encode_buf = polarssl_malloc( use_len ) ) == NULL )
ansond 0:137634ff4186 411 return( POLARSSL_ERR_PEM_MALLOC_FAILED );
ansond 0:137634ff4186 412
ansond 0:137634ff4186 413 if( ( ret = base64_encode( encode_buf, &use_len, der_data,
ansond 0:137634ff4186 414 der_len ) ) != 0 )
ansond 0:137634ff4186 415 {
ansond 0:137634ff4186 416 polarssl_free( encode_buf );
ansond 0:137634ff4186 417 return( ret );
ansond 0:137634ff4186 418 }
ansond 0:137634ff4186 419
ansond 0:137634ff4186 420 memcpy( p, header, strlen( header ) );
ansond 0:137634ff4186 421 p += strlen( header );
ansond 0:137634ff4186 422 c = encode_buf;
ansond 0:137634ff4186 423
ansond 0:137634ff4186 424 while( use_len )
ansond 0:137634ff4186 425 {
ansond 0:137634ff4186 426 len = ( use_len > 64 ) ? 64 : use_len;
ansond 0:137634ff4186 427 memcpy( p, c, len );
ansond 0:137634ff4186 428 use_len -= len;
ansond 0:137634ff4186 429 p += len;
ansond 0:137634ff4186 430 c += len;
ansond 0:137634ff4186 431 *p++ = '\n';
ansond 0:137634ff4186 432 }
ansond 0:137634ff4186 433
ansond 0:137634ff4186 434 memcpy( p, footer, strlen( footer ) );
ansond 0:137634ff4186 435 p += strlen( footer );
ansond 0:137634ff4186 436
ansond 0:137634ff4186 437 *p++ = '\0';
ansond 0:137634ff4186 438 *olen = p - buf;
ansond 0:137634ff4186 439
ansond 0:137634ff4186 440 polarssl_free( encode_buf );
ansond 0:137634ff4186 441 return( 0 );
ansond 0:137634ff4186 442 }
ansond 0:137634ff4186 443 #endif /* POLARSSL_PEM_WRITE_C */
ansond 0:137634ff4186 444 #endif /* POLARSSL_PEM_PARSE_C || POLARSSL_PEM_WRITE_C */
ansond 0:137634ff4186 445