OpenPGP: implement pgp_put_data()

This commit is contained in:
Nguyễn Hồng Quân 2012-06-01 17:40:39 +02:00 committed by Viktor Tarasov
parent a1ed22b6fd
commit 3ac834e277
1 changed files with 64 additions and 1 deletions

View File

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