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.
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 */
Generated on Tue Jul 12 2022 14:24:31 by
