diff mbox series

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

Message ID dcb40882817bb4c9396ca2dc209360ed7d4b9af9.1725972335.git.lukas@wunner.de
State New
Headers show
Series Migrate to sig_alg and templatize ecdsa | expand

Commit Message

Lukas Wunner Sept. 10, 2024, 2:30 p.m. UTC
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@wunner.de>
---
 crypto/rsassa-pkcs1.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)
diff mbox series

Patch

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.
+	 */
+	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 */