Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pem.c Source File

pem.c

00001 /*
00002  *  Privacy Enhanced Mail (PEM) decoding
00003  *
00004  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
00005  *  SPDX-License-Identifier: Apache-2.0
00006  *
00007  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
00008  *  not use this file except in compliance with the License.
00009  *  You may obtain a copy of the License at
00010  *
00011  *  http://www.apache.org/licenses/LICENSE-2.0
00012  *
00013  *  Unless required by applicable law or agreed to in writing, software
00014  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00015  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016  *  See the License for the specific language governing permissions and
00017  *  limitations under the License.
00018  *
00019  *  This file is part of mbed TLS (https://tls.mbed.org)
00020  */
00021 
00022 #if !defined(MBEDTLS_CONFIG_FILE)
00023 #include "mbedtls/config.h"
00024 #else
00025 #include MBEDTLS_CONFIG_FILE
00026 #endif
00027 
00028 #if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C)
00029 
00030 #include "mbedtls/pem.h"
00031 #include "mbedtls/base64.h"
00032 #include "mbedtls/des.h"
00033 #include "mbedtls/aes.h"
00034 #include "mbedtls/md5.h"
00035 #include "mbedtls/cipher.h"
00036 
00037 #include <string.h>
00038 
00039 #if defined(MBEDTLS_PLATFORM_C)
00040 #include "mbedtls/platform.h"
00041 #else
00042 #include <stdlib.h>
00043 #define mbedtls_calloc    calloc
00044 #define mbedtls_free       free
00045 #endif
00046 
00047 #if defined(MBEDTLS_PEM_PARSE_C)
00048 /* Implementation that should never be optimized out by the compiler */
00049 static void mbedtls_zeroize( void *v, size_t n ) {
00050     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
00051 }
00052 
00053 void mbedtls_pem_init( mbedtls_pem_context *ctx )
00054 {
00055     memset( ctx, 0, sizeof( mbedtls_pem_context ) );
00056 }
00057 
00058 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) &&         \
00059     ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
00060 /*
00061  * Read a 16-byte hex string and convert it to binary
00062  */
00063 static int pem_get_iv( const unsigned char *s, unsigned char *iv,
00064                        size_t iv_len )
00065 {
00066     size_t i, j, k;
00067 
00068     memset( iv, 0, iv_len );
00069 
00070     for( i = 0; i < iv_len * 2; i++, s++ )
00071     {
00072         if( *s >= '0' && *s <= '9' ) j = *s - '0'; else
00073         if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else
00074         if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else
00075             return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
00076 
00077         k = ( ( i & 1 ) != 0 ) ? j : j << 4;
00078 
00079         iv[i >> 1] = (unsigned char)( iv[i >> 1] | k );
00080     }
00081 
00082     return( 0 );
00083 }
00084 
00085 static void pem_pbkdf1( unsigned char *key, size_t keylen,
00086                         unsigned char *iv,
00087                         const unsigned char *pwd, size_t pwdlen )
00088 {
00089     mbedtls_md5_context md5_ctx;
00090     unsigned char md5sum[16];
00091     size_t use_len;
00092 
00093     mbedtls_md5_init( &md5_ctx );
00094 
00095     /*
00096      * key[ 0..15] = MD5(pwd || IV)
00097      */
00098     mbedtls_md5_starts( &md5_ctx );
00099     mbedtls_md5_update( &md5_ctx, pwd, pwdlen );
00100     mbedtls_md5_update( &md5_ctx, iv,  8 );
00101     mbedtls_md5_finish( &md5_ctx, md5sum );
00102 
00103     if( keylen <= 16 )
00104     {
00105         memcpy( key, md5sum, keylen );
00106 
00107         mbedtls_md5_free( &md5_ctx );
00108         mbedtls_zeroize( md5sum, 16 );
00109         return;
00110     }
00111 
00112     memcpy( key, md5sum, 16 );
00113 
00114     /*
00115      * key[16..23] = MD5(key[ 0..15] || pwd || IV])
00116      */
00117     mbedtls_md5_starts( &md5_ctx );
00118     mbedtls_md5_update( &md5_ctx, md5sum,  16 );
00119     mbedtls_md5_update( &md5_ctx, pwd, pwdlen );
00120     mbedtls_md5_update( &md5_ctx, iv,  8 );
00121     mbedtls_md5_finish( &md5_ctx, md5sum );
00122 
00123     use_len = 16;
00124     if( keylen < 32 )
00125         use_len = keylen - 16;
00126 
00127     memcpy( key + 16, md5sum, use_len );
00128 
00129     mbedtls_md5_free( &md5_ctx );
00130     mbedtls_zeroize( md5sum, 16 );
00131 }
00132 
00133 #if defined(MBEDTLS_DES_C)
00134 /*
00135  * Decrypt with DES-CBC, using PBKDF1 for key derivation
00136  */
00137 static void pem_des_decrypt( unsigned char des_iv[8],
00138                                unsigned char *buf, size_t buflen,
00139                                const unsigned char *pwd, size_t pwdlen )
00140 {
00141     mbedtls_des_context des_ctx;
00142     unsigned char des_key[8];
00143 
00144     mbedtls_des_init( &des_ctx );
00145 
00146     pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen );
00147 
00148     mbedtls_des_setkey_dec( &des_ctx, des_key );
00149     mbedtls_des_crypt_cbc( &des_ctx, MBEDTLS_DES_DECRYPT, buflen,
00150                      des_iv, buf, buf );
00151 
00152     mbedtls_des_free( &des_ctx );
00153     mbedtls_zeroize( des_key, 8 );
00154 }
00155 
00156 /*
00157  * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
00158  */
00159 static void pem_des3_decrypt( unsigned char des3_iv[8],
00160                                unsigned char *buf, size_t buflen,
00161                                const unsigned char *pwd, size_t pwdlen )
00162 {
00163     mbedtls_des3_context des3_ctx;
00164     unsigned char des3_key[24];
00165 
00166     mbedtls_des3_init( &des3_ctx );
00167 
00168     pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen );
00169 
00170     mbedtls_des3_set3key_dec( &des3_ctx, des3_key );
00171     mbedtls_des3_crypt_cbc( &des3_ctx, MBEDTLS_DES_DECRYPT, buflen,
00172                      des3_iv, buf, buf );
00173 
00174     mbedtls_des3_free( &des3_ctx );
00175     mbedtls_zeroize( des3_key, 24 );
00176 }
00177 #endif /* MBEDTLS_DES_C */
00178 
00179 #if defined(MBEDTLS_AES_C)
00180 /*
00181  * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
00182  */
00183 static void pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen,
00184                                unsigned char *buf, size_t buflen,
00185                                const unsigned char *pwd, size_t pwdlen )
00186 {
00187     mbedtls_aes_context aes_ctx;
00188     unsigned char aes_key[32];
00189 
00190     mbedtls_aes_init( &aes_ctx );
00191 
00192     pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen );
00193 
00194     mbedtls_aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 );
00195     mbedtls_aes_crypt_cbc( &aes_ctx, MBEDTLS_AES_DECRYPT, buflen,
00196                      aes_iv, buf, buf );
00197 
00198     mbedtls_aes_free( &aes_ctx );
00199     mbedtls_zeroize( aes_key, keylen );
00200 }
00201 #endif /* MBEDTLS_AES_C */
00202 
00203 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
00204           ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
00205 
00206 int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer,
00207                      const unsigned char *data, const unsigned char *pwd,
00208                      size_t pwdlen, size_t *use_len )
00209 {
00210     int ret, enc;
00211     size_t len;
00212     unsigned char *buf;
00213     const unsigned char *s1, *s2, *end;
00214 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) &&         \
00215     ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
00216     unsigned char pem_iv[16];
00217     mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE;
00218 #else
00219     ((void) pwd);
00220     ((void) pwdlen);
00221 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
00222           ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
00223 
00224     if( ctx == NULL )
00225         return( MBEDTLS_ERR_PEM_BAD_INPUT_DATA );
00226 
00227     s1 = (unsigned char *) strstr( (const char *) data, header );
00228 
00229     if( s1 == NULL )
00230         return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
00231 
00232     s2 = (unsigned char *) strstr( (const char *) data, footer );
00233 
00234     if( s2 == NULL || s2 <= s1 )
00235         return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
00236 
00237     s1 += strlen( header );
00238     if( *s1 == ' '  ) s1++;
00239     if( *s1 == '\r' ) s1++;
00240     if( *s1 == '\n' ) s1++;
00241     else return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
00242 
00243     end = s2;
00244     end += strlen( footer );
00245     if( *end == ' '  ) end++;
00246     if( *end == '\r' ) end++;
00247     if( *end == '\n' ) end++;
00248     *use_len = end - data;
00249 
00250     enc = 0;
00251 
00252     if( s2 - s1 >= 22 && memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
00253     {
00254 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) &&         \
00255     ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
00256         enc++;
00257 
00258         s1 += 22;
00259         if( *s1 == '\r' ) s1++;
00260         if( *s1 == '\n' ) s1++;
00261         else return( MBEDTLS_ERR_PEM_INVALID_DATA );
00262 
00263 
00264 #if defined(MBEDTLS_DES_C)
00265         if( s2 - s1 >= 23 && memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 )
00266         {
00267             enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC;
00268 
00269             s1 += 23;
00270             if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8 ) != 0 )
00271                 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
00272 
00273             s1 += 16;
00274         }
00275         else if( s2 - s1 >= 18 && memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 )
00276         {
00277             enc_alg = MBEDTLS_CIPHER_DES_CBC;
00278 
00279             s1 += 18;
00280             if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8) != 0 )
00281                 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
00282 
00283             s1 += 16;
00284         }
00285 #endif /* MBEDTLS_DES_C */
00286 
00287 #if defined(MBEDTLS_AES_C)
00288         if( s2 - s1 >= 14 && memcmp( s1, "DEK-Info: AES-", 14 ) == 0 )
00289         {
00290             if( s2 - s1 < 22 )
00291                 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG );
00292             else if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 )
00293                 enc_alg = MBEDTLS_CIPHER_AES_128_CBC;
00294             else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 )
00295                 enc_alg = MBEDTLS_CIPHER_AES_192_CBC;
00296             else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 )
00297                 enc_alg = MBEDTLS_CIPHER_AES_256_CBC;
00298             else
00299                 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG );
00300 
00301             s1 += 22;
00302             if( s2 - s1 < 32 || pem_get_iv( s1, pem_iv, 16 ) != 0 )
00303                 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
00304 
00305             s1 += 32;
00306         }
00307 #endif /* MBEDTLS_AES_C */
00308 
00309         if( enc_alg == MBEDTLS_CIPHER_NONE )
00310             return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG );
00311 
00312         if( *s1 == '\r' ) s1++;
00313         if( *s1 == '\n' ) s1++;
00314         else return( MBEDTLS_ERR_PEM_INVALID_DATA );
00315 #else
00316         return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE );
00317 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
00318           ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
00319     }
00320 
00321     if( s1 >= s2 )
00322         return( MBEDTLS_ERR_PEM_INVALID_DATA );
00323 
00324     ret = mbedtls_base64_decode( NULL, 0, &len, s1, s2 - s1 );
00325 
00326     if( ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER )
00327         return( MBEDTLS_ERR_PEM_INVALID_DATA + ret );
00328 
00329     if( ( buf = mbedtls_calloc( 1, len ) ) == NULL )
00330         return( MBEDTLS_ERR_PEM_ALLOC_FAILED );
00331 
00332     if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 )
00333     {
00334         mbedtls_free( buf );
00335         return( MBEDTLS_ERR_PEM_INVALID_DATA + ret );
00336     }
00337 
00338     if( enc != 0 )
00339     {
00340 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) &&         \
00341     ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
00342         if( pwd == NULL )
00343         {
00344             mbedtls_free( buf );
00345             return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED );
00346         }
00347 
00348 #if defined(MBEDTLS_DES_C)
00349         if( enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC )
00350             pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen );
00351         else if( enc_alg == MBEDTLS_CIPHER_DES_CBC )
00352             pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen );
00353 #endif /* MBEDTLS_DES_C */
00354 
00355 #if defined(MBEDTLS_AES_C)
00356         if( enc_alg == MBEDTLS_CIPHER_AES_128_CBC )
00357             pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen );
00358         else if( enc_alg == MBEDTLS_CIPHER_AES_192_CBC )
00359             pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen );
00360         else if( enc_alg == MBEDTLS_CIPHER_AES_256_CBC )
00361             pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen );
00362 #endif /* MBEDTLS_AES_C */
00363 
00364         /*
00365          * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
00366          * length bytes (allow 4 to be sure) in all known use cases.
00367          *
00368          * Use that as heurisitic to try detecting password mismatchs.
00369          */
00370         if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 )
00371         {
00372             mbedtls_free( buf );
00373             return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH );
00374         }
00375 #else
00376         mbedtls_free( buf );
00377         return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE );
00378 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
00379           ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
00380     }
00381 
00382     ctx->buf  = buf;
00383     ctx->buflen  = len;
00384 
00385     return( 0 );
00386 }
00387 
00388 void mbedtls_pem_free( mbedtls_pem_context *ctx )
00389 {
00390     mbedtls_free( ctx->buf  );
00391     mbedtls_free( ctx->info  );
00392 
00393     mbedtls_zeroize( ctx, sizeof( mbedtls_pem_context ) );
00394 }
00395 #endif /* MBEDTLS_PEM_PARSE_C */
00396 
00397 #if defined(MBEDTLS_PEM_WRITE_C)
00398 int mbedtls_pem_write_buffer( const char *header, const char *footer,
00399                       const unsigned char *der_data, size_t der_len,
00400                       unsigned char *buf, size_t buf_len, size_t *olen )
00401 {
00402     int ret;
00403     unsigned char *encode_buf, *c, *p = buf;
00404     size_t len = 0, use_len, add_len = 0;
00405 
00406     mbedtls_base64_encode( NULL, 0, &use_len, der_data, der_len );
00407     add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1;
00408 
00409     if( use_len + add_len > buf_len )
00410     {
00411         *olen = use_len + add_len;
00412         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
00413     }
00414 
00415     if( ( encode_buf = mbedtls_calloc( 1, use_len ) ) == NULL )
00416         return( MBEDTLS_ERR_PEM_ALLOC_FAILED );
00417 
00418     if( ( ret = mbedtls_base64_encode( encode_buf, use_len, &use_len, der_data,
00419                                der_len ) ) != 0 )
00420     {
00421         mbedtls_free( encode_buf );
00422         return( ret );
00423     }
00424 
00425     memcpy( p, header, strlen( header ) );
00426     p += strlen( header );
00427     c = encode_buf;
00428 
00429     while( use_len )
00430     {
00431         len = ( use_len > 64 ) ? 64 : use_len;
00432         memcpy( p, c, len );
00433         use_len -= len;
00434         p += len;
00435         c += len;
00436         *p++ = '\n';
00437     }
00438 
00439     memcpy( p, footer, strlen( footer ) );
00440     p += strlen( footer );
00441 
00442     *p++ = '\0';
00443     *olen = p - buf;
00444 
00445     mbedtls_free( encode_buf );
00446     return( 0 );
00447 }
00448 #endif /* MBEDTLS_PEM_WRITE_C */
00449 #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */