From 8fe377e93b4b56060e5bbfb6f3142ceaeca744fa Mon Sep 17 00:00:00 2001
From: Frank Morgner <frankmorgner@gmail.com>
Date: Fri, 25 May 2018 14:54:47 +0200
Subject: [PATCH] fixed out of bounds reads

Thanks to Eric Sesterhenn from X41 D-SEC GmbH
for reporting and suggesting security fixes.
---
 src/libopensc/asn1.c           |  1 +
 src/libopensc/card-asepcos.c   |  2 +-
 src/libopensc/card-authentic.c |  5 ++++-
 src/libopensc/card-cac.c       |  9 +++++++--
 src/libopensc/card-coolkey.c   |  2 +-
 src/libopensc/card-entersafe.c |  8 +++++---
 src/libopensc/card-epass2003.c | 35 ++++++++++++++++++----------------
 src/libopensc/card-gpk.c       |  3 +++
 src/libopensc/card-iasecc.c    |  2 +-
 src/libopensc/card-oberthur.c  |  7 +++++++
 src/libopensc/card-openpgp.c   |  6 ++++++
 src/libopensc/card-piv.c       |  9 +++++----
 src/libopensc/card-rtecp.c     |  2 +-
 src/libopensc/card-setcos.c    | 18 +++++++++++++++--
 src/libopensc/ef-gdo.c         |  2 +-
 src/libopensc/pkcs15-itacns.c  |  1 +
 src/libopensc/pkcs15-tcos.c    |  8 +++++---
 src/tools/opensc-tool.c        | 21 ++++++++++----------
 18 files changed, 95 insertions(+), 46 deletions(-)

