commit f01bfbd19b9c8243a40f7f17d554fe0eb9e89d0d
Author: Veronika Hanulíková <vhanulik@redhat.com>
Date:   Tue Jul 16 14:22:02 2024 +0200

    pkcs15-tcos: Check number of read bytes for cert
    
    Thanks Matteo Marini for report
    https://github.com/OpenSC/OpenSC/security/advisories/GHSA-p3mx-7472-h3j8
    
    fuzz_pkcs11/15

Index: opensc-0.13.0/src/libopensc/pkcs15-tcos.c
===================================================================
--- opensc-0.13.0.orig/src/libopensc/pkcs15-tcos.c
+++ opensc-0.13.0/src/libopensc/pkcs15-tcos.c
@@ -46,6 +46,7 @@ static int insert_cert(
 	struct sc_pkcs15_cert_info cert_info;
 	struct sc_pkcs15_object cert_obj;
 	unsigned char cert[20];
+	size_t cert_len = 0;
 	int r;
 
 	memset(&cert_info, 0, sizeof(cert_info));
@@ -63,11 +64,17 @@ static int insert_cert(
 			"Select(%s) failed\n", path);
 		return 1;
 	}
-	if(sc_read_binary(card, 0, cert, sizeof(cert), 0)<0){
+	r = sc_read_binary(card, 0, cert, sizeof(cert), 0);
+	if (r < 0) {
 		sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
 			"ReadBinary(%s) failed\n", path);
 		return 2;
 	}
+        cert_len = r; /* actual number of read bytes */
+        if (cert_len < 7 || (size_t)(7 + cert[5]) > cert_len) {
+                sc_log(ctx, "Invalid certificate length");
+                return 3;
+        }
 	if(cert[0]!=0x30 || cert[1]!=0x82){
 		sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
 			"Invalid Cert: %02X:%02X:...\n", cert[0], cert[1]);
@@ -76,6 +83,10 @@ static int insert_cert(
 
 	/* some certificates are prefixed by an OID */
 	if(cert[4]==0x06 && cert[5]<10 && cert[6+cert[5]]==0x30 && cert[7+cert[5]]==0x82){
+                if ((size_t)(9 + cert[5]) > cert_len) {
+                        sc_log(ctx, "Invalid certificate length");
+                        return 3;
+                }
 		cert_info.path.index=6+cert[5];
 		cert_info.path.count=(cert[8+cert[5]]<<8) + cert[9+cert[5]] + 4;
 	} else {
Index: opensc-0.13.0/src/libopensc/pkcs15-gemsafeV1.c
===================================================================
--- opensc-0.13.0.orig/src/libopensc/pkcs15-gemsafeV1.c
+++ opensc-0.13.0/src/libopensc/pkcs15-gemsafeV1.c
@@ -131,6 +131,7 @@ static int gemsafe_get_cert_len(sc_card_
 	unsigned int block=0;
 	int found = 0;
 	unsigned int offset=0, index_local, i=0;
+	int read_len;
 
 	r = sc_select_file(card, path, &file);
 	if (r < 0)
@@ -138,9 +139,11 @@ static int gemsafe_get_cert_len(sc_card_
 
 	/* Apparently, the Applet max read "quanta" is 248 bytes */
 	/* Initial read */
-	r = sc_read_binary(card, offset, ibuf, 248, 0);
-	if (r < 0)
-		return 0;
+	read_len = sc_read_binary(card, offset, ibuf, 248, 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!)
@@ -163,7 +166,7 @@ static int gemsafe_get_cert_len(sc_card_
 	 * the key_ref in the opensc.conf with flag = n.
 	 */
 	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) {
 			*key_ref = ibuf[ind+4];
 			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Using key_ref %d found at offset %d\n",
@@ -192,9 +195,16 @@ static int gemsafe_get_cert_len(sc_card_
 		    sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s: Could not read cert object\n", fn_name);
 		    return 0;
 		}
+		if (r == 0)
+			break;
+		read_len += r;
 	    }
 
 	}
+        if ((size_t)read_len < objlen) {
+                sc_log(card->ctx, "Could not read cert object");
+                return SC_ERROR_INTERNAL;
+        }
 
 	index_local = block*248 + i;
 
Index: opensc-0.13.0/src/pkcs15init/pkcs15-setcos.c
===================================================================
--- opensc-0.13.0.orig/src/pkcs15init/pkcs15-setcos.c
+++ opensc-0.13.0/src/pkcs15init/pkcs15-setcos.c
@@ -486,13 +486,16 @@ setcos_generate_key(struct sc_profile *p
 		r = sc_card_ctl(p15card->card, SC_CARDCTL_SETCOS_GETDATA, &data_obj);
 		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot get key modulus: 'SETCOS_GETDATA' failed");
 
+		if (data_obj.DataLen < 3 || data_obj.DataLen < pubkey->u.rsa.modulus.len)
+			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Cannot get key modulus: wrong length of raw key");
+
 		keybits = ((raw_pubkey[0] * 256) + raw_pubkey[1]);  /* modulus bit length */
 		if (keybits != key_info->modulus_length)  {
 			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "key-size from card[%i] does not match[%i]\n",
 					keybits, key_info->modulus_length);
 			SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_PKCS15INIT, "Failed to generate key");
 		}
-		memcpy (pubkey->u.rsa.modulus.data, &raw_pubkey[2], pubkey->u.rsa.modulus.len);
+		memcpy(pubkey->u.rsa.modulus.data, &raw_pubkey[2], pubkey->u.rsa.modulus.len);
 	}
 
 	sc_file_free(file);
Index: opensc-0.13.0/src/pkcs15init/pkcs15-sc-hsm.c
===================================================================
--- opensc-0.13.0.orig/src/pkcs15init/pkcs15-sc-hsm.c
+++ opensc-0.13.0/src/pkcs15init/pkcs15-sc-hsm.c
@@ -211,7 +211,7 @@ static int sc_hsm_determine_free_id(stru
 	LOG_TEST_RET(card->ctx, filelistlength, "Could not enumerate file and key identifier");
 
 	for (j = 0; j < 256; j++) {
-		for (i = 0; i < filelistlength; i += 2) {
+		for (i = 0; i + 1 < filelistlength; i += 2) {
 			if ((filelist[i] == range) && (filelist[i + 1] == j)) {
 				break;
 			}
