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.23.0/src/libopensc/pkcs15-tcos.c
===================================================================
--- opensc-0.23.0.orig/src/libopensc/pkcs15-tcos.c
+++ opensc-0.23.0/src/libopensc/pkcs15-tcos.c
@@ -45,6 +45,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));
@@ -57,24 +58,31 @@ 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_log(ctx, 
-			"Select(%s) failed\n", path);
+	if (sc_select_file(card, &cert_info.path, NULL) != SC_SUCCESS) {
+		sc_log(ctx, "Select(%s) failed", path);
 		return 1;
 	}
-	if(sc_read_binary(card, 0, cert, sizeof(cert), 0)<0){
-		sc_log(ctx, 
-			"ReadBinary(%s) failed\n", path);
+	r = sc_read_binary(card, 0, cert, sizeof(cert), 0);
+	if (r <= 0) {
+		sc_log(ctx, "ReadBinary(%s) failed\n", path);
 		return 2;
 	}
-	if(cert[0]!=0x30 || cert[1]!=0x82){
-		sc_log(ctx, 
-			"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_log(ctx, "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 {
@@ -82,12 +90,12 @@ static int insert_cert(
 		cert_info.path.count=(cert[2]<<8) + cert[3] + 4;
 	}
 
-	r=sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
-	if(r!=SC_SUCCESS){
-		sc_log(ctx,  "sc_pkcs15emu_add_x509_cert(%s) failed\n", path);
+	r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
+	if (r != SC_SUCCESS) {
+		sc_log(ctx, "sc_pkcs15emu_add_x509_cert(%s) failed", path);
 		return 4;
 	}
-	sc_log(ctx,  "%s: OK, Index=%d, Count=%d\n", path, cert_info.path.index, cert_info.path.count);
+	sc_log(ctx, "%s: OK, Index=%d, Count=%d", path, cert_info.path.index, cert_info.path.count);
 	return 0;
 }
 
Index: opensc-0.23.0/src/libopensc/pkcs15-gemsafeV1.c
===================================================================
--- opensc-0.23.0.orig/src/libopensc/pkcs15-gemsafeV1.c
+++ opensc-0.23.0/src/libopensc/pkcs15-gemsafeV1.c
@@ -168,6 +168,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);
@@ -176,9 +177,11 @@ static int gemsafe_get_cert_len(sc_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_
 	 * 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_
 	/* 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_
 			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.23.0/src/pkcs15init/pkcs15-setcos.c
===================================================================
--- opensc-0.23.0.orig/src/pkcs15init/pkcs15-setcos.c
+++ opensc-0.23.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);
 		LOG_TEST_RET(ctx, 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_log(ctx, 
@@ -495,7 +498,7 @@ setcos_generate_key(struct sc_profile *p
 				 keybits, key_info->modulus_length);
 			LOG_TEST_RET(ctx, 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.23.0/src/pkcs15init/pkcs15-sc-hsm.c
===================================================================
--- opensc-0.23.0.orig/src/pkcs15init/pkcs15-sc-hsm.c
+++ opensc-0.23.0/src/pkcs15init/pkcs15-sc-hsm.c
@@ -140,7 +140,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.23.0/src/libopensc/card-coolkey.c
===================================================================
--- opensc-0.23.0.orig/src/libopensc/card-coolkey.c
+++ opensc-0.23.0/src/libopensc/card-coolkey.c
@@ -1684,6 +1684,7 @@ static int coolkey_rsa_op(sc_card_t *car
 	u8 key_number;
 	size_t params_len;
 	u8 buf[MAX_COMPUTE_BUF + 2];
+	size_t buf_len;
 	u8 *buf_out;
 
 	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
@@ -1724,8 +1725,6 @@ static int coolkey_rsa_op(sc_card_t *car
 		ushort2bebytes(params.init.buf_len, 0);
 	} else {
 		/* The data fits in APDU. Copy it to the params object */
-		size_t buf_len;
-
 		params.init.location = COOLKEY_CRYPT_LOCATION_APDU;
 
 		params_len = sizeof(params.init) + datalen;
@@ -1745,6 +1744,7 @@ static int coolkey_rsa_op(sc_card_t *car
 	if (r < 0) {
 		goto done;
 	}
+	buf_len = crypt_out_len_p;
 
 	if (datalen > MAX_COMPUTE_BUF) {
 		u8 len_buf[2];
@@ -1763,7 +1763,12 @@ 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;
