[pkg-opensc-commit] [libp11] 06/86: More OpenSSL 1.1 changes and improved error handling for ECDH

Eric Dorland eric at moszumanska.debian.org
Sun Jul 24 21:40:17 UTC 2016


This is an automated email from the git hooks/post-receive script.

eric pushed a commit to branch master
in repository libp11.

commit 2c6af01c264874d5968fcebb6ef035ccda9599bc
Author: Doug Engert <deengert at gmail.com>
Date:   Tue Jan 19 10:02:26 2016 -0600

    More OpenSSL 1.1 changes and improved error handling for ECDH
    
    libp11.h includes pkcs11.h The CK_ECDH1_DERIVE_PARAMS structure
    is defined in the OpenSC version of pkcs11.h.
    This could be changed if the PKCS11_ecdh_derive was change to accept the
    6 values in the structure inline.
    
    Better error handling.
---
 src/libp11.exports |   1 +
 src/libp11.h       |  19 ++++++++++
 src/p11_ec.c       | 105 ++++++++++++++++++++++++++++++++++++++++++++---------
 src/p11_err.c      |   1 +
 src/p11_ops.c      |  90 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 198 insertions(+), 18 deletions(-)

diff --git a/src/libp11.exports b/src/libp11.exports
index 95213b6..6363e0e 100644
--- a/src/libp11.exports
+++ b/src/libp11.exports
@@ -40,3 +40,4 @@ PKCS11_get_ecdsa_method
 PKCS11_ecdsa_method_free
 ERR_load_PKCS11_strings
 PKCS11_get_ec_key_method
+PKCS11_ecdh_derive
diff --git a/src/libp11.h b/src/libp11.h
index 3a6867f..c76ca44 100644
--- a/src/libp11.h
+++ b/src/libp11.h
@@ -30,6 +30,7 @@
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
 #include <openssl/x509.h>
+#include <pkcs11.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -387,6 +388,23 @@ extern int PKCS11_store_certificate(PKCS11_TOKEN * token, X509 * x509,
 extern int PKCS11_ecdsa_sign(const unsigned char *m, unsigned int m_len,
 		unsigned char *sigret, unsigned int *siglen, PKCS11_KEY * key);
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100002L
+/**
+ * @param out returned secret
+ * @param outlen length of returned secret
+ * @param ecdh_mechanism CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE or others in future
+ * @param ec_params ptr to CK_ECDH1_DERIVE_PARAMS or in future CK_ECMQV_DERIVE_PARAMS
+ * @param outnewkey ptr to CK_OBJECT_HANDLE
+ * @param key private key object
+ */
+
+extern int PKCS11_ecdh_derive(unsigned char **out, size_t *out_len,
+		const unsigned long ecdh_mechanism,
+		const void * ec_params,
+		CK_OBJECT_HANDLE * outnewkey,
+		PKCS11_KEY * key);
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10100002L */
+
 /* rsa private key operations */
 extern int PKCS11_sign(int type, const unsigned char *m, unsigned int m_len,
 	unsigned char *sigret, unsigned int *siglen, PKCS11_KEY * key);
@@ -459,6 +477,7 @@ extern void ERR_load_PKCS11_strings(void);
 #define PKCS11_F_PKCS11_EC_KEY_SIGN			41
 #define PKCS11_F_PKCS11_EC_KEY_VERIFY		42
 #define PKCS11_F_PKCS11_GETSESSIONINFO		43
+#define PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY	44
 
 #define PKCS11_ERR_BASE				1024
 #define PKCS11_LOAD_MODULE_ERROR		(PKCS11_ERR_BASE+1)
diff --git a/src/p11_ec.c b/src/p11_ec.c
index a3c5486..5895a26 100644
--- a/src/p11_ec.c
+++ b/src/p11_ec.c
@@ -1,7 +1,7 @@
 /* libp11, a simple layer on to of PKCS#11 API
  * Copyright (C) 2005 Olaf Kirch <okir at lst.de>
  * Copyright (C) 2011, 2013 Douglas E. Engert <deengert at anl.gov>
- * Copyright (C) 2014 Douglas E. Engert <deengert at gmail.com>
+ * Copyright (C) 2014, 2016 Douglas E. Engert <deengert at gmail.com>
  * Copyright (C) 2016 Michał Trojnara <Michal.Trojnara at stunnel.org>
  *
  *  This library is free software; you can redistribute it and/or
@@ -209,10 +209,11 @@ static ECDSA_SIG * pkcs11_ecdsa_do_sign(const unsigned char *dgst, int dlen,
 		if (sig) {
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
 		/*
-		 * OpenSSL 1.1 does not have a way to alloc r and s 
-		 * the BN in ECDSA_SIG as it is now hidden. 
-		 * Will us dummy ASN1 seq to set it, then
-		 * ECDSA_SIG_get0 to get access to r and s 
+		 * OpenSSL 1.1 does not have a way to allocate r and s 
+		 * in ECDSA_SIG as it is now hidden. 
+		 * Will us dummy ASN1 so r and s are allocated then
+		 * use ECDSA_SIG_get0 to get access to r and s 
+		 * can then update r annd s
 		 */
 			const unsigned char *a;
 			unsigned char dasn1[8] =
