From fd3d07a88496dc0adfa2f6ff7eca9078ec087985 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 6 May 2015 20:37:20 +0200 Subject: [PATCH] Issue #451: Newer DNIe not working with OpenSC. This patch fixes 3 issues which consecutively have shown up when debugging the original problem: 1 - Newer DNIe report a byte count for public certificates which is the compressed size, while older DNIe report the uncompressed size. This resulted in short-reading the x509 certificates, and in an error parsing. Therefore, during initialization we proceed to set path->count for public certificates to -1. This ensures that the lenght of the certificates for reading will be set to file-> length, which has the correct size. 2 - pkcs11-tool -t was broken for DNIe (old and new)as it tried to strip pcks11 padding from the data to sign and OpenSC tried signatures with non-padded data (as the card had SC_ALGORITHM_RSA_RAW). The new algoflags (SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_PAD_PKCS1) and the removal of the strip-padding call fix the issue. 3 - The new cards won't allow setting the LE bytes when calculating the TLV, when LE equals 256. This caused an wrong SM object error response (0x69 0x88). Therefore, we don't send the LE bytes anymore in this case. The patch has been tested to work on the new problematic card and on another old one. close #451 --- src/libopensc/card-dnie.c | 26 +++++--------------------- src/libopensc/cwa14890.c | 19 +++++++++++-------- src/libopensc/pkcs15-dnie.c | 10 ++++++++++ 3 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/libopensc/card-dnie.c b/src/libopensc/card-dnie.c index 53ce7281..f6f1692b 100644 --- a/src/libopensc/card-dnie.c +++ b/src/libopensc/card-dnie.c @@ -497,8 +497,8 @@ static inline void init_flags(struct sc_card *card) card->max_send_size = (255 - 12); /* manual says 255, but we need 12 extra bytes when encoding */ card->max_recv_size = 255; - algoflags = SC_ALGORITHM_RSA_RAW; /* RSA support */ - algoflags |= SC_ALGORITHM_RSA_HASH_NONE; + /* RSA Support with PKCS1.5 padding */ + algoflags = SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_PAD_PKCS1; _sc_card_add_rsa_alg(card, 1024, algoflags, 0); _sc_card_add_rsa_alg(card, 2048, algoflags, 0); } @@ -1356,8 +1356,6 @@ static int dnie_compute_signature(struct sc_card *card, { int result = SC_SUCCESS; struct sc_apdu apdu; - u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; /* to compose digest+hash data */ - size_t sbuflen = 0; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; /* to receive sign response */ /* some preliminar checks */ @@ -1391,20 +1389,6 @@ static int dnie_compute_signature(struct sc_card *card, sc_log(card->ctx, "Compute signature len: '%d' bytes:\n%s\n============================================================", datalen, sc_dump_hex(data, datalen)); - if (datalen != 256) { - sc_log(card->ctx, "Expected pkcs#1 v1.5 DigestInfo data"); - LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH); - } - - /* try to strip pkcs1 padding */ - sbuflen = sizeof(sbuf); - memset(sbuf, 0, sbuflen); - result = sc_pkcs1_strip_01_padding(card->ctx, data, datalen, sbuf, &sbuflen); - if (result != SC_SUCCESS) { - sc_log(card->ctx, "Provided data is not pkcs#1 padded"); - /* TODO: study what to do on plain data */ - LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_PADDING); - } /*INS: 0x2A PERFORM SECURITY OPERATION * P1: 0x9E Resp: Digital Signature @@ -1413,9 +1397,9 @@ static int dnie_compute_signature(struct sc_card *card, apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; /* signature response size */ - apdu.data = sbuf; - apdu.lc = sbuflen; /* 15 SHA1 DigestInfo + 20 SHA1 computed Hash */ - apdu.datalen = sizeof(sbuf); + apdu.data = data; + apdu.lc = datalen; /* Caller determines the type of hash and its size */ + apdu.datalen = datalen; /* tell card to compute signature */ result = dnie_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, result, "compute_signature() failed"); diff --git a/src/libopensc/cwa14890.c b/src/libopensc/cwa14890.c index dc88ff7b..800ed6fc 100644 --- a/src/libopensc/cwa14890.c +++ b/src/libopensc/cwa14890.c @@ -1489,6 +1489,7 @@ int cwa_encode_apdu(sc_card_t * card, /* reserve enougth space for apdulen+tlv bytes * to-be-crypted buffer and result apdu buffer */ + /* TODO DEE add 4 more bytes for testing.... */ apdubuf = calloc(MAX(SC_MAX_APDU_BUFFER_SIZE, 20 + from->datalen), sizeof(u8)); @@ -1544,14 +1545,16 @@ int cwa_encode_apdu(sc_card_t * card, } /* if le byte is declared, compose and add Le TLV */ - /* TODO: study why original driver checks for le>=256? */ - if (from->le > 0) { - u8 le = 0xff & from->le; - res = cwa_compose_tlv(card, 0x97, 1, &le, &ccbuf, &cclen); - if (res != SC_SUCCESS) { - msg = "Encode APDU compose_tlv(0x97) failed"; - goto encode_end; - } + /* FIXME: For DNIe we must not send the le bytes + when le == 256 but this goes against the standard + and might break other cards reusing this code */ + if ((0xff & from->le) > 0) { + u8 le = 0xff & from->le; + res = cwa_compose_tlv(card, 0x97, 1, &le, &ccbuf, &cclen); + if (res != SC_SUCCESS) { + msg = "Encode APDU compose_tlv(0x97) failed"; + goto encode_end; + } } /* copy current data to apdu buffer (skip header and header padding) */ memcpy(apdubuf, ccbuf + 8, cclen - 8); diff --git a/src/libopensc/pkcs15-dnie.c b/src/libopensc/pkcs15-dnie.c index 94d7f4cb..c295c305 100644 --- a/src/libopensc/pkcs15-dnie.c +++ b/src/libopensc/pkcs15-dnie.c @@ -136,6 +136,7 @@ static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card) sc_pkcs15_object_t *p15_obj; size_t len = sizeof(buf); int rv; + struct sc_pkcs15_cert_info *p15_info = NULL; sc_context_t *ctx = p15card->card->ctx; LOG_FUNC_CALLED(ctx); @@ -225,6 +226,15 @@ static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card) && (p15_obj->auth_id.len == 0)) { p15_obj->auth_id.value[0] = 0x01; p15_obj->auth_id.len = 1; + }; + /* Set path count to -1 for public certificates, as they + will need to be decompressed and read_binary()'d, so + we make sure we end up reading the file->size and not the + path->count which is the compressed size on newer + DNIe versions */ + if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_CDF) ) { + p15_info = (struct sc_pkcs15_cert_info *) p15_obj ->data; + p15_info ->path.count = -1; } /* Remove found public keys as cannot be read_binary()'d */ if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PUKDF) ) {