1*62c56f98SSadaf Ebrahimi /*
2*62c56f98SSadaf Ebrahimi * PKCS#12 Personal Information Exchange Syntax
3*62c56f98SSadaf Ebrahimi *
4*62c56f98SSadaf Ebrahimi * Copyright The Mbed TLS Contributors
5*62c56f98SSadaf Ebrahimi * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6*62c56f98SSadaf Ebrahimi */
7*62c56f98SSadaf Ebrahimi /*
8*62c56f98SSadaf Ebrahimi * The PKCS #12 Personal Information Exchange Syntax Standard v1.1
9*62c56f98SSadaf Ebrahimi *
10*62c56f98SSadaf Ebrahimi * http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf
11*62c56f98SSadaf Ebrahimi * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn
12*62c56f98SSadaf Ebrahimi */
13*62c56f98SSadaf Ebrahimi
14*62c56f98SSadaf Ebrahimi #include "common.h"
15*62c56f98SSadaf Ebrahimi
16*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_PKCS12_C)
17*62c56f98SSadaf Ebrahimi
18*62c56f98SSadaf Ebrahimi #include "mbedtls/pkcs12.h"
19*62c56f98SSadaf Ebrahimi #include "mbedtls/asn1.h"
20*62c56f98SSadaf Ebrahimi #include "mbedtls/cipher.h"
21*62c56f98SSadaf Ebrahimi #include "mbedtls/platform_util.h"
22*62c56f98SSadaf Ebrahimi #include "mbedtls/error.h"
23*62c56f98SSadaf Ebrahimi
24*62c56f98SSadaf Ebrahimi #include <string.h>
25*62c56f98SSadaf Ebrahimi
26*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_DES_C)
27*62c56f98SSadaf Ebrahimi #include "mbedtls/des.h"
28*62c56f98SSadaf Ebrahimi #endif
29*62c56f98SSadaf Ebrahimi
30*62c56f98SSadaf Ebrahimi #include "psa_util_internal.h"
31*62c56f98SSadaf Ebrahimi
32*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_ASN1_PARSE_C)
33*62c56f98SSadaf Ebrahimi
pkcs12_parse_pbe_params(mbedtls_asn1_buf * params,mbedtls_asn1_buf * salt,int * iterations)34*62c56f98SSadaf Ebrahimi static int pkcs12_parse_pbe_params(mbedtls_asn1_buf *params,
35*62c56f98SSadaf Ebrahimi mbedtls_asn1_buf *salt, int *iterations)
36*62c56f98SSadaf Ebrahimi {
37*62c56f98SSadaf Ebrahimi int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
38*62c56f98SSadaf Ebrahimi unsigned char **p = ¶ms->p;
39*62c56f98SSadaf Ebrahimi const unsigned char *end = params->p + params->len;
40*62c56f98SSadaf Ebrahimi
41*62c56f98SSadaf Ebrahimi /*
42*62c56f98SSadaf Ebrahimi * pkcs-12PbeParams ::= SEQUENCE {
43*62c56f98SSadaf Ebrahimi * salt OCTET STRING,
44*62c56f98SSadaf Ebrahimi * iterations INTEGER
45*62c56f98SSadaf Ebrahimi * }
46*62c56f98SSadaf Ebrahimi *
47*62c56f98SSadaf Ebrahimi */
48*62c56f98SSadaf Ebrahimi if (params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
49*62c56f98SSadaf Ebrahimi return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT,
50*62c56f98SSadaf Ebrahimi MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
51*62c56f98SSadaf Ebrahimi }
52*62c56f98SSadaf Ebrahimi
53*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_asn1_get_tag(p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
54*62c56f98SSadaf Ebrahimi return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT, ret);
55*62c56f98SSadaf Ebrahimi }
56*62c56f98SSadaf Ebrahimi
57*62c56f98SSadaf Ebrahimi salt->p = *p;
58*62c56f98SSadaf Ebrahimi *p += salt->len;
59*62c56f98SSadaf Ebrahimi
60*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_asn1_get_int(p, end, iterations)) != 0) {
61*62c56f98SSadaf Ebrahimi return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT, ret);
62*62c56f98SSadaf Ebrahimi }
63*62c56f98SSadaf Ebrahimi
64*62c56f98SSadaf Ebrahimi if (*p != end) {
65*62c56f98SSadaf Ebrahimi return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT,
66*62c56f98SSadaf Ebrahimi MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
67*62c56f98SSadaf Ebrahimi }
68*62c56f98SSadaf Ebrahimi
69*62c56f98SSadaf Ebrahimi return 0;
70*62c56f98SSadaf Ebrahimi }
71*62c56f98SSadaf Ebrahimi
72*62c56f98SSadaf Ebrahimi #define PKCS12_MAX_PWDLEN 128
73*62c56f98SSadaf Ebrahimi
pkcs12_pbe_derive_key_iv(mbedtls_asn1_buf * pbe_params,mbedtls_md_type_t md_type,const unsigned char * pwd,size_t pwdlen,unsigned char * key,size_t keylen,unsigned char * iv,size_t ivlen)74*62c56f98SSadaf Ebrahimi static int pkcs12_pbe_derive_key_iv(mbedtls_asn1_buf *pbe_params, mbedtls_md_type_t md_type,
75*62c56f98SSadaf Ebrahimi const unsigned char *pwd, size_t pwdlen,
76*62c56f98SSadaf Ebrahimi unsigned char *key, size_t keylen,
77*62c56f98SSadaf Ebrahimi unsigned char *iv, size_t ivlen)
78*62c56f98SSadaf Ebrahimi {
79*62c56f98SSadaf Ebrahimi int ret, iterations = 0;
80*62c56f98SSadaf Ebrahimi mbedtls_asn1_buf salt;
81*62c56f98SSadaf Ebrahimi size_t i;
82*62c56f98SSadaf Ebrahimi unsigned char unipwd[PKCS12_MAX_PWDLEN * 2 + 2];
83*62c56f98SSadaf Ebrahimi
84*62c56f98SSadaf Ebrahimi if (pwdlen > PKCS12_MAX_PWDLEN) {
85*62c56f98SSadaf Ebrahimi return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA;
86*62c56f98SSadaf Ebrahimi }
87*62c56f98SSadaf Ebrahimi
88*62c56f98SSadaf Ebrahimi memset(&salt, 0, sizeof(mbedtls_asn1_buf));
89*62c56f98SSadaf Ebrahimi memset(&unipwd, 0, sizeof(unipwd));
90*62c56f98SSadaf Ebrahimi
91*62c56f98SSadaf Ebrahimi if ((ret = pkcs12_parse_pbe_params(pbe_params, &salt,
92*62c56f98SSadaf Ebrahimi &iterations)) != 0) {
93*62c56f98SSadaf Ebrahimi return ret;
94*62c56f98SSadaf Ebrahimi }
95*62c56f98SSadaf Ebrahimi
96*62c56f98SSadaf Ebrahimi for (i = 0; i < pwdlen; i++) {
97*62c56f98SSadaf Ebrahimi unipwd[i * 2 + 1] = pwd[i];
98*62c56f98SSadaf Ebrahimi }
99*62c56f98SSadaf Ebrahimi
100*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_pkcs12_derivation(key, keylen, unipwd, pwdlen * 2 + 2,
101*62c56f98SSadaf Ebrahimi salt.p, salt.len, md_type,
102*62c56f98SSadaf Ebrahimi MBEDTLS_PKCS12_DERIVE_KEY, iterations)) != 0) {
103*62c56f98SSadaf Ebrahimi return ret;
104*62c56f98SSadaf Ebrahimi }
105*62c56f98SSadaf Ebrahimi
106*62c56f98SSadaf Ebrahimi if (iv == NULL || ivlen == 0) {
107*62c56f98SSadaf Ebrahimi return 0;
108*62c56f98SSadaf Ebrahimi }
109*62c56f98SSadaf Ebrahimi
110*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_pkcs12_derivation(iv, ivlen, unipwd, pwdlen * 2 + 2,
111*62c56f98SSadaf Ebrahimi salt.p, salt.len, md_type,
112*62c56f98SSadaf Ebrahimi MBEDTLS_PKCS12_DERIVE_IV, iterations)) != 0) {
113*62c56f98SSadaf Ebrahimi return ret;
114*62c56f98SSadaf Ebrahimi }
115*62c56f98SSadaf Ebrahimi return 0;
116*62c56f98SSadaf Ebrahimi }
117*62c56f98SSadaf Ebrahimi
118*62c56f98SSadaf Ebrahimi #undef PKCS12_MAX_PWDLEN
119*62c56f98SSadaf Ebrahimi
120*62c56f98SSadaf Ebrahimi #if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
121*62c56f98SSadaf Ebrahimi int mbedtls_pkcs12_pbe_ext(mbedtls_asn1_buf *pbe_params, int mode,
122*62c56f98SSadaf Ebrahimi mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type,
123*62c56f98SSadaf Ebrahimi const unsigned char *pwd, size_t pwdlen,
124*62c56f98SSadaf Ebrahimi const unsigned char *data, size_t len,
125*62c56f98SSadaf Ebrahimi unsigned char *output, size_t output_size,
126*62c56f98SSadaf Ebrahimi size_t *output_len);
127*62c56f98SSadaf Ebrahimi #endif
128*62c56f98SSadaf Ebrahimi
129*62c56f98SSadaf Ebrahimi #if !defined(MBEDTLS_DEPRECATED_REMOVED)
mbedtls_pkcs12_pbe(mbedtls_asn1_buf * pbe_params,int mode,mbedtls_cipher_type_t cipher_type,mbedtls_md_type_t md_type,const unsigned char * pwd,size_t pwdlen,const unsigned char * data,size_t len,unsigned char * output)130*62c56f98SSadaf Ebrahimi int mbedtls_pkcs12_pbe(mbedtls_asn1_buf *pbe_params, int mode,
131*62c56f98SSadaf Ebrahimi mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type,
132*62c56f98SSadaf Ebrahimi const unsigned char *pwd, size_t pwdlen,
133*62c56f98SSadaf Ebrahimi const unsigned char *data, size_t len,
134*62c56f98SSadaf Ebrahimi unsigned char *output)
135*62c56f98SSadaf Ebrahimi {
136*62c56f98SSadaf Ebrahimi size_t output_len = 0;
137*62c56f98SSadaf Ebrahimi
138*62c56f98SSadaf Ebrahimi /* We assume caller of the function is providing a big enough output buffer
139*62c56f98SSadaf Ebrahimi * so we pass output_size as SIZE_MAX to pass checks, However, no guarantees
140*62c56f98SSadaf Ebrahimi * for the output size actually being correct.
141*62c56f98SSadaf Ebrahimi */
142*62c56f98SSadaf Ebrahimi return mbedtls_pkcs12_pbe_ext(pbe_params, mode, cipher_type, md_type,
143*62c56f98SSadaf Ebrahimi pwd, pwdlen, data, len, output, SIZE_MAX,
144*62c56f98SSadaf Ebrahimi &output_len);
145*62c56f98SSadaf Ebrahimi }
146*62c56f98SSadaf Ebrahimi #endif
147*62c56f98SSadaf Ebrahimi
mbedtls_pkcs12_pbe_ext(mbedtls_asn1_buf * pbe_params,int mode,mbedtls_cipher_type_t cipher_type,mbedtls_md_type_t md_type,const unsigned char * pwd,size_t pwdlen,const unsigned char * data,size_t len,unsigned char * output,size_t output_size,size_t * output_len)148*62c56f98SSadaf Ebrahimi int mbedtls_pkcs12_pbe_ext(mbedtls_asn1_buf *pbe_params, int mode,
149*62c56f98SSadaf Ebrahimi mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type,
150*62c56f98SSadaf Ebrahimi const unsigned char *pwd, size_t pwdlen,
151*62c56f98SSadaf Ebrahimi const unsigned char *data, size_t len,
152*62c56f98SSadaf Ebrahimi unsigned char *output, size_t output_size,
153*62c56f98SSadaf Ebrahimi size_t *output_len)
154*62c56f98SSadaf Ebrahimi {
155*62c56f98SSadaf Ebrahimi int ret, keylen = 0;
156*62c56f98SSadaf Ebrahimi unsigned char key[32];
157*62c56f98SSadaf Ebrahimi unsigned char iv[16];
158*62c56f98SSadaf Ebrahimi const mbedtls_cipher_info_t *cipher_info;
159*62c56f98SSadaf Ebrahimi mbedtls_cipher_context_t cipher_ctx;
160*62c56f98SSadaf Ebrahimi size_t finish_olen = 0;
161*62c56f98SSadaf Ebrahimi unsigned int padlen = 0;
162*62c56f98SSadaf Ebrahimi
163*62c56f98SSadaf Ebrahimi if (pwd == NULL && pwdlen != 0) {
164*62c56f98SSadaf Ebrahimi return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA;
165*62c56f98SSadaf Ebrahimi }
166*62c56f98SSadaf Ebrahimi
167*62c56f98SSadaf Ebrahimi cipher_info = mbedtls_cipher_info_from_type(cipher_type);
168*62c56f98SSadaf Ebrahimi if (cipher_info == NULL) {
169*62c56f98SSadaf Ebrahimi return MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE;
170*62c56f98SSadaf Ebrahimi }
171*62c56f98SSadaf Ebrahimi
172*62c56f98SSadaf Ebrahimi keylen = (int) mbedtls_cipher_info_get_key_bitlen(cipher_info) / 8;
173*62c56f98SSadaf Ebrahimi
174*62c56f98SSadaf Ebrahimi if (mode == MBEDTLS_PKCS12_PBE_DECRYPT) {
175*62c56f98SSadaf Ebrahimi if (output_size < len) {
176*62c56f98SSadaf Ebrahimi return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
177*62c56f98SSadaf Ebrahimi }
178*62c56f98SSadaf Ebrahimi }
179*62c56f98SSadaf Ebrahimi
180*62c56f98SSadaf Ebrahimi if (mode == MBEDTLS_PKCS12_PBE_ENCRYPT) {
181*62c56f98SSadaf Ebrahimi padlen = cipher_info->block_size - (len % cipher_info->block_size);
182*62c56f98SSadaf Ebrahimi if (output_size < (len + padlen)) {
183*62c56f98SSadaf Ebrahimi return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
184*62c56f98SSadaf Ebrahimi }
185*62c56f98SSadaf Ebrahimi }
186*62c56f98SSadaf Ebrahimi
187*62c56f98SSadaf Ebrahimi if ((ret = pkcs12_pbe_derive_key_iv(pbe_params, md_type, pwd, pwdlen,
188*62c56f98SSadaf Ebrahimi key, keylen,
189*62c56f98SSadaf Ebrahimi iv, mbedtls_cipher_info_get_iv_size(cipher_info))) != 0) {
190*62c56f98SSadaf Ebrahimi return ret;
191*62c56f98SSadaf Ebrahimi }
192*62c56f98SSadaf Ebrahimi
193*62c56f98SSadaf Ebrahimi mbedtls_cipher_init(&cipher_ctx);
194*62c56f98SSadaf Ebrahimi
195*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_cipher_setup(&cipher_ctx, cipher_info)) != 0) {
196*62c56f98SSadaf Ebrahimi goto exit;
197*62c56f98SSadaf Ebrahimi }
198*62c56f98SSadaf Ebrahimi
199*62c56f98SSadaf Ebrahimi if ((ret =
200*62c56f98SSadaf Ebrahimi mbedtls_cipher_setkey(&cipher_ctx, key, 8 * keylen,
201*62c56f98SSadaf Ebrahimi (mbedtls_operation_t) mode)) != 0) {
202*62c56f98SSadaf Ebrahimi goto exit;
203*62c56f98SSadaf Ebrahimi }
204*62c56f98SSadaf Ebrahimi
205*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
206*62c56f98SSadaf Ebrahimi /* PKCS12 uses CBC with PKCS7 padding */
207*62c56f98SSadaf Ebrahimi
208*62c56f98SSadaf Ebrahimi mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_PKCS7;
209*62c56f98SSadaf Ebrahimi #if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
210*62c56f98SSadaf Ebrahimi /* For historical reasons, when decrypting, this function works when
211*62c56f98SSadaf Ebrahimi * decrypting even when support for PKCS7 padding is disabled. In this
212*62c56f98SSadaf Ebrahimi * case, it ignores the padding, and so will never report a
213*62c56f98SSadaf Ebrahimi * password mismatch.
214*62c56f98SSadaf Ebrahimi */
215*62c56f98SSadaf Ebrahimi if (mode == MBEDTLS_PKCS12_PBE_DECRYPT) {
216*62c56f98SSadaf Ebrahimi padding = MBEDTLS_PADDING_NONE;
217*62c56f98SSadaf Ebrahimi }
218*62c56f98SSadaf Ebrahimi #endif
219*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_cipher_set_padding_mode(&cipher_ctx, padding)) != 0) {
220*62c56f98SSadaf Ebrahimi goto exit;
221*62c56f98SSadaf Ebrahimi }
222*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
223*62c56f98SSadaf Ebrahimi
224*62c56f98SSadaf Ebrahimi if ((ret =
225*62c56f98SSadaf Ebrahimi mbedtls_cipher_set_iv(&cipher_ctx, iv,
226*62c56f98SSadaf Ebrahimi mbedtls_cipher_info_get_iv_size(cipher_info))) != 0) {
227*62c56f98SSadaf Ebrahimi goto exit;
228*62c56f98SSadaf Ebrahimi }
229*62c56f98SSadaf Ebrahimi
230*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_cipher_reset(&cipher_ctx)) != 0) {
231*62c56f98SSadaf Ebrahimi goto exit;
232*62c56f98SSadaf Ebrahimi }
233*62c56f98SSadaf Ebrahimi
234*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_cipher_update(&cipher_ctx, data, len,
235*62c56f98SSadaf Ebrahimi output, output_len)) != 0) {
236*62c56f98SSadaf Ebrahimi goto exit;
237*62c56f98SSadaf Ebrahimi }
238*62c56f98SSadaf Ebrahimi
239*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_cipher_finish(&cipher_ctx, output + (*output_len), &finish_olen)) != 0) {
240*62c56f98SSadaf Ebrahimi ret = MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH;
241*62c56f98SSadaf Ebrahimi }
242*62c56f98SSadaf Ebrahimi
243*62c56f98SSadaf Ebrahimi *output_len += finish_olen;
244*62c56f98SSadaf Ebrahimi
245*62c56f98SSadaf Ebrahimi exit:
246*62c56f98SSadaf Ebrahimi mbedtls_platform_zeroize(key, sizeof(key));
247*62c56f98SSadaf Ebrahimi mbedtls_platform_zeroize(iv, sizeof(iv));
248*62c56f98SSadaf Ebrahimi mbedtls_cipher_free(&cipher_ctx);
249*62c56f98SSadaf Ebrahimi
250*62c56f98SSadaf Ebrahimi return ret;
251*62c56f98SSadaf Ebrahimi }
252*62c56f98SSadaf Ebrahimi
253*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_ASN1_PARSE_C */
254*62c56f98SSadaf Ebrahimi
pkcs12_fill_buffer(unsigned char * data,size_t data_len,const unsigned char * filler,size_t fill_len)255*62c56f98SSadaf Ebrahimi static void pkcs12_fill_buffer(unsigned char *data, size_t data_len,
256*62c56f98SSadaf Ebrahimi const unsigned char *filler, size_t fill_len)
257*62c56f98SSadaf Ebrahimi {
258*62c56f98SSadaf Ebrahimi unsigned char *p = data;
259*62c56f98SSadaf Ebrahimi size_t use_len;
260*62c56f98SSadaf Ebrahimi
261*62c56f98SSadaf Ebrahimi if (filler != NULL && fill_len != 0) {
262*62c56f98SSadaf Ebrahimi while (data_len > 0) {
263*62c56f98SSadaf Ebrahimi use_len = (data_len > fill_len) ? fill_len : data_len;
264*62c56f98SSadaf Ebrahimi memcpy(p, filler, use_len);
265*62c56f98SSadaf Ebrahimi p += use_len;
266*62c56f98SSadaf Ebrahimi data_len -= use_len;
267*62c56f98SSadaf Ebrahimi }
268*62c56f98SSadaf Ebrahimi } else {
269*62c56f98SSadaf Ebrahimi /* If either of the above are not true then clearly there is nothing
270*62c56f98SSadaf Ebrahimi * that this function can do. The function should *not* be called
271*62c56f98SSadaf Ebrahimi * under either of those circumstances, as you could end up with an
272*62c56f98SSadaf Ebrahimi * incorrect output but for safety's sake, leaving the check in as
273*62c56f98SSadaf Ebrahimi * otherwise we could end up with memory corruption.*/
274*62c56f98SSadaf Ebrahimi }
275*62c56f98SSadaf Ebrahimi }
276*62c56f98SSadaf Ebrahimi
277*62c56f98SSadaf Ebrahimi
calculate_hashes(mbedtls_md_type_t md_type,int iterations,unsigned char * diversifier,unsigned char * salt_block,unsigned char * pwd_block,unsigned char * hash_output,int use_salt,int use_password,size_t hlen,size_t v)278*62c56f98SSadaf Ebrahimi static int calculate_hashes(mbedtls_md_type_t md_type, int iterations,
279*62c56f98SSadaf Ebrahimi unsigned char *diversifier, unsigned char *salt_block,
280*62c56f98SSadaf Ebrahimi unsigned char *pwd_block, unsigned char *hash_output, int use_salt,
281*62c56f98SSadaf Ebrahimi int use_password, size_t hlen, size_t v)
282*62c56f98SSadaf Ebrahimi {
283*62c56f98SSadaf Ebrahimi int ret = -1;
284*62c56f98SSadaf Ebrahimi size_t i;
285*62c56f98SSadaf Ebrahimi const mbedtls_md_info_t *md_info;
286*62c56f98SSadaf Ebrahimi mbedtls_md_context_t md_ctx;
287*62c56f98SSadaf Ebrahimi md_info = mbedtls_md_info_from_type(md_type);
288*62c56f98SSadaf Ebrahimi if (md_info == NULL) {
289*62c56f98SSadaf Ebrahimi return MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE;
290*62c56f98SSadaf Ebrahimi }
291*62c56f98SSadaf Ebrahimi
292*62c56f98SSadaf Ebrahimi mbedtls_md_init(&md_ctx);
293*62c56f98SSadaf Ebrahimi
294*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_md_setup(&md_ctx, md_info, 0)) != 0) {
295*62c56f98SSadaf Ebrahimi return ret;
296*62c56f98SSadaf Ebrahimi }
297*62c56f98SSadaf Ebrahimi // Calculate hash( diversifier || salt_block || pwd_block )
298*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_md_starts(&md_ctx)) != 0) {
299*62c56f98SSadaf Ebrahimi goto exit;
300*62c56f98SSadaf Ebrahimi }
301*62c56f98SSadaf Ebrahimi
302*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_md_update(&md_ctx, diversifier, v)) != 0) {
303*62c56f98SSadaf Ebrahimi goto exit;
304*62c56f98SSadaf Ebrahimi }
305*62c56f98SSadaf Ebrahimi
306*62c56f98SSadaf Ebrahimi if (use_salt != 0) {
307*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_md_update(&md_ctx, salt_block, v)) != 0) {
308*62c56f98SSadaf Ebrahimi goto exit;
309*62c56f98SSadaf Ebrahimi }
310*62c56f98SSadaf Ebrahimi }
311*62c56f98SSadaf Ebrahimi
312*62c56f98SSadaf Ebrahimi if (use_password != 0) {
313*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_md_update(&md_ctx, pwd_block, v)) != 0) {
314*62c56f98SSadaf Ebrahimi goto exit;
315*62c56f98SSadaf Ebrahimi }
316*62c56f98SSadaf Ebrahimi }
317*62c56f98SSadaf Ebrahimi
318*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_md_finish(&md_ctx, hash_output)) != 0) {
319*62c56f98SSadaf Ebrahimi goto exit;
320*62c56f98SSadaf Ebrahimi }
321*62c56f98SSadaf Ebrahimi
322*62c56f98SSadaf Ebrahimi // Perform remaining ( iterations - 1 ) recursive hash calculations
323*62c56f98SSadaf Ebrahimi for (i = 1; i < (size_t) iterations; i++) {
324*62c56f98SSadaf Ebrahimi if ((ret = mbedtls_md(md_info, hash_output, hlen, hash_output))
325*62c56f98SSadaf Ebrahimi != 0) {
326*62c56f98SSadaf Ebrahimi goto exit;
327*62c56f98SSadaf Ebrahimi }
328*62c56f98SSadaf Ebrahimi }
329*62c56f98SSadaf Ebrahimi
330*62c56f98SSadaf Ebrahimi exit:
331*62c56f98SSadaf Ebrahimi mbedtls_md_free(&md_ctx);
332*62c56f98SSadaf Ebrahimi return ret;
333*62c56f98SSadaf Ebrahimi }
334*62c56f98SSadaf Ebrahimi
335*62c56f98SSadaf Ebrahimi
mbedtls_pkcs12_derivation(unsigned char * data,size_t datalen,const unsigned char * pwd,size_t pwdlen,const unsigned char * salt,size_t saltlen,mbedtls_md_type_t md_type,int id,int iterations)336*62c56f98SSadaf Ebrahimi int mbedtls_pkcs12_derivation(unsigned char *data, size_t datalen,
337*62c56f98SSadaf Ebrahimi const unsigned char *pwd, size_t pwdlen,
338*62c56f98SSadaf Ebrahimi const unsigned char *salt, size_t saltlen,
339*62c56f98SSadaf Ebrahimi mbedtls_md_type_t md_type, int id, int iterations)
340*62c56f98SSadaf Ebrahimi {
341*62c56f98SSadaf Ebrahimi int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
342*62c56f98SSadaf Ebrahimi unsigned int j;
343*62c56f98SSadaf Ebrahimi
344*62c56f98SSadaf Ebrahimi unsigned char diversifier[128];
345*62c56f98SSadaf Ebrahimi unsigned char salt_block[128], pwd_block[128], hash_block[128] = { 0 };
346*62c56f98SSadaf Ebrahimi unsigned char hash_output[MBEDTLS_MD_MAX_SIZE];
347*62c56f98SSadaf Ebrahimi unsigned char *p;
348*62c56f98SSadaf Ebrahimi unsigned char c;
349*62c56f98SSadaf Ebrahimi int use_password = 0;
350*62c56f98SSadaf Ebrahimi int use_salt = 0;
351*62c56f98SSadaf Ebrahimi
352*62c56f98SSadaf Ebrahimi size_t hlen, use_len, v, i;
353*62c56f98SSadaf Ebrahimi
354*62c56f98SSadaf Ebrahimi // This version only allows max of 64 bytes of password or salt
355*62c56f98SSadaf Ebrahimi if (datalen > 128 || pwdlen > 64 || saltlen > 64) {
356*62c56f98SSadaf Ebrahimi return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA;
357*62c56f98SSadaf Ebrahimi }
358*62c56f98SSadaf Ebrahimi
359*62c56f98SSadaf Ebrahimi if (pwd == NULL && pwdlen != 0) {
360*62c56f98SSadaf Ebrahimi return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA;
361*62c56f98SSadaf Ebrahimi }
362*62c56f98SSadaf Ebrahimi
363*62c56f98SSadaf Ebrahimi if (salt == NULL && saltlen != 0) {
364*62c56f98SSadaf Ebrahimi return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA;
365*62c56f98SSadaf Ebrahimi }
366*62c56f98SSadaf Ebrahimi
367*62c56f98SSadaf Ebrahimi use_password = (pwd && pwdlen != 0);
368*62c56f98SSadaf Ebrahimi use_salt = (salt && saltlen != 0);
369*62c56f98SSadaf Ebrahimi
370*62c56f98SSadaf Ebrahimi hlen = mbedtls_md_get_size_from_type(md_type);
371*62c56f98SSadaf Ebrahimi
372*62c56f98SSadaf Ebrahimi if (hlen <= 32) {
373*62c56f98SSadaf Ebrahimi v = 64;
374*62c56f98SSadaf Ebrahimi } else {
375*62c56f98SSadaf Ebrahimi v = 128;
376*62c56f98SSadaf Ebrahimi }
377*62c56f98SSadaf Ebrahimi
378*62c56f98SSadaf Ebrahimi memset(diversifier, (unsigned char) id, v);
379*62c56f98SSadaf Ebrahimi
380*62c56f98SSadaf Ebrahimi if (use_salt != 0) {
381*62c56f98SSadaf Ebrahimi pkcs12_fill_buffer(salt_block, v, salt, saltlen);
382*62c56f98SSadaf Ebrahimi }
383*62c56f98SSadaf Ebrahimi
384*62c56f98SSadaf Ebrahimi if (use_password != 0) {
385*62c56f98SSadaf Ebrahimi pkcs12_fill_buffer(pwd_block, v, pwd, pwdlen);
386*62c56f98SSadaf Ebrahimi }
387*62c56f98SSadaf Ebrahimi
388*62c56f98SSadaf Ebrahimi p = data;
389*62c56f98SSadaf Ebrahimi while (datalen > 0) {
390*62c56f98SSadaf Ebrahimi if (calculate_hashes(md_type, iterations, diversifier, salt_block,
391*62c56f98SSadaf Ebrahimi pwd_block, hash_output, use_salt, use_password, hlen,
392*62c56f98SSadaf Ebrahimi v) != 0) {
393*62c56f98SSadaf Ebrahimi goto exit;
394*62c56f98SSadaf Ebrahimi }
395*62c56f98SSadaf Ebrahimi
396*62c56f98SSadaf Ebrahimi use_len = (datalen > hlen) ? hlen : datalen;
397*62c56f98SSadaf Ebrahimi memcpy(p, hash_output, use_len);
398*62c56f98SSadaf Ebrahimi datalen -= use_len;
399*62c56f98SSadaf Ebrahimi p += use_len;
400*62c56f98SSadaf Ebrahimi
401*62c56f98SSadaf Ebrahimi if (datalen == 0) {
402*62c56f98SSadaf Ebrahimi break;
403*62c56f98SSadaf Ebrahimi }
404*62c56f98SSadaf Ebrahimi
405*62c56f98SSadaf Ebrahimi // Concatenating copies of hash_output into hash_block (B)
406*62c56f98SSadaf Ebrahimi pkcs12_fill_buffer(hash_block, v, hash_output, hlen);
407*62c56f98SSadaf Ebrahimi
408*62c56f98SSadaf Ebrahimi // B += 1
409*62c56f98SSadaf Ebrahimi for (i = v; i > 0; i--) {
410*62c56f98SSadaf Ebrahimi if (++hash_block[i - 1] != 0) {
411*62c56f98SSadaf Ebrahimi break;
412*62c56f98SSadaf Ebrahimi }
413*62c56f98SSadaf Ebrahimi }
414*62c56f98SSadaf Ebrahimi
415*62c56f98SSadaf Ebrahimi if (use_salt != 0) {
416*62c56f98SSadaf Ebrahimi // salt_block += B
417*62c56f98SSadaf Ebrahimi c = 0;
418*62c56f98SSadaf Ebrahimi for (i = v; i > 0; i--) {
419*62c56f98SSadaf Ebrahimi j = salt_block[i - 1] + hash_block[i - 1] + c;
420*62c56f98SSadaf Ebrahimi c = MBEDTLS_BYTE_1(j);
421*62c56f98SSadaf Ebrahimi salt_block[i - 1] = MBEDTLS_BYTE_0(j);
422*62c56f98SSadaf Ebrahimi }
423*62c56f98SSadaf Ebrahimi }
424*62c56f98SSadaf Ebrahimi
425*62c56f98SSadaf Ebrahimi if (use_password != 0) {
426*62c56f98SSadaf Ebrahimi // pwd_block += B
427*62c56f98SSadaf Ebrahimi c = 0;
428*62c56f98SSadaf Ebrahimi for (i = v; i > 0; i--) {
429*62c56f98SSadaf Ebrahimi j = pwd_block[i - 1] + hash_block[i - 1] + c;
430*62c56f98SSadaf Ebrahimi c = MBEDTLS_BYTE_1(j);
431*62c56f98SSadaf Ebrahimi pwd_block[i - 1] = MBEDTLS_BYTE_0(j);
432*62c56f98SSadaf Ebrahimi }
433*62c56f98SSadaf Ebrahimi }
434*62c56f98SSadaf Ebrahimi }
435*62c56f98SSadaf Ebrahimi
436*62c56f98SSadaf Ebrahimi ret = 0;
437*62c56f98SSadaf Ebrahimi
438*62c56f98SSadaf Ebrahimi exit:
439*62c56f98SSadaf Ebrahimi mbedtls_platform_zeroize(salt_block, sizeof(salt_block));
440*62c56f98SSadaf Ebrahimi mbedtls_platform_zeroize(pwd_block, sizeof(pwd_block));
441*62c56f98SSadaf Ebrahimi mbedtls_platform_zeroize(hash_block, sizeof(hash_block));
442*62c56f98SSadaf Ebrahimi mbedtls_platform_zeroize(hash_output, sizeof(hash_output));
443*62c56f98SSadaf Ebrahimi
444*62c56f98SSadaf Ebrahimi return ret;
445*62c56f98SSadaf Ebrahimi }
446*62c56f98SSadaf Ebrahimi
447*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_PKCS12_C */
448