Re: [PATCH v2] check whether the forced iteration count is out of range
"wangzhiqiang (Q)" <[email protected]>
| Newsgroups | dev.linux.lists.cryptsetup |
|---|---|
| Message-ID | <[email protected]> |
Hi, Milan This solves my problem well. Thanks wangzhiqiang 在 2023/2/1 3:50, Milan Broz 写道: > I tried to fix it a little bit differently, > please see https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/481 > > Does this solve the issue for you? > > This is really misconception in older OpenSSL API, so I limit it only there, > new version supports unsigned iteration count (as other libraries). > > > Thanks for the report! > > Milan > > On 1/29/23 13:59, wangzhiqiang (Q) wrote: >> 在 2023/1/29 16:36, Milan Broz 写道: >>> Hi, >>> >>> I think you are patching some old version - manuals are now maintained >>> in adoc format (*.8 files are generated) and that min./max cost mmessage is there, >>> see MINIMAL AND MAXIMAL PBKDF COSTS section in main branch. >> >> Yes. I use the old version(cryptsetup-2.3.3) and openssl version less than 3. >> MINIMAL AND MAXIMAL PBKDF COSTS section in main branch is well. >>> >>> On 1/29/23 04:06, wangzhiqiang (Q) wrote: >>>> From 303dee7999ea8297dad2961020d96710ee87714b Mon Sep 17 00:00:00 2001 >>>> From: wangzhiqiang <[email protected]> >>>> Date: Sat, 28 Jan 2023 15:09:44 +0800 >>>> Subject: [PATCH] check whether the forced iteration count is out of range >>>> >>>> 1. struct crypt_pbkdf_type has a uint32_t variable iterations, but >>>> PKCS5_PBKDF2_HMAC interface of openssl accept int variable, so >>>> return fail when it greater than INT_MAX. >>> >>> yes, but UINT32 limits should be be already checked, see below >> >>> >>>> >>>> 2. add boundary check for the iterations counts. >>> >>> CLI arguments are checked in src/tools_parse_arg_value.c, see how >>> CRYPT_ARG_UINT32 is processed there. It just do not print nice >>> message but only "invalid value" (and that is enough here). >> >> In main branch, tools_parse_arg_value can process UINT32 limits. >>> >>> The PBKDF2 arguments for libcryptsetup API are checked in >>> lib/utils_pbkdf.c. >> >> Function verify_pbkdf_params in lib/utils_pbkdf.c has check PBKDF2 arguments. >>> >>> Do you have some example, where this is not applied and value overflows? >>> If so, it should be fixed in these places. >>> >> I run follow command >> cryptsetup -c aes-xts-plain64 --key-size=512 --hash sha256 luksFormat --pbkdf=pbkdf2 --pbkdf-force-iterations=4294967295 /dev/sdb >> The program is over soon, it is not good because the iterations set to UINT32_MAX, >> the program should take a long time. >>> For the OpenSSL - this is a nice find that it used int in PKCS5_PBKDF2_HMAC() >>> but AFAIK new OSSL_PARAMS OpenSSL3 uses *unsigned* int.. >>> And checking providers PBKDF2 implementation in OpenSSL3 I even see they >>> use uint64 when parsing params. >>> >>> I'll ask OpenSSL - this iteration count should be clearly treated as unsigned. >>> (Cryptsetup has different crypto backends, it must behave the same regarding maximums.) >>> >> All crypto backends should remain the same, but the program cannot be encrypted as expected due to >> type conversion in the environment where OpenSSL of an earlier version is installed. >>> Please, if you can, use main git branch, create an issue or merge request in cryptsetup project, >>> discussion about patches is much easier there. >>> >> Now i have fixed the patch base on main branch. >> >> struct crypt_pbkdf_type has a uint32_t variable iterations, but >> PKCS5_PBKDF2_HMAC accept int variable in openssl(major version >> less than 3), so return EINVAL when it greater than INT_MAX. >> >> Signed-off-by: wangzhiqiang <[email protected]> >> --- >> v1->v2: >> - delete changes of manuals >> - delete check of UINT32 limits >> >> lib/crypto_backend/crypto_openssl.c | 2 +- >> lib/luks2/luks2_keyslot_luks2.c | 1 + >> 2 files changed, 2 insertions(+), 1 deletion(-) >> >> diff --git a/lib/crypto_backend/crypto_openssl.c b/lib/crypto_backend/crypto_openssl.c >> index 24a49549..39dd13a1 100644 >> --- a/lib/crypto_backend/crypto_openssl.c >> +++ b/lib/crypto_backend/crypto_openssl.c >> @@ -571,7 +571,7 @@ static int openssl_pbkdf2(const char *password, size_t password_length, >> EVP_KDF_free(pbkdf2); >> #else >> const EVP_MD *hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash)); >> - if (!hash_id) >> + if (!hash_id || iterations > INT_MAX) >> return -EINVAL; >> >> r = PKCS5_PBKDF2_HMAC(password, (int)password_length, (const unsigned char *)salt, >> diff --git a/lib/luks2/luks2_keyslot_luks2.c b/lib/luks2/luks2_keyslot_luks2.c >> index 78f74242..f01e196b 100644 >> --- a/lib/luks2/luks2_keyslot_luks2.c >> +++ b/lib/luks2/luks2_keyslot_luks2.c >> @@ -264,6 +264,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd, >> pbkdf.parallel_threads); >> free(salt); >> if (r < 0) { >> + log_err(cd, "Invalid parameter."); >> crypt_free_volume_key(derived_key); >> return r; >> } >> -- >> 2.33.0 >>> Thanks, >>> Milan >>> >>> >>>> >>>> Signed-off-by: wangzhiqiang <[email protected]> >>>> --- >>>> lib/crypto_backend/crypto_openssl.c | 2 +- >>>> lib/luks2/luks2_keyslot_luks2.c | 1 + >>>> man/cryptsetup.8 | 14 ++++++++++++++ >>>> src/cryptsetup.c | 5 +++++ >>>> 4 files changed, 21 insertions(+), 1 deletion(-) >>>> >>>> diff --git a/lib/crypto_backend/crypto_openssl.c b/lib/crypto_backend/crypto_openssl.c >>>> index 2edec7b..d76d89f 100644 >>>> --- a/lib/crypto_backend/crypto_openssl.c >>>> +++ b/lib/crypto_backend/crypto_openssl.c >>>> @@ -329,7 +329,7 @@ int crypt_pbkdf(const char *kdf, const char *hash, >>>> { >>>> const EVP_MD *hash_id; >>>> >>>> - if (!kdf) >>>> + if (!kdf || iterations > INT_MAX) >>>> return -EINVAL; >>>> >>>> if (!strcmp(kdf, "pbkdf2")) { >>>> diff --git a/lib/luks2/luks2_keyslot_luks2.c b/lib/luks2/luks2_keyslot_luks2.c >>>> index 156f0c1..fe5f1ed 100644 >>>> --- a/lib/luks2/luks2_keyslot_luks2.c >>>> +++ b/lib/luks2/luks2_keyslot_luks2.c >>>> @@ -254,6 +254,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd, >>>> pbkdf.iterations, pbkdf.max_memory_kb, >>>> pbkdf.parallel_threads); >>>> if (r < 0) { >>>> + log_err(cd, "Invalid parameter."); >>>> crypt_free_volume_key(derived_key); >>>> return r; >>>> } >>>> diff --git a/man/cryptsetup.8 b/man/cryptsetup.8 >>>> index bc3fff6..f6f1fe0 100644 >>>> --- a/man/cryptsetup.8 >>>> +++ b/man/cryptsetup.8 >>>> @@ -1096,6 +1096,20 @@ Note it can cause extremely long unlocking time. Use only is specified >>>> cases, for example, if you know that the formatted device will >>>> be used on some small embedded system. >>>> In this case, the LUKS PBKDF2 digest will be set to the minimum iteration count. >>>> + >>>> +\fBMINIMAL AND MAXIMAL PBKDF COSTS:\fR >>>> +For \fBPBKDF2\fR, the minimum iteration count is 1000 and >>>> +maximum is 4294967295 (maximum for 32bit unsigned integer), >>>> +except openssl, which supports only 2147483647 (maximum for 32bit integer). >>>> +Memory and parallel costs are unused for PBKDF2. >>>> +For \fBArgon2i\fR and \fBArgon2id\fR, minimum iteration count (CPU cost) is 4 and >>>> +maximum is 4294967295 (maximum for 32bit unsigned integer). >>>> +Minimum memory cost is 32 KiB and maximum is 4 GiB. (Limited by addresable >>>> +memory on some CPU platforms.) >>>> +If the memory cost parameter is benchmarked (not specified by a parameter) >>>> +it is always in range from 64 MiB to 1 GiB. >>>> +The parallel cost minimum is 1 and maximum 4 (if enough CPUs cores are available, >>>> +otherwise it is decreased). >>>> .TP >>>> .B "\-\-iter\-time, \-i <number of milliseconds>" >>>> The number of milliseconds to spend with PBKDF passphrase processing. >>>> diff --git a/src/cryptsetup.c b/src/cryptsetup.c >>>> index a0dc14b..decb39a 100644 >>>> --- a/src/cryptsetup.c >>>> +++ b/src/cryptsetup.c >>>> @@ -3921,6 +3921,11 @@ int main(int argc, const char **argv) >>>> _("PBKDF forced iterations cannot be combined with iteration time option."), >>>> poptGetInvocationName(popt_context)); >>>> >>>> + if (opt_pbkdf_iterations < 0 || opt_pbkdf_iterations > UINT32_MAX) >>>> + usage(popt_context, EXIT_FAILURE, >>>> + _("the minimum iteration count is 1000 and maximum is 4294967295."), >>>> + poptGetInvocationName(popt_context)); >>>> + >>>> if (opt_sector_size && strcmp(aname, "reencrypt") && strcmp(aname, "luksFormat") && >>>> (strcmp(aname, "open") || strcmp_or_null(opt_type, "plain"))) >>>> usage(popt_context, EXIT_FAILURE, >>>> -- >>>> 2.27.0 >>>>