xref: /aosp_15_r20/external/mbedtls/library/pkcs12.c (revision 62c56f9862f102b96d72393aff6076c951fb8148)
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 = &params->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