diff --git a/opensc-0.17.0-feitian.patch b/opensc-0.17.0-feitian.patch new file mode 100644 index 0000000..2dd5dd4 --- /dev/null +++ b/opensc-0.17.0-feitian.patch @@ -0,0 +1,460 @@ +From 8d7346406d166a9db4afd239e6669df3e3b99f79 Mon Sep 17 00:00:00 2001 +From: Feitian Technologies +Date: Mon, 4 Sep 2017 19:29:24 +0800 +Subject: [PATCH] Add ECC support and solve wrong Length status codes with SM + card + +Fix #1073 +Fix #1115 +--- + src/libopensc/card-epass2003.c | 171 ++++++++++++++++++++++++++++++++++---- + src/libopensc/cardctl.h | 4 +- + src/libopensc/sm.c | 2 +- + src/pkcs15init/pkcs15-epass2003.c | 49 +++++++++-- + 4 files changed, 197 insertions(+), 29 deletions(-) + +diff --git a/src/libopensc/card-epass2003.c b/src/libopensc/card-epass2003.c +index 84ab64569..7feab5984 100644 +--- a/src/libopensc/card-epass2003.c ++++ b/src/libopensc/card-epass2003.c +@@ -98,6 +98,8 @@ typedef struct epass2003_exdata_st { + unsigned char sk_enc[16]; /* encrypt session key */ + unsigned char sk_mac[16]; /* mac session key */ + unsigned char icv_mac[16]; /* instruction counter vector(for sm) */ ++ unsigned char currAlg; /* current Alg */ ++ unsigned int ecAlgFlags; /* Ec Alg mechanism type*/ + } epass2003_exdata; + + #define REVERSE_ORDER4(x) ( \ +@@ -170,6 +172,7 @@ static const struct sc_card_error epass2003_errors[] = { + static int epass2003_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu); + static int epass2003_select_file(struct sc_card *card, const sc_path_t * in_path, sc_file_t ** file_out); + int epass2003_refresh(struct sc_card *card); ++static int hash_data(const unsigned char *data, size_t datalen, unsigned char *hash, unsigned int mechanismType); + + static int + epass2003_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2) +@@ -403,6 +406,12 @@ sha1_digest(const unsigned char *input, size_t length, unsigned char *output) + return openssl_dig(EVP_sha1(), input, length, output); + } + ++static int ++sha256_digest(const unsigned char *input, size_t length, unsigned char *output) ++{ ++ return openssl_dig(EVP_sha256(), input, length, output); ++} ++ + + static int + gen_init_key(struct sc_card *card, unsigned char *key_enc, unsigned char *key_mac, +@@ -1140,6 +1149,7 @@ static int + epass2003_init(struct sc_card *card) + { + unsigned int flags; ++ unsigned int ext_flags; + unsigned char data[SC_MAX_APDU_BUFFER_SIZE] = { 0 }; + size_t datalen = SC_MAX_APDU_BUFFER_SIZE; + epass2003_exdata *exdata = NULL; +@@ -1192,6 +1202,11 @@ epass2003_init(struct sc_card *card) + _sc_card_add_rsa_alg(card, 1024, flags, 0); + _sc_card_add_rsa_alg(card, 2048, flags, 0); + ++ //set EC Alg Flags ++ flags = SC_ALGORITHM_ONBOARD_KEY_GEN|SC_ALGORITHM_ECDSA_HASH_SHA1|SC_ALGORITHM_ECDSA_HASH_SHA256|SC_ALGORITHM_ECDSA_HASH_NONE|SC_ALGORITHM_ECDSA_RAW; ++ ext_flags = 0; ++ _sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL); ++ + card->caps = SC_CARD_CAP_RNG | SC_CARD_CAP_APDU_EXT; + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +@@ -1561,6 +1576,13 @@ epass2003_set_security_env(struct sc_card *card, const sc_security_env_t * env, + u8 *p; + unsigned short fid = 0; + int r, locked = 0; ++ epass2003_exdata *exdata = NULL; ++ ++ if (!card->drv_data) ++ return SC_ERROR_INVALID_ARGUMENTS; ++ ++ exdata = (epass2003_exdata *)card->drv_data; ++ exdata->currAlg = SC_ALGORITHM_RSA; //default algorithm + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0); + switch (env->operation) { +@@ -1590,6 +1612,28 @@ epass2003_set_security_env(struct sc_card *card, const sc_security_env_t * env, + apdu.lc = r; + apdu.datalen = r; + apdu.data = sbuf; ++ ++ if (env->algorithm == SC_ALGORITHM_EC) ++ { ++ apdu.p2 = 0xB6; ++ exdata->currAlg = SC_ALGORITHM_EC; ++ if(env->algorithm_flags | SC_ALGORITHM_ECDSA_HASH_SHA1) ++ { ++ sbuf[2] = 0x91; ++ exdata->ecAlgFlags = SC_ALGORITHM_ECDSA_HASH_SHA1; ++ } ++ else if (env->algorithm_flags | SC_ALGORITHM_ECDSA_HASH_SHA256) ++ { ++ sbuf[2] = 0x92; ++ exdata->ecAlgFlags = SC_ALGORITHM_ECDSA_HASH_SHA256; ++ } ++ else ++ { ++ sc_log(card->ctx, "%0x Alg Not Support! ", env->algorithm_flags); ++ goto err; ++ } ++ } ++ + if (se_num > 0) { + r = sc_lock(card); + LOG_TEST_RET(card->ctx, r, "sc_lock() failed"); +@@ -1640,7 +1684,55 @@ static int epass2003_decipher(struct sc_card *card, const u8 * data, size_t data + struct sc_apdu apdu; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE] = { 0 }; + u8 sbuf[SC_MAX_APDU_BUFFER_SIZE] = { 0 }; ++ epass2003_exdata *exdata = NULL; ++ ++ LOG_FUNC_CALLED(card->ctx); ++ ++ if (!card->drv_data) ++ return SC_ERROR_INVALID_ARGUMENTS; ++ ++ exdata = (epass2003_exdata *)card->drv_data; + ++ if(exdata->currAlg == SC_ALGORITHM_EC) ++ { ++ unsigned char hash[HASH_LEN] = { 0 }; ++ if(exdata->ecAlgFlags | SC_ALGORITHM_ECDSA_HASH_SHA1) ++ { ++ hash_data(data, datalen, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); ++ sc_format_apdu(card, &apdu, SC_APDU_CASE_3,0x2A, 0x9E, 0x9A); ++ memset(sbuf, 0, sizeof(sbuf)); ++ memcpy(sbuf, hash, 0x14); ++ apdu.data = sbuf; ++ apdu.lc = 0x14; ++ apdu.datalen = 0x14; ++ } ++ else if (exdata->ecAlgFlags | SC_ALGORITHM_ECDSA_HASH_SHA256) ++ { ++ hash_data(data, datalen, hash, SC_ALGORITHM_ECDSA_HASH_SHA256); ++ sc_format_apdu(card, &apdu, SC_APDU_CASE_3,0x2A, 0x9E, 0x9A); ++ memset(sbuf, 0, sizeof(sbuf)); ++ memcpy(sbuf, hash, 0x20); ++ apdu.data = sbuf; ++ apdu.lc = 0x20; ++ apdu.datalen = 0x20; ++ } ++ else ++ { ++ return SC_ERROR_NOT_SUPPORTED; ++ } ++ apdu.resp = rbuf; ++ apdu.resplen = sizeof(rbuf); ++ apdu.le = 0; ++ ++ r = sc_transmit_apdu_t(card, &apdu); ++ LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); ++ if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { ++ size_t len = apdu.resplen > outlen ? outlen : apdu.resplen; ++ memcpy(out, apdu.resp, len); ++ LOG_FUNC_RETURN(card->ctx, len); ++ } ++ LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2)); ++ } + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_EXT, 0x2A, 0x80, 0x86); + apdu.resp = rbuf; + apdu.resplen = sizeof(rbuf); +@@ -1862,11 +1954,13 @@ epass2003_construct_fci(struct sc_card *card, const sc_file_t * file, + + } + else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { +- if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT) { ++ if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || ++ file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT) { + buf[0] = 0x11; + buf[1] = 0x00; + } +- else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) { ++ else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC || ++ file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { + buf[0] = 0x12; + buf[1] = 0x00; + } +@@ -1903,7 +1997,9 @@ epass2003_construct_fci(struct sc_card *card, const sc_file_t * file, + } + else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { + if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || +- file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) { ++ file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC|| ++ file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT|| ++ file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { + buf[0] = (file->size >> 8) & 0xFF; + buf[1] = file->size & 0xFF; + sc_asn1_put_tag(0x85, buf, 2, p, *outlen - (p - out), &p); +@@ -1942,13 +2038,14 @@ epass2003_construct_fci(struct sc_card *card, const sc_file_t * file, + ops[3] = SC_AC_OP_DELETE; + } + else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { +- if (file->ef_structure == +- SC_CARDCTL_OBERTHUR_KEY_RSA_CRT) { ++ if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT || ++ file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_CRT) { + ops[1] = SC_AC_OP_UPDATE; + ops[2] = SC_AC_OP_CRYPTO; + ops[3] = SC_AC_OP_DELETE; + } +- else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) { ++ else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC|| ++ file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { + ops[0] = SC_AC_OP_READ; + ops[1] = SC_AC_OP_UPDATE; + ops[2] = SC_AC_OP_CRYPTO; +@@ -1973,13 +2070,22 @@ epass2003_construct_fci(struct sc_card *card, const sc_file_t * file, + buf[ii] = rv; + } + sc_asn1_put_tag(0x86, buf, sizeof(ops), p, *outlen - (p - out), &p); ++ if(file->size == 256) ++ { ++ out[4]= 0x13; ++ } + + } + + /* VT ??? */ +- if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) { ++ if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC|| ++ file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC) { + unsigned char data[2] = {0x00, 0x66}; + sc_asn1_put_tag(0x87, data, sizeof(data), p, *outlen - (p - out), &p); ++ if(file->size == 256) ++ { ++ out[4]= 0x14; ++ } + } + + out[1] = p - out - 2; +@@ -2129,19 +2235,36 @@ internal_write_rsa_key(struct sc_card *card, unsigned short fid, struct sc_pkcs1 + + + static int +-hash_data(unsigned char *data, size_t datalen, unsigned char *hash) ++hash_data(const unsigned char *data, size_t datalen, unsigned char *hash, unsigned int mechanismType) + { +- unsigned char data_hash[24] = { 0 }; +- size_t len = 0; + + if ((NULL == data) || (NULL == hash)) + return SC_ERROR_INVALID_ARGUMENTS; + +- sha1_digest(data, datalen, data_hash); ++ if(mechanismType | SC_ALGORITHM_ECDSA_HASH_SHA1) ++ { ++ unsigned char data_hash[24] = { 0 }; ++ size_t len = 0; + +- len = REVERSE_ORDER4(datalen); +- memcpy(&data_hash[20], &len, 4); +- memcpy(hash, data_hash, 24); ++ sha1_digest(data, datalen, data_hash); ++ len = REVERSE_ORDER4(datalen); ++ memcpy(&data_hash[20], &len, 4); ++ memcpy(hash, data_hash, 24); ++ } ++ else if(mechanismType | SC_ALGORITHM_ECDSA_HASH_SHA256) ++ { ++ unsigned char data_hash[36] = { 0 }; ++ size_t len = 0; ++ ++ sha256_digest(data, datalen, data_hash); ++ len = REVERSE_ORDER4(datalen); ++ memcpy(&data_hash[32], &len, 4); ++ memcpy(hash, data_hash, 36); ++ } ++ else ++ { ++ return SC_ERROR_NOT_SUPPORTED; ++ } + + return SC_SUCCESS; + } +@@ -2214,7 +2337,7 @@ internal_install_pin(struct sc_card *card, sc_epass2003_wkey_data * pin) + int r; + unsigned char hash[HASH_LEN] = { 0 }; + +- r = hash_data(pin->key_data.es_secret.key_val, pin->key_data.es_secret.key_len, hash); ++ r = hash_data(pin->key_data.es_secret.key_val, pin->key_data.es_secret.key_len, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); + LOG_TEST_RET(card->ctx, r, "hash data failed"); + + r = install_secret_key(card, 0x04, pin->key_data.es_secret.kid, +@@ -2265,7 +2388,14 @@ epass2003_gen_key(struct sc_card *card, sc_epass2003_gen_key_data * data) + + LOG_FUNC_CALLED(card->ctx); + +- sbuf[0] = 0x01; ++ if(len == 256) ++ { ++ sbuf[0] = 0x02; ++ } ++ else ++ { ++ sbuf[0] = 0x01; ++ } + sbuf[1] = (u8) ((len >> 8) & 0xff); + sbuf[2] = (u8) (len & 0xff); + sbuf[3] = (u8) ((data->prkey_id >> 8) & 0xFF); +@@ -2285,6 +2415,10 @@ epass2003_gen_key(struct sc_card *card, sc_epass2003_gen_key_data * data) + + /* read public key */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xb4, 0x02, 0x00); ++ if(len == 256) ++ { ++ apdu.p1 = 0x00; ++ } + apdu.cla = 0x80; + apdu.lc = apdu.datalen = 2; + apdu.data = &sbuf[5]; +@@ -2349,6 +2483,7 @@ epass2003_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr) + { + LOG_FUNC_CALLED(card->ctx); + ++ sc_log(card->ctx, "cmd is %0lx", cmd); + switch (cmd) { + case SC_CARDCTL_ENTERSAFE_WRITE_KEY: + return epass2003_write_key(card, (sc_epass2003_wkey_data *) ptr); +@@ -2474,7 +2609,7 @@ external_key_auth(struct sc_card *card, unsigned char kid, + r = sc_get_challenge(card, random, 8); + LOG_TEST_RET(card->ctx, r, "get challenge external_key_auth failed"); + +- r = hash_data(data, datalen, hash); ++ r = hash_data(data, datalen, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); + LOG_TEST_RET(card->ctx, r, "hash data failed"); + + des3_encrypt_cbc(hash, HASH_LEN, iv, random, 8, tmp_data); +@@ -2501,7 +2636,7 @@ update_secret_key(struct sc_card *card, unsigned char ktype, unsigned char kid, + unsigned char tmp_data[256] = { 0 }; + unsigned char maxtries = 0; + +- r = hash_data(data, datalen, hash); ++ r = hash_data(data, datalen, hash, SC_ALGORITHM_ECDSA_HASH_SHA1); + LOG_TEST_RET(card->ctx, r, "hash data failed"); + + r = get_external_key_maxtries(card, &maxtries); +diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h +index 9a58427b7..b647b0537 100644 +--- a/src/libopensc/cardctl.h ++++ b/src/libopensc/cardctl.h +@@ -490,7 +490,9 @@ enum SC_CARDCTL_OBERTHUR_KEY_TYPE { + SC_CARDCTL_OBERTHUR_KEY_RSA_SFM, + SC_CARDCTL_OBERTHUR_KEY_RSA_CRT, + SC_CARDCTL_OBERTHUR_KEY_DSA_PUBLIC, +- SC_CARDCTL_OBERTHUR_KEY_DSA_PRIVATE ++ SC_CARDCTL_OBERTHUR_KEY_DSA_PRIVATE, ++ SC_CARDCTL_OBERTHUR_KEY_EC_CRT, ++ SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC + }; + + struct sc_cardctl_oberthur_genkey_info { +diff --git a/src/libopensc/sm.c b/src/libopensc/sm.c +index 94f7ce7c3..877a5ef12 100644 +--- a/src/libopensc/sm.c ++++ b/src/libopensc/sm.c +@@ -157,7 +157,7 @@ sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu) + } + + /* send APDU flagged as NO_SM */ +- sm_apdu->flags |= SC_APDU_FLAGS_NO_SM; ++ sm_apdu->flags |= SC_APDU_FLAGS_NO_SM | SC_APDU_FLAGS_NO_RETRY_WL; + rv = sc_transmit_apdu(card, sm_apdu); + if (rv < 0) { + card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); +diff --git a/src/pkcs15init/pkcs15-epass2003.c b/src/pkcs15init/pkcs15-epass2003.c +index 3be5ab856..786a71258 100644 +--- a/src/pkcs15init/pkcs15-epass2003.c ++++ b/src/pkcs15init/pkcs15-epass2003.c +@@ -312,6 +312,16 @@ cosm_new_file(struct sc_profile *profile, struct sc_card *card, + num); + while (1) { + switch (type) { ++ case SC_PKCS15_TYPE_PRKEY_EC: ++ desc = "RSA private key"; ++ _template = "private-key"; ++ structure = SC_CARDCTL_OBERTHUR_KEY_EC_CRT; ++ break; ++ case SC_PKCS15_TYPE_PUBKEY_EC: ++ desc = "RSA public key"; ++ _template = "public-key"; ++ structure = SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC; ++ break; + case SC_PKCS15_TYPE_PRKEY_RSA: + desc = "RSA private key"; + _template = "private-key"; +@@ -497,11 +507,14 @@ static int epass2003_pkcs15_generate_key(struct sc_profile *profile, + + SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); + +- if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) ++ if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA && obj->type != SC_PKCS15_TYPE_PRKEY_EC) + return SC_ERROR_NOT_SUPPORTED; + ++ if(obj->type == SC_PKCS15_TYPE_PRKEY_EC && keybits == 0) ++ keybits = 256; //EC key length is 256 ... ++ + /* allocate key object */ +- r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PRKEY_RSA, idx, &file); ++ r = cosm_new_file(profile, card, obj->type, idx, &file); //replace SC_PKCS15_TYPE_PRKEY_RSA with obj->type + SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_NORMAL, r, + "create key: failed to allocate new key object"); + file->size = keybits; +@@ -525,11 +538,18 @@ static int epass2003_pkcs15_generate_key(struct sc_profile *profile, + "index %"SC_FORMAT_LEN_SIZE_T"u; keybits %"SC_FORMAT_LEN_SIZE_T"u\n", + idx, keybits); + if (keybits < 1024 || keybits > 2048 || (keybits % 0x20)) { +- sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, +- "Unsupported key size %"SC_FORMAT_LEN_SIZE_T"u\n", +- keybits); +- r = SC_ERROR_INVALID_ARGUMENTS; +- goto err; ++ if(obj->type == SC_PKCS15_TYPE_PRKEY_EC && keybits == 256) ++ { ++ sc_log(card->ctx, "current Alg is EC,Only support 256 ..\n"); ++ } ++ else ++ { ++ sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, ++ "Unsupported key size %"SC_FORMAT_LEN_SIZE_T"u\n", ++ keybits); ++ r = SC_ERROR_INVALID_ARGUMENTS; ++ goto err; ++ } + } + + path = key_info->path; +@@ -549,12 +569,23 @@ static int epass2003_pkcs15_generate_key(struct sc_profile *profile, + SC_TEST_GOTO_ERR(card->ctx, SC_LOG_DEBUG_NORMAL, r, + "generate key: pkcs15init_authenticate(SC_AC_OP_CREATE) failed"); + +- if ((r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PUBKEY_RSA, idx, +- &pukf)) < 0) { ++ if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA ) ++ { ++ ++ r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PUBKEY_EC, idx, &pukf); ++ } ++ else ++ { ++ ++ r = cosm_new_file(profile, card, SC_PKCS15_TYPE_PUBKEY_RSA, idx, &pukf); ++ } ++ ++ if (r < 0) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + "generate key: create temporary pukf failed\n"); + goto err; + } ++ + pukf->size = keybits; + pukf->id = pukf->path.value[pukf->path.len - 2] * 0x100 + + pukf->path.value[pukf->path.len - 1]; + diff --git a/opensc.spec b/opensc.spec index 63b0afe..eb82094 100644 --- a/opensc.spec +++ b/opensc.spec @@ -23,6 +23,9 @@ Patch3: opensc-0.17.0-infinite-loop.patch Patch4: opensc-0.17.0-cac-alt.patch # Properly parse multi-byte length (#1473418) Patch5: opensc-0.17.0-simpletlv.patch +# Make Feitian tokens working again (#1558099) +# https://github.com/OpenSC/OpenSC/pull/1145 +Patch6: opensc-0.17.0-feitian.patch BuildRequires: pcsc-lite-devel BuildRequires: readline-devel @@ -55,6 +58,7 @@ every software/card that does so, too. %patch3 -p1 -b .infinite %patch4 -p1 -b .cac-alt %patch5 -p1 -b .simpletlv +%patch6 -p1 -b .feitian cp -p src/pkcs15init/README ./README.pkcs15init cp -p src/scconf/README.scconf .