myeid: fix to ECDH implementation

fixing #756
rebased by VTA
This commit is contained in:
Hannu Honkanen 2016-08-07 13:08:19 +02:00 committed by Viktor Tarasov
parent 6ad229e9f6
commit 6cd28cfc7c
3 changed files with 127 additions and 75 deletions

View File

@ -678,6 +678,10 @@ static int myeid_set_security_env_ec(sc_card_t *card, const sc_security_env_t *e
apdu.p1 = 0x41;
apdu.p2 = 0xB6;
break;
case SC_SEC_OPERATION_DERIVE:
apdu.p1 = 0x41;
apdu.p2 = 0xA4;
break;
default:
return SC_ERROR_INVALID_ARGUMENTS;
}
@ -920,20 +924,43 @@ int myeid_ecdh_derive(struct sc_card *card, const u8* pubkey, size_t pubkey_len,
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
int r;
size_t ext_len_bytes;
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x86, 0x00, 0x00);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
/* Fill in "Data objects in dynamic authentication template (tag 0x7C) structure */
sbuf[0] = 0x7C;
sbuf[1] = pubkey_len + 4;
sbuf[2] = 0x85;
sbuf[3] = pubkey_len;
memcpy(&sbuf[4], pubkey, pubkey_len);
/* Fill in "Data objects in dynamic authentication template" (tag 0x7C) structure
*
* TODO: encode the structure using OpenSC's ASN1-functions.
*
* Size of the structure depends on key length. With 521 bit keys two bytes are needed for defining length of a point.
*/
apdu.lc = pubkey_len + 4;
sbuf[0] = 0x7C;
ext_len_bytes = 0;
if (pubkey_len > 127)
{
sbuf[1] = 0x81;
sbuf[2] = (u8) (pubkey_len + 3);
sbuf[3] = 0x85;
sbuf[4] = 0x81;
sbuf[5] = (u8) (pubkey_len);
ext_len_bytes = 2;
}
else
{
sbuf[1] = pubkey_len + 2;
sbuf[2] = 0x85;
sbuf[3] = pubkey_len;
}
memcpy(&sbuf[4 + ext_len_bytes], pubkey, pubkey_len);
apdu.lc = pubkey_len + 4 + ext_len_bytes;
apdu.le = 0;
apdu.datalen = apdu.lc;
apdu.data = sbuf;
@ -952,7 +979,7 @@ int myeid_ecdh_derive(struct sc_card *card, const u8* pubkey, size_t pubkey_len,
memcpy(out, rbuf, apdu.resplen);
LOG_FUNC_RETURN(card->ctx, r);
LOG_FUNC_RETURN(card->ctx, apdu.resplen);
}

View File

@ -30,10 +30,12 @@
#include "libopensc/log.h"
#include "pkcs15-init.h"
#include "profile.h"
#include "libopensc/asn1.h"
#undef KEEP_AC_NONE_FOR_INIT_APPLET
#define MYEID_MAX_PINS 14
#define MYEID_MAX_RSA_KEY_LEN 2048
unsigned char MYEID_DEFAULT_PUBKEY[] = {0x01, 0x00, 0x01};
#define MYEID_DEFAULT_PUBKEY_LEN sizeof(MYEID_DEFAULT_PUBKEY)
@ -580,8 +582,11 @@ myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
struct sc_cardctl_myeid_gen_store_key_info args;
struct sc_file *file = NULL;
int r;
unsigned int cla,tag;
size_t taglen;
size_t keybits = key_info->modulus_length;
unsigned char raw_pubkey[256];
u8 raw_pubkey[MYEID_MAX_RSA_KEY_LEN / 8];
u8* dataptr;
LOG_FUNC_CALLED(ctx);
if (object->type != SC_PKCS15_TYPE_PRKEY_RSA && object->type != SC_PKCS15_TYPE_PRKEY_EC)
@ -633,7 +638,7 @@ myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
args.key_type = SC_CARDCTL_MYEID_KEY_EC;
}
/* Generate RSA key */
/* Generate the key */
r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args);
LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed");
@ -683,13 +688,23 @@ myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
r = sc_card_ctl(card, SC_CARDCTL_MYEID_GETDATA, &data_obj);
LOG_TEST_RET(ctx, r, "Cannot get EC public key: 'MYEID_GETDATA' failed");
dataptr = data_obj.Data;
r = sc_asn1_read_tag((const u8 **)&dataptr, data_obj.DataLen, &cla, &tag, &taglen);
LOG_TEST_RET(ctx, r, "Invalid EC public key data. Cannot parse DER structure.");
if (taglen == 0)
LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
if (pubkey->u.ec.ecpointQ.value)
free(pubkey->u.ec.ecpointQ.value);
pubkey->u.ec.ecpointQ.value = malloc(data_obj.DataLen - 2);
if (pubkey->u.ec.ecpointQ.value == NULL)
pubkey->u.ec.ecpointQ.value = malloc(taglen);
if (pubkey->u.ec.ecpointQ.value == NULL)
LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
memcpy(pubkey->u.ec.ecpointQ.value, data_obj.Data + 2, data_obj.DataLen - 2);
pubkey->u.ec.ecpointQ.len = data_obj.DataLen - 2;
memcpy(pubkey->u.ec.ecpointQ.value, dataptr, taglen);
pubkey->u.ec.ecpointQ.len = taglen;
if (pubkey->u.ec.params.named_curve)
free(pubkey->u.ec.params.named_curve);

