Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

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