PolarSSL v1.1.4
pem.c
Go to the documentation of this file.
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