View File

@ -2817,19 +2817,16 @@ static void show_object(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
}
static void
derive_key(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
static CK_OBJECT_HANDLE
derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE mech_mech)
{
unsigned char *value = NULL;
CK_ULONG value_len = 0;
#if defined(ENABLE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA)
CK_MECHANISM mech;
CK_OBJECT_CLASS newkey_class= CKO_SECRET_KEY;
CK_KEY_TYPE newkey_type = CKK_GENERIC_SECRET;
CK_BBOOL true = TRUE;
CK_BBOOL false = FALSE;
CK_OBJECT_HANDLE newkey = 0;
CK_RV rv;
int fd, r;
CK_ATTRIBUTE newkey_template[] = {
{CKA_TOKEN, &false, sizeof(false)}, /* session only object */
{CKA_CLASS, &newkey_class, sizeof(newkey_class)},
@ -2837,83 +2834,96 @@ derive_key(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
{CKA_ENCRYPT, &true, sizeof(true)},
{CKA_DECRYPT, &true, sizeof(true)}
};
#if defined(ENABLE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA)
CK_ECDH1_DERIVE_PARAMS ecdh_parms;
CK_RV rv;
BIO *bio_in = NULL;
EC_KEY *eckey = NULL;
const EC_GROUP *ecgroup = NULL;
const EC_POINT *ecpoint = NULL;
unsigned char buf[512];
#endif /* ENABLE_OPENSSL etc */
if (!opt_mechanism_used)
if (!find_mechanism(slot, CKF_DERIVE|CKF_HW, NULL, 0, &opt_mechanism))
util_fatal("Derive mechanism not supported");
size_t buf_size = 0;
int len;
printf("Using derive algorithm 0x%8.8lx %s\n", opt_mechanism, p11_mechanism_to_name(opt_mechanism));
printf("Using derive algorithm 0x%8.8lx %s\n", opt_mechanism, p11_mechanism_to_name(mech_mech));
memset(&mech, 0, sizeof(mech));
mech.mechanism = opt_mechanism;
mech.mechanism = mech_mech;
switch(opt_mechanism) {
#if defined(ENABLE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA)
case CKM_ECDH1_COFACTOR_DERIVE:
case CKM_ECDH1_DERIVE:
/* Use OpenSSL to read the other public key, and get the raw verion */
{
int len;
BIO *bio_in = NULL;
const EC_KEY *eckey = NULL;
const EC_GROUP *ecgroup = NULL;
const EC_POINT * ecpoint = NULL;
/* Use OpenSSL to read the other public key, and get the raw version */
bio_in = BIO_new(BIO_s_file());
if (BIO_read_filename(bio_in, opt_input) <= 0)
util_fatal("Cannot open %s: %m", opt_input);
bio_in = BIO_new(BIO_s_file());
if (BIO_read_filename(bio_in, opt_input) <= 0)
util_fatal("Cannot open %s: %m", opt_input);
eckey = d2i_EC_PUBKEY_bio(bio_in, NULL);
if (!eckey)
util_fatal("Cannot read EC key from %s", opt_input);
eckey = d2i_EC_PUBKEY_bio(bio_in, NULL);
if (!eckey)
util_fatal("Cannot read EC key from %s", opt_input);
ecpoint = EC_KEY_get0_public_key(eckey);
ecgroup = EC_KEY_get0_group(eckey);
if (!ecpoint || !ecgroup)
util_fatal("Failed to parse other EC key from %s", opt_input);
ecpoint = EC_KEY_get0_public_key(eckey);
ecgroup = EC_KEY_get0_group(eckey);
if (!ecpoint || !ecgroup)
util_fatal("Failed to parse other EC key from %s", opt_input);
buf_size = sizeof(buf);
len = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, buf_size, NULL);
len = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, sizeof(buf),NULL);
BIO_free(bio_in);
EC_KEY_free(eckey);
memset(&ecdh_parms, 0, sizeof(ecdh_parms));
ecdh_parms.kdf = CKD_NULL;
ecdh_parms.ulSharedDataLen = 0;
ecdh_parms.pSharedData = NULL;
ecdh_parms.ulPublicDataLen = len; /* TODO drop header */
ecdh_parms.pPublicData = buf; /* Cheat to test */
mech.pParameter = &ecdh_parms;
mech.ulParameterLen = sizeof(ecdh_parms);
}
break;
#endif /* ENABLE_OPENSSL && !OPENSSL_NO_EC && !OPENSSL_NO_ECDSA */
/* TODO add RSA but do not have card to test */
default:
util_fatal("mechanism not supported for derive");
break;
}
memset(&ecdh_parms, 0, sizeof(ecdh_parms));
ecdh_parms.kdf = CKD_NULL;
ecdh_parms.ulSharedDataLen = 0;
ecdh_parms.pSharedData = NULL;
ecdh_parms.ulPublicDataLen = len;
ecdh_parms.pPublicData = buf;
mech.pParameter = &ecdh_parms;
mech.ulParameterLen = sizeof(ecdh_parms);
rv = p11->C_DeriveKey(session, &mech, key, newkey_template, 5, &newkey);
if (rv != CKR_OK)
p11_fatal("C_DeriveKey", rv);
/*TODO get the key value and write to stdout or file */
value = getVALUE(session, newkey, &value_len);
return newkey;
#else
util_fatal("Derive EC key not supported");
#endif /* ENABLE_OPENSSL && !OPENSSL_NO_EC && !OPENSSL_NO_ECDSA */
}
static void
derive_key(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
{
CK_BYTE *value = NULL;
CK_ULONG value_len = 0;
CK_OBJECT_HANDLE derived_key = 0;
int rv, fd;
if (!opt_mechanism_used)
if (!find_mechanism(slot, CKF_DERIVE|CKF_HW, NULL, 0, &opt_mechanism))
util_fatal("Derive mechanism not supported");
switch(opt_mechanism) {
case CKM_ECDH1_COFACTOR_DERIVE:
case CKM_ECDH1_DERIVE:
derived_key= derive_ec_key(session, key, opt_mechanism);
break;
default:
util_fatal("mechanism not supported for derive");
break;
}
value = getVALUE(session, derived_key, &value_len);
if (value && value_len > 0) {
if (opt_output == NULL) {
fd = 1;
}
else {
fd = STDOUT_FILENO;
if (opt_output) {
fd = open(opt_output, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR|S_IWUSR);
if (fd < 0)
util_fatal("failed to open %s: %m", opt_output);
}
r = write(fd, value, value_len);
if (r < 0)
rv = write(fd, value, value_len);
if (rv < 0)
util_fatal("Failed to write to %s: %m", opt_output);
if (fd != 1)
if (opt_output)
close(fd);
}
}