epass2003: SM response with `87 81 01` fails to decode since 5ebb04ded (0.26.1 accepted it)

Ouverte
#3,900 3 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 4 jours

@frankmorgner y travaille déjà.

Depuis le 31/10/2026.

  • #3915 par @frankmorgner — ouverte

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
52/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
c
Domaine
backend, security

Piste de recherche

Read decrypt_response() and the existing workaround in epass2003_check_response_mac_and_sw() in src/libopensc/card-epass2003.c; compare the TLV parsing paths for the reported 87 81 01 response. Reproduce with the ePass2003 READ BINARY case described here. Done means pkcs15-tool -D reads all 4864 AODF bytes without -1200 and the dump output remains unchanged.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

Split out of #3892, as requested there.

Problem

When an SM response carries 112–127 bytes of plaintext, the ePass2003 encodes the cryptogram as 87 81 01 <128 bytes>. That is, 0x81 is sent as a short-form length byte. In DER that would be 87 81 81 01 .... Reproduced on current master (ccfa7600f) with a READ BINARY of the last 112 bytes of a 4864-byte AODF (offset 0x1290):

Outgoing APDU (19 bytes):
0C B0 12 90 0D 97 01 70 8E 08 ...
Incoming APDU (147 bytes):
87 81 01 28 0D D3 B4 6D ... (128 bytes cryptogram)  99 02 90 00  8E 08 <MAC>  90 00
  • 0.26.1: unwrapped APDU: resplen 112, SW 9000.
  • master: epass2003_check_response_mac_and_sw() already has a workaround for this encoding (Workaround, wrong BER-TLV ?), so the MAC check passes. decrypt_response() then parses the same TLV with sc_asn1_read_tag(), which reads 0x81 as a long-form length. It returns -1, epass2003_sm_free_wrapped_apdu() returns -1200, and SM is stopped.
  • sc_read_binary() then returns 4752 of 4864 bytes ("Subsequent read failed with -1200, returning what was read"). The short read is not reported to the caller. The next SELECT gets 6988 and re-establishes SM.

Trace (0.26.1 vs master): 7-sm-length-decoding.txt

This started with 5ebb04ded ("epass2003/iasecc: fixed possible heap over-reads"), together with bc2c29c4b ("Fix epass2003 regression with SM", #3693). Before those commits, decrypt_response() handled the 87 81 01 case itself, the same way epass2003_check_response_mac_and_sw() still does.

Proposed fix

I don't think sc_asn1_read_tag() should accept this encoding, since it is not valid BER. The card quirk belongs in the driver, next to the existing workaround. The patch below is tested on master (ccfa7600f) with an ePass2003: pkcs15-tool -D reads all 4864 bytes of the AODF (master: 4752), with no -1200, and the dump output is unchanged.

--- a/src/libopensc/card-epass2003.c
+++ b/src/libopensc/card-epass2003.c
@@ -1472,13 +1472,22 @@ decrypt_response(struct sc_card *card, unsigned char *in, size_t inlen, unsigned char *out, size_t * out_len)
 
 	exdata = (epass2003_exdata *)card->drv_data;
 
-	if (SC_SUCCESS != sc_asn1_read_tag(&p, inlen, &cla, &tag, &cipher_len) || p == NULL) {
-		return -1;
+	if (inlen > 3 && in[0] == 0x87 && in[1] == 0x81 && in[2] == 0x01) {
+		/* The card encodes a length of 0x81 as 81 instead of 81 81, see
+		 * epass2003_check_response_mac_and_sw() */
+		cipher_len = in[1];
+		p = in + 2;
+		if (cipher_len > inlen - 2)
+			return -1;
+	} else {
+		if (SC_SUCCESS != sc_asn1_read_tag(&p, inlen, &cla, &tag, &cipher_len) || p == NULL) {
+			return -1;
+		}
+		if ((cla | tag) == 0x99)
+			return 0;
+		if ((cla | tag) != 0x87)
+			return -1;
 	}
-	if ((cla | tag) == 0x99)
-		return 0;
-	if ((cla | tag) != 0x87)
-		return -1;
 
 	if (cipher_len < 2 || cipher_len > sizeof plaintext)
 		return -1;

I have only seen the card do this for length 0x81, so the patch covers only that case. I can open this as a PR.

Langage dominant
C
Étoiles
3.1k
Forks
858
Merge moyen
7 j 23 h
PR mergées (30 j)
28

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de OpenSC/OpenSC

Toutes les issues de OpenSC/OpenSC

Issues similaires

Plus d'issues C

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.