Attached are mods to engine_pkcs11 and libp11 to allow the use
of ECDSA sign operations.  A new p11_ec.c files is added. The code
still has a lot of debuging statements, fprintf(stderr,..
and needs some polishing.

There is an issue with OpenSSL where ECDSA_METHOD is defined in
an internal header file, ecs_locl.c, but ECDSA_METHOD needs to be overridden
by libp11. This has been reported as OpenSSL bug #2459 on 2/23/2011.

The code has been tested with OpenSSL-1.0.0a, using the OpenSSL
engine and req commands to generate a cert request using the pub key from
the card, and signing the request using the private key on the card.

So if anyone is interested, these mods can be used by building libp11:

export CPPFLAGS="-DBUILD_WITH_EC -I/some.path/openssl-1.0.0a/crypto/ecdsa/"
./configure

The code will then find #include "ecs_locl.h";

When OpenSSL addresses #r2459 the modification can be updated.

This meets my needs to allow creation of EC keys and certificate
to test ECDH and key derivation.

--

 Douglas E. Engert  <deeng...@anl.gov>
 Argonne National Laboratory
 9700 South Cass Avenue
 Argonne, Illinois  60439
 (630) 252-5444
Index: src/hw_pkcs11.c
===================================================================
--- src/hw_pkcs11.c     (revision 129)
+++ src/hw_pkcs11.c     (working copy)
@@ -62,6 +62,8 @@
 #include <config.h>
 #include <stdio.h>
 #include <string.h>
+#include <openssl/opensslv.h>
+#include <openssl/opensslconf.h>
 #include <openssl/crypto.h>
 #include <openssl/objects.h>
 #include <openssl/engine.h>
@@ -188,6 +190,11 @@
 #ifndef OPENSSL_NO_DH
            !ENGINE_set_DH(e, DH_get_default_method()) ||
 #endif
+#ifndef OPENSSL_NO_EC
+#ifndef OPENSSL_NO_ECDSA
+               !ENGINE_set_ECDSA(e, PKCS11_get_ecdsa_method()) ||
+#endif 
+#endif
            !ENGINE_set_RAND(e, RAND_SSLeay()) ||
 #if 0
            !ENGINE_set_BN_mod_exp(e, BN_mod_exp) ||
Index: src/Makefile.mak
===================================================================
--- src/Makefile.mak    (revision 197)
+++ src/Makefile.mak    (working copy)
@@ -10,7 +10,7 @@
 TARGET                  = libp11.dll
 
 OBJECTS                 = libpkcs11.obj p11_attr.obj p11_cert.obj p11_err.obj \
-       p11_key.obj p11_load.obj p11_misc.obj p11_rsa.obj p11_slot.obj 
p11_ops.obj
+       p11_key.obj p11_load.obj p11_misc.obj p11_rsa.obj p11_ec.obj 
p11_slot.obj p11_ops.obj
 
 all: $(TARGET) versioninfo.res
 
Index: src/p11_ec.c
===================================================================
--- src/p11_ec.c        (revision 0)
+++ src/p11_ec.c        (revision 0)
@@ -0,0 +1,244 @@
+/* libp11, a simple layer on to of PKCS#11 API
+ * Copyright (C) 2005 Olaf Kirch <o...@lst.de>
+ * Copyright (C) 2011 Douglas E. Engert <deeng...@anl.gov>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+/*
+ * This file implements the handling of EC keys stored on a
+ * PKCS11 token
+ */
+
+#include <config.h>
+#include <string.h>
+#include <openssl/opensslv.h>
+#include <openssl/opensslconf.h>
+
+#if defined(BUILD_WITH_EC) && !defined(OPENSSL_NO_EC) && 
!defined(OPENSSL_NO_ECDSA)
+/* OpenSSL has ECDSA_METHOD  defined in internal header file ecs_locl.h
+ * For now:
+ * CPPFLAGS="-DBUILD_WITH_EC -I/path.to.openssl-1.0.0a/crypto/ecdh"
+ * See OpenSSL bug report #2459 02/23/2011
+ * When this is fixed, the BUILD_WITH_EC test can be removed
+ * 
+ * TODO ECDH_METHOD is in ech_locl.h too!
+ */
+
+#include "ecs_locl.h"
+#include <openssl/evp.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include "libp11-int.h"
+
+static int pkcs11_get_ec_public(PKCS11_KEY *, EVP_PKEY *);
+static int pkcs11_get_ec_private(PKCS11_KEY *, EVP_PKEY *);
+
+
+/*
+ * Get EC key material and stach pointer in ex_data  
+ * Note we get called twice, once for private key, and once for public
+ * We need to get the EC_PARAMS and EC_POINT into both,
+ * as lib11 dates from RSA only where all the pub key components
+ * were also part of the privite key.  With EC the point
+ * is not in the privite key, and the params may or may not be. 
+ * 
+ */
+static int pkcs11_get_ec_private(PKCS11_KEY * key, EVP_PKEY * pk)
+{
+       CK_BBOOL sensitive, extractable;
+       EC_KEY * ec = NULL;
+       CK_RV ckrv;
+       int rv;
+       size_t ec_paramslen = 0;
+       CK_BYTE * ec_params = NULL;
+       size_t ec_pointlen = 0;
+       CK_BYTE * ec_point = NULL;
+       PKCS11_KEY * prkey;
+       PKCS11_KEY * pubkey;
+       
+       if (key->isPrivate) {  /* Are we being called for the prive or pub key 
*/
+               prkey = key;
+               pubkey = PKCS11_find_key_from_key(key);
+       } else {
+               pubkey = key;
+               prkey = PKCS11_find_key_from_key(key);
+       }
+
+fprintf(stderr,"%s:%d %p %p\n",__FUNCTION__,__LINE__,key, pk);
+fprintf(stderr,"%s:%d %p %p\n",__FUNCTION__,__LINE__, prkey, pubkey);
+
+       if (!(ec = EVP_PKEY_get1_EC_KEY(pk))) {
+               ERR_clear_error();      /* the above flags an error */
+               ec = EC_KEY_new();
+fprintf(stderr,"%s:%d \n",__FUNCTION__,__LINE__);
+               EVP_PKEY_set1_EC_KEY(pk, ec);
+       }
+
+       if (prkey) {
+               if (key_getattr(prkey, CKA_SENSITIVE, &sensitive, 
sizeof(sensitive))
+                   || key_getattr(prkey, CKA_EXTRACTABLE, &extractable, 
sizeof(extractable))) {
+                       EC_KEY_free(ec);
+fprintf(stderr,"%s:%d \n",__FUNCTION__,__LINE__);
+                       return -1;
+               }
+
+               /* For Openssl req we need at least the 
+                * EC_KEY_get0_group(ec_key)) to return the group. 
+                * Even if it fails will continue as a sign only does not need
+                * need this if the pkcs11 or card can figure this out.  
+                */ 
+       
+               if (key_getattr_var(prkey, CKA_EC_PARAMS, NULL, &ec_paramslen) 
== CKR_OK &&
+                               ec_paramslen > 0) {
+                       ec_params = malloc(ec_paramslen);
+                       ckrv = key_getattr_var(prkey, CKA_EC_PARAMS, ec_params, 
&ec_paramslen);
+fprintf(stderr,"%s:%d 0x%08x %p %d\n",__FUNCTION__,__LINE__,ckrv,ec_params, 
ec_paramslen);
+                       if (ckrv == CKR_OK) {
+                               const unsigned char * a = ec_params;
+                               /* convert to OpenSSL parmas */
+                               d2i_ECParameters(&ec, &a, ec_paramslen);
+                       }
+               }
+       }
+
+       /* Now get the ec_point */
+       
+       if (pubkey) {
+               if (key_getattr_var(pubkey, CKA_EC_POINT, NULL, &ec_pointlen) 
== CKR_OK &&
+                                       ec_pointlen > 0) {
+                       ec_point = malloc(ec_pointlen);
+                       ckrv = key_getattr_var(pubkey, CKA_EC_POINT, ec_point, 
&ec_pointlen);
+fprintf(stderr,"%s:%d 0x%08x %p %d\n",__FUNCTION__,__LINE__,ckrv,ec_point, 
ec_pointlen);
+                       if (ckrv == CKR_OK) {
+                               /* PKCS#11 returns ASN1 octstring*/
+                               const unsigned char * a;
+                               /* TODO we have asn1 octet string, need to 
strip off 04 len */
+               
+                               a = ec_point + 2;
+                               o2i_ECPublicKey(&ec, &a, ec_pointlen-2);
+EC_KEY_print_fp(stderr, ec, 5);
+fprintf(stderr,"%s:%d\n",__FUNCTION__,__LINE__);
+                       }
+               }
+       }
+fprintf(stderr,"%s:%d %p \n",__FUNCTION__,__LINE__,ec);
+
+       /* If the key is not extractable, create a key object
+        * that will use the card's functions to sign & decrypt
+        */
+       if (ec_point)
+               free(ec_point);
+       if (ec_params)
+               free(ec_params);
+
+       if (sensitive || !extractable) {
+               ECDSA_set_ex_data(ec, 0, key);
+fprintf(stderr,"%s:%d %p \n",__FUNCTION__,__LINE__,ec);
+               return 0;
+       }
+
+       return -1;
+}
+
+static int pkcs11_get_ec_public(PKCS11_KEY * key, EVP_PKEY * pk)
+{
+       /* TBD */
+fprintf(stderr,"%s:%d %p %p \n",__FUNCTION__,__LINE__,key,pk);
+       return pkcs11_get_ec_private(key, pk);
+}
+
+/* TODO Looks like this is never called */
+static int pkcs11_ecdsa_do_sign_setup(EC_KEY *ec, BN_CTX *ctx_in,
+       BIGNUM **kinvp, BIGNUM **rp) {
+
+fprintf(stderr,"%s:%d \n",__FUNCTION__,__LINE__);
+
+       if (*kinvp != NULL) 
+               BN_clear_free(*kinvp);
+       *kinvp = BN_new();
+
+       if (*rp != NULL)
+               BN_clear_free(*rp);
+       *rp = BN_new();
+       return 1;
+}
+
+static ECDSA_SIG * pkcs11_ecdsa_do_sign(const unsigned char *dgst, int dlen,
+                       const BIGNUM *inv, const BIGNUM *r, EC_KEY * ec)
+{
+       int type;
+       unsigned char sigret[512]; /* HACK for now */
+       ECDSA_SIG * sig = NULL;
+       PKCS11_KEY * key = NULL;
+       int siglen;
+       int nLen = 48; /* HACK */;
+       int rv;
+
+fprintf(stderr,"%s:%d dgst %p:%d %p\n",__FUNCTION__,__LINE__,dgst,dlen,ec);
+       key = (PKCS11_KEY *) ECDSA_get_ex_data(ec, 0);
+       if  (key == NULL)
+               return NULL;
+
+       siglen = sizeof(sigret);
+       
+       rv = PKCS11_ecdsa_sign(dgst,dlen,sigret,&siglen, key);
+       nLen = siglen / 2;
+       if (rv > 0) {
+               sig = ECDSA_SIG_new();
+               if (sig) { 
+                       BN_bin2bn(&sigret[0], nLen, sig->r);
+                       BN_bin2bn(&sigret[nLen], nLen, sig->s);
+               }
+       } 
+       return sig;
+}
+
+/*
+ * Overload the default OpenSSL methods for ECDSA
+ */
+ECDSA_METHOD *PKCS11_get_ecdsa_method(void)
+{
+       static ECDSA_METHOD ops;
+
+fprintf(stderr,"%s:%d\n",__FUNCTION__,__LINE__);
+       if (!ops.ecdsa_do_sign) {
+               ops = *ECDSA_get_default_method();
+               ops.ecdsa_do_sign = pkcs11_ecdsa_do_sign;
+               ops.ecdsa_sign_setup = pkcs11_ecdsa_do_sign_setup; 
+       }
+       return &ops;
+}
+
+PKCS11_KEY_ops pkcs11_ec_ops = {
+       EVP_PKEY_EC,
+       pkcs11_get_ec_public,
+       pkcs11_get_ec_private
+};
+
+#else
+/* if not built with EC or OpenSSL does not support ECDSA
+ * add these so engine_pocs11 can be built now and not
+ * require further changes */
+void * PKCS11_get_ecdsa_method(void)
+{
+#if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA)
+       return ECDSA_get_default_method();
+#else
+fprintf(stderr,"ECDSA support not built with libp11\n");
+       return NULL;
+#endif
+}
+#endif /*BUILD_WITH_EC  OPENSSL_NO_EC */
Index: src/p11_key.c
===================================================================
--- src/p11_key.c       (revision 197)
+++ src/p11_key.c       (working copy)
@@ -51,6 +51,7 @@
 {
        PKCS11_TOKEN_private *priv = PRIVTOKEN(token);
 
+fprintf(stderr,"%s %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
        if (priv->nkeys < 0) {
                priv->nkeys = 0;
                if (pkcs11_find_keys(token, CKO_PRIVATE_KEY)) {
@@ -78,6 +79,7 @@
         PKCS11_KEY *key;
         unsigned int n, count;
 
+fprintf(stderr,"%s %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
        cpriv = PRIVCERT(cert);
         if (PKCS11_enumerate_keys(CERT2TOKEN(cert), &key, &count))
                 return NULL;
@@ -91,6 +93,35 @@
 }
 
 /*
+ * Find key matching a key of the other type pub vs priv
+ */
+PKCS11_KEY *PKCS11_find_key_from_key(PKCS11_KEY * keyin)
+{
+               PKCS11_TOKEN_private *tpriv;
+        PKCS11_KEY_private *kinpriv;
+        PKCS11_KEY_private *kpriv;
+        PKCS11_KEY *key;
+               int isprivate;
+        unsigned int n, count;
+
+fprintf(stderr,"%s %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
+               kinpriv = PRIVKEY(keyin);
+               tpriv = KEY2TOKEN(keyin);
+        PKCS11_enumerate_keys(KEY2TOKEN(keyin), &key, &count);
+               /* We want to use all the keys, the above only returns count 
for private */
+               count = tpriv->nkeys;
+               if (count < 2)  /* must be at least two key to have a match */
+                               return;
+        for (n = 0; n < count; n++, key++) {
+                kpriv = PRIVKEY(key);
+                               if (keyin->isPrivate != key->isPrivate 
+                       && kinpriv->id_len == kpriv->id_len
+                    && !memcmp(kinpriv->id, kpriv->id, kinpriv->id_len))
+                        return key;
+        }
+        return NULL;
+}
+/*
  * Store a private key on the token
  */
 int PKCS11_store_private_key(PKCS11_TOKEN * token, EVP_PKEY * pk, char *label, 
unsigned char *id, size_t id_len)
@@ -168,6 +199,7 @@
 {
        PKCS11_KEY_private *priv = PRIVKEY(key);
 
+fprintf(stderr,"%s %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
        if (key->evp_key == NULL) {
                EVP_PKEY *pk = EVP_PKEY_new();
                if (pk == NULL)
@@ -185,6 +217,7 @@
 
 EVP_PKEY *PKCS11_get_public_key(PKCS11_KEY * key)
 {
+fprintf(stderr,"%s %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
        return PKCS11_get_private_key(key);
 }
 
@@ -199,6 +232,7 @@
        CK_SESSION_HANDLE session;
        int rv, res = -1;
 
+fprintf(stderr,"%s %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
        /* Make sure we have a session */
        if (!PRIVSLOT(slot)->haveSession && PKCS11_open_session(slot, 0))
                return -1;
@@ -225,6 +259,7 @@
        CK_ULONG count;
        int rv;
 
+fprintf(stderr,"%s %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
        /* Get the next matching object */
        rv = CRYPTOKI_call(ctx, C_FindObjects(session, &obj, 1, &count));
        CRYPTOKI_checkerr(PKCS11_F_PKCS11_ENUM_KEYS, rv);
@@ -251,6 +286,7 @@
        PKCS11_KEY_ops *ops;
        size_t size;
 
+fprintf(stderr,"%s %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
        size = sizeof(key_type);
        if (pkcs11_getattr_var(token, obj, CKA_KEY_TYPE, &key_type, &size))
                return -1;
@@ -259,6 +295,9 @@
        case CKK_RSA:
                ops = &pkcs11_rsa_ops;
                break;
+       case CKK_EC:
+               ops = &pkcs11_ec_ops;
+               break;
        default:
                /* Ignore any keys we don't understand */
                return 0;
@@ -307,6 +346,7 @@
 {
        PKCS11_TOKEN_private *priv = PRIVTOKEN(token);
 
+fprintf(stderr,"%s %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
        while (priv->nkeys > 0) {
                PKCS11_KEY *key = &priv->keys[--(priv->nkeys)];
 
Index: src/libp11.exports
===================================================================
--- src/libp11.exports  (revision 197)
+++ src/libp11.exports  (working copy)
@@ -34,4 +34,5 @@
 PKCS11_seed_random
 PKCS11_generate_random
 PKCS11_get_rsa_method
+PKCS11_get_ecdsa_method
 ERR_load_PKCS11_strings
Index: src/p11_ops.c
===================================================================
--- src/p11_ops.c       (revision 197)
+++ src/p11_ops.c       (working copy)
@@ -24,6 +24,49 @@
 #include <string.h>
 #include "libp11-int.h"
 
+#ifdef BUILD_WITH_EC
+int 
+PKCS11_ecdsa_sign(const unsigned char *m, unsigned int m_len,
+               unsigned char *sigret, unsigned int *siglen, const PKCS11_KEY * 
key)
+{
+/* signature size is the issue, will assume caller has a big buffer ! */
+/* No padding or other stuff needed, we can cal PKCS11 from here */
+       int rv;
+       PKCS11_KEY_private *priv;
+       PKCS11_SLOT *slot;
+       PKCS11_CTX *ctx;
+       CK_SESSION_HANDLE session;
+       CK_MECHANISM mechanism;
+       CK_ULONG ck_sigsize;
+
+       ctx = KEY2CTX(key);
+       priv = PRIVKEY(key);
+       slot = TOKEN2SLOT(priv->parent);
+       session = PRIVSLOT(slot)->session;
+
+       ck_sigsize = *siglen;
+
+       memset(&mechanism, 0, sizeof(mechanism));
+       mechanism.mechanism = CKM_ECDSA;
+
+       if((rv = CRYPTOKI_call(ctx, C_SignInit
+                              (session, &mechanism, priv->object))) == 0) {
+               rv = CRYPTOKI_call(ctx, C_Sign
+                                  (session, (CK_BYTE *) m, m_len,
+                                   sigret, &ck_sigsize));
+       }
+
+       if (rv) {
+               PKCS11err(PKCS11_F_PKCS11_EC_KEY_SIGN, pkcs11_map_err(rv));
+               return -1;
+       }
+       *siglen = ck_sigsize;
+
+       return ck_sigsize;
+}
+#endif /* BUILD_WITH_EC */
+
+/* Following used for RSA */
 int
 PKCS11_sign(int type, const unsigned char *m, unsigned int m_len,
                unsigned char *sigret, unsigned int *siglen, const PKCS11_KEY * 
key)
Index: src/libp11-int.h
===================================================================
--- src/libp11-int.h    (revision 197)
+++ src/libp11-int.h    (working copy)
@@ -143,6 +143,9 @@
 #define key_getattr_bn(key, t, bn) \
        pkcs11_getattr_bn(KEY2TOKEN((key)), PRIVKEY((key))->object, (t), (bn))
 
+#define key_getattr_var(key, t, p, s) \
+       pkcs11_getattr_var(KEY2TOKEN((key)), PRIVKEY((key))->object, (t), (p), 
(s))
+
 typedef int (*pkcs11_i2d_fn) (void *, unsigned char **);
 extern void pkcs11_addattr(CK_ATTRIBUTE_PTR, int, const void *, size_t);
 extern void pkcs11_addattr_int(CK_ATTRIBUTE_PTR, int, unsigned long);
@@ -155,5 +158,6 @@
 extern void *memdup(const void *, size_t);
 
 extern PKCS11_KEY_ops pkcs11_rsa_ops;
+extern PKCS11_KEY_ops pkcs11_ec_ops;
 
 #endif
Index: src/Makefile.am
===================================================================
--- src/Makefile.am     (revision 197)
+++ src/Makefile.am     (working copy)
@@ -9,7 +9,7 @@
 pkgconfig_DATA = libp11.pc
 
 libp11_la_SOURCES = libpkcs11.c p11_attr.c p11_cert.c p11_err.c p11_key.c \
-       p11_load.c p11_misc.c p11_ops.c p11_rsa.c p11_slot.c \
+       p11_load.c p11_misc.c p11_ops.c p11_rsa.c p11_ec.c p11_slot.c \
        libp11.exports
 if WIN32
 libp11_la_SOURCES += versioninfo.rc
Index: src/libp11.h
===================================================================
--- src/libp11.h        (revision 197)
+++ src/libp11.h        (working copy)
@@ -258,6 +258,9 @@
 /* Find the corresponding key (if any) */
 extern PKCS11_KEY *PKCS11_find_key(PKCS11_CERT *);
 
+/* Find the corresponding key (if any)  pub <-> priv base on label */
+extern PKCS11_KEY *PKCS11_find_key_from_key(PKCS11_KEY *);
+
 /* Get a list of all certificates associated with this token */
 extern int PKCS11_enumerate_certs(PKCS11_TOKEN *, PKCS11_CERT **, unsigned int 
*);
 
@@ -413,6 +416,8 @@
 #define PKCS11_F_PKCS11_GENERATE_RANDOM                21
 #define PKCS11_F_PKCS11_CHANGE_PIN             22
 #define PKCS11_F_PKCS11_GETATTR                        40
+#define PKCS11_F_PKCS11_EC_KEY_SIGN                    41
+#define PKCS11_F_PKCS11_EC_KEY_VERIFY          42
 
 #define PKCS11_ERR_BASE                                1024
 #define PKCS11_LOAD_MODULE_ERROR               (PKCS11_ERR_BASE+1)
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to