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
This commit is contained in:
Hector Sanjuan 2015-05-06 20:37:20 +02:00 committed by Viktor Tarasov
parent ef4edb74ba
commit fd3d07a884
3 changed files with 26 additions and 29 deletions

View File

@ -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");

View File

@ -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);

View File

@ -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) ) {