Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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 #include "mbedtls/platform_util.h"
00037 
00038 #include <string.h>
00039 
00040 #if defined(MBEDTLS_PLATFORM_C)
00041 #include "mbedtls/platform.h"
00042 #else
00043 #include <stdlib.h>
00044 #define mbedtls_calloc    calloc
00045 #define mbedtls_free       free
00046 #endif
00047 
00048 #if defined(MBEDTLS_PEM_PARSE_C)
00049 void mbedtls_pem_init( mbedtls_pem_context *ctx )
00050 {
00051     memset( ctx, 0, sizeof( mbedtls_pem_context ) );
00052 }
00053 
00054 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) &&         \
00055     ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
00056 /*
00057  * Read a 16-byte hex string and convert it to binary
00058  */
00059 static int pem_get_iv( const unsigned char *s, unsigned char *iv,
00060                        size_t iv_len )
00061 {
00062     size_t i, j, k;
00063 
00064     memset( iv, 0, iv_len );
00065 
00066     for( i = 0; i < iv_len * 2; i++, s++ )
00067     {
00068         if( *s >= '0' && *s <= '9' ) j = *s - '0'; else
00069         if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else
00070         if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else
00071             return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
00072 
00073         k = ( ( i & 1 ) != 0 ) ? j : j << 4;
00074 
00075         iv[i >> 1] = (unsigned char)( iv[i >> 1] | k );
00076     }
00077 
00078     return( 0 );
00079 }
00080 
00081 static int pem_pbkdf1( unsigned char *key, size_t keylen,
00082                        unsigned char *iv,
00083                        const unsigned char *pwd, size_t pwdlen )
00084 {
00085     mbedtls_md5_context md5_ctx;
00086     unsigned char md5sum[16];
00087     size_t use_len;
00088     int ret;
00089 
00090     mbedtls_md5_init( &md5_ctx );
00091 
00092     /*
00093      * key[ 0..15] = MD5(pwd || IV)
00094      */
00095     if( ( ret = mbedtls_md5_starts_ret( &md5_ctx ) ) != 0 )
00096         goto exit;
00097     if( ( ret = mbedtls_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 )
00098         goto exit;
00099     if( ( ret = mbedtls_md5_update_ret( &md5_ctx, iv,  8 ) ) != 0 )
00100         goto exit;
00101     if( ( ret = mbedtls_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 )
00102         goto exit;
00103 
00104     if( keylen <= 16 )
00105     {
00106         memcpy( key, md5sum, keylen );
00107         goto exit;
00108     }
00109 
00110     memcpy( key, md5sum, 16 );
00111 
00112     /*
00113      * key[16..23] = MD5(key[ 0..15] || pwd || IV])
00114      */
00115     if( ( ret = mbedtls_md5_starts_ret( &md5_ctx ) ) != 0 )
00116         goto exit;
00117     if( ( ret = mbedtls_md5_update_ret( &md5_ctx, md5sum, 16 ) ) != 0 )
00118         goto exit;
00119     if( ( ret = mbedtls_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 )
00120         goto exit;
00121     if( ( ret = mbedtls_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 )
00122         goto exit;
00123     if( ( ret = mbedtls_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 )
00124         goto exit;
00125 
00126     use_len = 16;
00127     if( keylen < 32 )
00128         use_len = keylen - 16;
00129 
00130     memcpy( key + 16, md5sum, use_len );
00131 
00132 exit:
00133     mbedtls_md5_free( &md5_ctx );
00134     mbedtls_platform_zeroize( md5sum, 16 );
00135 
00136     return( ret );
00137 }
00138 
00139 #if defined(MBEDTLS_DES_C)
00140 /*
00141  * Decrypt with DES-CBC, using PBKDF1 for key derivation
00142  */
00143 static int pem_des_decrypt( unsigned char des_iv[8],
00144                             unsigned char *buf, size_t buflen,
00145                             const unsigned char *pwd, size_t pwdlen )
00146 {
00147     mbedtls_des_context des_ctx;
00148     unsigned char des_key[8];
00149     int ret;
00150 
00151     mbedtls_des_init( &des_ctx );
00152 
00153     if( ( ret = pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ) ) != 0 )
00154         goto exit;
00155 
00156     if( ( ret = mbedtls_des_setkey_dec( &des_ctx, des_key ) ) != 0 )
00157         goto exit;
00158     ret = mbedtls_des_crypt_cbc( &des_ctx, MBEDTLS_DES_DECRYPT, buflen,
00159                      des_iv, buf, buf );
00160 
00161 exit:
00162     mbedtls_des_free( &des_ctx );
00163     mbedtls_platform_zeroize( des_key, 8 );
00164 
00165     return( ret );
00166 }
00167 
00168 /*
00169  * Decrypt with 3DES-CBC, using PBKDF1 for key derivation
00170  */
00171 static int pem_des3_decrypt( unsigned char des3_iv[8],
00172                              unsigned char *buf, size_t buflen,
00173                              const unsigned char *pwd, size_t pwdlen )
00174 {
00175     mbedtls_des3_context des3_ctx;
00176     unsigned char des3_key[24];
00177     int ret;
00178 
00179     mbedtls_des3_init( &des3_ctx );
00180 
00181     if( ( ret = pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ) ) != 0 )
00182         goto exit;
00183 
00184     if( ( ret = mbedtls_des3_set3key_dec( &des3_ctx, des3_key ) ) != 0 )
00185         goto exit;
00186     ret = mbedtls_des3_crypt_cbc( &des3_ctx, MBEDTLS_DES_DECRYPT, buflen,
00187                      des3_iv, buf, buf );
00188 
00189 exit:
00190     mbedtls_des3_free( &des3_ctx );
00191     mbedtls_platform_zeroize( des3_key, 24 );
00192 
00193     return( ret );
00194 }
00195 #endif /* MBEDTLS_DES_C */
00196 
00197 #if defined(MBEDTLS_AES_C)
00198 /*
00199  * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation
00200  */
00201 static int pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen,
00202                             unsigned char *buf, size_t buflen,
00203                             const unsigned char *pwd, size_t pwdlen )
00204 {
00205     mbedtls_aes_context aes_ctx;
00206     unsigned char aes_key[32];
00207     int ret;
00208 
00209     mbedtls_aes_init( &aes_ctx );
00210 
00211     if( ( ret = pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ) ) != 0 )
00212         goto exit;
00213 
00214     if( ( ret = mbedtls_aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ) ) != 0 )
00215         goto exit;
00216     ret = mbedtls_aes_crypt_cbc( &aes_ctx, MBEDTLS_AES_DECRYPT, buflen,
00217                      aes_iv, buf, buf );
00218 
00219 exit:
00220     mbedtls_aes_free( &aes_ctx );
00221     mbedtls_platform_zeroize( aes_key, keylen );
00222 
00223     return( ret );
00224 }
00225 #endif /* MBEDTLS_AES_C */
00226 
00227 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
00228           ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
00229 
00230 int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer,
00231                      const unsigned char *data, const unsigned char *pwd,
00232                      size_t pwdlen, size_t *use_len )
00233 {
00234     int ret, enc;
00235     size_t len;
00236     unsigned char *buf;
00237     const unsigned char *s1, *s2, *end;
00238 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) &&         \
00239     ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
00240     unsigned char pem_iv[16];
00241     mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE;
00242 #else
00243     ((void) pwd);
00244     ((void) pwdlen);
00245 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
00246           ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
00247 
00248     if( ctx == NULL )
00249         return( MBEDTLS_ERR_PEM_BAD_INPUT_DATA );
00250 
00251     s1 = (unsigned char *) strstr( (const char *) data, header );
00252 
00253     if( s1 == NULL )
00254         return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
00255 
00256     s2 = (unsigned char *) strstr( (const char *) data, footer );
00257 
00258     if( s2 == NULL || s2 <= s1 )
00259         return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
00260 
00261     s1 += strlen( header );
00262     if( *s1 == ' '  ) s1++;
00263     if( *s1 == '\r' ) s1++;
00264     if( *s1 == '\n' ) s1++;
00265     else return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT );
00266 
00267     end = s2;
00268     end += strlen( footer );
00269     if( *end == ' '  ) end++;
00270     if( *end == '\r' ) end++;
00271     if( *end == '\n' ) end++;
00272     *use_len = end - data;
00273 
00274     enc = 0;
00275 
00276     if( s2 - s1 >= 22 && memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
00277     {
00278 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) &&         \
00279     ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
00280         enc++;
00281 
00282         s1 += 22;
00283         if( *s1 == '\r' ) s1++;
00284         if( *s1 == '\n' ) s1++;
00285         else return( MBEDTLS_ERR_PEM_INVALID_DATA );
00286 
00287 
00288 #if defined(MBEDTLS_DES_C)
00289         if( s2 - s1 >= 23 && memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 )
00290         {
00291             enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC;
00292 
00293             s1 += 23;
00294             if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8 ) != 0 )
00295                 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
00296 
00297             s1 += 16;
00298         }
00299         else if( s2 - s1 >= 18 && memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 )
00300         {
00301             enc_alg = MBEDTLS_CIPHER_DES_CBC;
00302 
00303             s1 += 18;
00304             if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8) != 0 )
00305                 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
00306 
00307             s1 += 16;
00308         }
00309 #endif /* MBEDTLS_DES_C */
00310 
00311 #if defined(MBEDTLS_AES_C)
00312         if( s2 - s1 >= 14 && memcmp( s1, "DEK-Info: AES-", 14 ) == 0 )
00313         {
00314             if( s2 - s1 < 22 )
00315                 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG );
00316             else if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 )
00317                 enc_alg = MBEDTLS_CIPHER_AES_128_CBC;
00318             else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 )
00319                 enc_alg = MBEDTLS_CIPHER_AES_192_CBC;
00320             else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 )
00321                 enc_alg = MBEDTLS_CIPHER_AES_256_CBC;
00322             else
00323                 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG );
00324 
00325             s1 += 22;
00326             if( s2 - s1 < 32 || pem_get_iv( s1, pem_iv, 16 ) != 0 )
00327                 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV );
00328 
00329             s1 += 32;
00330         }
00331 #endif /* MBEDTLS_AES_C */
00332 
00333         if( enc_alg == MBEDTLS_CIPHER_NONE )
00334             return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG );
00335 
00336         if( *s1 == '\r' ) s1++;
00337         if( *s1 == '\n' ) s1++;
00338         else return( MBEDTLS_ERR_PEM_INVALID_DATA );
00339 #else
00340         return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE );
00341 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
00342           ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
00343     }
00344 
00345     if( s1 >= s2 )
00346         return( MBEDTLS_ERR_PEM_INVALID_DATA );
00347 
00348     ret = mbedtls_base64_decode( NULL, 0, &len, s1, s2 - s1 );
00349 
00350     if( ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER )
00351         return( MBEDTLS_ERR_PEM_INVALID_DATA + ret );
00352 
00353     if( ( buf = mbedtls_calloc( 1, len ) ) == NULL )
00354         return( MBEDTLS_ERR_PEM_ALLOC_FAILED );
00355 
00356     if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 )
00357     {
00358         mbedtls_platform_zeroize( buf, len );
00359         mbedtls_free( buf );
00360         return( MBEDTLS_ERR_PEM_INVALID_DATA + ret );
00361     }
00362 
00363     if( enc != 0 )
00364     {
00365 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) &&         \
00366     ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) )
00367         if( pwd == NULL )
00368         {
00369             mbedtls_platform_zeroize( buf, len );
00370             mbedtls_free( buf );
00371             return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED );
00372         }
00373 
00374         ret = 0;
00375 
00376 #if defined(MBEDTLS_DES_C)
00377         if( enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC )
00378             ret = pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen );
00379         else if( enc_alg == MBEDTLS_CIPHER_DES_CBC )
00380             ret = pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen );
00381 #endif /* MBEDTLS_DES_C */
00382 
00383 #if defined(MBEDTLS_AES_C)
00384         if( enc_alg == MBEDTLS_CIPHER_AES_128_CBC )
00385             ret = pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen );
00386         else if( enc_alg == MBEDTLS_CIPHER_AES_192_CBC )
00387             ret = pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen );
00388         else if( enc_alg == MBEDTLS_CIPHER_AES_256_CBC )
00389             ret = pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen );
00390 #endif /* MBEDTLS_AES_C */
00391 
00392         if( ret != 0 )
00393         {
00394             mbedtls_free( buf );
00395             return( ret );
00396         }
00397 
00398         /*
00399          * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
00400          * length bytes (allow 4 to be sure) in all known use cases.
00401          *
00402          * Use that as a heuristic to try to detect password mismatches.
00403          */
00404         if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 )
00405         {
00406             mbedtls_platform_zeroize( buf, len );
00407             mbedtls_free( buf );
00408             return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH );
00409         }
00410 #else
00411         mbedtls_platform_zeroize( buf, len );
00412         mbedtls_free( buf );
00413         return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE );
00414 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC &&
00415           ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */
00416     }
00417 
00418     ctx->buf  = buf;
00419     ctx->buflen  = len;
00420 
00421     return( 0 );
00422 }
00423 
00424 void mbedtls_pem_free( mbedtls_pem_context *ctx )
00425 {
00426     if ( ctx->buf  != NULL )
00427     {
00428         mbedtls_platform_zeroize( ctx->buf , ctx->buflen  );
00429         mbedtls_free( ctx->buf  );
00430     }
00431     mbedtls_free( ctx->info  );
00432 
00433     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pem_context ) );
00434 }
00435 #endif /* MBEDTLS_PEM_PARSE_C */
00436 
00437 #if defined(MBEDTLS_PEM_WRITE_C)
00438 int mbedtls_pem_write_buffer( const char *header, const char *footer,
00439                       const unsigned char *der_data, size_t der_len,
00440                       unsigned char *buf, size_t buf_len, size_t *olen )
00441 {
00442     int ret;
00443     unsigned char *encode_buf = NULL, *c, *p = buf;
00444     size_t len = 0, use_len, add_len = 0;
00445 
00446     mbedtls_base64_encode( NULL, 0, &use_len, der_data, der_len );
00447     add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1;
00448 
00449     if( use_len + add_len > buf_len )
00450     {
00451         *olen = use_len + add_len;
00452         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
00453     }
00454 
00455     if( use_len != 0 &&
00456         ( ( encode_buf = mbedtls_calloc( 1, use_len ) ) == NULL ) )
00457         return( MBEDTLS_ERR_PEM_ALLOC_FAILED );
00458 
00459     if( ( ret = mbedtls_base64_encode( encode_buf, use_len, &use_len, der_data,
00460                                der_len ) ) != 0 )
00461     {
00462         mbedtls_free( encode_buf );
00463         return( ret );
00464     }
00465 
00466     memcpy( p, header, strlen( header ) );
00467     p += strlen( header );
00468     c = encode_buf;
00469 
00470     while( use_len )
00471     {
00472         len = ( use_len > 64 ) ? 64 : use_len;
00473         memcpy( p, c, len );
00474         use_len -= len;
00475         p += len;
00476         c += len;
00477         *p++ = '\n';
00478     }
00479 
00480     memcpy( p, footer, strlen( footer ) );
00481     p += strlen( footer );
00482 
00483     *p++ = '\0';
00484     *olen = p - buf;
00485 
00486     mbedtls_free( encode_buf );
00487     return( 0 );
00488 }
00489 #endif /* MBEDTLS_PEM_WRITE_C */
00490 #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */