From 5fa633075d8c804300db6f479a8b730e0b51ecdb Mon Sep 17 00:00:00 2001 From: Doug Engert Date: Tue, 3 Dec 2019 18:08:32 -0600 Subject: [PATCH] GIDS Decipher fix for TPM GIDS decipher APDU fails with status '65 00' or '67 00' if "Padding Indication" byte is present. Debug logs of Microsoft certutil -v -scinfo using Microsoft drivers show that for a decipher, the "Padding Indication" is not present. It maybe needed if Secure Messaging is added later. Extended APDU is turned off as this may not be supported on some cards. Chaining is used used instead, it works on all cards. RAW RSA is turned off, it is supported. Tested with pkcs11-tool on Windows 10 with a TPM 2.0 module. On branch gids-decipher Changes to be committed: modified: src/libopensc/card-gids.c Date: Tue Dec 3 18:08:32 2019 -0600 interactive rebase in progress; onto 01678e87 Last commands done (3 commands done): squash c968d0dd GIDS No Padding Indication Byte squash 0fa940fc Take 3 No commands remaining. You are currently rebasing branch 'gids-decipher' on '01678e87'. --- src/libopensc/card-gids.c | 68 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/src/libopensc/card-gids.c b/src/libopensc/card-gids.c index 27576f99..9954e098 100644 --- a/src/libopensc/card-gids.c +++ b/src/libopensc/card-gids.c @@ -156,6 +156,25 @@ struct gids_private_data { size_t buffersize; }; +static void fixup_transceive_length(const struct sc_card *card, + struct sc_apdu *apdu) +{ + if (card == NULL || apdu == NULL) { + return; + } + + if (apdu->lc > sc_get_max_send_size(card)) { + /* The lower layers will automatically do chaining */ + apdu->flags |= SC_APDU_FLAGS_CHAINING; + } + + if (apdu->le > sc_get_max_recv_size(card)) { + /* The lower layers will automatically do a GET RESPONSE, if possible. + * All other workarounds must be carried out by the upper layers. */ + apdu->le = sc_get_max_recv_size(card); + } +} + // LOW LEVEL API /////////////////////////////////////////// @@ -643,10 +662,12 @@ static int gids_init(sc_card_t * card) data->masterfilesize = sizeof(data->masterfile); /* supported RSA keys and how padding is done */ - flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_ONBOARD_KEY_GEN | SC_ALGORITHM_RSA_RAW; + flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_ONBOARD_KEY_GEN; + /* fix me: add other algorithms when the gids specification will tell how to extract the algo id from the FCP */ _sc_card_add_rsa_alg(card, 1024, flags, 0); _sc_card_add_rsa_alg(card, 2048, flags, 0); + return SC_SUCCESS; } @@ -820,6 +841,49 @@ err: return r; } + +static int +gids_decipher(struct sc_card *card, + const u8 * crgram, size_t crgram_len, + u8 * out, size_t outlen) +{ + int r; + struct sc_apdu apdu; + + if (card == NULL || crgram == NULL || out == NULL) { + return SC_ERROR_INVALID_ARGUMENTS; + } + LOG_FUNC_CALLED(card->ctx); + sc_log(card->ctx, + "Gids decipher: in-len %"SC_FORMAT_LEN_SIZE_T"u, out-len %"SC_FORMAT_LEN_SIZE_T"u", + crgram_len, outlen); + + /* INS: 0x2A PERFORM SECURITY OPERATION + * P1: 0x80 Resp: Plain value + * P2: 0x86 Cmd: Padding indicator byte followed by cryptogram + * Implementation by Microsoft indicates that Padding indicator + * must not be sent. It may only be needed if Secure Messaging + * is used. This driver does not support SM. + */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A, 0x80, 0x86); + apdu.resp = out; + apdu.resplen = outlen; + apdu.le = outlen; + + apdu.data = crgram; /* Skip padding indication not needed unless SM */ + apdu.lc = crgram_len; + apdu.datalen = crgram_len; + + fixup_transceive_length(card, &apdu); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) + LOG_FUNC_RETURN(card->ctx, apdu.resplen); + + LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); +} + // deauthenticate all pins static int gids_logout(sc_card_t *card) { @@ -2090,7 +2154,7 @@ static struct sc_card_driver *sc_get_driver(void) gids_ops.logout = gids_logout; gids_ops.restore_security_env = NULL; gids_ops.set_security_env = gids_set_security_env; - gids_ops.decipher = iso_ops->decipher; + gids_ops.decipher = gids_decipher; gids_ops.compute_signature = iso_ops->compute_signature; gids_ops.change_reference_data = NULL; // see pin_cmd gids_ops.reset_retry_counter = NULL; // see pin_cmd