Re: [PATCH v2 07/19] crypto: rsassa-pkcs1 - Harden digest length verification

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue Sep 10, 2024 at 5:30 PM EEST, Lukas Wunner wrote:
> The RSASSA-PKCS1-v1_5 sign operation currently only checks that the
> digest length is less than "key_size - hash_prefix->size - 11".
> The verify operation merely checks that it's more than zero.
>
> Actually the precise digest length is known because the hash algorithm
> is specified upon instance creation and the digest length is encoded
> into the final byte of the hash algorithm's Full Hash Prefix.
>
> So check for the exact digest length rather than solely relying on
> imprecise maximum/minimum checks.
>
> Keep the maximum length check for the sign operation as a safety net,
> but drop the now unnecessary minimum check for the verify operation.
>
> Signed-off-by: Lukas Wunner <lukas@xxxxxxxxx>
> ---
>  crypto/rsassa-pkcs1.c | 20 +++++++++++++++++++-
>  1 file changed, 19 insertions(+), 1 deletion(-)
>
> diff --git a/crypto/rsassa-pkcs1.c b/crypto/rsassa-pkcs1.c
> index 779c080fc013..8f42a5712806 100644
> --- a/crypto/rsassa-pkcs1.c
> +++ b/crypto/rsassa-pkcs1.c
> @@ -11,6 +11,7 @@
>  #include <linux/scatterlist.h>
>  #include <crypto/akcipher.h>
>  #include <crypto/algapi.h>
> +#include <crypto/hash.h>
>  #include <crypto/sig.h>
>  #include <crypto/internal/akcipher.h>
>  #include <crypto/internal/rsa.h>
> @@ -118,6 +119,20 @@ static const struct hash_prefix *rsassa_pkcs1_find_hash_prefix(const char *name)
>  	return NULL;
>  }
>  
> +static unsigned int rsassa_pkcs1_hash_len(const struct hash_prefix *p)
> +{
> +	/*
> +	 * The final byte of the Full Hash Prefix encodes the hash length.
> +	 *
> +	 * This needs to be revisited should hash algorithms with more than
> +	 * 1016 bits (127 bytes * 8) ever be added.  The length would then
> +	 * be encoded into more than one byte by ASN.1.
> +	 */

Maybe this could be moved outside the function.

> +	static_assert(HASH_MAX_DIGESTSIZE <= 127);
> +
> +	return p->data[p->size - 1];
> +}
> +
>  struct rsassa_pkcs1_ctx {
>  	struct crypto_akcipher *child;
>  	unsigned int key_size;
> @@ -152,6 +167,9 @@ static int rsassa_pkcs1_sign(struct crypto_sig *tfm,
>  	if (dlen < ctx->key_size)
>  		return -EOVERFLOW;
>  
> +	if (slen != rsassa_pkcs1_hash_len(hash_prefix))
> +		return -EINVAL;
> +
>  	if (slen + hash_prefix->size > ctx->key_size - 11)
>  		return -EOVERFLOW;
>  
> @@ -217,7 +235,7 @@ static int rsassa_pkcs1_verify(struct crypto_sig *tfm,
>  	/* RFC 8017 sec 8.2.2 step 1 - length checking */
>  	if (!ctx->key_size ||
>  	    slen != ctx->key_size ||
> -	    !dlen)
> +	    dlen != rsassa_pkcs1_hash_len(hash_prefix))
>  		return -EINVAL;
>  
>  	/* RFC 8017 sec 8.2.2 step 2 - RSA verification */


BR, Jarkko





[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]
  Powered by Linux