[398] | 1 | /*
|
---|
| 2 | * Privacy Enhanced Mail (PEM) decoding
|
---|
| 3 | *
|
---|
| 4 | * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
---|
| 5 | * SPDX-License-Identifier: Apache-2.0
|
---|
| 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 */
|
---|