@@ -227,18 +228,6 @@ static ECDSA_SIG * pkcs11_ecdsa_do_sign(const unsigned char *dgst, int dlen,
 #else
 			BN_bin2bn(&sigret[0], nLen, sig->r);
 			BN_bin2bn(&sigret[nLen], nLen, sig->s);
-#if 0
-/* TODO remove this gdb debugging  */
-	{
-	    int ilen = 0;
-	    unsigned char tmpsigbuff[512];
-	    unsigned char **tmpsig = &tmpsigbuff;
-
-	    ilen = i2d_ECDSA_SIG(sig,NULL);
-	    ilen = i2d_ECDSA_SIG(sig, tmpsig);
-	    printf("ilen=&d\n",ilen);
-	}
-#endif
 #endif
 		}
 	}
@@ -246,6 +235,85 @@ static ECDSA_SIG * pkcs11_ecdsa_do_sign(const unsigned char *dgst, int dlen,
 }
 
 #if OPENSSL_VERSION_NUMBER >= 0x10100002L
+/* Our version of the ossl_ecdh_compute_key replaced in the EC_KEY_METHOD */
+static int pkcs11_ec_ckey(void *out,
+		size_t outlen,
+		const EC_POINT *ecpointpeer,
+		const EC_KEY *ecdh,
+		void *(*KDF) (const void *in,
+			size_t inlen,
+			void *out,
+			size_t *outlen))
+{
+	int ret = -1;
+	size_t buflen;
+	unsigned char *buf = NULL;
+	size_t peerbuflen;
+	unsigned char *peerbuf = NULL;
+	const EC_GROUP *ecgroup = NULL;
+	const EC_POINT *ecpoint = NULL;
+	CK_ECDH1_DERIVE_PARAMS ecdh_parms;
+	PKCS11_KEY * key = NULL;
+
+	key = (PKCS11_KEY *) EC_KEY_get_ex_data(ecdh, ec_key_ex_index);
+
+	if (key == NULL) {
+	    ret -1;
+	    goto err;
+	}
+
+	/* assume both peer and ecdh are same group */
+	ecgroup = EC_KEY_get0_group(ecdh);
+	buflen = (EC_GROUP_get_degree(ecgroup) + 7) / 8;
+
+	buf = OPENSSL_malloc(buflen);
+	if (buf == NULL) {
+		ret = -1;
+		goto err;
+	}
+
+	peerbuflen = 2*buflen + 1;
+	peerbuf = OPENSSL_malloc(peerbuflen);
+	if (peerbuf == NULL) {
+		ret = -1;
+		goto err;
+	}
+
+	ecdh_parms.kdf = CKD_NULL;
+	ecdh_parms.ulSharedDataLen = 0;
+	ecdh_parms.pSharedData = NULL;
+	ecdh_parms.ulPublicDataLen = peerbuflen;
+	ret = EC_POINT_point2oct(ecgroup,
+			ecpointpeer,
+			POINT_CONVERSION_UNCOMPRESSED,
+			peerbuf, peerbuflen,NULL);
+	ecdh_parms.ulPublicDataLen = peerbuflen;
+	ecdh_parms.pPublicData = peerbuf;
+
+
+	ret = PKCS11_ecdh_derive(&buf, &buflen, CKM_ECDH1_DERIVE,
+		(const void *)&ecdh_parms, NULL, key);
+
+	if (KDF != 0) {
+		if (KDF(buf, buflen, out, &outlen) == NULL) {
+			ret -1;
+			goto err;
+		}
+		ret = outlen;
+	} else {
+		if (outlen > buflen)
+		    outlen = buflen;
+		memcpy(out, buf, outlen);
+		ret = outlen;
+	}
+err:
+	OPENSSL_free(buf);
+	return (ret);
+}
+#endif
+
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100002L
 static void alloc_ec_key_ex_index() {
 	if (ec_key_ex_index == 0) {
 		while (ec_key_ex_index == 0) /* Workaround for OpenSSL RT3710 */
@@ -319,10 +387,11 @@ EC_KEY_METHOD *PKCS11_get_ec_key_method(void)
 		EC_KEY_METHOD_get_sign(ops, &orig_sign,
 			&orig_sign_setup, &orig_sign_sig);
 
-/* TODO look at which routines to use */
 		EC_KEY_METHOD_set_sign(ops, orig_sign,
 			pkcs11_ecdsa_sign_setup,
 			pkcs11_ecdsa_do_sign);
+
+		EC_KEY_METHOD_set_compute_key(ops, pkcs11_ec_ckey);
 	}
 	return ops;
 }
