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