Index: opensc-0.11.6/src/libopensc/asn1.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/asn1.c
+++ opensc-0.11.6/src/libopensc/asn1.c
@@ -91,6 +91,7 @@ int sc_asn1_read_tag(const u8 ** buf, si
 	len = *p & 0x7f;
 	if (*p++ & 0x80) {
 		unsigned int a = 0;
+		left--;
 		if (len > 4 || len > left)
 			return SC_ERROR_INVALID_ASN1_OBJECT;
 		left -= len;
Index: opensc-0.11.6/src/libopensc/card-asepcos.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/card-asepcos.c
+++ opensc-0.11.6/src/libopensc/card-asepcos.c
@@ -164,7 +164,7 @@ static int asepcos_parse_sec_attr(sc_car
 
 	while (len != 0) {
 		unsigned int amode, tlen = 3;
-		if (len < 5 && p[0] != 0x80 && p[1] != 0x01) {
+		if (len < 5 || p[0] != 0x80 || p[1] != 0x01) {
 			sc_error(card->ctx, "invalid access mode encoding");
 			return SC_ERROR_INTERNAL;
 		}
Index: opensc-0.11.6/src/libopensc/card-entersafe.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/card-entersafe.c
+++ opensc-0.11.6/src/libopensc/card-entersafe.c
@@ -1252,10 +1252,12 @@ static int entersafe_gen_key(sc_card_t *
 		 SC_FUNC_RETURN(card->ctx,4,SC_ERROR_OUT_OF_MEMORY);
 
 	p=rbuf;
-	assert(*p=='E');
+	if (*p!='E')
+		SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_DATA);
 	p+=2+p[1];
 	/* N */
-	assert(*p=='N');
+	if (*p!='N')
+               SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_DATA);
 	++p;
 	if(*p++>0x80)
 	{
Index: opensc-0.11.6/src/libopensc/card-gpk.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/card-gpk.c
+++ opensc-0.11.6/src/libopensc/card-gpk.c
@@ -449,6 +449,9 @@ gpk_parse_fileinfo(sc_card_t *card,
 		if (sp[0] == 0x85) {
 			unsigned int	ac[3], n;
 
+			if (sp + 11 + 2*3 >= end)
+				break;
+
 			file->id = (sp[4] << 8) | sp[5];
 			file->size = (sp[8] << 8) | sp[9];
 			file->record_length = sp[7];
Index: opensc-0.11.6/src/libopensc/card-oberthur.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/card-oberthur.c
+++ opensc-0.11.6/src/libopensc/card-oberthur.c
@@ -519,6 +519,9 @@ auth_select_file(sc_card_t *card, const
 	assert(card != NULL && in_path != NULL);
 
 	memcpy(&path, in_path, sizeof(sc_path_t));
+
+	if (!auth_current_df)
+               return SC_ERROR_OBJECT_NOT_FOUND;
 	
 	sc_debug(card->ctx, "in_path; type=%d, path=%s, out %p\n", 
 			in_path->type, sc_print_path(in_path), file_out);
@@ -2053,6 +2056,10 @@ auth_read_binary(sc_card_t *card, unsign
 #endif
 	
 	SC_FUNC_CALLED(card->ctx, 1);
+
+	if (!auth_current_ef)
+               SC_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid auth_current_ef");
+
 	sc_debug(card->ctx,"offset %i; size %i; flags 0x%lX\n", offset, count, flags);
 	sc_debug(card->ctx,"last selected : magic %X; ef %X\n", 
 			auth_current_ef->magic, auth_current_ef->ef_structure);
Index: opensc-0.11.6/src/libopensc/card-openpgp.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/card-openpgp.c
+++ opensc-0.11.6/src/libopensc/card-openpgp.c
@@ -268,11 +268,18 @@ pgp_enumerate_blob(sc_card_t *card, stru
 	while (in < end) {
 		unsigned int	tag, len, type = SC_FILE_TYPE_WORKING_EF;
 		unsigned char	c;
+		const u8 	*data = in;
+
+		if (!in)
+			return SC_ERROR_OBJECT_NOT_VALID;
 
 		c = *in++;
 		if (c == 0x00 || c == 0xFF)
 			continue;
 
+		if (data + len > blob->data + blob->len)
+			return SC_ERROR_OBJECT_NOT_VALID;
+
 		tag = c;
 		if (tag & 0x20)
 			type = SC_FILE_TYPE_DF;
Index: opensc-0.11.6/src/libopensc/card-setcos.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/card-setcos.c
+++ opensc-0.11.6/src/libopensc/card-setcos.c
@@ -786,6 +786,8 @@ static void parse_sec_attr_44(sc_file_t
 	/* Check all sub-AC definitions whitin the total AC */
 	while (len > 1) {				/* minimum length = 2 */
 		int	iACLen   = buf[iOffset] & 0x0F;
+		if ((size_t) iACLen > len)
+			break;
 
 		iPinCount = -1;			/* default no pin required */
 		iMethod = SC_AC_NONE;		/* default no authentication required */
@@ -803,7 +805,10 @@ static void parse_sec_attr_44(sc_file_t
 
 			/* Get KeyNumber if available */
 			if(iKeyLen) {
-				int iSC = buf[iOffset+iACLen];
+				int iSC;
+				if (len < 1+iACLen)
+					break;
+				iSC = buf[iOffset+iACLen];
 
 				switch( (iSC>>5) & 0x03 ){
 				case 0:
@@ -822,11 +827,15 @@ static void parse_sec_attr_44(sc_file_t
 
 			/* Get PinNumber if available */
 			if (iACLen > (1+iParmLen+iKeyLen)) {  /* check via total length if pin is present */
+				if (len < 1+1+1+iParmLen)
+					break;
 				iKeyRef = buf[iOffset+1+1+iParmLen];  /* PTL + AM-header + parameter-bytes */
 				iMethod = SC_AC_CHV;
 			}
 
 			/* Convert SETCOS command to OpenSC command group */
+			if (len < 1+2)
+				break;
 			switch(buf[iOffset+2]){
 			case 0x2A:			/* crypto operation */
 				iOperation = SC_AC_OP_CRYPTO;
@@ -860,7 +869,10 @@ static void parse_sec_attr_44(sc_file_t
 			iPinCount = iACLen - 1;		
 
 			if (buf[iOffset] & 0x20) {
-				int iSC = buf[iOffset + iACLen];
+				int iSC;
+				if (len < 1 + iACLen)
+					break;
+				iSC = buf[iOffset + iACLen];
 
 				switch( (iSC>>5) & 0x03 ) {
 				case 0:
@@ -881,6 +893,8 @@ static void parse_sec_attr_44(sc_file_t
 
 			/* Pin present ? */
 			if ( iPinCount > 0 ) {
+				if (len < 1 + 2)
+					break;
 				iKeyRef = buf[iOffset + 2];	/* pin ref */
 				iMethod = SC_AC_CHV;
 			}
Index: opensc-0.11.6/src/libopensc/pkcs15-tcos.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/pkcs15-tcos.c
+++ opensc-0.11.6/src/libopensc/pkcs15-tcos.c
@@ -122,7 +122,7 @@ static int insert_key(
 		int i, rec_no=0;
 		if(prkey_info.path.len>=2) prkey_info.path.len-=2;
 		sc_append_file_id(&prkey_info.path, 0x5349);
-		if(sc_select_file(card, &prkey_info.path, NULL)!=SC_SUCCESS){
+		if(sc_select_file(card, &prkey_info.path, NULL)!=SC_SUCCESS || !f->prop_attr){
 			if(ctx->debug>=1) sc_debug(ctx,"Select(%s) failed\n", sc_print_path(&prkey_info.path));
 			return 1;
 		}
@@ -144,7 +144,8 @@ static int insert_key(
 			if(buf[i]==0xB8) can_crypt++;
 		}
 	} else {
-		if(sc_select_file(card, &prkey_info.path, &f)!=SC_SUCCESS){
+		if(sc_select_file(card, &prkey_info.path, &f)!=SC_SUCCESS
+				|| !f->prop_attr || f->prop_attr_len < 2){
 			if(ctx->debug>=1) sc_debug(ctx,"Select(%s) failed\n", sc_print_path(&prkey_info.path));
 			return 1;
 		}
@@ -225,7 +226,8 @@ static int insert_pin(
 			return 1;
 		}
 	} else {
-		if(sc_select_file(card, &pin_info.path, &f)!=SC_SUCCESS){
+		if(sc_select_file(card, &pin_info.path, &f)!=SC_SUCCESS
+			   	|| !f->prop_attr || f->prop_attr_len < 4){
 			if(ctx->debug>=1) sc_debug(ctx,"Select(%s) failed\n", path);
 			return 1;
 		}
Index: opensc-0.11.6/src/tools/opensc-tool.c
===================================================================
--- opensc-0.11.6.orig/src/tools/opensc-tool.c
+++ opensc-0.11.6/src/tools/opensc-tool.c
@@ -399,7 +399,7 @@ static int enum_dir(sc_path_t path, int
 {
 	sc_file_t *file;
 	int r, file_type;
-	u8 files[SC_MAX_APDU_BUFFER_SIZE];
+	u8 files[SC_MAX_EXT_APDU_BUFFER_SIZE];
 
 	r = sc_select_file(card, &path, &file);
 	if (r) {
@@ -419,14 +419,15 @@ static int enum_dir(sc_path_t path, int
 		}
 		if (r == 0) {
 			printf("Empty directory\n");
-		} else
-		for (i = 0; i < r/2; i++) {
-			sc_path_t tmppath;
+		} else {
+			for (i = 0; i < r/2; i++) {
+				sc_path_t tmppath;
 
-			memcpy(&tmppath, &path, sizeof(path));
-			memcpy(tmppath.value + tmppath.len, files + 2*i, 2);
-			tmppath.len += 2;
-			enum_dir(tmppath, depth + 1);
+				memcpy(&tmppath, &path, sizeof(path));
+				memcpy(tmppath.value + tmppath.len, files + 2*i, 2);
+				tmppath.len += 2;
+				enum_dir(tmppath, depth + 1);
+			}
 		}
 	}
 	return 0;
Index: opensc-0.11.6/src/libopensc/card-piv.c
===================================================================
--- opensc-0.11.6.orig/src/libopensc/card-piv.c
+++ opensc-0.11.6/src/libopensc/card-piv.c
@@ -352,7 +352,7 @@ static int piv_general_io(sc_card_t *car
 		 * the buffer is bigger, so it will not produce "ASN1.tag too long!" */
 
 		body = rbuf;
-		if (sc_asn1_read_tag(&body, 0xffff, &cla_out, &tag_out, &bodylen) !=  SC_SUCCESS) 		{
+		if (sc_asn1_read_tag(&body, rbuflen, &cla_out, &tag_out, &bodylen) !=  SC_SUCCESS) 		{
 			sc_debug(card->ctx, "***** received buffer tag MISSING ");
 			body = rbuf;
 			/* some readers/cards might return 6c 00 */ 
