From: Milan Broz <gmazyland@gmail.com>
To: "wangzhiqiang (Q)" <wangzhiqiang95@huawei.com>,
cryptsetup@lists.linux.dev
Cc: liuzhiqiang26@huawei.com, linfeilong@huawei.com, lijinlin3@huawei.com
Subject: Re: [PATCH v2] check whether the forced iteration count is out of range
Date: Tue, 31 Jan 2023 20:50:31 +0100 [thread overview]
Message-ID: <da4dc6ca-1dea-8307-7dac-8d51169789f4@gmail.com> (raw)
In-Reply-To: <58e45d98-4ffb-4ff9-8d02-0b9590fe931b@huawei.com>
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 <wangzhiqiang95@huawei.com>
>>> 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 <wangzhiqiang95@huawei.com>
> ---
> 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 <wangzhiqiang95@huawei.com>
>>> ---
>>> 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
>>>
next prev parent reply other threads:[~2023-01-31 19:50 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-29 3:06 [PATCH] check whether the forced iteration count is out of range wangzhiqiang (Q)
2023-01-29 8:36 ` Milan Broz
2023-01-29 12:59 ` [PATCH v2] " wangzhiqiang (Q)
2023-01-31 19:50 ` Milan Broz [this message]
2023-02-02 1:20 ` wangzhiqiang (Q)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=da4dc6ca-1dea-8307-7dac-8d51169789f4@gmail.com \
--to=gmazyland@gmail.com \
--cc=cryptsetup@lists.linux.dev \
--cc=lijinlin3@huawei.com \
--cc=linfeilong@huawei.com \
--cc=liuzhiqiang26@huawei.com \
--cc=wangzhiqiang95@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox