[pkg-opensc-commit] [opensc] 176/295: card-rtecp: Fix rtecp_change_reference_data (#958)

Eric Dorland eric at moszumanska.debian.org
Sat Jun 24 21:11:29 UTC 2017


This is an automated email from the git hooks/post-receive script.

eric pushed a commit to branch master
in repository opensc.

commit a0870826a254df14970ca862f1c6c09b16f2e18e
Author: konstantinpersidskiy <konstantin.persidskiy at gmail.com>
Date:   Mon Feb 20 23:36:55 2017 +0300

    card-rtecp: Fix rtecp_change_reference_data (#958)
    
    * card-rtecp: Fix rtecp_change_reference_data (resolves #931)
    
    * Replace filthy comment, move assert
    
    * card-rtecp: Fix rtecp_change_reference_data (resolves #931)
---
 src/libopensc/card-rtecp.c | 74 +++++++++++++++++++++++++++-------------------
 1 file changed, 44 insertions(+), 30 deletions(-)

diff --git a/src/libopensc/card-rtecp.c b/src/libopensc/card-rtecp.c
index 8e3a498..5f9d3e3 100644
--- a/src/libopensc/card-rtecp.c
+++ b/src/libopensc/card-rtecp.c
@@ -430,52 +430,66 @@ static int rtecp_change_reference_data(sc_card_t *card, unsigned int type,
 		const u8 *newref, size_t newlen, int *tries_left)
 {
 	sc_apdu_t apdu;
-	u8 tmp[2], buf[0x1000], *p = buf;
-	size_t taglen;
-	int r;
+	u8 rsf_length[2], *buf, *buf_end, *p; 
+	size_t val_length, buf_length, max_transmit_length;
+	int transmits_num, r;
 
 	assert(card && card->ctx && newref);
 	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "newlen = %u\n", newlen);
-	if (newlen > sizeof(buf) - 2 - sizeof(tmp) - 2 * (sizeof(buf) / 0xFF + 1))
+	if (newlen > 0xFFFF)
 		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
-
 	if (type == SC_AC_CHV && old && oldlen != 0)
 	{
 		r = sc_verify(card, type, ref_qualifier, old, oldlen, tries_left);
 		SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Verify old pin failed");
 	}
-	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier);
-	tmp[0] = (newlen >> 8) & 0xFF;
-	tmp[1] = newlen & 0xFF;
-	sc_asn1_put_tag(0x80, tmp, sizeof(tmp), p, sizeof(buf) - (p - buf), &p);
-	r = sc_asn1_put_tag(0xA5, newref, newlen, p, sizeof(buf) - (p - buf), &p);
-	if (r == SC_ERROR_INVALID_ARGUMENTS)
+	
+	max_transmit_length = sc_get_max_send_size(card);
+	assert(max_transmit_length > 2);
+	/*
+	 * (2 + sizeof(rsf_length) + newlen) - total length of data we need to transfer,
+	 * (max_transmit_length - 2) - amount of useful data we can transfer in one transmit (2 bytes for 0xA5 tag)
+	 */
+	transmits_num = (2 + sizeof(rsf_length) + newlen) / (max_transmit_length - 2) + 1;
+	/* buffer length = size of 0x80 TLV + size of RSF-file + (size of Tag and Length)*(number of APDUs) */
+	buf_length = (2 + sizeof(rsf_length)) + newlen + 2*(transmits_num); 
+	p = buf = (u8 *)malloc(buf_length);
+	if (buf == NULL)
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
+	buf_end = buf + buf_length; 
+
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier);	
+	/* put 0x80 TLV */
+	rsf_length[0] = (newlen >> 8) & 0xFF;
+	rsf_length[1] = newlen & 0xFF;
+	assert(buf_end - p >= (int)(2 + sizeof(rsf_length)));
+	sc_asn1_put_tag(0x80, rsf_length, sizeof(rsf_length), p, buf_end - p, &p);
+	/* put 0xA5 TLVs (one or more); each transmit must begin with 0xA5 TLV */
+	while (newlen)
 	{
-		while (newlen)
-		{
-			assert(sizeof(buf) - (p - buf) >= newlen + 2);
-			assert((p - buf) % 0xFF < 0x80);
-			if ((p - buf) % 0xFF % 0x80 + newlen + 2 > 0xFF)
-				taglen = 0xFF - 2 - (p - buf) % 0xFF % 0x80;
-			else
-				taglen = newlen;
-			*p++ = 0xA5;
-			*p++ = (u8)taglen;
-			assert(taglen <= newlen);
-			memcpy(p, newref, taglen);
-			p += taglen;
-			newref += taglen;
-			newlen -= taglen;
-			if (newlen)
-				apdu.flags |= SC_APDU_FLAGS_CHAINING;
-		}
+		assert(buf_end - p >= (int)(newlen + 2));
+		if ((p - buf) % max_transmit_length + newlen + 2 > max_transmit_length)
+			val_length = max_transmit_length - (p - buf) % max_transmit_length - 2;
+		else
+			val_length = newlen;
+		/* not using sc_asn1_put_tag(...) because rtecp do not support asn1 properly (when val_length > 127) */
+		*p++ = 0xA5;
+		*p++ = (u8)val_length;
+		assert(val_length <= newlen);
+		memcpy(p, newref, val_length);
+		p += val_length;
+		newref += val_length;
+		newlen -= val_length;
+		if (newlen)
+			apdu.flags |= SC_APDU_FLAGS_CHAINING;
 	}
 	apdu.lc = p - buf;
 	apdu.data = buf;
 	apdu.datalen = p - buf;
 
 	r = sc_transmit_apdu(card, &apdu);
-	sc_mem_clear(buf, sizeof(buf));
+	sc_mem_clear(buf, buf_length);
+	free(buf);
 	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
 	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
 	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/opensc.git



More information about the pkg-opensc-commit mailing list