All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lukas Wunner <lukas@wunner.de>
To: Stefan Berger <stefanb@linux.ibm.com>
Cc: keyrings@vger.kernel.org, linux-crypto@vger.kernel.org,
	davem@davemloft.net, herbert@gondor.apana.org.au,
	dhowells@redhat.com, zohar@linux.ibm.com, jarkko@kernel.org,
	linux-integrity@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-kernel@vger.kernel.org, patrick@puiterwijk.org
Subject: Re: [PATCH v12 02/10] crypto: Add support for ECDSA signature verification
Date: Mon, 22 Jul 2024 15:17:33 +0200	[thread overview]
Message-ID: <Zp5b7ZQaXfGbkCVC@wunner.de> (raw)
In-Reply-To: <6eee0c55-40cd-4e7b-8819-1a4c9596062a@linux.ibm.com>

On Mon, Jul 22, 2024 at 08:19:41AM -0400, Stefan Berger wrote:
> On 7/17/24 12:17, Lukas Wunner wrote:
> > On Tue, Mar 16, 2021 at 05:07:32PM -0400, Stefan Berger wrote:
> > > +/*
> > > + * Get the r and s components of a signature from the X509 certificate.
> > > + */
> > > +static int ecdsa_get_signature_rs(u64 *dest, size_t hdrlen, unsigned char tag,
> > > +				  const void *value, size_t vlen, unsigned int ndigits)
> > > +{
> > > +	size_t keylen = ndigits * sizeof(u64);
> > > +	ssize_t diff = vlen - keylen;
> > > +	const char *d = value;
> > > +	u8 rs[ECC_MAX_BYTES];
> > > +
> > > +	if (!value || !vlen)
> > > +		return -EINVAL;
> > > +
> > > +	/* diff = 0: 'value' has exacly the right size
> > > +	 * diff > 0: 'value' has too many bytes; one leading zero is allowed that
> > > +	 *           makes the value a positive integer; error on more
> > > +	 * diff < 0: 'value' is missing leading zeros, which we add
> > > +	 */
> > > +	if (diff > 0) {
> > > +		/* skip over leading zeros that make 'value' a positive int */
> > > +		if (*d == 0) {
> > > +			vlen -= 1;
> > > +			diff--;
> > > +			d++;
> > > +		}
> > > +		if (diff)
> > > +			return -EINVAL;
> > > +	}
> > > +	if (-diff >= keylen)
> > > +		return -EINVAL;
> > 
> > There's an oddity in the above-quoted function.  The check ...
> > 
> > +	if (-diff >= keylen)
> > +		return -EINVAL;
> > 
> > ... seems superfluous.
> 
> You're right, this check is not necessary.

After staring at the code a little longer I've realized that
the purpose of this if-clause is likely to check for a signed
integer overflow.  So it *does* seem to have a purpose,
but it's quite subtle and not very obvious.

I've provisionally added the (untested) commit below to my
development branch to make it more obvious what's going on.
Using check_sub_overflow() might be an alternative.

I want to ask mips maintainers first whether signed integer
overflows can really cause an exception on their arch
as commit 36ccf1c0e391 suggests, despite -fno-strict-overflow...

-- >8 --

Subject: [PATCH] crypto: ecdsa - Avoid signed integer overflow on signature
 decoding

When extracting a signature component R or S from an ASN.1-encoded
integer, ecdsa_get_signature_rs() subtracts the expected length
"bufsize" from the ASN.1 length "vlen" (both of unsigned type size_t)
and stores the result in "diff" (of signed type ssize_t).

This results in a signed integer overflow if vlen > SSIZE_MAX + bufsize.

The kernel is compiled with -fno-strict-overflow, which implies -fwrapv,
meaning signed integer overflow is not undefined behavior.  And the
function does check for overflow:

       if (-diff >= bufsize)
               return -EINVAL;

However that's not very readable and may trigger a false-positive with
CONFIG_UBSAN_SIGNED_WRAP=y.  It also seems that certain Mips CPUs may
raise an exception regardless of -fno-strict-overflow (see do_ov() in
arch/mips/kernel/traps.c).

Avoid by comparing the two unsigned variables directly and erroring out
if "vlen" is too large.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 crypto/ecdsa.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c
index 08c2c76..0cead9b 100644
--- a/crypto/ecdsa.c
+++ b/crypto/ecdsa.c
@@ -36,29 +36,20 @@ static int ecdsa_get_signature_rs(u64 *dest, size_t hdrlen, unsigned char tag,
 				  const void *value, size_t vlen, unsigned int ndigits)
 {
 	size_t bufsize = ndigits * sizeof(u64);
-	ssize_t diff = vlen - bufsize;
 	const char *d = value;
 
-	if (!value || !vlen)
+	if (!value || !vlen || vlen > bufsize + 1)
 		return -EINVAL;
 
-	/* diff = 0: 'value' has exacly the right size
-	 * diff > 0: 'value' has too many bytes; one leading zero is allowed that
-	 *           makes the value a positive integer; error on more
-	 * diff < 0: 'value' is missing leading zeros
-	 */
-	if (diff > 0) {
+	if (vlen > bufsize) {
 		/* skip over leading zeros that make 'value' a positive int */
 		if (*d == 0) {
 			vlen -= 1;
-			diff--;
 			d++;
-		}
-		if (diff)
+		} else {
 			return -EINVAL;
+		}
 	}
-	if (-diff >= bufsize)
-		return -EINVAL;
 
 	ecc_digits_from_bytes(d, vlen, dest, ndigits);
 
-- 
2.43.0

  reply	other threads:[~2024-07-22 13:24 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-16 21:07 [PATCH v12 00/10] Add support for x509 certs with NIST P384/256/192 keys Stefan Berger
2021-03-16 21:07 ` [PATCH v12 01/10] oid_registry: Add OIDs for ECDSA with SHA224/256/384/512 Stefan Berger
2021-03-16 21:07 ` [PATCH v12 02/10] crypto: Add support for ECDSA signature verification Stefan Berger
2024-07-17 16:17   ` Lukas Wunner
2024-07-22 12:19     ` Stefan Berger
2024-07-22 13:17       ` Lukas Wunner [this message]
2021-03-16 21:07 ` [PATCH v12 03/10] crypto: Add NIST P384 curve parameters Stefan Berger
2021-03-16 21:07 ` [PATCH v12 04/10] crypto: Add math to support fast NIST P384 Stefan Berger
2021-03-16 21:07 ` [PATCH v12 05/10] ecdsa: Register NIST P384 and extend test suite Stefan Berger
2021-03-16 21:07 ` [PATCH v12 06/10] x509: Detect sm2 keys by their parameters OID Stefan Berger
2021-03-16 21:07 ` [PATCH v12 07/10] x509: Add support for parsing x509 certs with ECDSA keys Stefan Berger
2021-03-16 21:07 ` [PATCH v12 08/10] ima: Support EC keys for signature verification Stefan Berger
2021-03-16 21:07 ` [PATCH v12 09/10] x509: Add OID for NIST P384 and extend parser for it Stefan Berger
2021-03-16 21:07 ` [PATCH v12 10/10] certs: Add support for using elliptic curve keys for signing modules Stefan Berger
2021-03-16 21:16 ` [PATCH v12 00/10] Add support for x509 certs with NIST P384/256/192 keys Stefan Berger
2021-03-26  9:30 ` Herbert Xu

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=Zp5b7ZQaXfGbkCVC@wunner.de \
    --to=lukas@wunner.de \
    --cc=davem@davemloft.net \
    --cc=dhowells@redhat.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=jarkko@kernel.org \
    --cc=keyrings@vger.kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=patrick@puiterwijk.org \
    --cc=stefanb@linux.ibm.com \
    --cc=zohar@linux.ibm.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.