commit: r1541 - in neon/trunk: macros src

joe at manyfish.co.uk joe at manyfish.co.uk
Sun Aug 31 05:56:12 EDT 2008


Author: joe
Date: Sun Aug 31 02:56:10 2008
New Revision: 1541

Modified:
   neon/trunk/macros/neon.m4
   neon/trunk/src/ne_openssl.c
   neon/trunk/src/ne_pkcs11.c
   neon/trunk/src/ne_privssl.h

Log:
Support PKCS#11 in OpenSSL builds:

* src/ne_openssl.c (ne__ssl_clicert_exkey_import): New function.

* src/ne_privssl.h (ne__ssl_clicert_exkey_import): New prototype.

* src/ne_pkcs11.c [HAVE_OPENSSL] (pk11_rsa_sign, pk11_rsa_init,
  pk11_rsa_finish, pk11_rsa_method): New functions.
  (pk11_find_pkey): Ignore DSA privkeys if using OpenSSL.
  (ne_ssl_set_pkcs11_provider): Omit GnuTLS code for OpenSSL.

* macros/neon.m4 (NEON_SSL): Support pakchois with OpenSSL too.


Modified: neon/trunk/macros/neon.m4
==============================================================================
--- neon/trunk/macros/neon.m4	(original)
+++ neon/trunk/macros/neon.m4	Sun Aug 31 02:56:10 2008
@@ -979,19 +979,6 @@
    if test ${ac_cv_func_gnutls_x509_dn_get_rdn_ava}X${ac_cv_header_iconv_h} = yesXyes; then
       AC_CHECK_FUNCS(iconv)
    fi
-
-   if test x${ac_cv_func_gnutls_sign_callback_set} = xyes; then
-      if test "$with_pakchois" != "no"; then
-         # PKCS#11... ho!
-         NE_PKG_CONFIG(NE_PK11, pakchois,
-           [AC_MSG_NOTICE(using pakchois for PKCS11 support)
-            AC_DEFINE(HAVE_PAKCHOIS, 1, [Define if pakchois library supported])
-            CPPFLAGS="$CPPFLAGS ${NE_PK11_CFLAGS}"
-            NEON_LIBS="${NEON_LIBS} ${NE_PK11_LIBS}"],
-           [AC_MSG_NOTICE(pakchois library not found; no PKCS11 support)])
-      fi
-   fi
-
    ;;
 *) # Default to off; only create crypto-enabled binaries if requested.
    NE_DISABLE_SUPPORT(SSL, [SSL support is not enabled])
@@ -1035,6 +1022,18 @@
   ;;
 esac
 
+case ${with_pakchois}X${ac_cv_func_gnutls_sign_callback_set}Y${ne_cv_lib_ssl097} in
+noX*Y*) ;;
+*X*Yyes|*XyesX*)
+    # PKCS#11... ho!
+    NE_PKG_CONFIG(NE_PK11, pakchois,
+      [AC_MSG_NOTICE(using pakchois for PKCS11 support)
+       AC_DEFINE(HAVE_PAKCHOIS, 1, [Define if pakchois library supported])
+       CPPFLAGS="$CPPFLAGS ${NE_PK11_CFLAGS}"
+       NEON_LIBS="${NEON_LIBS} ${NE_PK11_LIBS}"],
+      [AC_MSG_NOTICE(pakchois library not found; no PKCS11 support)])
+   ;;
+esac
 ])
 
 dnl Check for Kerberos installation

Modified: neon/trunk/src/ne_openssl.c
==============================================================================
--- neon/trunk/src/ne_openssl.c	(original)
+++ neon/trunk/src/ne_openssl.c	Sun Aug 31 02:56:10 2008
@@ -820,6 +820,48 @@
     }
 }
 
