xref: /optee_os/lib/libmbedtls/mbedtls/library/pkcs5.c (revision 32b3180828fa15a49ccc86ecb4be9d274c140c89)
1817466cbSJens Wiklander /**
2817466cbSJens Wiklander  * \file pkcs5.c
3817466cbSJens Wiklander  *
4817466cbSJens Wiklander  * \brief PKCS#5 functions
5817466cbSJens Wiklander  *
6817466cbSJens Wiklander  * \author Mathias Olsson <mathias@kompetensum.com>
7817466cbSJens Wiklander  *
87901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
97901324dSJerome Forissier  *  SPDX-License-Identifier: Apache-2.0
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
12817466cbSJens Wiklander  *  not use this file except in compliance with the License.
13817466cbSJens Wiklander  *  You may obtain a copy of the License at
14817466cbSJens Wiklander  *
15817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
16817466cbSJens Wiklander  *
17817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
18817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
19817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
21817466cbSJens Wiklander  *  limitations under the License.
22817466cbSJens Wiklander  */
23817466cbSJens Wiklander /*
24817466cbSJens Wiklander  * PKCS#5 includes PBKDF2 and more
25817466cbSJens Wiklander  *
26817466cbSJens Wiklander  * http://tools.ietf.org/html/rfc2898 (Specification)
27817466cbSJens Wiklander  * http://tools.ietf.org/html/rfc6070 (Test vectors)
28817466cbSJens Wiklander  */
29817466cbSJens Wiklander 
307901324dSJerome Forissier #include "common.h"
31817466cbSJens Wiklander 
32817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C)
33817466cbSJens Wiklander 
34817466cbSJens Wiklander #include "mbedtls/pkcs5.h"
3511fa71b9SJerome Forissier #include "mbedtls/error.h"
363d3b0591SJens Wiklander 
373d3b0591SJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C)
38817466cbSJens Wiklander #include "mbedtls/asn1.h"
39817466cbSJens Wiklander #include "mbedtls/cipher.h"
40817466cbSJens Wiklander #include "mbedtls/oid.h"
413d3b0591SJens Wiklander #endif /* MBEDTLS_ASN1_PARSE_C */
42817466cbSJens Wiklander 
43817466cbSJens Wiklander #include <string.h>
44817466cbSJens Wiklander 
45817466cbSJens Wiklander #include "mbedtls/platform.h"
46*32b31808SJens Wiklander 
47*32b31808SJens Wiklander #include "hash_info.h"
48*32b31808SJens Wiklander #include "mbedtls/psa_util.h"
49*32b31808SJens Wiklander 
50*32b31808SJens Wiklander #if !defined(MBEDTLS_MD_C)
51*32b31808SJens Wiklander #define PSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status,   \
52*32b31808SJens Wiklander                                                            psa_to_md_errors,              \
53*32b31808SJens Wiklander                                                            psa_generic_status_to_mbedtls)
54817466cbSJens Wiklander #endif
55817466cbSJens Wiklander 
563d3b0591SJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C)
57817466cbSJens Wiklander static int pkcs5_parse_pbkdf2_params(const mbedtls_asn1_buf *params,
58817466cbSJens Wiklander                                      mbedtls_asn1_buf *salt, int *iterations,
59817466cbSJens Wiklander                                      int *keylen, mbedtls_md_type_t *md_type)
60817466cbSJens Wiklander {
6111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
62817466cbSJens Wiklander     mbedtls_asn1_buf prf_alg_oid;
63817466cbSJens Wiklander     unsigned char *p = params->p;
64817466cbSJens Wiklander     const unsigned char *end = params->p + params->len;
65817466cbSJens Wiklander 
66*32b31808SJens Wiklander     if (params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
67*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
68*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
69*32b31808SJens Wiklander     }
70817466cbSJens Wiklander     /*
71817466cbSJens Wiklander      *  PBKDF2-params ::= SEQUENCE {
72817466cbSJens Wiklander      *    salt              OCTET STRING,
73817466cbSJens Wiklander      *    iterationCount    INTEGER,
74817466cbSJens Wiklander      *    keyLength         INTEGER OPTIONAL
75817466cbSJens Wiklander      *    prf               AlgorithmIdentifier DEFAULT algid-hmacWithSHA1
76817466cbSJens Wiklander      *  }
77817466cbSJens Wiklander      *
78817466cbSJens Wiklander      */
7911fa71b9SJerome Forissier     if ((ret = mbedtls_asn1_get_tag(&p, end, &salt->len,
80*32b31808SJens Wiklander                                     MBEDTLS_ASN1_OCTET_STRING)) != 0) {
81*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
82*32b31808SJens Wiklander     }
83817466cbSJens Wiklander 
84817466cbSJens Wiklander     salt->p = p;
85817466cbSJens Wiklander     p += salt->len;
86817466cbSJens Wiklander 
87*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_int(&p, end, iterations)) != 0) {
88*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
89817466cbSJens Wiklander     }
90817466cbSJens Wiklander 
91*32b31808SJens Wiklander     if (p == end) {
92*32b31808SJens Wiklander         return 0;
93*32b31808SJens Wiklander     }
94817466cbSJens Wiklander 
95*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_int(&p, end, keylen)) != 0) {
96*32b31808SJens Wiklander         if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
97*32b31808SJens Wiklander             return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
98*32b31808SJens Wiklander         }
99*32b31808SJens Wiklander     }
100817466cbSJens Wiklander 
101*32b31808SJens Wiklander     if (p == end) {
102*32b31808SJens Wiklander         return 0;
103*32b31808SJens Wiklander     }
104817466cbSJens Wiklander 
105*32b31808SJens Wiklander     if ((ret = mbedtls_asn1_get_alg_null(&p, end, &prf_alg_oid)) != 0) {
106*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
107*32b31808SJens Wiklander     }
108817466cbSJens Wiklander 
109*32b31808SJens Wiklander     if (mbedtls_oid_get_md_hmac(&prf_alg_oid, md_type) != 0) {
110*32b31808SJens Wiklander         return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
111*32b31808SJens Wiklander     }
112*32b31808SJens Wiklander 
113*32b31808SJens Wiklander     if (p != end) {
114*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
115*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
116*32b31808SJens Wiklander     }
117*32b31808SJens Wiklander 
118*32b31808SJens Wiklander     return 0;
119817466cbSJens Wiklander }
120817466cbSJens Wiklander 
121817466cbSJens Wiklander int mbedtls_pkcs5_pbes2(const mbedtls_asn1_buf *pbe_params, int mode,
122817466cbSJens Wiklander                         const unsigned char *pwd,  size_t pwdlen,
123817466cbSJens Wiklander                         const unsigned char *data, size_t datalen,
124817466cbSJens Wiklander                         unsigned char *output)
125817466cbSJens Wiklander {
126817466cbSJens Wiklander     int ret, iterations = 0, keylen = 0;
127817466cbSJens Wiklander     unsigned char *p, *end;
128817466cbSJens Wiklander     mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params;
129817466cbSJens Wiklander     mbedtls_asn1_buf salt;
130817466cbSJens Wiklander     mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1;
131817466cbSJens Wiklander     unsigned char key[32], iv[32];
132817466cbSJens Wiklander     size_t olen = 0;
133817466cbSJens Wiklander     const mbedtls_cipher_info_t *cipher_info;
134817466cbSJens Wiklander     mbedtls_cipher_type_t cipher_alg;
135817466cbSJens Wiklander     mbedtls_cipher_context_t cipher_ctx;
136817466cbSJens Wiklander 
137817466cbSJens Wiklander     p = pbe_params->p;
138817466cbSJens Wiklander     end = p + pbe_params->len;
139817466cbSJens Wiklander 
140817466cbSJens Wiklander     /*
141817466cbSJens Wiklander      *  PBES2-params ::= SEQUENCE {
142817466cbSJens Wiklander      *    keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
143817466cbSJens Wiklander      *    encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
144817466cbSJens Wiklander      *  }
145817466cbSJens Wiklander      */
146*32b31808SJens Wiklander     if (pbe_params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
147*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
148*32b31808SJens Wiklander                                  MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
149*32b31808SJens Wiklander     }
150817466cbSJens Wiklander 
15111fa71b9SJerome Forissier     if ((ret = mbedtls_asn1_get_alg(&p, end, &kdf_alg_oid,
152*32b31808SJens Wiklander                                     &kdf_alg_params)) != 0) {
153*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
154*32b31808SJens Wiklander     }
155817466cbSJens Wiklander 
156817466cbSJens Wiklander     // Only PBKDF2 supported at the moment
157817466cbSJens Wiklander     //
158*32b31808SJens Wiklander     if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid) != 0) {
159*32b31808SJens Wiklander         return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
160*32b31808SJens Wiklander     }
161817466cbSJens Wiklander 
162817466cbSJens Wiklander     if ((ret = pkcs5_parse_pbkdf2_params(&kdf_alg_params,
163817466cbSJens Wiklander                                          &salt, &iterations, &keylen,
164*32b31808SJens Wiklander                                          &md_type)) != 0) {
165*32b31808SJens Wiklander         return ret;
166817466cbSJens Wiklander     }
167817466cbSJens Wiklander 
168817466cbSJens Wiklander     if ((ret = mbedtls_asn1_get_alg(&p, end, &enc_scheme_oid,
169*32b31808SJens Wiklander                                     &enc_scheme_params)) != 0) {
170*32b31808SJens Wiklander         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
171817466cbSJens Wiklander     }
172817466cbSJens Wiklander 
173*32b31808SJens Wiklander     if (mbedtls_oid_get_cipher_alg(&enc_scheme_oid, &cipher_alg) != 0) {
174*32b31808SJens Wiklander         return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
175*32b31808SJens Wiklander     }
176817466cbSJens Wiklander 
177817466cbSJens Wiklander     cipher_info = mbedtls_cipher_info_from_type(cipher_alg);
178*32b31808SJens Wiklander     if (cipher_info == NULL) {
179*32b31808SJens Wiklander         return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
180*32b31808SJens Wiklander     }
181817466cbSJens Wiklander 
182817466cbSJens Wiklander     /*
183817466cbSJens Wiklander      * The value of keylen from pkcs5_parse_pbkdf2_params() is ignored
184817466cbSJens Wiklander      * since it is optional and we don't know if it was set or not
185817466cbSJens Wiklander      */
186817466cbSJens Wiklander     keylen = cipher_info->key_bitlen / 8;
187817466cbSJens Wiklander 
188817466cbSJens Wiklander     if (enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING ||
189*32b31808SJens Wiklander         enc_scheme_params.len != cipher_info->iv_size) {
190*32b31808SJens Wiklander         return MBEDTLS_ERR_PKCS5_INVALID_FORMAT;
191817466cbSJens Wiklander     }
192817466cbSJens Wiklander 
193817466cbSJens Wiklander     mbedtls_cipher_init(&cipher_ctx);
194817466cbSJens Wiklander 
195817466cbSJens Wiklander     memcpy(iv, enc_scheme_params.p, enc_scheme_params.len);
196817466cbSJens Wiklander 
197*32b31808SJens Wiklander     if ((ret = mbedtls_pkcs5_pbkdf2_hmac_ext(md_type, pwd, pwdlen, salt.p,
198*32b31808SJens Wiklander                                              salt.len, iterations, keylen,
199*32b31808SJens Wiklander                                              key)) != 0) {
200817466cbSJens Wiklander         goto exit;
201817466cbSJens Wiklander     }
202817466cbSJens Wiklander 
203*32b31808SJens Wiklander     if ((ret = mbedtls_cipher_setup(&cipher_ctx, cipher_info)) != 0) {
204817466cbSJens Wiklander         goto exit;
205*32b31808SJens Wiklander     }
206817466cbSJens Wiklander 
20711fa71b9SJerome Forissier     if ((ret = mbedtls_cipher_setkey(&cipher_ctx, key, 8 * keylen,
208*32b31808SJens Wiklander                                      (mbedtls_operation_t) mode)) != 0) {
209817466cbSJens Wiklander         goto exit;
210*32b31808SJens Wiklander     }
211817466cbSJens Wiklander 
212817466cbSJens Wiklander     if ((ret = mbedtls_cipher_crypt(&cipher_ctx, iv, enc_scheme_params.len,
213*32b31808SJens Wiklander                                     data, datalen, output, &olen)) != 0) {
214817466cbSJens Wiklander         ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH;
215*32b31808SJens Wiklander     }
216817466cbSJens Wiklander 
217817466cbSJens Wiklander exit:
218817466cbSJens Wiklander     mbedtls_cipher_free(&cipher_ctx);
219817466cbSJens Wiklander 
220*32b31808SJens Wiklander     return ret;
221817466cbSJens Wiklander }
2223d3b0591SJens Wiklander #endif /* MBEDTLS_ASN1_PARSE_C */
223817466cbSJens Wiklander 
224*32b31808SJens Wiklander #if defined(MBEDTLS_MD_C)
225*32b31808SJens Wiklander static int pkcs5_pbkdf2_hmac(mbedtls_md_context_t *ctx,
22611fa71b9SJerome Forissier                              const unsigned char *password,
227817466cbSJens Wiklander                              size_t plen, const unsigned char *salt, size_t slen,
228817466cbSJens Wiklander                              unsigned int iteration_count,
229817466cbSJens Wiklander                              uint32_t key_length, unsigned char *output)
230817466cbSJens Wiklander {
2317901324dSJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
232817466cbSJens Wiklander     unsigned int i;
233817466cbSJens Wiklander     unsigned char md1[MBEDTLS_MD_MAX_SIZE];
234817466cbSJens Wiklander     unsigned char work[MBEDTLS_MD_MAX_SIZE];
235817466cbSJens Wiklander     unsigned char md_size = mbedtls_md_get_size(ctx->md_info);
236817466cbSJens Wiklander     size_t use_len;
237817466cbSJens Wiklander     unsigned char *out_p = output;
238817466cbSJens Wiklander     unsigned char counter[4];
239817466cbSJens Wiklander 
240817466cbSJens Wiklander     memset(counter, 0, 4);
241817466cbSJens Wiklander     counter[3] = 1;
242817466cbSJens Wiklander 
2433d3b0591SJens Wiklander #if UINT_MAX > 0xFFFFFFFF
244*32b31808SJens Wiklander     if (iteration_count > 0xFFFFFFFF) {
245*32b31808SJens Wiklander         return MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA;
246*32b31808SJens Wiklander     }
2473d3b0591SJens Wiklander #endif
248817466cbSJens Wiklander 
249*32b31808SJens Wiklander     if ((ret = mbedtls_md_hmac_starts(ctx, password, plen)) != 0) {
250*32b31808SJens Wiklander         return ret;
251*32b31808SJens Wiklander     }
252*32b31808SJens Wiklander     while (key_length) {
253817466cbSJens Wiklander         // U1 ends up in work
254817466cbSJens Wiklander         //
255*32b31808SJens Wiklander         if ((ret = mbedtls_md_hmac_update(ctx, salt, slen)) != 0) {
2567901324dSJerome Forissier             goto cleanup;
257*32b31808SJens Wiklander         }
258817466cbSJens Wiklander 
259*32b31808SJens Wiklander         if ((ret = mbedtls_md_hmac_update(ctx, counter, 4)) != 0) {
2607901324dSJerome Forissier             goto cleanup;
261*32b31808SJens Wiklander         }
262817466cbSJens Wiklander 
263*32b31808SJens Wiklander         if ((ret = mbedtls_md_hmac_finish(ctx, work)) != 0) {
2647901324dSJerome Forissier             goto cleanup;
265*32b31808SJens Wiklander         }
266817466cbSJens Wiklander 
267*32b31808SJens Wiklander         if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) {
2687901324dSJerome Forissier             goto cleanup;
269*32b31808SJens Wiklander         }
27011fa71b9SJerome Forissier 
271817466cbSJens Wiklander         memcpy(md1, work, md_size);
272817466cbSJens Wiklander 
273*32b31808SJens Wiklander         for (i = 1; i < iteration_count; i++) {
274817466cbSJens Wiklander             // U2 ends up in md1
275817466cbSJens Wiklander             //
276*32b31808SJens Wiklander             if ((ret = mbedtls_md_hmac_update(ctx, md1, md_size)) != 0) {
2777901324dSJerome Forissier                 goto cleanup;
278*32b31808SJens Wiklander             }
279817466cbSJens Wiklander 
280*32b31808SJens Wiklander             if ((ret = mbedtls_md_hmac_finish(ctx, md1)) != 0) {
2817901324dSJerome Forissier                 goto cleanup;
282*32b31808SJens Wiklander             }
283817466cbSJens Wiklander 
284*32b31808SJens Wiklander             if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) {
2857901324dSJerome Forissier                 goto cleanup;
286*32b31808SJens Wiklander             }
28711fa71b9SJerome Forissier 
288817466cbSJens Wiklander             // U1 xor U2
289817466cbSJens Wiklander             //
290*32b31808SJens Wiklander             mbedtls_xor(work, work, md1, md_size);
291817466cbSJens Wiklander         }
292817466cbSJens Wiklander 
293817466cbSJens Wiklander         use_len = (key_length < md_size) ? key_length : md_size;
294817466cbSJens Wiklander         memcpy(out_p, work, use_len);
295817466cbSJens Wiklander 
296817466cbSJens Wiklander         key_length -= (uint32_t) use_len;
297817466cbSJens Wiklander         out_p += use_len;
298817466cbSJens Wiklander 
299*32b31808SJens Wiklander         for (i = 4; i > 0; i--) {
300*32b31808SJens Wiklander             if (++counter[i - 1] != 0) {
301817466cbSJens Wiklander                 break;
302817466cbSJens Wiklander             }
303*32b31808SJens Wiklander         }
304*32b31808SJens Wiklander     }
305817466cbSJens Wiklander 
3067901324dSJerome Forissier cleanup:
3077901324dSJerome Forissier     /* Zeroise buffers to clear sensitive data from memory. */
3087901324dSJerome Forissier     mbedtls_platform_zeroize(work, MBEDTLS_MD_MAX_SIZE);
3097901324dSJerome Forissier     mbedtls_platform_zeroize(md1, MBEDTLS_MD_MAX_SIZE);
3107901324dSJerome Forissier 
311*32b31808SJens Wiklander     return ret;
312*32b31808SJens Wiklander }
313*32b31808SJens Wiklander 
314*32b31808SJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED)
315*32b31808SJens Wiklander int mbedtls_pkcs5_pbkdf2_hmac(mbedtls_md_context_t *ctx,
316*32b31808SJens Wiklander                               const unsigned char *password,
317*32b31808SJens Wiklander                               size_t plen, const unsigned char *salt, size_t slen,
318*32b31808SJens Wiklander                               unsigned int iteration_count,
319*32b31808SJens Wiklander                               uint32_t key_length, unsigned char *output)
320*32b31808SJens Wiklander {
321*32b31808SJens Wiklander     return pkcs5_pbkdf2_hmac(ctx, password, plen, salt, slen, iteration_count,
322*32b31808SJens Wiklander                              key_length, output);
323*32b31808SJens Wiklander }
324*32b31808SJens Wiklander #endif
325*32b31808SJens Wiklander #endif /* MBEDTLS_MD_C */
326*32b31808SJens Wiklander 
327*32b31808SJens Wiklander int mbedtls_pkcs5_pbkdf2_hmac_ext(mbedtls_md_type_t md_alg,
328*32b31808SJens Wiklander                                   const unsigned char *password,
329*32b31808SJens Wiklander                                   size_t plen, const unsigned char *salt, size_t slen,
330*32b31808SJens Wiklander                                   unsigned int iteration_count,
331*32b31808SJens Wiklander                                   uint32_t key_length, unsigned char *output)
332*32b31808SJens Wiklander {
333*32b31808SJens Wiklander #if defined(MBEDTLS_MD_C)
334*32b31808SJens Wiklander     mbedtls_md_context_t md_ctx;
335*32b31808SJens Wiklander     const mbedtls_md_info_t *md_info = NULL;
336*32b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
337*32b31808SJens Wiklander 
338*32b31808SJens Wiklander     md_info = mbedtls_md_info_from_type(md_alg);
339*32b31808SJens Wiklander     if (md_info == NULL) {
340*32b31808SJens Wiklander         return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
341*32b31808SJens Wiklander     }
342*32b31808SJens Wiklander 
343*32b31808SJens Wiklander     mbedtls_md_init(&md_ctx);
344*32b31808SJens Wiklander 
345*32b31808SJens Wiklander     if ((ret = mbedtls_md_setup(&md_ctx, md_info, 1)) != 0) {
346*32b31808SJens Wiklander         goto exit;
347*32b31808SJens Wiklander     }
348*32b31808SJens Wiklander     ret = pkcs5_pbkdf2_hmac(&md_ctx, password, plen, salt, slen,
349*32b31808SJens Wiklander                             iteration_count, key_length, output);
350*32b31808SJens Wiklander exit:
351*32b31808SJens Wiklander     mbedtls_md_free(&md_ctx);
352*32b31808SJens Wiklander     return ret;
353*32b31808SJens Wiklander #else
354*32b31808SJens Wiklander     unsigned int i;
355*32b31808SJens Wiklander     unsigned char md1[PSA_HASH_MAX_SIZE];
356*32b31808SJens Wiklander     unsigned char work[PSA_HASH_MAX_SIZE];
357*32b31808SJens Wiklander     const unsigned char md_size = mbedtls_hash_info_get_size(md_alg);
358*32b31808SJens Wiklander     psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
359*32b31808SJens Wiklander 
360*32b31808SJens Wiklander     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
361*32b31808SJens Wiklander     psa_status_t status_destruction = PSA_ERROR_CORRUPTION_DETECTED;
362*32b31808SJens Wiklander     size_t use_len, out_len;
363*32b31808SJens Wiklander     unsigned char *out_p = output;
364*32b31808SJens Wiklander     unsigned char counter[4];
365*32b31808SJens Wiklander     mbedtls_svc_key_id_t psa_hmac_key = MBEDTLS_SVC_KEY_ID_INIT;
366*32b31808SJens Wiklander     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
367*32b31808SJens Wiklander     const psa_algorithm_t alg = PSA_ALG_HMAC(mbedtls_hash_info_psa_from_md(md_alg));
368*32b31808SJens Wiklander     const size_t out_size = PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, 0, alg);
369*32b31808SJens Wiklander 
370*32b31808SJens Wiklander     memset(counter, 0, sizeof(counter));
371*32b31808SJens Wiklander     counter[3] = 1;
372*32b31808SJens Wiklander 
373*32b31808SJens Wiklander     psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
374*32b31808SJens Wiklander     psa_set_key_algorithm(&attributes,  alg);
375*32b31808SJens Wiklander     psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC);
376*32b31808SJens Wiklander 
377*32b31808SJens Wiklander     if (key_length == 0) {
378*32b31808SJens Wiklander         return 0;
379*32b31808SJens Wiklander     }
380*32b31808SJens Wiklander     if ((status = psa_import_key(&attributes,
381*32b31808SJens Wiklander                                  password, plen,
382*32b31808SJens Wiklander                                  &psa_hmac_key)) != PSA_SUCCESS) {
383*32b31808SJens Wiklander         return MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA;
384*32b31808SJens Wiklander     }
385*32b31808SJens Wiklander 
386*32b31808SJens Wiklander #if UINT_MAX > 0xFFFFFFFF
387*32b31808SJens Wiklander     if (iteration_count > 0xFFFFFFFF) {
388*32b31808SJens Wiklander         return MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA;
389*32b31808SJens Wiklander     }
390*32b31808SJens Wiklander #endif
391*32b31808SJens Wiklander 
392*32b31808SJens Wiklander     while (key_length) {
393*32b31808SJens Wiklander         status = psa_mac_sign_setup(&operation, psa_hmac_key,
394*32b31808SJens Wiklander                                     PSA_ALG_HMAC(alg));
395*32b31808SJens Wiklander         if (status != PSA_SUCCESS) {
396*32b31808SJens Wiklander             goto cleanup;
397*32b31808SJens Wiklander         }
398*32b31808SJens Wiklander         // U1 ends up in work
399*32b31808SJens Wiklander         if ((status = psa_mac_update(&operation, salt, slen)) != PSA_SUCCESS) {
400*32b31808SJens Wiklander             goto cleanup;
401*32b31808SJens Wiklander         }
402*32b31808SJens Wiklander 
403*32b31808SJens Wiklander         if ((status = psa_mac_update(&operation, counter, sizeof(counter))) != PSA_SUCCESS) {
404*32b31808SJens Wiklander             goto cleanup;
405*32b31808SJens Wiklander         }
406*32b31808SJens Wiklander 
407*32b31808SJens Wiklander         if ((status = psa_mac_sign_finish(&operation, work, out_size, &out_len))
408*32b31808SJens Wiklander             != PSA_SUCCESS) {
409*32b31808SJens Wiklander             goto cleanup;
410*32b31808SJens Wiklander         }
411*32b31808SJens Wiklander 
412*32b31808SJens Wiklander         memcpy(md1, work, out_len);
413*32b31808SJens Wiklander 
414*32b31808SJens Wiklander         for (i = 1; i < iteration_count; i++) {
415*32b31808SJens Wiklander             // U2 ends up in md1
416*32b31808SJens Wiklander             //
417*32b31808SJens Wiklander             status = psa_mac_sign_setup(&operation, psa_hmac_key,
418*32b31808SJens Wiklander                                         PSA_ALG_HMAC(alg));
419*32b31808SJens Wiklander             if (status != PSA_SUCCESS) {
420*32b31808SJens Wiklander                 goto cleanup;
421*32b31808SJens Wiklander             }
422*32b31808SJens Wiklander             if ((status = psa_mac_update(&operation, md1, md_size)) != PSA_SUCCESS) {
423*32b31808SJens Wiklander                 goto cleanup;
424*32b31808SJens Wiklander             }
425*32b31808SJens Wiklander             if ((status =
426*32b31808SJens Wiklander                      psa_mac_sign_finish(&operation, md1, out_size, &out_len)) != PSA_SUCCESS) {
427*32b31808SJens Wiklander                 goto cleanup;
428*32b31808SJens Wiklander             }
429*32b31808SJens Wiklander 
430*32b31808SJens Wiklander             // U1 xor U2
431*32b31808SJens Wiklander             //
432*32b31808SJens Wiklander             mbedtls_xor(work, work, md1, md_size);
433*32b31808SJens Wiklander         }
434*32b31808SJens Wiklander 
435*32b31808SJens Wiklander         use_len = (key_length < md_size) ? key_length : md_size;
436*32b31808SJens Wiklander         memcpy(out_p, work, use_len);
437*32b31808SJens Wiklander 
438*32b31808SJens Wiklander         key_length -= (uint32_t) use_len;
439*32b31808SJens Wiklander         out_p += use_len;
440*32b31808SJens Wiklander 
441*32b31808SJens Wiklander         for (i = 4; i > 0; i--) {
442*32b31808SJens Wiklander             if (++counter[i - 1] != 0) {
443*32b31808SJens Wiklander                 break;
444*32b31808SJens Wiklander             }
445*32b31808SJens Wiklander         }
446*32b31808SJens Wiklander     }
447*32b31808SJens Wiklander 
448*32b31808SJens Wiklander cleanup:
449*32b31808SJens Wiklander     /* Zeroise buffers to clear sensitive data from memory. */
450*32b31808SJens Wiklander     mbedtls_platform_zeroize(work, PSA_HASH_MAX_SIZE);
451*32b31808SJens Wiklander     mbedtls_platform_zeroize(md1, PSA_HASH_MAX_SIZE);
452*32b31808SJens Wiklander     status_destruction = psa_destroy_key(psa_hmac_key);
453*32b31808SJens Wiklander     if (status == PSA_SUCCESS && status_destruction != PSA_SUCCESS) {
454*32b31808SJens Wiklander         status = status_destruction;
455*32b31808SJens Wiklander     }
456*32b31808SJens Wiklander     status_destruction = psa_mac_abort(&operation);
457*32b31808SJens Wiklander     if (status == PSA_SUCCESS && status_destruction != PSA_SUCCESS) {
458*32b31808SJens Wiklander         status = status_destruction;
459*32b31808SJens Wiklander     }
460*32b31808SJens Wiklander 
461*32b31808SJens Wiklander     return PSA_TO_MBEDTLS_ERR(status);
462*32b31808SJens Wiklander #endif /* !MBEDTLS_MD_C */
463817466cbSJens Wiklander }
464817466cbSJens Wiklander 
465817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
466817466cbSJens Wiklander 
467*32b31808SJens Wiklander #if !defined(MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA)
468817466cbSJens Wiklander int mbedtls_pkcs5_self_test(int verbose)
469817466cbSJens Wiklander {
470*32b31808SJens Wiklander     if (verbose != 0) {
471817466cbSJens Wiklander         mbedtls_printf("  PBKDF2 (SHA1): skipped\n\n");
472*32b31808SJens Wiklander     }
473817466cbSJens Wiklander 
474*32b31808SJens Wiklander     return 0;
475817466cbSJens Wiklander }
476817466cbSJens Wiklander #else
477817466cbSJens Wiklander 
478817466cbSJens Wiklander #define MAX_TESTS   6
479817466cbSJens Wiklander 
48011fa71b9SJerome Forissier static const size_t plen_test_data[MAX_TESTS] =
481817466cbSJens Wiklander { 8, 8, 8, 24, 9 };
482817466cbSJens Wiklander 
48311fa71b9SJerome Forissier static const unsigned char password_test_data[MAX_TESTS][32] =
484817466cbSJens Wiklander {
485817466cbSJens Wiklander     "password",
486817466cbSJens Wiklander     "password",
487817466cbSJens Wiklander     "password",
488817466cbSJens Wiklander     "passwordPASSWORDpassword",
489817466cbSJens Wiklander     "pass\0word",
490817466cbSJens Wiklander };
491817466cbSJens Wiklander 
49211fa71b9SJerome Forissier static const size_t slen_test_data[MAX_TESTS] =
493817466cbSJens Wiklander { 4, 4, 4, 36, 5 };
494817466cbSJens Wiklander 
49511fa71b9SJerome Forissier static const unsigned char salt_test_data[MAX_TESTS][40] =
496817466cbSJens Wiklander {
497817466cbSJens Wiklander     "salt",
498817466cbSJens Wiklander     "salt",
499817466cbSJens Wiklander     "salt",
500817466cbSJens Wiklander     "saltSALTsaltSALTsaltSALTsaltSALTsalt",
501817466cbSJens Wiklander     "sa\0lt",
502817466cbSJens Wiklander };
503817466cbSJens Wiklander 
50411fa71b9SJerome Forissier static const uint32_t it_cnt_test_data[MAX_TESTS] =
505817466cbSJens Wiklander { 1, 2, 4096, 4096, 4096 };
506817466cbSJens Wiklander 
50711fa71b9SJerome Forissier static const uint32_t key_len_test_data[MAX_TESTS] =
508817466cbSJens Wiklander { 20, 20, 20, 25, 16 };
509817466cbSJens Wiklander 
51011fa71b9SJerome Forissier static const unsigned char result_key_test_data[MAX_TESTS][32] =
511817466cbSJens Wiklander {
512817466cbSJens Wiklander     { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
513817466cbSJens Wiklander       0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
514817466cbSJens Wiklander       0x2f, 0xe0, 0x37, 0xa6 },
515817466cbSJens Wiklander     { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
516817466cbSJens Wiklander       0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
517817466cbSJens Wiklander       0xd8, 0xde, 0x89, 0x57 },
518817466cbSJens Wiklander     { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
519817466cbSJens Wiklander       0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
520817466cbSJens Wiklander       0x65, 0xa4, 0x29, 0xc1 },
521817466cbSJens Wiklander     { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
522817466cbSJens Wiklander       0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
523817466cbSJens Wiklander       0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
524817466cbSJens Wiklander       0x38 },
525817466cbSJens Wiklander     { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
526817466cbSJens Wiklander       0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 },
527817466cbSJens Wiklander };
528817466cbSJens Wiklander 
529817466cbSJens Wiklander int mbedtls_pkcs5_self_test(int verbose)
530817466cbSJens Wiklander {
531817466cbSJens Wiklander     int ret, i;
532817466cbSJens Wiklander     unsigned char key[64];
533817466cbSJens Wiklander 
534*32b31808SJens Wiklander     for (i = 0; i < MAX_TESTS; i++) {
535*32b31808SJens Wiklander         if (verbose != 0) {
536817466cbSJens Wiklander             mbedtls_printf("  PBKDF2 (SHA1) #%d: ", i);
537*32b31808SJens Wiklander         }
538817466cbSJens Wiklander 
539*32b31808SJens Wiklander         ret = mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA1, password_test_data[i],
54011fa71b9SJerome Forissier                                             plen_test_data[i], salt_test_data[i],
54111fa71b9SJerome Forissier                                             slen_test_data[i], it_cnt_test_data[i],
54211fa71b9SJerome Forissier                                             key_len_test_data[i], key);
543817466cbSJens Wiklander         if (ret != 0 ||
544*32b31808SJens Wiklander             memcmp(result_key_test_data[i], key, key_len_test_data[i]) != 0) {
545*32b31808SJens Wiklander             if (verbose != 0) {
546817466cbSJens Wiklander                 mbedtls_printf("failed\n");
547*32b31808SJens Wiklander             }
548817466cbSJens Wiklander 
549817466cbSJens Wiklander             ret = 1;
550817466cbSJens Wiklander             goto exit;
551817466cbSJens Wiklander         }
552817466cbSJens Wiklander 
553*32b31808SJens Wiklander         if (verbose != 0) {
554817466cbSJens Wiklander             mbedtls_printf("passed\n");
555817466cbSJens Wiklander         }
556*32b31808SJens Wiklander     }
557817466cbSJens Wiklander 
558*32b31808SJens Wiklander     if (verbose != 0) {
559817466cbSJens Wiklander         mbedtls_printf("\n");
560*32b31808SJens Wiklander     }
561817466cbSJens Wiklander 
562817466cbSJens Wiklander exit:
563*32b31808SJens Wiklander     return ret;
564817466cbSJens Wiklander }
565*32b31808SJens Wiklander #endif /* MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA */
566817466cbSJens Wiklander 
567817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
568817466cbSJens Wiklander 
569817466cbSJens Wiklander #endif /* MBEDTLS_PKCS5_C */
570