[pkg-opensc-commit] [opensc] 58/295: myeid: fix to ECDH implementation
Eric Dorland
eric at moszumanska.debian.org
Sat Jun 24 21:11:16 UTC 2017
This is an automated email from the git hooks/post-receive script.
eric pushed a commit to branch master
in repository opensc.
commit 6cd28cfc7c5d9aa2ace94d60549f58f5cd3c4a49
Author: Hannu Honkanen <hannu.honkanen at aventra.fi>
Date: Sun Aug 7 13:08:19 2016 +0200
myeid: fix to ECDH implementation
fixing #756
rebased by VTA
---
src/libopensc/card-myeid.c | 41 ++++++++++---
src/pkcs15init/pkcs15-myeid.c | 27 +++++++--
src/tools/pkcs11-tool.c | 132 +++++++++++++++++++++++-------------------
3 files changed, 126 insertions(+), 74 deletions(-)
diff --git a/src/libopensc/card-myeid.c b/src/libopensc/card-myeid.c
index 87be4da..3514626 100644
--- a/src/libopensc/card-myeid.c
+++ b/src/libopensc/card-myeid.c
@@ -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 */
+ /* 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;
@@ -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);
}
diff --git a/src/pkcs15init/pkcs15-myeid.c b/src/pkcs15init/pkcs15-myeid.c
index d3e9885..cb61001 100644
--- a/src/pkcs15init/pkcs15-myeid.c
+++ b/src/pkcs15init/pkcs15-myeid.c
@@ -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);
diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c
index 7c0b702..6bd885b 100644
--- a/src/tools/pkcs11-tool.c
+++ b/src/tools/pkcs11-tool.c
@@ -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 */
-
+ 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);
}
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/opensc.git
More information about the pkg-opensc-commit
mailing list