- implemented decipher() operation
- removed SC_CARDCTL_GET_PK_ALGORITHMS card_ctl - minor signing fixes git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@328 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
6ca0cb108c
commit
ccb6bb1b1c
|
@ -90,8 +90,6 @@ struct gpk_private_data {
|
||||||
};
|
};
|
||||||
#define DRVDATA(card) ((struct gpk_private_data *) ((card)->drv_data))
|
#define DRVDATA(card) ((struct gpk_private_data *) ((card)->drv_data))
|
||||||
|
|
||||||
static struct sc_pk_info *gpk_add_algorithm(struct sc_cardctl_pk_algorithms *,
|
|
||||||
unsigned int, unsigned int);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ATRs of GPK4000 cards courtesy of libscez
|
* ATRs of GPK4000 cards courtesy of libscez
|
||||||
|
@ -153,7 +151,7 @@ gpk_init(struct sc_card *card)
|
||||||
{
|
{
|
||||||
struct gpk_private_data *priv;
|
struct gpk_private_data *priv;
|
||||||
struct atrinfo *ai;
|
struct atrinfo *ai;
|
||||||
unsigned long exponent, flags;
|
unsigned long exponent, flags, kg;
|
||||||
|
|
||||||
if (!(ai = gpk_identify(card)))
|
if (!(ai = gpk_identify(card)))
|
||||||
return SC_ERROR_INVALID_CARD;
|
return SC_ERROR_INVALID_CARD;
|
||||||
|
@ -177,9 +175,10 @@ gpk_init(struct sc_card *card)
|
||||||
flags |= SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_PAD_ANSI
|
flags |= SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_PAD_ANSI
|
||||||
| SC_ALGORITHM_RSA_PAD_ISO9796;
|
| SC_ALGORITHM_RSA_PAD_ISO9796;
|
||||||
exponent = (ai->variant / 1000 < 16)? 0x10001 : -1;
|
exponent = (ai->variant / 1000 < 16)? 0x10001 : -1;
|
||||||
_sc_card_add_rsa_alg(card, 512, flags, exponent);
|
kg = (ai->variant >= 8000)? SC_ALGORITHM_ONBOARD_KEY_GEN : 0;
|
||||||
|
_sc_card_add_rsa_alg(card, 512, flags|kg, exponent);
|
||||||
_sc_card_add_rsa_alg(card, 768, flags, exponent);
|
_sc_card_add_rsa_alg(card, 768, flags, exponent);
|
||||||
_sc_card_add_rsa_alg(card, 1024, flags, exponent);
|
_sc_card_add_rsa_alg(card, 1024, flags|kg, exponent);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1119,7 +1118,16 @@ gpk_set_security_env(struct sc_card *card,
|
||||||
|
|
||||||
/* Right now, the OpenSC flags do not support any padding
|
/* Right now, the OpenSC flags do not support any padding
|
||||||
* other than PKCS#1. */
|
* other than PKCS#1. */
|
||||||
priv->sec_padding = 0;
|
if (env->flags & SC_ALGORITHM_RSA_PAD_PKCS1)
|
||||||
|
priv->sec_padding = 0;
|
||||||
|
else if (env->flags & SC_ALGORITHM_RSA_PAD_ANSI)
|
||||||
|
priv->sec_padding = 1;
|
||||||
|
else if (env->flags & SC_ALGORITHM_RSA_PAD_ISO9796)
|
||||||
|
priv->sec_padding = 2;
|
||||||
|
else {
|
||||||
|
error(card->ctx, "Padding algorithm not supported.\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
switch (env->operation) {
|
switch (env->operation) {
|
||||||
case SC_SEC_OPERATION_SIGN:
|
case SC_SEC_OPERATION_SIGN:
|
||||||
|
@ -1131,9 +1139,17 @@ gpk_set_security_env(struct sc_card *card,
|
||||||
if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) {
|
if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) {
|
||||||
context = GPK_AUTH_RSA_SHA;
|
context = GPK_AUTH_RSA_SHA;
|
||||||
priv->sec_hash_len = 20;
|
priv->sec_hash_len = 20;
|
||||||
} else {
|
} else
|
||||||
|
if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5_SHA1) {
|
||||||
|
context = GPK_AUTH_RSA_SSL;
|
||||||
|
priv->sec_hash_len = 36;
|
||||||
|
} else
|
||||||
|
if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5) {
|
||||||
context = GPK_AUTH_RSA_MD5;
|
context = GPK_AUTH_RSA_MD5;
|
||||||
priv->sec_hash_len = 16;
|
priv->sec_hash_len = 16;
|
||||||
|
} else {
|
||||||
|
error(card->ctx, "Unsupported signature algorithm");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SC_SEC_OPERATION_DECIPHER:
|
case SC_SEC_OPERATION_DECIPHER:
|
||||||
|
@ -1204,6 +1220,21 @@ gpk_restore_security_env(struct sc_card *card, int se_num)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Revert buffer (needed for all GPK crypto operations because
|
||||||
|
* they want LSB byte order internally
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
reverse(u8 *out, size_t outlen, const u8 *in, size_t inlen)
|
||||||
|
{
|
||||||
|
if (inlen > outlen)
|
||||||
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||||
|
outlen = inlen;
|
||||||
|
while (inlen--)
|
||||||
|
*out++ = in[inlen];
|
||||||
|
return outlen;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use the card's on-board hashing functions to hash some data
|
* Use the card's on-board hashing functions to hash some data
|
||||||
*/
|
*/
|
||||||
|
@ -1256,12 +1287,10 @@ gpk_init_hashed(struct sc_card *card, const u8 *digest, unsigned int len)
|
||||||
{
|
{
|
||||||
struct sc_apdu apdu;
|
struct sc_apdu apdu;
|
||||||
u8 tsegid[64];
|
u8 tsegid[64];
|
||||||
unsigned int k;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(len <= sizeof(tsegid));
|
r = reverse(tsegid, sizeof(tsegid), digest, len);
|
||||||
for (k = 0; k < len; k++)
|
SC_TEST_RET(card->ctx, r, "Failed to reverse buffer");
|
||||||
tsegid[k] = digest[len-1-k];
|
|
||||||
|
|
||||||
memset(&apdu, 0, sizeof(apdu));
|
memset(&apdu, 0, sizeof(apdu));
|
||||||
apdu.cse = SC_APDU_CASE_3_SHORT;
|
apdu.cse = SC_APDU_CASE_3_SHORT;
|
||||||
|
@ -1290,7 +1319,6 @@ gpk_compute_signature(struct sc_card *card, const u8 *data,
|
||||||
struct gpk_private_data *priv = DRVDATA(card);
|
struct gpk_private_data *priv = DRVDATA(card);
|
||||||
struct sc_apdu apdu;
|
struct sc_apdu apdu;
|
||||||
u8 cardsig[1024/8];
|
u8 cardsig[1024/8];
|
||||||
unsigned int n, len;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (data_len > priv->sec_mod_len) {
|
if (data_len > priv->sec_mod_len) {
|
||||||
|
@ -1323,15 +1351,62 @@ gpk_compute_signature(struct sc_card *card, const u8 *data,
|
||||||
|
|
||||||
/* The GPK returns the signature as little endian numbers.
|
/* The GPK returns the signature as little endian numbers.
|
||||||
* Need to revert these */
|
* Need to revert these */
|
||||||
len = priv->sec_mod_len;
|
r = reverse(out, outlen, cardsig, apdu.resplen);
|
||||||
if (len > outlen) {
|
SC_TEST_RET(card->ctx, r, "Failed to reverse signature");
|
||||||
error(card->ctx, "Signature buffer too small\n");
|
|
||||||
return SC_ERROR_BUFFER_TOO_SMALL;
|
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 int
|
||||||
|
gpk_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) {
|
||||||
|
error(card->ctx,
|
||||||
|
"Data length (%u) does not match key modulus %u.\n",
|
||||||
|
inlen, priv->sec_mod_len);
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (n = 0; n < len; n++)
|
/* First revert the cryptogram */
|
||||||
out[n] = cardsig[len-1-n];
|
r = reverse(buffer, sizeof(buffer), in, inlen);
|
||||||
return len;
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1381,99 +1456,6 @@ gpk_erase_card(struct sc_card *card)
|
||||||
SC_FUNC_RETURN(card->ctx, 2, r);
|
SC_FUNC_RETURN(card->ctx, 2, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Get list of supported public key algorithms and sizes
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
gpk_get_pk_algorithms(struct sc_card *card,
|
|
||||||
struct sc_cardctl_pk_algorithms *res)
|
|
||||||
{
|
|
||||||
struct gpk_private_data *priv = DRVDATA(card);
|
|
||||||
struct sc_apdu apdu;
|
|
||||||
struct sc_path path;
|
|
||||||
unsigned int gpkclass;
|
|
||||||
u8 cardinfo[13], max_session_key;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
memset(res, 0, sizeof(*res));
|
|
||||||
|
|
||||||
gpk_add_algorithm(res, SC_ALGORITHM_RSA, 512);
|
|
||||||
gpk_add_algorithm(res, SC_ALGORITHM_RSA, 768);
|
|
||||||
gpk_add_algorithm(res, SC_ALGORITHM_RSA, 1024);
|
|
||||||
|
|
||||||
gpkclass = (priv->variant / 1000) * 1000;
|
|
||||||
|
|
||||||
/* GPK8000 and GPK16000 support on-board key generation
|
|
||||||
* for 512 and 1024 bit keys */
|
|
||||||
if (gpkclass >= 8000) {
|
|
||||||
res->algorithms[0].pk_onboard_generation = 1;
|
|
||||||
res->algorithms[2].pk_onboard_generation = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cards prior to the GPK16000 do not allow RSA exponents
|
|
||||||
* other that 0x10001 */
|
|
||||||
if (gpkclass < 16000) {
|
|
||||||
res->algorithms[0].pk_rsa_exponent = 0x10001;
|
|
||||||
res->algorithms[1].pk_rsa_exponent = 0x10001;
|
|
||||||
res->algorithms[1].pk_rsa_exponent = 0x10001;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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, &max_session_key, 1, 0)) < 0)
|
|
||||||
return r;
|
|
||||||
res->algorithms[0].pk_rsa_unwrap = max_session_key;
|
|
||||||
res->algorithms[1].pk_rsa_unwrap = max_session_key;
|
|
||||||
res->algorithms[2].pk_rsa_unwrap = max_session_key;
|
|
||||||
|
|
||||||
/* Do a Get Info call to find out whether DSA is
|
|
||||||
* supported. */
|
|
||||||
memset(&apdu, 0, sizeof(apdu));
|
|
||||||
apdu.cse = SC_APDU_CASE_2_SHORT;
|
|
||||||
apdu.cla = 0x80;
|
|
||||||
apdu.ins = 0xC0;
|
|
||||||
apdu.p1 = 0x02;
|
|
||||||
apdu.p2 = 0xA4;
|
|
||||||
apdu.le = sizeof(cardinfo);
|
|
||||||
apdu.resp= cardinfo;
|
|
||||||
apdu.resplen = sizeof(cardinfo);
|
|
||||||
|
|
||||||
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 (cardinfo[11] & 0x10) {
|
|
||||||
/* We have DSA support */
|
|
||||||
gpk_add_algorithm(res, SC_ALGORITHM_DSA, 512);
|
|
||||||
gpk_add_algorithm(res, SC_ALGORITHM_DSA, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This should really be made available to all card drivers,
|
|
||||||
* and added to sc-internal.h
|
|
||||||
*/
|
|
||||||
static struct sc_pk_info *
|
|
||||||
gpk_add_algorithm(struct sc_cardctl_pk_algorithms *res,
|
|
||||||
unsigned int algo, unsigned int keysize)
|
|
||||||
{
|
|
||||||
struct sc_pk_info *p;
|
|
||||||
|
|
||||||
res->algorithms = realloc(res->algorithms,
|
|
||||||
(res->count + 1) * sizeof(*p));
|
|
||||||
p = res->algorithms + res->count++;
|
|
||||||
|
|
||||||
memset(p, 0, sizeof(*p));
|
|
||||||
p->pk_algorithm = algo;
|
|
||||||
p->pk_keylength = keysize;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock a file Access Condition.
|
* Lock a file Access Condition.
|
||||||
*
|
*
|
||||||
|
@ -1611,6 +1593,33 @@ gpk_pkfile_load(struct sc_card *card, struct sc_cardctl_gpk_pkload *args)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the maximum size of a session key the card is
|
||||||
|
* willing to decrypt
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
static int
|
||||||
|
gpk_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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dispatch card_ctl calls
|
* Dispatch card_ctl calls
|
||||||
*/
|
*/
|
||||||
|
@ -1620,9 +1629,6 @@ gpk_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr)
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SC_CARDCTL_ERASE_CARD:
|
case SC_CARDCTL_ERASE_CARD:
|
||||||
return gpk_erase_card(card);
|
return gpk_erase_card(card);
|
||||||
case SC_CARDCTL_GET_PK_ALGORITHMS:
|
|
||||||
return gpk_get_pk_algorithms(card,
|
|
||||||
(struct sc_cardctl_pk_algorithms *) ptr);
|
|
||||||
case SC_CARDCTL_GPK_LOCK:
|
case SC_CARDCTL_GPK_LOCK:
|
||||||
return gpk_lock(card, (struct sc_cardctl_gpk_lock *) ptr);
|
return gpk_lock(card, (struct sc_cardctl_gpk_lock *) ptr);
|
||||||
case SC_CARDCTL_GPK_PKINIT:
|
case SC_CARDCTL_GPK_PKINIT:
|
||||||
|
@ -1663,6 +1669,7 @@ sc_get_driver()
|
||||||
gpk_ops.set_security_env= gpk_set_security_env;
|
gpk_ops.set_security_env= gpk_set_security_env;
|
||||||
gpk_ops.restore_security_env= gpk_restore_security_env;
|
gpk_ops.restore_security_env= gpk_restore_security_env;
|
||||||
gpk_ops.compute_signature= gpk_compute_signature;
|
gpk_ops.compute_signature= gpk_compute_signature;
|
||||||
|
gpk_ops.decipher = gpk_decipher;
|
||||||
gpk_ops.reset_retry_counter = gpk_reset_retry_counter;
|
gpk_ops.reset_retry_counter = gpk_reset_retry_counter;
|
||||||
gpk_ops.change_reference_data = gpk_change_reference_data;
|
gpk_ops.change_reference_data = gpk_change_reference_data;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue