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 #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 mbedtls_platform_zeroize( ctx->buf , ctx->buflen ); 00428 mbedtls_free( ctx->buf ); 00429 mbedtls_free( ctx->info ); 00430 00431 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pem_context ) ); 00432 } 00433 #endif /* MBEDTLS_PEM_PARSE_C */ 00434 00435 #if defined(MBEDTLS_PEM_WRITE_C) 00436 int mbedtls_pem_write_buffer( const char *header, const char *footer, 00437 const unsigned char *der_data, size_t der_len, 00438 unsigned char *buf, size_t buf_len, size_t *olen ) 00439 { 00440 int ret; 00441 unsigned char *encode_buf = NULL, *c, *p = buf; 00442 size_t len = 0, use_len, add_len = 0; 00443 00444 mbedtls_base64_encode( NULL, 0, &use_len, der_data, der_len ); 00445 add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1; 00446 00447 if( use_len + add_len > buf_len ) 00448 { 00449 *olen = use_len + add_len; 00450 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 00451 } 00452 00453 if( use_len != 0 && 00454 ( ( encode_buf = mbedtls_calloc( 1, use_len ) ) == NULL ) ) 00455 return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); 00456 00457 if( ( ret = mbedtls_base64_encode( encode_buf, use_len, &use_len, der_data, 00458 der_len ) ) != 0 ) 00459 { 00460 mbedtls_free( encode_buf ); 00461 return( ret ); 00462 } 00463 00464 memcpy( p, header, strlen( header ) ); 00465 p += strlen( header ); 00466 c = encode_buf; 00467 00468 while( use_len ) 00469 { 00470 len = ( use_len > 64 ) ? 64 : use_len; 00471 memcpy( p, c, len ); 00472 use_len -= len; 00473 p += len; 00474 c += len; 00475 *p++ = '\n'; 00476 } 00477 00478 memcpy( p, footer, strlen( footer ) ); 00479 p += strlen( footer ); 00480 00481 *p++ = '\0'; 00482 *olen = p - buf; 00483 00484 mbedtls_free( encode_buf ); 00485 return( 0 ); 00486 } 00487 #endif /* MBEDTLS_PEM_WRITE_C */ 00488 #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */
Generated on Tue Jul 12 2022 12:45:41 by