+#ifdef HAVE_PAKCHOIS
+ne_ssl_client_cert *ne__ssl_clicert_exkey_import(const unsigned char *der,
+                                                 size_t der_len,
+                                                 const RSA_METHOD *method)
+{
+    ne_ssl_client_cert *cc;
+    ne_d2i_uchar *p;
+    X509 *x5;
+    RSA *pk;    
+    EVP_PKEY *epk, *tpk;
+
+    p = der;
+    x5 = d2i_X509(NULL, &p, der_len); /* p is incremented */
+    if (x5 == NULL) {
+        ERR_clear_error();
+        return NULL;
+    }
+    
+    pk = RSA_new();
+    RSA_set_method(pk, method);
+    epk = EVP_PKEY_new();
+    EVP_PKEY_assign_RSA(epk, pk);
+    
+    /* It is necessary to initialize pk->n otherwise OpenSSL will barf
+     * later calling RSA_size() on this RSA structure.
+     * X509_get_pubkey() forces the relevant RSA parameters to be
+     * extracted from the certificate. */
+    tpk = X509_get_pubkey(x5);
+    pk->n = BN_dup(tpk->pkey.rsa->n);
+    EVP_PKEY_free(tpk);
+
+    cc = ne_calloc(sizeof *cc);
+    
+    cc->decrypted = 1;
+    cc->pkey = epk;
+
+    populate_cert(&cc->cert, x5);
+
+    return cc;    
+}
+#endif
+
 int ne_ssl_clicert_encrypted(const ne_ssl_client_cert *cc)
 {
     return !cc->decrypted;

Modified: neon/trunk/src/ne_pkcs11.c
==============================================================================
--- neon/trunk/src/ne_pkcs11.c	(original)
+++ neon/trunk/src/ne_pkcs11.c	Sun Aug 31 02:56:10 2008
@@ -64,6 +64,101 @@
 
 */
 
+#ifdef HAVE_OPENSSL
+
+#include <openssl/rsa.h>
+#include <openssl/err.h>
+
+#define PK11_RSA_ERR (RSA_F_RSA_EAY_PRIVATE_ENCRYPT)
+
+/* RSA_METHOD ->rsa_sign calback. */
+static int pk11_rsa_sign(int type,
+                         const unsigned char *m, unsigned int mlen,
+                         unsigned char *sigret, unsigned int *siglen, 
+                         const RSA *r)
+{
+    ne_ssl_pkcs11_provider *prov = (ne_ssl_pkcs11_provider *)r->meth->app_data;
+    ck_rv_t rv;
+    struct ck_mechanism mech;
+    unsigned long len;
+
+    if (!prov->session || prov->privkey == CK_INVALID_HANDLE) {
+        NE_DEBUG(NE_DBG_SSL, "pk11: Cannot sign, no session/key.\n");
+        RSAerr(PK11_RSA_ERR,ERR_R_RSA_LIB);
+        return 0;
+    }
+
+    mech.mechanism = CKM_RSA_PKCS;
+    mech.parameter = NULL;
+    mech.parameter_len = 0;
+
+    /* Initialize signing operation; using the private key discovered
+     * earlier. */
+    rv = pakchois_sign_init(prov->session, &mech, prov->privkey);
+    if (rv != CKR_OK) {
+        NE_DEBUG(NE_DBG_SSL, "pk11: SignInit failed: %lx.\n", rv);
+        RSAerr(PK11_RSA_ERR, ERR_R_RSA_LIB);
+        return 0;
+    }
+
+    len = *siglen = RSA_size(r);
+    rv = pakchois_sign(prov->session, (unsigned char *)m, mlen, sigret, &len);
+    if (rv != CKR_OK) {
+        NE_DEBUG(NE_DBG_SSL, "pk11: Sign failed.\n");
+        RSAerr(PK11_RSA_ERR, ERR_R_RSA_LIB);
+        return 0;
+    }
+
+    NE_DEBUG(NE_DBG_SSL, "pk11: Signed successfully.\n");
+    return 1;
+}
+
+/* RSA_METHOD ->rsa_init implementation; called during RSA_new(rsa). */
+static int pk11_rsa_init(RSA *rsa)
+{
+    /* Ensures that RSA_sign() uses meth->rsa_sign: */
+    rsa->flags |= RSA_FLAG_SIGN_VER;
+    return 1;
+}
+
+/* RSA_METHOD ->rsa_finish implementation; called during
+ * RSA_free(rsa). */
+static int pk11_rsa_finish(RSA *rsa)
+{
+    RSA_METHOD *meth = (RSA_METHOD *)rsa->meth;
+
+    /* Freeing the dynamically allocated method here works as well as
+     * doing anything else: */
+    ne_free(meth);
+    /* Does not appear that rsa->meth will be used after this, but in
+     * case it is, ensure a NULL pointer dereference rather than a
+     * random pointer dereference. */
+    rsa->meth = NULL;
+
+    return 0;
+}
+
+/* Return an RSA_METHOD which will use the PKCS#11 provider to
+ * implement the signing operation. */
+static RSA_METHOD *pk11_rsa_method(ne_ssl_pkcs11_provider *prov)
+{
+    RSA_METHOD *m = ne_calloc(sizeof *m);
+
+    m->name = "neon PKCS#11";
+    m->rsa_sign = pk11_rsa_sign;
+    
+    m->init = pk11_rsa_init;
+    m->finish = pk11_rsa_finish;
+    
+    /* This is hopefully under control of the RSA_METHOD. */
+    m->app_data = (char *)prov;
+
+    m->flags = RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_SIGN_VER;
+    
+    return m;    
+}
+#endif
+
 static int pk11_find_x509(ne_ssl_pkcs11_provider *prov,
                           pakchois_session_t *pks, 
                           unsigned char *certid, unsigned long *cid_len)
@@ -87,7 +182,7 @@
     a[1].value = &type;
     a[1].value_len = sizeof type;
 
-    rv = pakchois_find_objects_init(pks, a, 2);
+    rv = pakchois_find_objects_init(pks, a, 1);
     if (rv != CKR_OK) {
         NE_DEBUG(NE_DBG_SSL, "pk11: FindObjectsInit failed.\n");
         return 0;
@@ -110,7 +205,11 @@
         if (pakchois_get_attribute_value(pks, obj, a, 3) == CKR_OK) {
             ne_ssl_client_cert *cc;
             
+#ifdef HAVE_GNUTLS
             cc = ne__ssl_clicert_exkey_import(value, a[0].value_len);
+#else
+            cc = ne__ssl_clicert_exkey_import(value, a[0].value_len, pk11_rsa_method(prov));
+#endif
             if (cc) {
                 NE_DEBUG(NE_DBG_SSL, "pk11: Imported X.509 cert.\n");
                 prov->clicert = cc;
@@ -128,6 +227,13 @@
     return found;    
 }
 
+#ifdef HAVE_OPENSSL
+/* No DSA support for OpenSSL (yet, anyway). */
+#define KEYTYPE_IS_DSA(kt) (0)
+#else
+#define KEYTYPE_IS_DSA(kt) (kt == CKK_DSA)
+#endif
+
 static int pk11_find_pkey(ne_ssl_pkcs11_provider *prov, 
                           pakchois_session_t *pks,
                           unsigned char *certid, unsigned long cid_len)
@@ -167,7 +273,7 @@
         a[0].value_len = sizeof prov->keytype;
 
         if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK
-            && (prov->keytype == CKK_RSA || prov->keytype == CKK_DSA)) {
+            && (prov->keytype == CKK_RSA || KEYTYPE_IS_DSA(prov->keytype))) {
             found = 1;
             prov->privkey = obj;
         }
@@ -192,6 +298,7 @@
         && pk11_find_pkey(prov, pks, certid, cid_len);
 }
 
+#ifdef HAVE_GNUTLS
 /* Callback invoked by GnuTLS to provide the signature.  The signature
  * operation is handled here by the PKCS#11 provider.  */
 static int pk11_sign_callback(gnutls_session_t session,
@@ -244,6 +351,7 @@
 
     return 0;
 }
+#endif
 
 static void terminate_string(unsigned char *str, size_t len)
 {
@@ -460,14 +568,15 @@
 {
     provider->pin_fn = fn;
     provider->pin_data = userdata;
-
 }
 
 void ne_ssl_set_pkcs11_provider(ne_session *sess, 
                                 ne_ssl_pkcs11_provider *provider)
 {
+#ifdef HAVE_GNUTLS
     sess->ssl_context->sign_func = pk11_sign_callback;
     sess->ssl_context->sign_data = provider;
+#endif
 
     ne_ssl_provide_clicert(sess, pk11_provide, provider);
 }

Modified: neon/trunk/src/ne_privssl.h
==============================================================================
--- neon/trunk/src/ne_privssl.h	(original)
+++ neon/trunk/src/ne_privssl.h	Sun Aug 31 02:56:10 2008
@@ -44,6 +44,12 @@
 
 typedef SSL *ne_ssl_socket;
 
+/* Create a clicert object from cert DER {der, der_len}, using given
+ * RSA_METHOD for the RSA object. */
+ne_ssl_client_cert *ne__ssl_clicert_exkey_import(const unsigned char *der,
+                                                 size_t der_len,
+                                                 const RSA_METHOD *method);
+
 #endif /* HAVE_OPENSSL */
 
 #ifdef HAVE_GNUTLS




More information about the neon-commits mailing list