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