[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