1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * PKCS#12 Personal Information Exchange Syntax 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 57901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander */ 19817466cbSJens Wiklander /* 20817466cbSJens Wiklander * The PKCS #12 Personal Information Exchange Syntax Standard v1.1 21817466cbSJens Wiklander * 22817466cbSJens Wiklander * http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf 23817466cbSJens Wiklander * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn 24817466cbSJens Wiklander */ 25817466cbSJens Wiklander 267901324dSJerome Forissier #include "common.h" 27817466cbSJens Wiklander 28817466cbSJens Wiklander #if defined(MBEDTLS_PKCS12_C) 29817466cbSJens Wiklander 30817466cbSJens Wiklander #include "mbedtls/pkcs12.h" 31817466cbSJens Wiklander #include "mbedtls/asn1.h" 32817466cbSJens Wiklander #include "mbedtls/cipher.h" 333d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 3411fa71b9SJerome Forissier #include "mbedtls/error.h" 35817466cbSJens Wiklander 36817466cbSJens Wiklander #include <string.h> 37817466cbSJens Wiklander 38*32b31808SJens Wiklander #if !defined(MBEDTLS_MD_C) 39*32b31808SJens Wiklander #include "mbedtls/psa_util.h" 40*32b31808SJens Wiklander #define PSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status, \ 41*32b31808SJens Wiklander psa_to_md_errors, \ 42*32b31808SJens Wiklander psa_generic_status_to_mbedtls) 43817466cbSJens Wiklander #endif 44817466cbSJens Wiklander 45817466cbSJens Wiklander #if defined(MBEDTLS_DES_C) 46817466cbSJens Wiklander #include "mbedtls/des.h" 47817466cbSJens Wiklander #endif 48817466cbSJens Wiklander 49*32b31808SJens Wiklander #include "hash_info.h" 50*32b31808SJens Wiklander #include "mbedtls/psa_util.h" 51*32b31808SJens Wiklander 523d3b0591SJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C) 53817466cbSJens Wiklander 54817466cbSJens Wiklander static int pkcs12_parse_pbe_params(mbedtls_asn1_buf *params, 55817466cbSJens Wiklander mbedtls_asn1_buf *salt, int *iterations) 56817466cbSJens Wiklander { 5711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 58817466cbSJens Wiklander unsigned char **p = ¶ms->p; 59817466cbSJens Wiklander const unsigned char *end = params->p + params->len; 60817466cbSJens Wiklander 61817466cbSJens Wiklander /* 62817466cbSJens Wiklander * pkcs-12PbeParams ::= SEQUENCE { 63817466cbSJens Wiklander * salt OCTET STRING, 64817466cbSJens Wiklander * iterations INTEGER 65817466cbSJens Wiklander * } 66817466cbSJens Wiklander * 67817466cbSJens Wiklander */ 68*32b31808SJens Wiklander if (params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) { 69*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT, 70*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); 71*32b31808SJens Wiklander } 72817466cbSJens Wiklander 73*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING)) != 0) { 74*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT, ret); 75*32b31808SJens Wiklander } 76817466cbSJens Wiklander 77817466cbSJens Wiklander salt->p = *p; 78817466cbSJens Wiklander *p += salt->len; 79817466cbSJens Wiklander 80*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_int(p, end, iterations)) != 0) { 81*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT, ret); 82*32b31808SJens Wiklander } 83817466cbSJens Wiklander 84*32b31808SJens Wiklander if (*p != end) { 85*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT, 86*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 87*32b31808SJens Wiklander } 88817466cbSJens Wiklander 89*32b31808SJens Wiklander return 0; 90817466cbSJens Wiklander } 91817466cbSJens Wiklander 92817466cbSJens Wiklander #define PKCS12_MAX_PWDLEN 128 93817466cbSJens Wiklander 94817466cbSJens Wiklander static int pkcs12_pbe_derive_key_iv(mbedtls_asn1_buf *pbe_params, mbedtls_md_type_t md_type, 95817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen, 96817466cbSJens Wiklander unsigned char *key, size_t keylen, 97817466cbSJens Wiklander unsigned char *iv, size_t ivlen) 98817466cbSJens Wiklander { 99817466cbSJens Wiklander int ret, iterations = 0; 100817466cbSJens Wiklander mbedtls_asn1_buf salt; 101817466cbSJens Wiklander size_t i; 102817466cbSJens Wiklander unsigned char unipwd[PKCS12_MAX_PWDLEN * 2 + 2]; 103817466cbSJens Wiklander 104*32b31808SJens Wiklander if (pwdlen > PKCS12_MAX_PWDLEN) { 105*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA; 106*32b31808SJens Wiklander } 107817466cbSJens Wiklander 108817466cbSJens Wiklander memset(&salt, 0, sizeof(mbedtls_asn1_buf)); 109817466cbSJens Wiklander memset(&unipwd, 0, sizeof(unipwd)); 110817466cbSJens Wiklander 111817466cbSJens Wiklander if ((ret = pkcs12_parse_pbe_params(pbe_params, &salt, 112*32b31808SJens Wiklander &iterations)) != 0) { 113*32b31808SJens Wiklander return ret; 114*32b31808SJens Wiklander } 115817466cbSJens Wiklander 116*32b31808SJens Wiklander for (i = 0; i < pwdlen; i++) { 117817466cbSJens Wiklander unipwd[i * 2 + 1] = pwd[i]; 118*32b31808SJens Wiklander } 119817466cbSJens Wiklander 120817466cbSJens Wiklander if ((ret = mbedtls_pkcs12_derivation(key, keylen, unipwd, pwdlen * 2 + 2, 121817466cbSJens Wiklander salt.p, salt.len, md_type, 122*32b31808SJens Wiklander MBEDTLS_PKCS12_DERIVE_KEY, iterations)) != 0) { 123*32b31808SJens Wiklander return ret; 124817466cbSJens Wiklander } 125817466cbSJens Wiklander 126*32b31808SJens Wiklander if (iv == NULL || ivlen == 0) { 127*32b31808SJens Wiklander return 0; 128*32b31808SJens Wiklander } 129817466cbSJens Wiklander 130817466cbSJens Wiklander if ((ret = mbedtls_pkcs12_derivation(iv, ivlen, unipwd, pwdlen * 2 + 2, 131817466cbSJens Wiklander salt.p, salt.len, md_type, 132*32b31808SJens Wiklander MBEDTLS_PKCS12_DERIVE_IV, iterations)) != 0) { 133*32b31808SJens Wiklander return ret; 134817466cbSJens Wiklander } 135*32b31808SJens Wiklander return 0; 136817466cbSJens Wiklander } 137817466cbSJens Wiklander 138817466cbSJens Wiklander #undef PKCS12_MAX_PWDLEN 139817466cbSJens Wiklander 140817466cbSJens Wiklander int mbedtls_pkcs12_pbe(mbedtls_asn1_buf *pbe_params, int mode, 141817466cbSJens Wiklander mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type, 142817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen, 143817466cbSJens Wiklander const unsigned char *data, size_t len, 144817466cbSJens Wiklander unsigned char *output) 145817466cbSJens Wiklander { 146817466cbSJens Wiklander int ret, keylen = 0; 147817466cbSJens Wiklander unsigned char key[32]; 148817466cbSJens Wiklander unsigned char iv[16]; 149817466cbSJens Wiklander const mbedtls_cipher_info_t *cipher_info; 150817466cbSJens Wiklander mbedtls_cipher_context_t cipher_ctx; 151817466cbSJens Wiklander size_t olen = 0; 152817466cbSJens Wiklander 153*32b31808SJens Wiklander if (pwd == NULL && pwdlen != 0) { 154*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA; 155*32b31808SJens Wiklander } 156039e02dfSJerome Forissier 157817466cbSJens Wiklander cipher_info = mbedtls_cipher_info_from_type(cipher_type); 158*32b31808SJens Wiklander if (cipher_info == NULL) { 159*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE; 160*32b31808SJens Wiklander } 161817466cbSJens Wiklander 162817466cbSJens Wiklander keylen = cipher_info->key_bitlen / 8; 163817466cbSJens Wiklander 164817466cbSJens Wiklander if ((ret = pkcs12_pbe_derive_key_iv(pbe_params, md_type, pwd, pwdlen, 165817466cbSJens Wiklander key, keylen, 166*32b31808SJens Wiklander iv, cipher_info->iv_size)) != 0) { 167*32b31808SJens Wiklander return ret; 168817466cbSJens Wiklander } 169817466cbSJens Wiklander 170817466cbSJens Wiklander mbedtls_cipher_init(&cipher_ctx); 171817466cbSJens Wiklander 172*32b31808SJens Wiklander if ((ret = mbedtls_cipher_setup(&cipher_ctx, cipher_info)) != 0) { 173817466cbSJens Wiklander goto exit; 174817466cbSJens Wiklander } 175817466cbSJens Wiklander 176*32b31808SJens Wiklander if ((ret = 177*32b31808SJens Wiklander mbedtls_cipher_setkey(&cipher_ctx, key, 8 * keylen, 178*32b31808SJens Wiklander (mbedtls_operation_t) mode)) != 0) { 179*32b31808SJens Wiklander goto exit; 180*32b31808SJens Wiklander } 181*32b31808SJens Wiklander 182*32b31808SJens Wiklander if ((ret = mbedtls_cipher_set_iv(&cipher_ctx, iv, cipher_info->iv_size)) != 0) { 183*32b31808SJens Wiklander goto exit; 184*32b31808SJens Wiklander } 185*32b31808SJens Wiklander 186*32b31808SJens Wiklander if ((ret = mbedtls_cipher_reset(&cipher_ctx)) != 0) { 187*32b31808SJens Wiklander goto exit; 188*32b31808SJens Wiklander } 189*32b31808SJens Wiklander 190*32b31808SJens Wiklander if ((ret = mbedtls_cipher_update(&cipher_ctx, data, len, 191*32b31808SJens Wiklander output, &olen)) != 0) { 192*32b31808SJens Wiklander goto exit; 193*32b31808SJens Wiklander } 194*32b31808SJens Wiklander 195*32b31808SJens Wiklander if ((ret = mbedtls_cipher_finish(&cipher_ctx, output + olen, &olen)) != 0) { 196817466cbSJens Wiklander ret = MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH; 197*32b31808SJens Wiklander } 198817466cbSJens Wiklander 199817466cbSJens Wiklander exit: 2003d3b0591SJens Wiklander mbedtls_platform_zeroize(key, sizeof(key)); 2013d3b0591SJens Wiklander mbedtls_platform_zeroize(iv, sizeof(iv)); 202817466cbSJens Wiklander mbedtls_cipher_free(&cipher_ctx); 203817466cbSJens Wiklander 204*32b31808SJens Wiklander return ret; 205817466cbSJens Wiklander } 206817466cbSJens Wiklander 2073d3b0591SJens Wiklander #endif /* MBEDTLS_ASN1_PARSE_C */ 2083d3b0591SJens Wiklander 209817466cbSJens Wiklander static void pkcs12_fill_buffer(unsigned char *data, size_t data_len, 210817466cbSJens Wiklander const unsigned char *filler, size_t fill_len) 211817466cbSJens Wiklander { 212817466cbSJens Wiklander unsigned char *p = data; 213817466cbSJens Wiklander size_t use_len; 214817466cbSJens Wiklander 215*32b31808SJens Wiklander if (filler != NULL && fill_len != 0) { 216*32b31808SJens Wiklander while (data_len > 0) { 217817466cbSJens Wiklander use_len = (data_len > fill_len) ? fill_len : data_len; 218817466cbSJens Wiklander memcpy(p, filler, use_len); 219817466cbSJens Wiklander p += use_len; 220817466cbSJens Wiklander data_len -= use_len; 221817466cbSJens Wiklander } 222*32b31808SJens Wiklander } else { 223039e02dfSJerome Forissier /* If either of the above are not true then clearly there is nothing 224039e02dfSJerome Forissier * that this function can do. The function should *not* be called 225039e02dfSJerome Forissier * under either of those circumstances, as you could end up with an 226039e02dfSJerome Forissier * incorrect output but for safety's sake, leaving the check in as 227039e02dfSJerome Forissier * otherwise we could end up with memory corruption.*/ 228039e02dfSJerome Forissier } 229039e02dfSJerome Forissier } 230817466cbSJens Wiklander 231*32b31808SJens Wiklander 232*32b31808SJens Wiklander static int calculate_hashes(mbedtls_md_type_t md_type, int iterations, 233*32b31808SJens Wiklander unsigned char *diversifier, unsigned char *salt_block, 234*32b31808SJens Wiklander unsigned char *pwd_block, unsigned char *hash_output, int use_salt, 235*32b31808SJens Wiklander int use_password, size_t hlen, size_t v) 236*32b31808SJens Wiklander { 237*32b31808SJens Wiklander #if defined(MBEDTLS_MD_C) 238*32b31808SJens Wiklander int ret = -1; 239*32b31808SJens Wiklander size_t i; 240*32b31808SJens Wiklander const mbedtls_md_info_t *md_info; 241*32b31808SJens Wiklander mbedtls_md_context_t md_ctx; 242*32b31808SJens Wiklander md_info = mbedtls_md_info_from_type(md_type); 243*32b31808SJens Wiklander if (md_info == NULL) { 244*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE; 245*32b31808SJens Wiklander } 246*32b31808SJens Wiklander 247*32b31808SJens Wiklander mbedtls_md_init(&md_ctx); 248*32b31808SJens Wiklander 249*32b31808SJens Wiklander if ((ret = mbedtls_md_setup(&md_ctx, md_info, 0)) != 0) { 250*32b31808SJens Wiklander return ret; 251*32b31808SJens Wiklander } 252*32b31808SJens Wiklander // Calculate hash( diversifier || salt_block || pwd_block ) 253*32b31808SJens Wiklander if ((ret = mbedtls_md_starts(&md_ctx)) != 0) { 254*32b31808SJens Wiklander goto exit; 255*32b31808SJens Wiklander } 256*32b31808SJens Wiklander 257*32b31808SJens Wiklander if ((ret = mbedtls_md_update(&md_ctx, diversifier, v)) != 0) { 258*32b31808SJens Wiklander goto exit; 259*32b31808SJens Wiklander } 260*32b31808SJens Wiklander 261*32b31808SJens Wiklander if (use_salt != 0) { 262*32b31808SJens Wiklander if ((ret = mbedtls_md_update(&md_ctx, salt_block, v)) != 0) { 263*32b31808SJens Wiklander goto exit; 264*32b31808SJens Wiklander } 265*32b31808SJens Wiklander } 266*32b31808SJens Wiklander 267*32b31808SJens Wiklander if (use_password != 0) { 268*32b31808SJens Wiklander if ((ret = mbedtls_md_update(&md_ctx, pwd_block, v)) != 0) { 269*32b31808SJens Wiklander goto exit; 270*32b31808SJens Wiklander } 271*32b31808SJens Wiklander } 272*32b31808SJens Wiklander 273*32b31808SJens Wiklander if ((ret = mbedtls_md_finish(&md_ctx, hash_output)) != 0) { 274*32b31808SJens Wiklander goto exit; 275*32b31808SJens Wiklander } 276*32b31808SJens Wiklander 277*32b31808SJens Wiklander // Perform remaining ( iterations - 1 ) recursive hash calculations 278*32b31808SJens Wiklander for (i = 1; i < (size_t) iterations; i++) { 279*32b31808SJens Wiklander if ((ret = mbedtls_md(md_info, hash_output, hlen, hash_output)) 280*32b31808SJens Wiklander != 0) { 281*32b31808SJens Wiklander goto exit; 282*32b31808SJens Wiklander } 283*32b31808SJens Wiklander } 284*32b31808SJens Wiklander 285*32b31808SJens Wiklander exit: 286*32b31808SJens Wiklander mbedtls_md_free(&md_ctx); 287*32b31808SJens Wiklander return ret; 288*32b31808SJens Wiklander #else 289*32b31808SJens Wiklander psa_hash_operation_t op = PSA_HASH_OPERATION_INIT; 290*32b31808SJens Wiklander psa_algorithm_t alg = mbedtls_psa_translate_md(md_type); 291*32b31808SJens Wiklander psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 292*32b31808SJens Wiklander psa_status_t status_abort = PSA_ERROR_CORRUPTION_DETECTED; 293*32b31808SJens Wiklander size_t i, out_len, out_size = PSA_HASH_LENGTH(alg); 294*32b31808SJens Wiklander 295*32b31808SJens Wiklander if (alg == PSA_ALG_NONE) { 296*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE; 297*32b31808SJens Wiklander } 298*32b31808SJens Wiklander 299*32b31808SJens Wiklander if ((status = psa_hash_setup(&op, alg)) != PSA_SUCCESS) { 300*32b31808SJens Wiklander goto exit; 301*32b31808SJens Wiklander } 302*32b31808SJens Wiklander 303*32b31808SJens Wiklander // Calculate hash( diversifier || salt_block || pwd_block ) 304*32b31808SJens Wiklander if ((status = psa_hash_update(&op, diversifier, v)) != PSA_SUCCESS) { 305*32b31808SJens Wiklander goto exit; 306*32b31808SJens Wiklander } 307*32b31808SJens Wiklander 308*32b31808SJens Wiklander if (use_salt != 0) { 309*32b31808SJens Wiklander if ((status = psa_hash_update(&op, salt_block, v)) != PSA_SUCCESS) { 310*32b31808SJens Wiklander goto exit; 311*32b31808SJens Wiklander } 312*32b31808SJens Wiklander } 313*32b31808SJens Wiklander 314*32b31808SJens Wiklander if (use_password != 0) { 315*32b31808SJens Wiklander if ((status = psa_hash_update(&op, pwd_block, v)) != PSA_SUCCESS) { 316*32b31808SJens Wiklander goto exit; 317*32b31808SJens Wiklander } 318*32b31808SJens Wiklander } 319*32b31808SJens Wiklander 320*32b31808SJens Wiklander if ((status = psa_hash_finish(&op, hash_output, out_size, &out_len)) 321*32b31808SJens Wiklander != PSA_SUCCESS) { 322*32b31808SJens Wiklander goto exit; 323*32b31808SJens Wiklander } 324*32b31808SJens Wiklander 325*32b31808SJens Wiklander // Perform remaining ( iterations - 1 ) recursive hash calculations 326*32b31808SJens Wiklander for (i = 1; i < (size_t) iterations; i++) { 327*32b31808SJens Wiklander if ((status = psa_hash_compute(alg, hash_output, hlen, hash_output, 328*32b31808SJens Wiklander out_size, &out_len)) != PSA_SUCCESS) { 329*32b31808SJens Wiklander goto exit; 330*32b31808SJens Wiklander } 331*32b31808SJens Wiklander } 332*32b31808SJens Wiklander 333*32b31808SJens Wiklander exit: 334*32b31808SJens Wiklander status_abort = psa_hash_abort(&op); 335*32b31808SJens Wiklander if (status == PSA_SUCCESS) { 336*32b31808SJens Wiklander status = status_abort; 337*32b31808SJens Wiklander } 338*32b31808SJens Wiklander return PSA_TO_MBEDTLS_ERR(status); 339*32b31808SJens Wiklander #endif /* !MBEDTLS_MD_C */ 340*32b31808SJens Wiklander } 341*32b31808SJens Wiklander 342*32b31808SJens Wiklander 343817466cbSJens Wiklander int mbedtls_pkcs12_derivation(unsigned char *data, size_t datalen, 344817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen, 345817466cbSJens Wiklander const unsigned char *salt, size_t saltlen, 346817466cbSJens Wiklander mbedtls_md_type_t md_type, int id, int iterations) 347817466cbSJens Wiklander { 34811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 349817466cbSJens Wiklander unsigned int j; 350817466cbSJens Wiklander 351817466cbSJens Wiklander unsigned char diversifier[128]; 352*32b31808SJens Wiklander unsigned char salt_block[128], pwd_block[128], hash_block[128] = { 0 }; 353*32b31808SJens Wiklander unsigned char hash_output[MBEDTLS_HASH_MAX_SIZE]; 354817466cbSJens Wiklander unsigned char *p; 355817466cbSJens Wiklander unsigned char c; 356039e02dfSJerome Forissier int use_password = 0; 357039e02dfSJerome Forissier int use_salt = 0; 358817466cbSJens Wiklander 359817466cbSJens Wiklander size_t hlen, use_len, v, i; 360817466cbSJens Wiklander 361817466cbSJens Wiklander // This version only allows max of 64 bytes of password or salt 362*32b31808SJens Wiklander if (datalen > 128 || pwdlen > 64 || saltlen > 64) { 363*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA; 364*32b31808SJens Wiklander } 365817466cbSJens Wiklander 366*32b31808SJens Wiklander if (pwd == NULL && pwdlen != 0) { 367*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA; 368*32b31808SJens Wiklander } 369039e02dfSJerome Forissier 370*32b31808SJens Wiklander if (salt == NULL && saltlen != 0) { 371*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA; 372*32b31808SJens Wiklander } 373039e02dfSJerome Forissier 374039e02dfSJerome Forissier use_password = (pwd && pwdlen != 0); 375039e02dfSJerome Forissier use_salt = (salt && saltlen != 0); 376039e02dfSJerome Forissier 377*32b31808SJens Wiklander hlen = mbedtls_hash_info_get_size(md_type); 378817466cbSJens Wiklander 379*32b31808SJens Wiklander if (hlen <= 32) { 380817466cbSJens Wiklander v = 64; 381*32b31808SJens Wiklander } else { 382817466cbSJens Wiklander v = 128; 383*32b31808SJens Wiklander } 384817466cbSJens Wiklander 385817466cbSJens Wiklander memset(diversifier, (unsigned char) id, v); 386817466cbSJens Wiklander 387*32b31808SJens Wiklander if (use_salt != 0) { 388817466cbSJens Wiklander pkcs12_fill_buffer(salt_block, v, salt, saltlen); 389039e02dfSJerome Forissier } 390039e02dfSJerome Forissier 391*32b31808SJens Wiklander if (use_password != 0) { 392817466cbSJens Wiklander pkcs12_fill_buffer(pwd_block, v, pwd, pwdlen); 393039e02dfSJerome Forissier } 394817466cbSJens Wiklander 395817466cbSJens Wiklander p = data; 396*32b31808SJens Wiklander while (datalen > 0) { 397*32b31808SJens Wiklander if (calculate_hashes(md_type, iterations, diversifier, salt_block, 398*32b31808SJens Wiklander pwd_block, hash_output, use_salt, use_password, hlen, 399*32b31808SJens Wiklander v) != 0) { 400817466cbSJens Wiklander goto exit; 401817466cbSJens Wiklander } 402817466cbSJens Wiklander 403817466cbSJens Wiklander use_len = (datalen > hlen) ? hlen : datalen; 404817466cbSJens Wiklander memcpy(p, hash_output, use_len); 405817466cbSJens Wiklander datalen -= use_len; 406817466cbSJens Wiklander p += use_len; 407817466cbSJens Wiklander 408*32b31808SJens Wiklander if (datalen == 0) { 409817466cbSJens Wiklander break; 410*32b31808SJens Wiklander } 411817466cbSJens Wiklander 412817466cbSJens Wiklander // Concatenating copies of hash_output into hash_block (B) 413817466cbSJens Wiklander pkcs12_fill_buffer(hash_block, v, hash_output, hlen); 414817466cbSJens Wiklander 415817466cbSJens Wiklander // B += 1 416*32b31808SJens Wiklander for (i = v; i > 0; i--) { 417*32b31808SJens Wiklander if (++hash_block[i - 1] != 0) { 418817466cbSJens Wiklander break; 419*32b31808SJens Wiklander } 420*32b31808SJens Wiklander } 421817466cbSJens Wiklander 422*32b31808SJens Wiklander if (use_salt != 0) { 423817466cbSJens Wiklander // salt_block += B 424817466cbSJens Wiklander c = 0; 425*32b31808SJens Wiklander for (i = v; i > 0; i--) { 426817466cbSJens Wiklander j = salt_block[i - 1] + hash_block[i - 1] + c; 427039e02dfSJerome Forissier c = MBEDTLS_BYTE_1(j); 428039e02dfSJerome Forissier salt_block[i - 1] = MBEDTLS_BYTE_0(j); 429039e02dfSJerome Forissier } 430817466cbSJens Wiklander } 431817466cbSJens Wiklander 432*32b31808SJens Wiklander if (use_password != 0) { 433817466cbSJens Wiklander // pwd_block += B 434817466cbSJens Wiklander c = 0; 435*32b31808SJens Wiklander for (i = v; i > 0; i--) { 436817466cbSJens Wiklander j = pwd_block[i - 1] + hash_block[i - 1] + c; 437039e02dfSJerome Forissier c = MBEDTLS_BYTE_1(j); 438039e02dfSJerome Forissier pwd_block[i - 1] = MBEDTLS_BYTE_0(j); 439039e02dfSJerome Forissier } 440817466cbSJens Wiklander } 441817466cbSJens Wiklander } 442817466cbSJens Wiklander 443817466cbSJens Wiklander ret = 0; 444817466cbSJens Wiklander 445817466cbSJens Wiklander exit: 4463d3b0591SJens Wiklander mbedtls_platform_zeroize(salt_block, sizeof(salt_block)); 4473d3b0591SJens Wiklander mbedtls_platform_zeroize(pwd_block, sizeof(pwd_block)); 4483d3b0591SJens Wiklander mbedtls_platform_zeroize(hash_block, sizeof(hash_block)); 4493d3b0591SJens Wiklander mbedtls_platform_zeroize(hash_output, sizeof(hash_output)); 450817466cbSJens Wiklander 451*32b31808SJens Wiklander return ret; 452817466cbSJens Wiklander } 453817466cbSJens Wiklander 454817466cbSJens Wiklander #endif /* MBEDTLS_PKCS12_C */ 455