From 3ac834e27748dab81d2ab07a5f958f1f34f62b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?= Date: Fri, 1 Jun 2012 17:40:39 +0200 Subject: [PATCH] OpenPGP: implement pgp_put_data() --- src/libopensc/card-openpgp.c | 65 +++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c index a25d4c2d..1467e516 100644 --- a/src/libopensc/card-openpgp.c +++ b/src/libopensc/card-openpgp.c @@ -1014,7 +1014,70 @@ pgp_do_iswritable(sc_card_t *card, unsigned int tag, struct blob **ref_blob) static int pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len) { - LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); + sc_apdu_t apdu; + struct pgp_priv_data *priv = DRVDATA(card); + struct blob *affected_blob = NULL; + int r; + + LOG_FUNC_CALLED(card->ctx); + + /* Check if the tag is writable */ + if (!pgp_do_iswritable(card, tag, &affected_blob)) { + sc_log(card->ctx, "The %04X DO is not writable.", tag); + return SC_ERROR_NOT_ALLOWED; + } + + /* Build APDU */ + if (buf_len > 0xFF && card->caps & SC_CARD_CAP_APDU_EXT) { + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_EXT, 0xDA, tag >> 8, tag); + } + else { + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xDA, tag >> 8, tag); + /* In short APDU, the Lc only takes 1 byte */ + apdu.lc = ((buf_len > 0xFF) && !(card->caps & SC_CARD_CAP_APDU_EXT)) ? 0xFF : buf_len; + } + /* TODO: + * Command chaining for the large data. + **/ + apdu.data = buf; + apdu.datalen = buf_len; + apdu.lc = buf_len; + + if (buf == NULL && buf_len == 0) { + /* Erase DO content. + * + * We won't call sc_transmit_apdu() in order to bypass + * the check of APDU, because sc_transmit_apdu() does not allow + * null data. */ + r = sc_lock(card); /* acquire card lock*/ + sc_log(card->ctx, "card->reader->ops->transmit"); + r = card->reader->ops->transmit(card->reader, &apdu); + /* all done => release lock */ + if (sc_unlock(card) != SC_SUCCESS) + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "sc_unlock failed"); + + return r; + } + /* Send APDU to card */ + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + /* Check response */ + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + + /* Instruct more in case of error */ + if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Please verify PIN first."); + } + LOG_TEST_RET(card->ctx, r, "Card returned error"); + + /* Update the corresponding file */ + sc_log(card->ctx, "To update the corresponding blob data"); + r = pgp_set_blob(affected_blob, buf, buf_len); + if (r < 0) + sc_log(card->ctx, "Failed to update the blob %04X. Error %d.", affected_blob->id, r); + /* The pgp_update_tag_blob()'s failure won't affect */ + + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, buf_len); }