Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbedtls by
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 */
Generated on Tue Jul 12 2022 17:25:42 by
