PolarSSL v1.1.4
|
00001 /* 00002 * Privacy Enhanced Mail (PEM) decoding 00003 * 00004 * Copyright (C) 2006-2010, Brainspark B.V. 00005 * 00006 * This file is part of PolarSSL (http://www.polarssl.org) 00007 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org> 00008 * 00009 * All rights reserved. 00010 * 00011 * This program is free software; you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License as published by 00013 * the Free Software Foundation; either version 2 of the License, or 00014 * (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License along 00022 * with this program; if not, write to the Free Software Foundation, Inc., 00023 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00024 */ 00025 00026 #include "polarssl/config.h" 00027 00028 #if defined(POLARSSL_PEM_C) 00029 00030 #include "polarssl/pem.h" 00031 #include "polarssl/base64.h" 00032 #include "polarssl/des.h" 00033 #include "polarssl/aes.h" 00034 #include "polarssl/md5.h" 00035 #include "polarssl/cipher.h" 00036 00037 #include <stdlib.h> 00038 00039 void pem_init( pem_context *ctx ) 00040 { 00041 memset( ctx, 0, sizeof( pem_context ) ); 00042 } 00043 00044 #if defined(POLARSSL_MD5_C) && (defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C)) 00045 /* 00046 * Read a 16-byte hex string and convert it to binary 00047 */ 00048 static int pem_get_iv( const unsigned char *s, unsigned char *iv, size_t iv_len ) 00049 { 00050 size_t i, j, k; 00051 00052 memset( iv, 0, iv_len ); 00053 00054 for( i = 0; i < iv_len * 2; i++, s++ ) 00055 { 00056 if( *s >= '0' && *s <= '9' ) j = *s - '0'; else 00057 if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else 00058 if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else 00059 return( POLARSSL_ERR_PEM_INVALID_ENC_IV ); 00060 00061 k = ( ( i & 1 ) != 0 ) ? j : j << 4; 00062 00063 iv[i >> 1] = (unsigned char)( iv[i >> 1] | k ); 00064 } 00065 00066 return( 0 ); 00067 } 00068 00069 static void pem_pbkdf1( unsigned char *key, size_t keylen, 00070 unsigned char *iv, 00071 const unsigned char *pwd, size_t pwdlen ) 00072 { 00073 md5_context md5_ctx; 00074 unsigned char md5sum[16]; 00075 size_t use_len; 00076 00077 /* 00078 * key[ 0..15] = MD5(pwd || IV) 00079 */ 00080 md5_starts( &md5_ctx ); 00081 md5_update( &md5_ctx, pwd, pwdlen ); 00082 md5_update( &md5_ctx, iv, 8 ); 00083 md5_finish( &md5_ctx, md5sum ); 00084 00085 if( keylen <= 16 ) 00086 { 00087 memcpy( key, md5sum, keylen ); 00088 00089 memset( &md5_ctx, 0, sizeof( md5_ctx ) ); 00090 memset( md5sum, 0, 16 ); 00091 return; 00092 } 00093 00094 memcpy( key, md5sum, 16 ); 00095 00096 /* 00097 * key[16..23] = MD5(key[ 0..15] || pwd || IV]) 00098 */ 00099 md5_starts( &md5_ctx ); 00100 md5_update( &md5_ctx, md5sum, 16 ); 00101 md5_update( &md5_ctx, pwd, pwdlen ); 00102 md5_update( &md5_ctx, iv, 8 ); 00103 md5_finish( &md5_ctx, md5sum ); 00104 00105 use_len = 16; 00106 if( keylen < 32 ) 00107 use_len = keylen - 16; 00108 00109 memcpy( key + 16, md5sum, use_len ); 00110 00111 memset( &md5_ctx, 0, sizeof( md5_ctx ) ); 00112 memset( md5sum, 0, 16 ); 00113 } 00114 00115 #if defined(POLARSSL_DES_C) 00116 /* 00117 * Decrypt with DES-CBC, using PBKDF1 for key derivation 00118 */ 00119 static void pem_des_decrypt( unsigned char des_iv[8], 00120 unsigned char *buf, size_t buflen, 00121 const unsigned char *pwd, size_t pwdlen ) 00122 { 00123 des_context des_ctx; 00124 unsigned char des_key[8]; 00125 00126 pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ); 00127 00128 des_setkey_dec( &des_ctx, des_key ); 00129 des_crypt_cbc( &des_ctx, DES_DECRYPT, buflen, 00130 des_iv, buf, buf ); 00131 00132 memset( &des_ctx, 0, sizeof( des_ctx ) ); 00133 memset( des_key, 0, 8 ); 00134 } 00135 00136 /* 00137 * Decrypt with 3DES-CBC, using PBKDF1 for key derivation 00138 */ 00139 static void pem_des3_decrypt( unsigned char des3_iv[8], 00140 unsigned char *buf, size_t buflen, 00141 const unsigned char *pwd, size_t pwdlen ) 00142 { 00143 des3_context des3_ctx; 00144 unsigned char des3_key[24]; 00145 00146 pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ); 00147 00148 des3_set3key_dec( &des3_ctx, des3_key ); 00149 des3_crypt_cbc( &des3_ctx, DES_DECRYPT, buflen, 00150 des3_iv, buf, buf ); 00151 00152 memset( &des3_ctx, 0, sizeof( des3_ctx ) ); 00153 memset( des3_key, 0, 24 ); 00154 } 00155 #endif /* POLARSSL_DES_C */ 00156 00157 #if defined(POLARSSL_AES_C) 00158 /* 00159 * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation 00160 */ 00161 static void pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen, 00162 unsigned char *buf, size_t buflen, 00163 const unsigned char *pwd, size_t pwdlen ) 00164 { 00165 aes_context aes_ctx; 00166 unsigned char aes_key[32]; 00167 00168 pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ); 00169 00170 aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ); 00171 aes_crypt_cbc( &aes_ctx, AES_DECRYPT, buflen, 00172 aes_iv, buf, buf ); 00173 00174 memset( &aes_ctx, 0, sizeof( aes_ctx ) ); 00175 memset( aes_key, 0, keylen ); 00176 } 00177 #endif /* POLARSSL_AES_C */ 00178 00179 #endif /* POLARSSL_MD5_C && (POLARSSL_AES_C || POLARSSL_DES_C) */ 00180 00181 int pem_read_buffer( pem_context *ctx, char *header, char *footer, const unsigned char *data, const unsigned char *pwd, size_t pwdlen, size_t *use_len ) 00182 { 00183 int ret, enc; 00184 size_t len; 00185 unsigned char *buf; 00186 unsigned char *s1, *s2; 00187 #if defined(POLARSSL_MD5_C) && (defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C)) 00188 unsigned char pem_iv[16]; 00189 cipher_type_t enc_alg = POLARSSL_CIPHER_NONE; 00190 #else 00191 ((void) pwd); 00192 ((void) pwdlen); 00193 #endif /* POLARSSL_MD5_C && (POLARSSL_AES_C || POLARSSL_DES_C) */ 00194 00195 if( ctx == NULL ) 00196 return( POLARSSL_ERR_PEM_INVALID_DATA ); 00197 00198 s1 = (unsigned char *) strstr( (char *) data, header ); 00199 00200 if( s1 == NULL ) 00201 return( POLARSSL_ERR_PEM_NO_HEADER_PRESENT ); 00202 00203 s2 = (unsigned char *) strstr( (char *) data, footer ); 00204 00205 if( s2 == NULL || s2 <= s1 ) 00206 return( POLARSSL_ERR_PEM_INVALID_DATA ); 00207 00208 s1 += strlen( header ); 00209 if( *s1 == '\r' ) s1++; 00210 if( *s1 == '\n' ) s1++; 00211 else return( POLARSSL_ERR_PEM_INVALID_DATA ); 00212 00213 enc = 0; 00214 00215 if( memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 ) 00216 { 00217 #if defined(POLARSSL_MD5_C) && (defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C)) 00218 enc++; 00219 00220 s1 += 22; 00221 if( *s1 == '\r' ) s1++; 00222 if( *s1 == '\n' ) s1++; 00223 else return( POLARSSL_ERR_PEM_INVALID_DATA ); 00224 00225 00226 #if defined(POLARSSL_DES_C) 00227 if( memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 ) 00228 { 00229 enc_alg = POLARSSL_CIPHER_DES_EDE3_CBC; 00230 00231 s1 += 23; 00232 if( pem_get_iv( s1, pem_iv, 8 ) != 0 ) 00233 return( POLARSSL_ERR_PEM_INVALID_ENC_IV ); 00234 00235 s1 += 16; 00236 } 00237 else if( memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 ) 00238 { 00239 enc_alg = POLARSSL_CIPHER_DES_CBC; 00240 00241 s1 += 18; 00242 if( pem_get_iv( s1, pem_iv, 8) != 0 ) 00243 return( POLARSSL_ERR_PEM_INVALID_ENC_IV ); 00244 00245 s1 += 16; 00246 } 00247 #endif /* POLARSSL_DES_C */ 00248 00249 #if defined(POLARSSL_AES_C) 00250 if( memcmp( s1, "DEK-Info: AES-", 14 ) == 0 ) 00251 { 00252 if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 ) 00253 enc_alg = POLARSSL_CIPHER_AES_128_CBC; 00254 else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 ) 00255 enc_alg = POLARSSL_CIPHER_AES_192_CBC; 00256 else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 ) 00257 enc_alg = POLARSSL_CIPHER_AES_256_CBC; 00258 else 00259 return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG ); 00260 00261 s1 += 22; 00262 if( pem_get_iv( s1, pem_iv, 16 ) != 0 ) 00263 return( POLARSSL_ERR_PEM_INVALID_ENC_IV ); 00264 00265 s1 += 32; 00266 } 00267 #endif /* POLARSSL_AES_C */ 00268 00269 if( enc_alg == POLARSSL_CIPHER_NONE ) 00270 return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG ); 00271 00272 if( *s1 == '\r' ) s1++; 00273 if( *s1 == '\n' ) s1++; 00274 else return( POLARSSL_ERR_PEM_INVALID_DATA ); 00275 #else 00276 return( POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE ); 00277 #endif /* POLARSSL_MD5_C && (POLARSSL_AES_C || POLARSSL_DES_C) */ 00278 } 00279 00280 len = 0; 00281 ret = base64_decode( NULL, &len, s1, s2 - s1 ); 00282 00283 if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER ) 00284 return( POLARSSL_ERR_PEM_INVALID_DATA + ret ); 00285 00286 if( ( buf = (unsigned char *) malloc( len ) ) == NULL ) 00287 return( POLARSSL_ERR_PEM_MALLOC_FAILED ); 00288 00289 if( ( ret = base64_decode( buf, &len, s1, s2 - s1 ) ) != 0 ) 00290 { 00291 free( buf ); 00292 return( POLARSSL_ERR_PEM_INVALID_DATA + ret ); 00293 } 00294 00295 if( enc != 0 ) 00296 { 00297 #if defined(POLARSSL_MD5_C) && (defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C)) 00298 if( pwd == NULL ) 00299 { 00300 free( buf ); 00301 return( POLARSSL_ERR_PEM_PASSWORD_REQUIRED ); 00302 } 00303 00304 #if defined(POLARSSL_DES_C) 00305 if( enc_alg == POLARSSL_CIPHER_DES_EDE3_CBC ) 00306 pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen ); 00307 else if( enc_alg == POLARSSL_CIPHER_DES_CBC ) 00308 pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen ); 00309 #endif /* POLARSSL_DES_C */ 00310 00311 #if defined(POLARSSL_AES_C) 00312 if( enc_alg == POLARSSL_CIPHER_AES_128_CBC ) 00313 pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen ); 00314 else if( enc_alg == POLARSSL_CIPHER_AES_192_CBC ) 00315 pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen ); 00316 else if( enc_alg == POLARSSL_CIPHER_AES_256_CBC ) 00317 pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen ); 00318 #endif /* POLARSSL_AES_C */ 00319 00320 if( buf[0] != 0x30 || buf[1] != 0x82 || 00321 buf[4] != 0x02 || buf[5] != 0x01 ) 00322 { 00323 free( buf ); 00324 return( POLARSSL_ERR_PEM_PASSWORD_MISMATCH ); 00325 } 00326 #else 00327 return( POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE ); 00328 #endif 00329 } 00330 00331 ctx->buf = buf; 00332 ctx->buflen = len; 00333 s2 += strlen( footer ); 00334 if( *s2 == '\r' ) s2++; 00335 if( *s2 == '\n' ) s2++; 00336 *use_len = s2 - data; 00337 00338 return( 0 ); 00339 } 00340 00341 void pem_free( pem_context *ctx ) 00342 { 00343 if( ctx->buf ) 00344 free( ctx->buf ); 00345 00346 if( ctx->info ) 00347 free( ctx->info ); 00348 00349 memset( ctx, 0, sizeof( pem_context ) ); 00350 } 00351 00352 #endif