summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--macros/neon.m425
-rw-r--r--src/ne_openssl.c42
-rw-r--r--src/ne_pkcs11.c115
-rw-r--r--src/ne_privssl.h6
4 files changed, 172 insertions, 16 deletions
diff --git a/macros/neon.m4 b/macros/neon.m4
index b219eb1..a6e28f5 100644
--- a/macros/neon.m4
+++ b/macros/neon.m4
@@ -979,19 +979,6 @@ gnutls)
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 @@ posix|yes)
;;
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
diff --git a/src/ne_openssl.c b/src/ne_openssl.c
index 5ccfa76..91ef671 100644
--- a/src/ne_openssl.c
+++ b/src/ne_openssl.c
@@ -820,6 +820,48 @@ ne_ssl_client_cert *ne_ssl_clicert_read(const char *filename)
}
}
+#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;
diff --git a/src/ne_pkcs11.c b/src/ne_pkcs11.c
index 9a480a8..80b1f45 100644
--- a/src/ne_pkcs11.c
+++ b/src/ne_pkcs11.c
@@ -64,6 +64,101 @@ struct ne_ssl_pkcs11_provider_s {
*/
+#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 @@ static int pk11_find_x509(ne_ssl_pkcs11_provider *prov,
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 @@ static int pk11_find_x509(ne_ssl_pkcs11_provider *prov,
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 @@ static int pk11_find_x509(ne_ssl_pkcs11_provider *prov,
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 @@ static int pk11_find_pkey(ne_ssl_pkcs11_provider *prov,
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 @@ static int find_client_cert(ne_ssl_pkcs11_provider *prov,
&& 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 @@ static int pk11_sign_callback(gnutls_session_t session,
return 0;
}
+#endif
static void terminate_string(unsigned char *str, size_t len)
{
@@ -460,14 +568,15 @@ void ne_ssl_pkcs11_provider_pin(ne_ssl_pkcs11_provider *provider,
{
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);
}
diff --git a/src/ne_privssl.h b/src/ne_privssl.h
index 09fa7e3..6aab772 100644
--- a/src/ne_privssl.h
+++ b/src/ne_privssl.h
@@ -44,6 +44,12 @@ struct ne_ssl_context_s {
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