From 360e95d45ac4123255a4c796db96337f332160ad Mon Sep 17 00:00:00 2001
From: Frank Morgner <frankmorgner@gmail.com>
Date: Fri, 25 May 2018 23:34:14 +0200
Subject: [PATCH] fixed out of bounds writes

Thanks to Eric Sesterhenn from X41 D-SEC GmbH
for reporting the problems.
---
 src/libopensc/card-cac.c         |  2 +-
 src/libopensc/card-epass2003.c   |  3 ++-
 src/libopensc/card-muscle.c      |  7 +++++--
 src/libopensc/card-tcos.c        |  6 +++---
 src/libopensc/pkcs15-esteid.c    |  2 +-
 src/libopensc/pkcs15-gemsafeV1.c |  2 +-
 src/libopensc/pkcs15-sc-hsm.c    | 14 ++++++++------
 src/libopensc/sc.c               |  2 +-
 src/tools/cryptoflex-tool.c      |  5 +++--
 src/tools/egk-tool.c             |  2 +-
 src/tools/util.c                 |  5 +++--
 11 files changed, 29 insertions(+), 21 deletions(-)

Index: opensc-0.11.6/src/libopensc/card-muscle.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/card-muscle.c
+++ opensc-0.11.6/src/libopensc/card-muscle.c
@@ -493,7 +493,9 @@ static int muscle_list_files(sc_card_t *
 	mscfs_check_cache(priv->fs);
 	
 	for(x = 0; x < fs->cache.size; x++) {
-		u8* oid= fs->cache.array[x].objectId.id;
+		u8* oid = fs->cache.array[x].objectId.id;
+		if (bufLen < 2)
+			break;
 		if (card->ctx->debug >= 2) {
 			sc_debug(card->ctx, "FILE: %02X%02X%02X%02X\n",
 				oid[0],oid[1],oid[2],oid[3]);
@@ -503,7 +505,8 @@ static int muscle_list_files(sc_card_t *
 			buf[1] = oid[3];
 			if(buf[0] == 0x00 && buf[1] == 0x00) continue; /* No directories/null names outside of root */
 			buf += 2;
-			count+=2;
+			count += 2;
+			bufLen -= 2;
 		}
 	}
 	return count;
Index: opensc-0.11.6/src/libopensc/card-tcos.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/card-tcos.c
+++ opensc-0.11.6/src/libopensc/card-tcos.c
@@ -399,7 +399,7 @@ static int tcos_select_file(sc_card_t *c
 	file->path = *in_path;
 
 	for(i=2; i+1<apdu.resplen && i+1+apdu.resp[i+1]<apdu.resplen; i+=2+apdu.resp[i+1]){
-		int j, len=apdu.resp[i+1];
+		size_t j, len=apdu.resp[i+1];
 		unsigned char type=apdu.resp[i], *d=apdu.resp+i+2;
 
 		switch (type) {
@@ -423,8 +423,8 @@ static int tcos_select_file(sc_card_t *c
 			file->id = (d[0]<<8) | d[1];
 			break;
 		case 0x84:
-			memcpy(file->name, d, len);
-			file->namelen = len;
+			file->namelen = MIN(sizeof file->name, len);
+			memcpy(file->name, d, file->namelen);
 			break;
 		case 0x86:
 			sc_file_set_sec_attr(file, d, len); 
Index: opensc-0.11.6/src/libopensc/pkcs15-esteid.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/pkcs15-esteid.c
+++ opensc-0.11.6/src/libopensc/pkcs15-esteid.c
@@ -72,7 +72,7 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card
 	r = sc_read_record (card, SC_ESTEID_PD_DOCUMENT_NR, buff, 8,
 	                    SC_RECORD_BY_REC_NR);
 	SC_TEST_RET (card->ctx, r, "read document number failed");
-	buff[r] = '\0';
+	buff[MIN((size_t) r, (sizeof buff)-1)] = '\0';
 	set_string (&p15card->serial_number, (const char *) buff);
 
 	p15card->flags = SC_PKCS15_CARD_FLAG_PRN_GENERATION
Index: opensc-0.11.6/src/libopensc/pkcs15-gemsafeV1.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/pkcs15-gemsafeV1.c
+++ opensc-0.11.6/src/libopensc/pkcs15-gemsafeV1.c
@@ -59,6 +59,8 @@ typedef struct cdata_st {
 	int         obj_flags;
 } cdata;
 
+const unsigned int gemsafe_cert_max = 12;
+
 const cdata gemsafe_cert[] = {
 	{"DS certificate", 0, "3F0016000004","45", SC_PKCS15_CO_FLAG_MODIFIABLE},
 	{NULL, 0, NULL, 0, 0}
@@ -158,7 +160,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) {
+	while (ibuf[ind] == 0x01 && i < gemsafe_cert_max) {
 		if (ibuf[ind+1] == 0xFE) {
 			*key_ref = ibuf[ind+4];
 			sc_debug(card->ctx, "Using key_ref %d found at offset %d\n",
Index: opensc-0.11.6/src/libopensc/sc.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/sc.c
+++ opensc-0.11.6/src/libopensc/sc.c
@@ -554,7 +554,7 @@ int sc_file_set_sec_attr(sc_file_t *file
 	u8 *tmp;
 	assert(sc_file_valid(file));
 
-	if (sec_attr == NULL) {
+	if (sec_attr == NULL || sec_attr_len) {
 		if (file->sec_attr != NULL)
 			free(file->sec_attr);
 		file->sec_attr = NULL;
Index: opensc-0.11.6/src/tools/cryptoflex-tool.c
===================================================================
--- opensc-0.11.6.orig/src/tools/cryptoflex-tool.c
+++ opensc-0.11.6/src/tools/cryptoflex-tool.c
@@ -28,6 +28,7 @@
 #include <openssl/err.h>
 #include <opensc/pkcs15.h>
 #include <compat_strlcpy.h>
+#include "../libopensc/internal.h"
 #include "util.h"
 
 static const char *app_name = "cryptoflex-tool";
@@ -347,7 +348,7 @@ static int read_public_key(RSA *rsa)
 		fprintf(stderr, "Unable to select public key file: %s\n", sc_strerror(r));
 		return 2;
 	}
-	bufsize = file->size;
+	bufsize = MIN(file->size, sizeof buf);
 	sc_file_free(file);
 	r = sc_read_binary(card, 0, buf, bufsize, 0);
 	if (r < 0) {
@@ -398,7 +399,7 @@ static int read_private_key(RSA *rsa)
 	e = sc_file_get_acl_entry(file, SC_AC_OP_READ);
 	if (e == NULL || e->method == SC_AC_NEVER)
 		return 10;
-	bufsize = file->size;
+	bufsize = MIN(file->size, sizeof buf);
 	sc_file_free(file);
 	r = sc_read_binary(card, 0, buf, bufsize, 0);
 	if (r < 0) {
Index: opensc-0.11.6/src/tools/util.c
===================================================================
--- opensc-0.11.6.orig/src/tools/util.c
+++ opensc-0.11.6/src/tools/util.c
@@ -228,10 +228,11 @@ const char * util_acl_to_str(const sc_ac
 			strcpy(buf, "????");
 			break;
 		}
-		strcat(line, buf);
-		strcat(line, " ");
+		strncat(line, buf, sizeof line);
+		strncat(line, " ", sizeof line);
 		e = e->next;
 	}
+	line[(sizeof line)-1] = '\0'; /* make sure it's NUL terminated */
 	line[strlen(line)-1] = 0; /* get rid of trailing space */
 	return line;
 }
