1 // SPDX-License-Identifier: Apache-2.0 2 /* 3 * Privacy Enhanced Mail (PEM) decoding 4 * 5 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); you may 8 * not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 * This file is part of mbed TLS (https://tls.mbed.org) 20 */ 21 22 #if !defined(MBEDTLS_CONFIG_FILE) 23 #include "mbedtls/config.h" 24 #else 25 #include MBEDTLS_CONFIG_FILE 26 #endif 27 28 #if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) 29 30 #include "mbedtls/pem.h" 31 #include "mbedtls/base64.h" 32 #include "mbedtls/des.h" 33 #include "mbedtls/aes.h" 34 #include "mbedtls/md5.h" 35 #include "mbedtls/cipher.h" 36 #include "mbedtls/platform_util.h" 37 #include "mbedtls/error.h" 38 39 #include <string.h> 40 41 #if defined(MBEDTLS_PLATFORM_C) 42 #include "mbedtls/platform.h" 43 #else 44 #include <stdlib.h> 45 #define mbedtls_calloc calloc 46 #define mbedtls_free free 47 #endif 48 49 #if defined(MBEDTLS_PEM_PARSE_C) 50 void mbedtls_pem_init( mbedtls_pem_context *ctx ) 51 { 52 memset( ctx, 0, sizeof( mbedtls_pem_context ) ); 53 } 54 55 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ 56 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) 57 /* 58 * Read a 16-byte hex string and convert it to binary 59 */ 60 static int pem_get_iv( const unsigned char *s, unsigned char *iv, 61 size_t iv_len ) 62 { 63 size_t i, j, k; 64 65 memset( iv, 0, iv_len ); 66 67 for( i = 0; i < iv_len * 2; i++, s++ ) 68 { 69 if( *s >= '0' && *s <= '9' ) j = *s - '0'; else 70 if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else 71 if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else 72 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); 73 74 k = ( ( i & 1 ) != 0 ) ? j : j << 4; 75 76 iv[i >> 1] = (unsigned char)( iv[i >> 1] | k ); 77 } 78 79 return( 0 ); 80 } 81 82 static int pem_pbkdf1( unsigned char *key, size_t keylen, 83 unsigned char *iv, 84 const unsigned char *pwd, size_t pwdlen ) 85 { 86 mbedtls_md5_context md5_ctx; 87 unsigned char md5sum[16]; 88 size_t use_len; 89 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 90 91 mbedtls_md5_init( &md5_ctx ); 92 93 /* 94 * key[ 0..15] = MD5(pwd || IV) 95 */ 96 if( ( ret = mbedtls_md5_starts_ret( &md5_ctx ) ) != 0 ) 97 goto exit; 98 if( ( ret = mbedtls_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 ) 99 goto exit; 100 if( ( ret = mbedtls_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 ) 101 goto exit; 102 if( ( ret = mbedtls_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 ) 103 goto exit; 104 105 if( keylen <= 16 ) 106 { 107 memcpy( key, md5sum, keylen ); 108 goto exit; 109 } 110 111 memcpy( key, md5sum, 16 ); 112 113 /* 114 * key[16..23] = MD5(key[ 0..15] || pwd || IV]) 115 */ 116 if( ( ret = mbedtls_md5_starts_ret( &md5_ctx ) ) != 0 ) 117 goto exit; 118 if( ( ret = mbedtls_md5_update_ret( &md5_ctx, md5sum, 16 ) ) != 0 ) 119 goto exit; 120 if( ( ret = mbedtls_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 ) 121 goto exit; 122 if( ( ret = mbedtls_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 ) 123 goto exit; 124 if( ( ret = mbedtls_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 ) 125 goto exit; 126 127 use_len = 16; 128 if( keylen < 32 ) 129 use_len = keylen - 16; 130 131 memcpy( key + 16, md5sum, use_len ); 132 133 exit: 134 mbedtls_md5_free( &md5_ctx ); 135 mbedtls_platform_zeroize( md5sum, 16 ); 136 137 return( ret ); 138 } 139 140 #if defined(MBEDTLS_DES_C) 141 /* 142 * Decrypt with DES-CBC, using PBKDF1 for key derivation 143 */ 144 static int pem_des_decrypt( unsigned char des_iv[8], 145 unsigned char *buf, size_t buflen, 146 const unsigned char *pwd, size_t pwdlen ) 147 { 148 mbedtls_des_context des_ctx; 149 unsigned char des_key[8]; 150 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 151 152 mbedtls_des_init( &des_ctx ); 153 154 if( ( ret = pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ) ) != 0 ) 155 goto exit; 156 157 if( ( ret = mbedtls_des_setkey_dec( &des_ctx, des_key ) ) != 0 ) 158 goto exit; 159 ret = mbedtls_des_crypt_cbc( &des_ctx, MBEDTLS_DES_DECRYPT, buflen, 160 des_iv, buf, buf ); 161 162 exit: 163 mbedtls_des_free( &des_ctx ); 164 mbedtls_platform_zeroize( des_key, 8 ); 165 166 return( ret ); 167 } 168 169 /* 170 * Decrypt with 3DES-CBC, using PBKDF1 for key derivation 171 */ 172 static int pem_des3_decrypt( unsigned char des3_iv[8], 173 unsigned char *buf, size_t buflen, 174 const unsigned char *pwd, size_t pwdlen ) 175 { 176 mbedtls_des3_context des3_ctx; 177 unsigned char des3_key[24]; 178 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 179 180 mbedtls_des3_init( &des3_ctx ); 181 182 if( ( ret = pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ) ) != 0 ) 183 goto exit; 184 185 if( ( ret = mbedtls_des3_set3key_dec( &des3_ctx, des3_key ) ) != 0 ) 186 goto exit; 187 ret = mbedtls_des3_crypt_cbc( &des3_ctx, MBEDTLS_DES_DECRYPT, buflen, 188 des3_iv, buf, buf ); 189 190 exit: 191 mbedtls_des3_free( &des3_ctx ); 192 mbedtls_platform_zeroize( des3_key, 24 ); 193 194 return( ret ); 195 } 196 #endif /* MBEDTLS_DES_C */ 197 198 #if defined(MBEDTLS_AES_C) 199 /* 200 * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation 201 */ 202 static int pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen, 203 unsigned char *buf, size_t buflen, 204 const unsigned char *pwd, size_t pwdlen ) 205 { 206 mbedtls_aes_context aes_ctx; 207 unsigned char aes_key[32]; 208 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 209 210 mbedtls_aes_init( &aes_ctx ); 211 212 if( ( ret = pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ) ) != 0 ) 213 goto exit; 214 215 if( ( ret = mbedtls_aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ) ) != 0 ) 216 goto exit; 217 ret = mbedtls_aes_crypt_cbc( &aes_ctx, MBEDTLS_AES_DECRYPT, buflen, 218 aes_iv, buf, buf ); 219 220 exit: 221 mbedtls_aes_free( &aes_ctx ); 222 mbedtls_platform_zeroize( aes_key, keylen ); 223 224 return( ret ); 225 } 226 #endif /* MBEDTLS_AES_C */ 227 228 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && 229 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ 230 231 int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer, 232 const unsigned char *data, const unsigned char *pwd, 233 size_t pwdlen, size_t *use_len ) 234 { 235 int ret, enc; 236 size_t len; 237 unsigned char *buf; 238 const unsigned char *s1, *s2, *end; 239 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ 240 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) 241 unsigned char pem_iv[16]; 242 mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE; 243 #else 244 ((void) pwd); 245 ((void) pwdlen); 246 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && 247 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ 248 249 if( ctx == NULL ) 250 return( MBEDTLS_ERR_PEM_BAD_INPUT_DATA ); 251 252 s1 = (unsigned char *) strstr( (const char *) data, header ); 253 254 if( s1 == NULL ) 255 return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); 256 257 s2 = (unsigned char *) strstr( (const char *) data, footer ); 258 259 if( s2 == NULL || s2 <= s1 ) 260 return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); 261 262 s1 += strlen( header ); 263 if( *s1 == ' ' ) s1++; 264 if( *s1 == '\r' ) s1++; 265 if( *s1 == '\n' ) s1++; 266 else return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); 267 268 end = s2; 269 end += strlen( footer ); 270 if( *end == ' ' ) end++; 271 if( *end == '\r' ) end++; 272 if( *end == '\n' ) end++; 273 *use_len = end - data; 274 275 enc = 0; 276 277 if( s2 - s1 >= 22 && memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 ) 278 { 279 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ 280 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) 281 enc++; 282 283 s1 += 22; 284 if( *s1 == '\r' ) s1++; 285 if( *s1 == '\n' ) s1++; 286 else return( MBEDTLS_ERR_PEM_INVALID_DATA ); 287 288 289 #if defined(MBEDTLS_DES_C) 290 if( s2 - s1 >= 23 && memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 ) 291 { 292 enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC; 293 294 s1 += 23; 295 if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8 ) != 0 ) 296 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); 297 298 s1 += 16; 299 } 300 else if( s2 - s1 >= 18 && memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 ) 301 { 302 enc_alg = MBEDTLS_CIPHER_DES_CBC; 303 304 s1 += 18; 305 if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8) != 0 ) 306 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); 307 308 s1 += 16; 309 } 310 #endif /* MBEDTLS_DES_C */ 311 312 #if defined(MBEDTLS_AES_C) 313 if( s2 - s1 >= 14 && memcmp( s1, "DEK-Info: AES-", 14 ) == 0 ) 314 { 315 if( s2 - s1 < 22 ) 316 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); 317 else if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 ) 318 enc_alg = MBEDTLS_CIPHER_AES_128_CBC; 319 else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 ) 320 enc_alg = MBEDTLS_CIPHER_AES_192_CBC; 321 else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 ) 322 enc_alg = MBEDTLS_CIPHER_AES_256_CBC; 323 else 324 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); 325 326 s1 += 22; 327 if( s2 - s1 < 32 || pem_get_iv( s1, pem_iv, 16 ) != 0 ) 328 return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); 329 330 s1 += 32; 331 } 332 #endif /* MBEDTLS_AES_C */ 333 334 if( enc_alg == MBEDTLS_CIPHER_NONE ) 335 return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); 336 337 if( *s1 == '\r' ) s1++; 338 if( *s1 == '\n' ) s1++; 339 else return( MBEDTLS_ERR_PEM_INVALID_DATA ); 340 #else 341 return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); 342 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && 343 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ 344 } 345 346 if( s1 >= s2 ) 347 return( MBEDTLS_ERR_PEM_INVALID_DATA ); 348 349 ret = mbedtls_base64_decode( NULL, 0, &len, s1, s2 - s1 ); 350 351 if( ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER ) 352 return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); 353 354 if( ( buf = mbedtls_calloc( 1, len ) ) == NULL ) 355 return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); 356 357 if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 ) 358 { 359 mbedtls_platform_zeroize( buf, len ); 360 mbedtls_free( buf ); 361 return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); 362 } 363 364 if( enc != 0 ) 365 { 366 #if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ 367 ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) 368 if( pwd == NULL ) 369 { 370 mbedtls_platform_zeroize( buf, len ); 371 mbedtls_free( buf ); 372 return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ); 373 } 374 375 ret = 0; 376 377 #if defined(MBEDTLS_DES_C) 378 if( enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC ) 379 ret = pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen ); 380 else if( enc_alg == MBEDTLS_CIPHER_DES_CBC ) 381 ret = pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen ); 382 #endif /* MBEDTLS_DES_C */ 383 384 #if defined(MBEDTLS_AES_C) 385 if( enc_alg == MBEDTLS_CIPHER_AES_128_CBC ) 386 ret = pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen ); 387 else if( enc_alg == MBEDTLS_CIPHER_AES_192_CBC ) 388 ret = pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen ); 389 else if( enc_alg == MBEDTLS_CIPHER_AES_256_CBC ) 390 ret = pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen ); 391 #endif /* MBEDTLS_AES_C */ 392 393 if( ret != 0 ) 394 { 395 mbedtls_free( buf ); 396 return( ret ); 397 } 398 399 /* 400 * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3 401 * length bytes (allow 4 to be sure) in all known use cases. 402 * 403 * Use that as a heuristic to try to detect password mismatches. 404 */ 405 if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 ) 406 { 407 mbedtls_platform_zeroize( buf, len ); 408 mbedtls_free( buf ); 409 return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ); 410 } 411 #else 412 mbedtls_platform_zeroize( buf, len ); 413 mbedtls_free( buf ); 414 return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); 415 #endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && 416 ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ 417 } 418 419 ctx->buf = buf; 420 ctx->buflen = len; 421 422 return( 0 ); 423 } 424 425 void mbedtls_pem_free( mbedtls_pem_context *ctx ) 426 { 427 if ( ctx->buf != NULL ) 428 { 429 mbedtls_platform_zeroize( ctx->buf, ctx->buflen ); 430 mbedtls_free( ctx->buf ); 431 } 432 mbedtls_free( ctx->info ); 433 434 mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pem_context ) ); 435 } 436 #endif /* MBEDTLS_PEM_PARSE_C */ 437 438 #if defined(MBEDTLS_PEM_WRITE_C) 439 int mbedtls_pem_write_buffer( const char *header, const char *footer, 440 const unsigned char *der_data, size_t der_len, 441 unsigned char *buf, size_t buf_len, size_t *olen ) 442 { 443 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 444 unsigned char *encode_buf = NULL, *c, *p = buf; 445 size_t len = 0, use_len, add_len = 0; 446 447 mbedtls_base64_encode( NULL, 0, &use_len, der_data, der_len ); 448 add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1; 449 450 if( use_len + add_len > buf_len ) 451 { 452 *olen = use_len + add_len; 453 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); 454 } 455 456 if( use_len != 0 && 457 ( ( encode_buf = mbedtls_calloc( 1, use_len ) ) == NULL ) ) 458 return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); 459 460 if( ( ret = mbedtls_base64_encode( encode_buf, use_len, &use_len, der_data, 461 der_len ) ) != 0 ) 462 { 463 mbedtls_free( encode_buf ); 464 return( ret ); 465 } 466 467 memcpy( p, header, strlen( header ) ); 468 p += strlen( header ); 469 c = encode_buf; 470 471 while( use_len ) 472 { 473 len = ( use_len > 64 ) ? 64 : use_len; 474 memcpy( p, c, len ); 475 use_len -= len; 476 p += len; 477 c += len; 478 *p++ = '\n'; 479 } 480 481 memcpy( p, footer, strlen( footer ) ); 482 p += strlen( footer ); 483 484 *p++ = '\0'; 485 *olen = p - buf; 486 487 mbedtls_free( encode_buf ); 488 return( 0 ); 489 } 490 #endif /* MBEDTLS_PEM_WRITE_C */ 491 #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ 492