From 673065630bf4aaf03c370fc791ef6a6239431214 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Veronika=20Hanul=C3=ADkov=C3=A1?= <vhanulik@redhat.com>
Date: Wed, 17 Jul 2024 09:15:43 +0200
Subject: [PATCH] pkcs15-gemsafeV1: Check length of buffer for object

Number of actually read bytes may differ from
the stated object length.

Thanks Matteo Marini for report
https://github.com/OpenSC/OpenSC/security/advisories/GHSA-p3mx-7472-h3j8

fuzz_pkcs15_crypt/15

CVE: CVE-2024-45619
Upstream-Status: Backport [https://github.com/OpenSC/OpenSC/commit/673065630bf4aaf03c370fc791ef6a6239431214]

Signed-off-by: Zhang Peng <peng.zhang1.cn@windriver.com>
---
 src/libopensc/pkcs15-gemsafeV1.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/src/libopensc/pkcs15-gemsafeV1.c b/src/libopensc/pkcs15-gemsafeV1.c
index add4c3e68..46cc420bf 100644
--- a/src/libopensc/pkcs15-gemsafeV1.c
+++ b/src/libopensc/pkcs15-gemsafeV1.c
@@ -168,6 +168,7 @@ static int gemsafe_get_cert_len(sc_card_t *card)
 	struct sc_file *file;
 	size_t objlen, certlen;
 	unsigned int ind, i=0;
+	int read_len;
 
 	sc_format_path(GEMSAFE_PATH, &path);
 	r = sc_select_file(card, &path, &file);
@@ -176,9 +177,11 @@ static int gemsafe_get_cert_len(sc_card_t *card)
 	sc_file_free(file);
 
 	/* Initial read */
-	r = sc_read_binary(card, 0, ibuf, GEMSAFE_READ_QUANTUM, 0);
-	if (r < 0)
+	read_len = sc_read_binary(card, 0, ibuf, GEMSAFE_READ_QUANTUM, 0);
+	if (read_len <= 2) {
+		sc_log(card->ctx, "Invalid size of object data: %d", read_len);
 		return SC_ERROR_INTERNAL;
+	}
 
 	/* Actual stored object size is encoded in first 2 bytes
 	 * (allocated EF space is much greater!)
@@ -207,7 +210,7 @@ static int gemsafe_get_cert_len(sc_card_t *card)
 	 * the private key.
 	 */
 	ind = 2; /* skip length */
-	while (ibuf[ind] == 0x01 && i < gemsafe_cert_max) {
+	while (ind + 1 < (size_t)read_len && ibuf[ind] == 0x01 && i < gemsafe_cert_max) {
 		if (ibuf[ind+1] == 0xFE) {
 			gemsafe_prkeys[i].ref = ibuf[ind+4];
 			sc_log(card->ctx, "Key container %d is allocated and uses key_ref %d",
@@ -234,7 +237,7 @@ static int gemsafe_get_cert_len(sc_card_t *card)
 	/* Read entire file, then dissect in memory.
 	 * Gemalto ClassicClient seems to do it the same way.
 	 */
-	iptr = ibuf + GEMSAFE_READ_QUANTUM;
+	iptr = ibuf + read_len;
 	while ((size_t)(iptr - ibuf) < objlen) {
 		r = sc_read_binary(card, iptr - ibuf, iptr,
 				   MIN(GEMSAFE_READ_QUANTUM, objlen - (iptr - ibuf)), 0);
@@ -242,7 +245,14 @@ static int gemsafe_get_cert_len(sc_card_t *card)
 			sc_log(card->ctx, "Could not read cert object");
 			return SC_ERROR_INTERNAL;
 		}
-		iptr += GEMSAFE_READ_QUANTUM;
+		if (r == 0)
+			break;
+		read_len += r;
+		iptr += r;
+	}
+	if ((size_t)read_len < objlen) {
+		sc_log(card->ctx, "Could not read cert object");
+		return SC_ERROR_INTERNAL;
 	}
 
 	/* Search buffer for certificates, they start with 0x3082. */
--
2.34.1
