• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * \file pkcs5.c
3  *
4  * \brief PKCS#5 functions
5  *
6  * \author Mathias Olsson <mathias@kompetensum.com>
7  *
8  *  Copyright The Mbed TLS Contributors
9  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
10  */
11 /*
12  * PKCS#5 includes PBKDF2 and more
13  *
14  * http://tools.ietf.org/html/rfc2898 (Specification)
15  * http://tools.ietf.org/html/rfc6070 (Test vectors)
16  */
17 
18 #include "common.h"
19 
20 #if defined(MBEDTLS_PKCS5_C)
21 
22 #include "mbedtls/pkcs5.h"
23 #include "mbedtls/error.h"
24 
25 #if defined(MBEDTLS_ASN1_PARSE_C)
26 #include "mbedtls/asn1.h"
27 #include "mbedtls/cipher.h"
28 #include "mbedtls/oid.h"
29 #endif /* MBEDTLS_ASN1_PARSE_C */
30 
31 #include <string.h>
32 
33 #include "mbedtls/platform.h"
34 
35 
36 #if defined(MBEDTLS_ASN1_PARSE_C)
pkcs5_parse_pbkdf2_params(const mbedtls_asn1_buf * params,mbedtls_asn1_buf * salt,int * iterations,int * keylen,mbedtls_md_type_t * md_type)37 static int pkcs5_parse_pbkdf2_params(const mbedtls_asn1_buf *params,
38                                      mbedtls_asn1_buf *salt, int *iterations,
39                                      int *keylen, mbedtls_md_type_t *md_type)
40 {
41     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
42     mbedtls_asn1_buf prf_alg_oid;
43     unsigned char *p = params->p;
44     const unsigned char *end = params->p + params->len;
45 
46     if (params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
47         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
48                                  MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
49     }
50     /*
51      *  PBKDF2-params ::= SEQUENCE {
52      *    salt              OCTET STRING,
53      *    iterationCount    INTEGER,
54      *    keyLength         INTEGER OPTIONAL
55      *    prf               AlgorithmIdentifier DEFAULT algid-hmacWithSHA1
56      *  }
57      *
58      */
59     if ((ret = mbedtls_asn1_get_tag(&p, end, &salt->len,
60                                     MBEDTLS_ASN1_OCTET_STRING)) != 0) {
61         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
62     }
63 
64     salt->p = p;
65     p += salt->len;
66 
67     if ((ret = mbedtls_asn1_get_int(&p, end, iterations)) != 0) {
68         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
69     }
70 
71     if (p == end) {
72         return 0;
73     }
74 
75     if ((ret = mbedtls_asn1_get_int(&p, end, keylen)) != 0) {
76         if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
77             return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
78         }
79     }
80 
81     if (p == end) {
82         return 0;
83     }
84 
85     if ((ret = mbedtls_asn1_get_alg_null(&p, end, &prf_alg_oid)) != 0) {
86         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
87     }
88 
89     if (mbedtls_oid_get_md_hmac(&prf_alg_oid, md_type) != 0) {
90         return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
91     }
92 
93     if (p != end) {
94         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
95                                  MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
96     }
97 
98     return 0;
99 }
100 
101 #if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
102 int mbedtls_pkcs5_pbes2_ext(const mbedtls_asn1_buf *pbe_params, int mode,
103                             const unsigned char *pwd,  size_t pwdlen,
104                             const unsigned char *data, size_t datalen,
105                             unsigned char *output, size_t output_size,
106                             size_t *output_len);
107 #endif
108 
mbedtls_pkcs5_pbes2(const mbedtls_asn1_buf * pbe_params,int mode,const unsigned char * pwd,size_t pwdlen,const unsigned char * data,size_t datalen,unsigned char * output)109 int mbedtls_pkcs5_pbes2(const mbedtls_asn1_buf *pbe_params, int mode,
110                         const unsigned char *pwd,  size_t pwdlen,
111                         const unsigned char *data, size_t datalen,
112                         unsigned char *output)
113 {
114     size_t output_len = 0;
115 
116     /* We assume caller of the function is providing a big enough output buffer
117      * so we pass output_size as SIZE_MAX to pass checks, However, no guarantees
118      * for the output size actually being correct.
119      */
120     return mbedtls_pkcs5_pbes2_ext(pbe_params, mode, pwd, pwdlen, data,
121                                    datalen, output, SIZE_MAX, &output_len);
122 }
123 
mbedtls_pkcs5_pbes2_ext(const mbedtls_asn1_buf * pbe_params,int mode,const unsigned char * pwd,size_t pwdlen,const unsigned char * data,size_t datalen,unsigned char * output,size_t output_size,size_t * output_len)124 int mbedtls_pkcs5_pbes2_ext(const mbedtls_asn1_buf *pbe_params, int mode,
125                             const unsigned char *pwd,  size_t pwdlen,
126                             const unsigned char *data, size_t datalen,
127                             unsigned char *output, size_t output_size,
128                             size_t *output_len)
129 {
130     int ret, iterations = 0, keylen = 0;
131     unsigned char *p, *end;
132     mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params;
133     mbedtls_asn1_buf salt;
134     mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1;
135     unsigned char key[32], iv[32];
136     const mbedtls_md_info_t *md_info;
137     const mbedtls_cipher_info_t *cipher_info;
138     mbedtls_md_context_t md_ctx;
139     mbedtls_cipher_type_t cipher_alg;
140     mbedtls_cipher_context_t cipher_ctx;
141     unsigned int padlen = 0;
142 
143     p = pbe_params->p;
144     end = p + pbe_params->len;
145 
146     /*
147      *  PBES2-params ::= SEQUENCE {
148      *    keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
149      *    encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
150      *  }
151      */
152     if (pbe_params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
153         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
154                                  MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
155     }
156 
157     if ((ret = mbedtls_asn1_get_alg(&p, end, &kdf_alg_oid,
158                                     &kdf_alg_params)) != 0) {
159         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
160     }
161 
162     // Only PBKDF2 supported at the moment
163     //
164     if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid) != 0) {
165         return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
166     }
167 
168     if ((ret = pkcs5_parse_pbkdf2_params(&kdf_alg_params,
169                                          &salt, &iterations, &keylen,
170                                          &md_type)) != 0) {
171         return ret;
172     }
173 
174     md_info = mbedtls_md_info_from_type(md_type);
175     if (md_info == NULL) {
176         return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
177     }
178 
179     if ((ret = mbedtls_asn1_get_alg(&p, end, &enc_scheme_oid,
180                                     &enc_scheme_params)) != 0) {
181         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
182     }
183 
184     if (mbedtls_oid_get_cipher_alg(&enc_scheme_oid, &cipher_alg) != 0) {
185         return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
186     }
187 
188     cipher_info = mbedtls_cipher_info_from_type(cipher_alg);
189     if (cipher_info == NULL) {
190         return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
191     }
192 
193     /*
194      * The value of keylen from pkcs5_parse_pbkdf2_params() is ignored
195      * since it is optional and we don't know if it was set or not
196      */
197     keylen = cipher_info->key_bitlen / 8;
198 
199     if (enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING ||
200         enc_scheme_params.len != cipher_info->iv_size) {
201         return MBEDTLS_ERR_PKCS5_INVALID_FORMAT;
202     }
203 
204     if (mode == MBEDTLS_PKCS5_DECRYPT) {
205         if (output_size < datalen) {
206             return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
207         }
208     }
209 
210     if (mode == MBEDTLS_PKCS5_ENCRYPT) {
211         padlen = cipher_info->block_size - (datalen % cipher_info->block_size);
212         if (output_size < (datalen + padlen)) {
213             return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
214         }
215     }
216 
217     mbedtls_md_init(&md_ctx);
218 
219     mbedtls_cipher_init(&cipher_ctx);
220 
221     memcpy(iv, enc_scheme_params.p, enc_scheme_params.len);
222 
223     if ((ret = mbedtls_md_setup(&md_ctx, md_info, 1)) != 0) {
224         goto exit;
225     }
226 
227     if ((ret = mbedtls_pkcs5_pbkdf2_hmac(&md_ctx, pwd, pwdlen, salt.p, salt.len,
228                                          iterations, keylen, key)) != 0) {
229         goto exit;
230     }
231 
232     if ((ret = mbedtls_cipher_setup(&cipher_ctx, cipher_info)) != 0) {
233         goto exit;
234     }
235 
236     if ((ret = mbedtls_cipher_setkey(&cipher_ctx, key, 8 * keylen,
237                                      (mbedtls_operation_t) mode)) != 0) {
238         goto exit;
239     }
240 
241 #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
242     /* PKCS5 uses CBC with PKCS7 padding (which is the same as
243      * "PKCS5 padding" except that it's typically only called PKCS5
244      * with 64-bit-block ciphers).
245      */
246     mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_PKCS7;
247 #if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
248     /* For historical reasons, when decrypting, this function works when
249      * decrypting even when support for PKCS7 padding is disabled. In this
250      * case, it ignores the padding, and so will never report a
251      * password mismatch.
252      */
253     if (mode == MBEDTLS_DECRYPT) {
254         padding = MBEDTLS_PADDING_NONE;
255     }
256 #endif
257     if ((ret = mbedtls_cipher_set_padding_mode(&cipher_ctx, padding)) != 0) {
258         goto exit;
259     }
260 #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
261     if ((ret = mbedtls_cipher_crypt(&cipher_ctx, iv, enc_scheme_params.len,
262                                     data, datalen, output, output_len)) != 0) {
263         ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH;
264     }
265 
266 exit:
267     mbedtls_md_free(&md_ctx);
268     mbedtls_cipher_free(&cipher_ctx);
269 
270     return ret;
271 }
272 #endif /* MBEDTLS_ASN1_PARSE_C */
273 
mbedtls_pkcs5_pbkdf2_hmac(mbedtls_md_context_t * ctx,const unsigned char * password,size_t plen,const unsigned char * salt,size_t slen,unsigned int iteration_count,uint32_t key_length,unsigned char * output)274 int mbedtls_pkcs5_pbkdf2_hmac(mbedtls_md_context_t *ctx,
275                               const unsigned char *password,
276                               size_t plen, const unsigned char *salt, size_t slen,
277                               unsigned int iteration_count,
278                               uint32_t key_length, unsigned char *output)
279 {
280     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
281     int j;
282     unsigned int i;
283     unsigned char md1[MBEDTLS_MD_MAX_SIZE];
284     unsigned char work[MBEDTLS_MD_MAX_SIZE];
285     unsigned char md_size = mbedtls_md_get_size(ctx->md_info);
286     size_t use_len;
287     unsigned char *out_p = output;
288     unsigned char counter[4];
289 
290     memset(counter, 0, 4);
291     counter[3] = 1;
292 
293 #if UINT_MAX > 0xFFFFFFFF
294     if (iteration_count > 0xFFFFFFFF) {
295         return MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA;
296     }
297 #endif
298 
299     if ((ret = mbedtls_md_hmac_starts(ctx, password, plen)) != 0) {
300         return ret;
301     }
302     while (key_length) {
303         // U1 ends up in work
304         //
305         if ((ret = mbedtls_md_hmac_update(ctx, salt, slen)) != 0) {
306             goto cleanup;
307         }
308 
309         if ((ret = mbedtls_md_hmac_update(ctx, counter, 4)) != 0) {
310             goto cleanup;
311         }
312 
313         if ((ret = mbedtls_md_hmac_finish(ctx, work)) != 0) {
314             goto cleanup;
315         }
316 
317         if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) {
318             goto cleanup;
319         }
320 
321         memcpy(md1, work, md_size);
322 
323         for (i = 1; i < iteration_count; i++) {
324             // U2 ends up in md1
325             //
326             if ((ret = mbedtls_md_hmac_update(ctx, md1, md_size)) != 0) {
327                 goto cleanup;
328             }
329 
330             if ((ret = mbedtls_md_hmac_finish(ctx, md1)) != 0) {
331                 goto cleanup;
332             }
333 
334             if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) {
335                 goto cleanup;
336             }
337 
338             // U1 xor U2
339             //
340             for (j = 0; j < md_size; j++) {
341                 work[j] ^= md1[j];
342             }
343         }
344 
345         use_len = (key_length < md_size) ? key_length : md_size;
346         memcpy(out_p, work, use_len);
347 
348         key_length -= (uint32_t) use_len;
349         out_p += use_len;
350 
351         for (i = 4; i > 0; i--) {
352             if (++counter[i - 1] != 0) {
353                 break;
354             }
355         }
356     }
357 
358 cleanup:
359     /* Zeroise buffers to clear sensitive data from memory. */
360     mbedtls_platform_zeroize(work, MBEDTLS_MD_MAX_SIZE);
361     mbedtls_platform_zeroize(md1, MBEDTLS_MD_MAX_SIZE);
362 
363     return ret;
364 }
365 
366 #if defined(MBEDTLS_SELF_TEST)
367 
368 #if !defined(MBEDTLS_SHA1_C)
mbedtls_pkcs5_self_test(int verbose)369 int mbedtls_pkcs5_self_test(int verbose)
370 {
371     if (verbose != 0) {
372         mbedtls_printf("  PBKDF2 (SHA1): skipped\n\n");
373     }
374 
375     return 0;
376 }
377 #else
378 
379 #define MAX_TESTS   6
380 
381 static const size_t plen_test_data[MAX_TESTS] =
382 { 8, 8, 8, 24, 9 };
383 
384 static const unsigned char password_test_data[MAX_TESTS][32] =
385 {
386     "password",
387     "password",
388     "password",
389     "passwordPASSWORDpassword",
390     "pass\0word",
391 };
392 
393 static const size_t slen_test_data[MAX_TESTS] =
394 { 4, 4, 4, 36, 5 };
395 
396 static const unsigned char salt_test_data[MAX_TESTS][40] =
397 {
398     "salt",
399     "salt",
400     "salt",
401     "saltSALTsaltSALTsaltSALTsaltSALTsalt",
402     "sa\0lt",
403 };
404 
405 static const uint32_t it_cnt_test_data[MAX_TESTS] =
406 { 1, 2, 4096, 4096, 4096 };
407 
408 static const uint32_t key_len_test_data[MAX_TESTS] =
409 { 20, 20, 20, 25, 16 };
410 
411 static const unsigned char result_key_test_data[MAX_TESTS][32] =
412 {
413     { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
414       0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
415       0x2f, 0xe0, 0x37, 0xa6 },
416     { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
417       0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
418       0xd8, 0xde, 0x89, 0x57 },
419     { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
420       0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
421       0x65, 0xa4, 0x29, 0xc1 },
422     { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
423       0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
424       0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
425       0x38 },
426     { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
427       0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 },
428 };
429 
mbedtls_pkcs5_self_test(int verbose)430 int mbedtls_pkcs5_self_test(int verbose)
431 {
432     mbedtls_md_context_t sha1_ctx;
433     const mbedtls_md_info_t *info_sha1;
434     int ret, i;
435     unsigned char key[64];
436 
437     mbedtls_md_init(&sha1_ctx);
438 
439     info_sha1 = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
440     if (info_sha1 == NULL) {
441         ret = 1;
442         goto exit;
443     }
444 
445     if ((ret = mbedtls_md_setup(&sha1_ctx, info_sha1, 1)) != 0) {
446         ret = 1;
447         goto exit;
448     }
449 
450     for (i = 0; i < MAX_TESTS; i++) {
451         if (verbose != 0) {
452             mbedtls_printf("  PBKDF2 (SHA1) #%d: ", i);
453         }
454 
455         ret = mbedtls_pkcs5_pbkdf2_hmac(&sha1_ctx, password_test_data[i],
456                                         plen_test_data[i], salt_test_data[i],
457                                         slen_test_data[i], it_cnt_test_data[i],
458                                         key_len_test_data[i], key);
459         if (ret != 0 ||
460             memcmp(result_key_test_data[i], key, key_len_test_data[i]) != 0) {
461             if (verbose != 0) {
462                 mbedtls_printf("failed\n");
463             }
464 
465             ret = 1;
466             goto exit;
467         }
468 
469         if (verbose != 0) {
470             mbedtls_printf("passed\n");
471         }
472     }
473 
474     if (verbose != 0) {
475         mbedtls_printf("\n");
476     }
477 
478 exit:
479     mbedtls_md_free(&sha1_ctx);
480 
481     return ret;
482 }
483 #endif /* MBEDTLS_SHA1_C */
484 
485 #endif /* MBEDTLS_SELF_TEST */
486 
487 #endif /* MBEDTLS_PKCS5_C */
488