diff --git a/src/p11_err.c b/src/p11_err.c
index 7fb987e..46a9f80 100644
--- a/src/p11_err.c
+++ b/src/p11_err.c
@@ -47,6 +47,7 @@ static ERR_STRING_DATA PKCS11_str_functs[] = {
 	{ERR_PACK(0, PKCS11_F_PKCS11_STORE_PUBLIC_KEY, 0), "PKCS11_store_public_key"},
 	{ERR_PACK(0, PKCS11_F_PKCS11_STORE_CERTIFICATE, 0), "PKCS11_store_certificate"},
 	{ERR_PACK(0, PKCS11_F_PKCS11_CHANGE_PIN, 0), "PKCS11_change_pin"},
+	{ERR_PACK(0, PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, 0), "PKCS11_ecdh_derive"},
 	{0, NULL}
 };
 
diff --git a/src/p11_ops.c b/src/p11_ops.c
index 516bdec..d537170 100644
--- a/src/p11_ops.c
+++ b/src/p11_ops.c
@@ -25,6 +25,96 @@
 #include <openssl/ossl_typ.h>
 #include <openssl/asn1.h>
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100002L
+/* initial code will only support what what is needed for engine
+ * i.e. CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE
+ * and CK_EC_KDF_TYPE  supported by token
+  */
+extern int PKCS11_ecdh_derive(unsigned char **out, size_t *outlen,
+		const unsigned long ecdh_mechanism,
+		const void * ec_params,
+		CK_OBJECT_HANDLE *outnewkey,
+		PKCS11_KEY * key)
+{
+	int rv;
+	PKCS11_KEY_private *priv;
+	PKCS11_SLOT *slot;
+	PKCS11_CTX *ctx;
+	PKCS11_TOKEN *token;
+	CK_SESSION_HANDLE session;
+	CK_MECHANISM mechanism;
+
+	CK_BBOOL true = TRUE;
+	CK_BBOOL false = FALSE;
+	CK_OBJECT_HANDLE newkey;
+	CK_OBJECT_CLASS newkey_class= CKO_SECRET_KEY;
+	CK_KEY_TYPE newkey_type = CKK_GENERIC_SECRET;
+	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)}
+	};
+
+	ctx = KEY2CTX(key);
+	priv = PRIVKEY(key);
+	token = KEY2TOKEN(key);
+	slot = KEY2SLOT(key);
+
+	CHECK_KEY_FORK(key);
+
+	session = PRIVSLOT(slot)->session;
+
+	memset(&mechanism, 0, sizeof(mechanism));
+	mechanism.mechanism  = ecdh_mechanism;
+	mechanism.pParameter =  (void*)ec_params;
+	switch (ecdh_mechanism) {
+		case CKM_ECDH1_DERIVE:
+		case CKM_ECDH1_COFACTOR_DERIVE:
+			mechanism.ulParameterLen  = sizeof(CK_ECDH1_DERIVE_PARAMS);
+			break;
+//		case CK_ECMQV_DERIVE_PARAMS:
+//			mechanism.ulParameterLen  = sizeof(CK_ECMQV_DERIVE_PARAMS);
+//			break;
+		default:
+		    PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, PKCS11_NOT_SUPPORTED);
+		    return -1;
+	}
+
+	CRYPTO_w_lock(PRIVSLOT(slot)->lockid);
+	rv = CRYPTOKI_call(ctx, C_DeriveKey(session, &mechanism, priv->object, newkey_template, 5, &newkey));
+	if (rv) {
+	    PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(rv));
+	    return -1;
+	}
+
+	/* if requested copy new secret key value */
+	/* TODO for now engine only we will assume caller provided big enough out buffer */
+	/* for libp11, we could return the secret key object, slot and session somehow. */
+	/* that would require keeping track of secret key objects too. */
+	/* we need to handle the secret object so we can free it. */
+
+	if (out && outlen) {
+		if (*out == NULL
+			&& !pkcs11_getattr_var(token, newkey, CKA_VALUE, NULL, outlen)
+			&& *outlen > 0) {
+			*out = OPENSSL_malloc(*outlen);
+		}
+
+		if (*out) {
+		 pkcs11_getattr_var(token, newkey, CKA_VALUE, *out, outlen);
+		}
+	}
+
+	if (outnewkey) {
+	    *outnewkey = newkey;
+	}   /* TODO else free newkey */
+	
+	return 1;
+}
+#endif
+
 int
 PKCS11_ecdsa_sign(const unsigned char *m, unsigned int m_len,
 		unsigned char *sigret, unsigned int *siglen, PKCS11_KEY * key)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/libp11.git



More information about the pkg-opensc-commit mailing list