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.19.0/src/libopensc/pkcs15-tcos.c
===================================================================
--- opensc-0.19.0.orig/src/libopensc/pkcs15-tcos.c
+++ opensc-0.19.0/src/libopensc/pkcs15-tcos.c
@@ -50,6 +50,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));
@@ -62,24 +63,32 @@ static int insert_cert(
 	strlcpy(cert_obj.label, label, sizeof(cert_obj.label));
 	cert_obj.flags = writable ? SC_PKCS15_CO_FLAG_MODIFIABLE : 0;
 
-	if(sc_select_file(card, &cert_info.path, NULL)!=SC_SUCCESS){
-		sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
-			"Select(%s) failed\n", path);
+	if(sc_select_file(card, &cert_info.path, NULL) != SC_SUCCESS) {
+		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Select(%s) failed\n", path);
 		return 1;
 	}
-	if(sc_read_binary(card, 0, cert, sizeof(cert), 0)<0){
-		sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
-			"ReadBinary(%s) failed\n", path);
+	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;
 	}
-	if(cert[0]!=0x30 || cert[1]!=0x82){
-		sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
-			"Invalid Cert: %02X:%02X:...\n", cert[0], cert[1]);
+
+	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]);
 		return 3;
 	}
 
 	/* 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 (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.19.0/src/libopensc/pkcs15-gemsafeV1.c
===================================================================
--- opensc-0.19.0.orig/src/libopensc/pkcs15-gemsafeV1.c
+++ opensc-0.19.0/src/libopensc/pkcs15-gemsafeV1.c
@@ -170,6 +170,7 @@ static int gemsafe_get_cert_len(sc_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);
@@ -177,9 +178,11 @@ static int gemsafe_get_cert_len(sc_card_
 		return SC_ERROR_INTERNAL;
 
 	/* 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!)
@@ -208,7 +211,7 @@ static int gemsafe_get_cert_len(sc_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",
@@ -235,7 +238,7 @@ static int gemsafe_get_cert_len(sc_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);
@@ -243,7 +246,14 @@ static int gemsafe_get_cert_len(sc_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. */
Index: opensc-0.19.0/src/pkcs15init/pkcs15-setcos.c
===================================================================
--- opensc-0.19.0.orig/src/pkcs15init/pkcs15-setcos.c
+++ opensc-0.19.0/src/pkcs15init/pkcs15-setcos.c
@@ -488,6 +488,9 @@ 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,
@@ -495,7 +498,7 @@ setcos_generate_key(struct sc_profile *p
 				 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.19.0/src/pkcs15init/pkcs15-sc-hsm.c
===================================================================
--- opensc-0.19.0.orig/src/pkcs15init/pkcs15-sc-hsm.c
+++ opensc-0.19.0/src/pkcs15init/pkcs15-sc-hsm.c
@@ -139,7 +139,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;
 			}
Index: opensc-0.19.0/src/libopensc/card-coolkey.c
===================================================================
--- opensc-0.19.0.orig/src/libopensc/card-coolkey.c
+++ opensc-0.19.0/src/libopensc/card-coolkey.c
@@ -1684,8 +1684,8 @@ static int coolkey_rsa_op(sc_card_t *car
 	coolkey_compute_crypt_params_t params;
 	u8 key_number;
 	size_t params_len;
-	size_t buf_len;
 	u8 buf[MAX_COMPUTE_BUF+2];
+	size_t buf_len;
 	u8 *buf_out;
 
 	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
@@ -1741,6 +1741,7 @@ static int coolkey_rsa_op(sc_card_t *car
 	if (crypt_in_len) {
 		memcpy(params.buf, crypt_in, crypt_in_len);
 	}
+	buf_len = *crypt_out_len_p;
 
 
 	r = coolkey_apdu_io(card, COOLKEY_CLASS, COOLKEY_INS_COMPUTE_CRYPT,
@@ -1767,7 +1768,16 @@ static int coolkey_rsa_op(sc_card_t *car
 					priv->nonce, sizeof(priv->nonce));
 
 	} else {
-		size_t out_length = bebytes2ushort(buf);
+		size_t out_length;
+                if (buf_len < 2) {
+                        r = SC_ERROR_WRONG_LENGTH;
+                        goto done;
+                }
+                out_length = bebytes2ushort(buf);
+                if (out_length > sizeof buf - 2) {
+                        r = SC_ERROR_WRONG_LENGTH;
+                        goto done;
+ 		}
 		out_length = MIN(out_length, max_out_len);
 		memcpy(out, buf+2, out_length);
 		r = out_length;
