📄 card-gpk.c
字号:
struct sc_apdu apdu; unsigned int count, chain, len; int r; chain = 0x01; for (count = 0; count < datalen; count += len) { unsigned char buffer[GPK_HASH_CHUNK+2]; if ((len = datalen - count) > GPK_HASH_CHUNK) len = GPK_HASH_CHUNK; else chain |= 0x10; buffer[0] = 0x55; buffer[1] = len; memcpy(buffer+2, data + count, len); memset(&apdu, 0, sizeof(apdu)); apdu.cse = SC_APDU_CASE_3_SHORT; apdu.cla = 0x80; apdu.ins = 0xDA; apdu.p1 = chain; apdu.p2 = len; apdu.lc = len + 2; apdu.data= buffer; apdu.datalen = len + 2; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, r, "Card returned error"); chain = 0; } return 0;}#endif/* * Send the hashed data to the card. */static intgpk_init_hashed(struct sc_card *card, const u8 *digest, unsigned int len){ struct sc_apdu apdu; u8 tsegid[64]; int r; r = reverse(tsegid, sizeof(tsegid), digest, len); SC_TEST_RET(card->ctx, r, "Failed to reverse buffer"); memset(&apdu, 0, sizeof(apdu)); apdu.cse = SC_APDU_CASE_3_SHORT; apdu.cla = 0x80; apdu.ins = 0xEA; apdu.lc = len; apdu.data= tsegid; apdu.datalen = len; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, r, "Card returned error"); return r;}/* * Compute a signature. * Note we hash everything manually and send it to the card. */static intgpk_compute_signature(struct sc_card *card, const u8 *data, size_t data_len, u8 * out, size_t outlen){ struct gpk_private_data *priv = DRVDATA(card); struct sc_apdu apdu; u8 cardsig[1024/8]; int r; if (data_len > priv->sec_mod_len) { sc_error(card->ctx, "Data length (%u) does not match key modulus %u.\n", data_len, priv->sec_mod_len); return SC_ERROR_INTERNAL; } if (sizeof(cardsig) < priv->sec_mod_len) return SC_ERROR_BUFFER_TOO_SMALL; r = gpk_init_hashed(card, data, data_len); SC_TEST_RET(card->ctx, r, "Failed to send hash to card"); /* Now sign the hash. * The GPK has Internal Authenticate and PK_Sign. I am not * sure what the difference between the two is. */ memset(&apdu, 0, sizeof(apdu)); apdu.cse = SC_APDU_CASE_2_SHORT; apdu.cla = 0x80; apdu.ins = 0x86;#if 0 /* Don't know why I did this. It conflicts with the spec * (but it worked with the gpk4k, strange). --okir */ apdu.p1 = priv->sec_padding; apdu.p2 = priv->sec_mod_len;#else apdu.p2 = priv->sec_padding;#endif apdu.resp= cardsig; apdu.resplen = sizeof(cardsig); apdu.le = priv->sec_mod_len; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, r, "Card returned error"); /* The GPK returns the signature as little endian numbers. * Need to revert these */ r = reverse(out, outlen, cardsig, apdu.resplen); SC_TEST_RET(card->ctx, r, "Failed to reverse signature"); return r;}/* * Decrypt some RSA encrypted piece of data. * Due to legal restrictions, the GPK will not let you see the * full cleartext block, just the last N bytes. * The GPK documentation refers to N as the MaxSessionKey size, * probably because this feature limits the maximum size of an * SSL session key you will be able to decrypt using this card. */static intgpk_decipher(struct sc_card *card, const u8 *in, size_t inlen, u8 *out, size_t outlen){ struct gpk_private_data *priv = DRVDATA(card); struct sc_apdu apdu; u8 buffer[256]; int r; if (inlen != priv->sec_mod_len) { sc_error(card->ctx, "Data length (%u) does not match key modulus %u.\n", inlen, priv->sec_mod_len); return SC_ERROR_INVALID_ARGUMENTS; } /* First revert the cryptogram */ r = reverse(buffer, sizeof(buffer), in, inlen); SC_TEST_RET(card->ctx, r, "Cryptogram too large"); in = buffer; memset(&apdu, 0, sizeof(apdu)); apdu.cse = SC_APDU_CASE_3_SHORT; apdu.cla = 0x80; apdu.ins = 0x1C; apdu.p2 = 0; /* PKCS1 padding */ apdu.lc = inlen; apdu.data= in; apdu.datalen = inlen; apdu.resp= buffer; apdu.resplen = sizeof(buffer); apdu.sensitive = 1; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, r, "Card returned error"); /* Reverse the data we got back */ r = reverse(out, outlen, buffer, apdu.resplen); SC_TEST_RET(card->ctx, r, "Failed to reverse buffer"); return r;}/* * Erase card */static intgpk_erase_card(struct sc_card *card){ struct gpk_private_data *priv = DRVDATA(card); struct sc_apdu apdu; u8 offset; int r; SC_FUNC_CALLED(card->ctx, 1); switch (priv->variant) { case GPK4000_su256: case GPK4000_sdo: offset = 0x6B; /* courtesy gemplus hotline */ break; case GPK4000_s: offset = 7; break; case GPK8000: case GPK8000_8K: case GPK8000_16K: case GPK16000: offset = 0; break; default: return SC_ERROR_NOT_SUPPORTED; } memset(&apdu, 0, sizeof(apdu)); apdu.cse = SC_APDU_CASE_1; apdu.cla = 0xDB; apdu.ins = 0xDE; apdu.p2 = offset; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, r, "Card returned error"); priv->key_set = 0; SC_FUNC_RETURN(card->ctx, 2, r);}/* * Lock a file Access Condition. * * File must be selected, and we assume that any authentication * that needs to be presented in order to allow this operation * have been presented (ACs from the DF; AC1 for sensitive files, * AC2 for normal files). */static intgpk_lock(struct sc_card *card, struct sc_cardctl_gpk_lock *args){ struct gpk_private_data *priv = DRVDATA(card); struct sc_file *file = args->file; struct sc_apdu apdu; u8 data[8], crycks[3], resp[3]; int r; if (card->ctx->debug) sc_debug(card->ctx, "gpk_lock(0x%04X, %u)\n", file->id, args->operation); memset(data, 0, sizeof(data)); data[0] = file->id >> 8; data[1] = file->id; switch (args->operation) { case SC_AC_OP_UPDATE: data[2] = 0x40; break; case SC_AC_OP_WRITE: data[3] = 0x40; break; case SC_AC_OP_READ: data[4] = 0x40; break; default: return SC_ERROR_INVALID_ARGUMENTS; } memset(&apdu, 0, sizeof(apdu)); apdu.cse = SC_APDU_CASE_3_SHORT; apdu.cla = 0x80; apdu.ins = 0x16; apdu.p1 = (file->type == SC_FILE_TYPE_DF)? 1 : 2; apdu.p2 = 0; apdu.lc = 5; apdu.datalen = 5; apdu.data = data; if (priv->key_set) { apdu.cla = 0x84; apdu.cse = SC_APDU_CASE_4_SHORT; r = gpk_compute_crycks(card, &apdu, crycks); if (r) return r; apdu.resp = resp; apdu.resplen = sizeof(resp); /* XXX? */ } r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, r, "Card returned error"); if (priv->key_set) r = gpk_verify_crycks(card, &apdu, crycks); return r;}/* * Initialize the private portion of a public key file */static intgpk_pkfile_init(struct sc_card *card, struct sc_cardctl_gpk_pkinit *args){ struct sc_apdu apdu; int r; if (card->ctx->debug) sc_debug(card->ctx, "gpk_pkfile_init(%u)\n", args->privlen); memset(&apdu, 0, sizeof(apdu)); apdu.cse = SC_APDU_CASE_1; apdu.cla = 0x80; apdu.ins = 0x12; apdu.p1 = args->file->id & 0x1F; apdu.p2 = args->privlen / 4; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, r, "Card returned error"); return r;}/* * Store a privat key component */static intgpk_pkfile_load(struct sc_card *card, struct sc_cardctl_gpk_pkload *args){ struct gpk_private_data *priv = DRVDATA(card); des_key_schedule k1, k2; struct sc_apdu apdu; unsigned int n; u8 temp[256]; int r; sc_debug(card->ctx, "gpk_pkfile_load(fid=%04x, len=%d, datalen=%d)\n", args->file->id, args->len, args->datalen);#if 0 if (card->ctx->debug > 5) { char buf[2048]; sc_hex_dump(card->ctx, args->data, args->datalen, buf, sizeof(buf)); sc_debug(card->ctx, "Sending %d bytes (cleartext):\n%s", args->datalen, buf); }#endif memset(&apdu, 0, sizeof(apdu)); apdu.cse = SC_APDU_CASE_3_SHORT; apdu.cla = 0x80; apdu.ins = 0x18; apdu.p1 = args->file->id & 0x1F; apdu.p2 = args->len; apdu.lc = args->datalen; apdu.sensitive = 1; /* encrypt the private key material */ assert(args->datalen <= sizeof(temp)); if (!priv->key_set) { sc_error(card->ctx, "No secure messaging key set!\n"); return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; } DES_set_key_unchecked((des_cblock *) priv->key, &k1); DES_set_key_unchecked((des_cblock *) (priv->key+8), &k2); for (n = 0; n < args->datalen; n += 8) { des_ecb2_encrypt((des_cblock *) (args->data + n), (des_cblock *) (temp + n), k1, k2, DES_ENCRYPT); } apdu.data = temp; apdu.datalen = args->datalen; /* Forget the key. The card seems to forget it, too :) */ priv->key_set = 0; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, r, "Card returned error"); SC_FUNC_RETURN(card->ctx, 1, r);}/* * This function lets pkcs15init query for the transport key */static intgpk_get_default_key(struct sc_card *card, struct sc_cardctl_default_key *data){ if (data->method == SC_AC_PRO && data->key_ref == 1) { if (data->len < 16) return SC_ERROR_BUFFER_TOO_SMALL; memcpy(data->key_data, "TEST KEYTEST KEY", 16); data->len = 16; return 0; } return SC_ERROR_NO_DEFAULT_KEY;}/* * Get the maximum size of a session key the card is * willing to decrypt */#if 0static intgpk_max_session_key(struct sc_card *card){ struct gpk_private_data *priv = DRVDATA(card); struct sc_path path; u8 value; int r; if (priv->max_session_key) return priv->max_session_key; /* GPK cards limit the amount of data they're willing * to RSA decrypt. This data is stored in EFMaxSessionKey */ sc_format_path("01000001", &path); if ((r = sc_select_file(card, &path, NULL)) < 0 || (r = sc_read_binary(card, 0, &value, 1, 0)) < 0) return r; priv->max_session_key = value; return value;}#endif/* * GetInfo call */intgpk_get_info(struct sc_card *card, u8 p1, u8 p2, u8 *buf, size_t buflen){ struct sc_apdu apdu; int r; memset(&apdu, 0, sizeof(apdu)); apdu.cse = SC_APDU_CASE_2_SHORT; apdu.cla = 0x80; apdu.ins = 0xC0; apdu.p1 = p1; apdu.p2 = p2; apdu.le = buflen; apdu.resp = buf; apdu.resplen = buflen; r = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_TEST_RET(card->ctx, r, "Card returned error"); return r;}/* * Dispatch card_ctl calls */static intgpk_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr){ switch (cmd) { case SC_CARDCTL_ERASE_CARD: return gpk_erase_card(card); case SC_CARDCTL_GET_DEFAULT_KEY: return gpk_get_default_key(card, (struct sc_cardctl_default_key *) ptr); case SC_CARDCTL_GPK_VARIANT: *(int *) ptr = DRVDATA(card)->variant; return 0; case SC_CARDCTL_GPK_LOCK: return gpk_lock(card, (struct sc_cardctl_gpk_lock *) ptr); case SC_CARDCTL_GPK_PKINIT: return gpk_pkfile_init(card, (struct sc_cardctl_gpk_pkinit *) ptr); case SC_CARDCTL_GPK_PKLOAD: return gpk_pkfile_load(card, (struct sc_cardctl_gpk_pkload *) ptr); case SC_CARDCTL_GPK_IS_LOCKED: *(int *) ptr = DRVDATA(card)->locked; return 0; } return SC_ERROR_NOT_SUPPORTED;}static intgpk_build_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, struct sc_pin_cmd_data *data){ static u8 sbuf[8]; int r; if (data->pin_type != SC_AC_CHV) return SC_ERROR_INVALID_ARGUMENTS; /* XXX deal with secure messaging here */ memset(apdu, 0, sizeof(*apdu)); apdu->cse = SC_APDU_CASE_3_SHORT; data->flags |= SC_PIN_CMD_NEED_PADDING; switch (data->cmd) { case SC_PIN_CMD_VERIFY: /* Copy PIN to buffer and pad */ data->pin1.encoding = SC_PIN_ENCODING_ASCII; data->pin1.pad_length = 8; data->pin1.pad_char = 0x00; data->pin1.offset = 5; r = sc_build_pin(sbuf, 8, &data->pin1, 1); if (r < 0) return r; apdu->cla = 0x00; apdu->ins = 0x20; apdu->p1 = 0x00; break; case SC_PIN_CMD_CHANGE: case SC_PIN_CMD_UNBLOCK: /* Copy PINs to buffer, BCD-encoded, and pad */ data->pin1.encoding = SC_PIN_ENCODING_BCD; data->pin1.pad_length = 8; data->pin1.pad_char = 0x00; data->pin1.offset = 5; data->pin2.encoding = SC_PIN_ENCODING_BCD; data->pin2.pad_length = 8; data->pin2.pad_char = 0x00; data->pin2.offset = 5 + 4; if ((r = sc_build_pin(sbuf, 4, &data->pin1, 1)) < 0 || (r = sc_build_pin(sbuf + 4, 4, &data->pin2, 1)) < 0) return r; apdu->cla = 0x80; apdu->ins = 0x24; apdu->p1 = (data->cmd == SC_PIN_CMD_CHANGE)? 0x00 : 0x01; break; default: return SC_ERROR_NOT_SUPPORTED; } apdu->p2 = data->pin_reference & 7; apdu->lc = 8; apdu->datalen = 8; apdu->data = sbuf; apdu->sensitive = 1; return 0;}static intgpk_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left){ struct sc_apdu apdu; int r; /* Special case - External Authenticate */ if (data->cmd == SC_PIN_CMD_VERIFY && data->pin_type == SC_AC_PRO) return gpk_select_key(card, data->pin_reference, data->pin1.data, data->pin1.len); r = gpk_build_pin_apdu(card, &apdu, data); if (r < 0) return r; data->apdu = &apdu; return iso_ops->pin_cmd(card, data, tries_left);}/* * Initialize the driver struct */static struct sc_card_driver *sc_get_driver(){ if (gpk_ops.match_card == NULL) { struct sc_card_driver *iso_drv; iso_drv = sc_get_iso7816_driver(); iso_ops = iso_drv->ops; gpk_ops = *iso_ops; gpk_ops.match_card = gpk_match; gpk_ops.init = gpk_init; gpk_ops.finish = gpk_finish; gpk_ops.select_file = gpk_select_file; gpk_ops.read_binary = gpk_read_binary; gpk_ops.write_binary = gpk_write_binary; gpk_ops.update_binary = gpk_update_binary; gpk_ops.create_file = gpk_create_file; /* gpk_ops.check_sw = gpk_check_sw; */ gpk_ops.card_ctl = gpk_card_ctl; gpk_ops.set_security_env= gpk_set_security_env; gpk_ops.restore_security_env= gpk_restore_security_env; gpk_ops.compute_signature= gpk_compute_signature; gpk_ops.decipher = gpk_decipher; gpk_ops.pin_cmd = gpk_pin_cmd; } return &gpk_drv;}struct sc_card_driver *sc_get_gpk_driver(){ return sc_get_driver();}#endif /* HAVE_OPENSSL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -