Skip to content

Commit

Permalink
myeid: fix to ECDH implementation
Browse files Browse the repository at this point in the history
fixing #756
rebased by VTA
  • Loading branch information
hhonkanen authored and viktorTarasov committed Aug 13, 2016
1 parent 6ad229e commit 6cd28cf
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 74 deletions.
41 changes: 34 additions & 7 deletions src/libopensc/card-myeid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 */
/* 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.
*/

sbuf[0] = 0x7C;
sbuf[1] = pubkey_len + 4;
sbuf[2] = 0x85;
sbuf[3] = pubkey_len;
memcpy(&sbuf[4], pubkey, pubkey_len);
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;
}

apdu.lc = pubkey_len + 4;
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;

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


Expand Down
27 changes: 21 additions & 6 deletions src/pkcs15init/pkcs15-myeid.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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);
Expand Down
132 changes: 71 additions & 61 deletions src/tools/pkcs11-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -2817,103 +2817,113 @@ 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)},
{CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)},
{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 */

size_t buf_size = 0;
int len;

printf("Using derive algorithm 0x%8.8lx %s\n", opt_mechanism, p11_mechanism_to_name(mech_mech));
memset(&mech, 0, sizeof(mech));
mech.mechanism = mech_mech;

/* 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);

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

buf_size = sizeof(buf);
len = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, buf_size, 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;
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);

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");

printf("Using derive algorithm 0x%8.8lx %s\n", opt_mechanism, p11_mechanism_to_name(opt_mechanism));
memset(&mech, 0, sizeof(mech));
mech.mechanism = opt_mechanism;

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;

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

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

len = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, sizeof(buf),NULL);

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);
}
derived_key= derive_ec_key(session, key, opt_mechanism);
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;
}

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);
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);
}
}
Expand Down

0 comments on commit 6cd28cf

Please sign in to comment.