From: Adriaan de Jong Date: Thu, 30 Jun 2011 14:28:56 +0000 (+0200) Subject: Separated OpenSSL-specific parts of the PKCS#11 driver X-Git-Tag: v2.3-alpha1~110 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5fe5fe9e6264d45154a7ece8c85fa70173429ff8;p=thirdparty%2Fopenvpn.git Separated OpenSSL-specific parts of the PKCS#11 driver Signed-off-by: Adriaan de Jong Acked-by: James Yonan Signed-off-by: David Sommerseth --- diff --git a/Makefile.am b/Makefile.am index bdda0be96..0108d8fef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -114,7 +114,7 @@ openvpn_SOURCES = \ multi.c multi.h \ ntlm.c ntlm.h \ occ.c occ.h occ-inline.h \ - pkcs11.c pkcs11.h \ + pkcs11.c pkcs11.h pkcs11_backend.h \ openvpn.c openvpn.h \ openvpn-plugin.h \ options.c options.h \ @@ -156,6 +156,7 @@ configure.h: Makefile if USE_OPENSSL openvpn_SOURCES += \ crypto_openssl.c crypto_openssl.h \ + pkcs11_openssl.c \ ssl_openssl.c ssl_openssl.h \ ssl_verify_openssl.c ssl_verify_openssl.h endif diff --git a/pkcs11.c b/pkcs11.c index 9cf18e5f5..5e051b856 100644 --- a/pkcs11.c +++ b/pkcs11.c @@ -27,7 +27,6 @@ #if defined(ENABLE_PKCS11) #include -#include #include "basic.h" #include "error.h" #include "manage.h" @@ -35,6 +34,7 @@ #include "pkcs11.h" #include "misc.h" #include "otime.h" +#include "pkcs11_backend.h" static time_t @@ -605,16 +605,13 @@ cleanup: } int -SSL_CTX_use_pkcs11 ( - SSL_CTX * const ssl_ctx, +tls_ctx_use_pkcs11 ( + struct tls_root_ctx * const ssl_ctx, bool pkcs11_id_management, const char * const pkcs11_id ) { - X509 *x509 = NULL; - RSA *rsa = NULL; pkcs11h_certificate_id_t certificate_id = NULL; pkcs11h_certificate_t certificate = NULL; - pkcs11h_openssl_session_t openssl_session = NULL; CK_RV rv = CKR_OK; bool ok = false; @@ -624,7 +621,7 @@ SSL_CTX_use_pkcs11 ( dmsg ( D_PKCS11_DEBUG, - "PKCS#11: SSL_CTX_use_pkcs11 - entered - ssl_ctx=%p, pkcs11_id_management=%d, pkcs11_id='%s'", + "PKCS#11: tls_ctx_use_pkcs11 - entered - ssl_ctx=%p, pkcs11_id_management=%d, pkcs11_id='%s'", (void *)ssl_ctx, pkcs11_id_management ? 1 : 0, pkcs11_id @@ -689,54 +686,22 @@ SSL_CTX_use_pkcs11 ( goto cleanup; } - if ((openssl_session = pkcs11h_openssl_createSession (certificate)) == NULL ) { - msg (M_WARN, "PKCS#11: Cannot initialize openssl session"); + if ( + (pkcs11_init_tls_session ( + certificate, + ssl_ctx + )) + ) { + /* Handled by SSL context free */ + certificate = NULL; goto cleanup; } - /* - * Will be released by openssl_session - */ + /* Handled by SSL context free */ certificate = NULL; - - if ((rsa = pkcs11h_openssl_session_getRSA (openssl_session)) == NULL) { - msg (M_WARN, "PKCS#11: Unable get rsa object"); - goto cleanup; - } - - if ((x509 = pkcs11h_openssl_session_getX509 (openssl_session)) == NULL) { - msg (M_WARN, "PKCS#11: Unable get certificate object"); - goto cleanup; - } - - if (!SSL_CTX_use_RSAPrivateKey (ssl_ctx, rsa)) { - msg (M_WARN, "PKCS#11: Cannot set private key for openssl"); - goto cleanup; - } - - if (!SSL_CTX_use_certificate (ssl_ctx, x509)) { - msg (M_WARN, "PKCS#11: Cannot set certificate for openssl"); - goto cleanup; - } - ok = true; cleanup: - /* - * openssl objects have reference - * count, so release them - */ - - if (x509 != NULL) { - X509_free (x509); - x509 = NULL; - } - - if (rsa != NULL) { - RSA_free (rsa); - rsa = NULL; - } - if (certificate != NULL) { pkcs11h_certificate_freeCertificate (certificate); certificate = NULL; @@ -746,15 +711,10 @@ cleanup: pkcs11h_certificate_freeCertificateId (certificate_id); certificate_id = NULL; } - - if (openssl_session != NULL) { - pkcs11h_openssl_freeSession (openssl_session); - openssl_session = NULL; - } dmsg ( D_PKCS11_DEBUG, - "PKCS#11: SSL_CTX_use_pkcs11 - return ok=%d, rv=%ld", + "PKCS#11: tls_ctx_use_pkcs11 - return ok=%d, rv=%ld", ok ? 1 : 0, rv ); @@ -867,13 +827,10 @@ show_pkcs11_ids ( ); for (current = user_certificates;current != NULL; current = current->next) { pkcs11h_certificate_t certificate = NULL; - X509 *x509 = NULL; - BIO *bio = NULL; char dn[1024] = {0}; char serial[1024] = {0}; char *ser = NULL; size_t ser_len = 0; - int n; if ( (rv = pkcs11h_certificate_serializeCertificateId ( @@ -918,31 +875,26 @@ show_pkcs11_ids ( goto cleanup1; } - if ((x509 = pkcs11h_openssl_getX509 (certificate)) == NULL) { - msg (M_FATAL, "PKCS#11: Cannot get X509"); + if ( + (pkcs11_certificate_dn ( + certificate, + dn, + sizeof(dn) + )) + ) { goto cleanup1; } - X509_NAME_oneline ( - X509_get_subject_name (x509), - dn, - sizeof (dn) - ); - - if ((bio = BIO_new (BIO_s_mem ())) == NULL) { - msg (M_FATAL, "PKCS#11: Cannot create BIO"); + if ( + (pkcs11_certificate_serial ( + certificate, + serial, + sizeof(serial) + )) + ) { goto cleanup1; } - i2a_ASN1_INTEGER(bio, X509_get_serialNumber (x509)); - n = BIO_read (bio, serial, sizeof (serial)-1); - if (n<0) { - serial[0] = '\x0'; - } - else { - serial[n] = 0; - } - msg ( M_INFO|M_NOPREFIX|M_NOLF, ( @@ -958,10 +910,6 @@ show_pkcs11_ids ( ); cleanup1: - if (x509 != NULL) { - X509_free (x509); - x509 = NULL; - } if (certificate != NULL) { pkcs11h_certificate_freeCertificate (certificate); diff --git a/pkcs11.h b/pkcs11.h index abe03b9a6..4261871d4 100644 --- a/pkcs11.h +++ b/pkcs11.h @@ -27,7 +27,7 @@ #if defined(ENABLE_PKCS11) -#include +#include "ssl_common.h" bool pkcs11_initialize ( @@ -63,8 +63,8 @@ pkcs11_management_id_get ( ); int -SSL_CTX_use_pkcs11 ( - SSL_CTX * const ssl_ctx, +tls_ctx_use_pkcs11 ( + struct tls_root_ctx * const ssl_ctx, bool pkcs11_id_management, const char * const pkcs11_id ); diff --git a/pkcs11_backend.h b/pkcs11_backend.h new file mode 100644 index 000000000..6b5ad3195 --- /dev/null +++ b/pkcs11_backend.h @@ -0,0 +1,77 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2010 Fox Crypto B.V. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file PKCS #11 SSL library-specific backend + */ + +#ifndef PKCS11_BACKEND_H_ +#define PKCS11_BACKEND_H_ + +#include "syshead.h" + +#if defined(ENABLE_PKCS11) + +#include "ssl_common.h" + +#include + +/** + * Retrieve PKCS #11 Certificate's DN in a printable format. + * + * @param certificate The PKCS #11 helper certificate object + * @param dn Buffer that the certificate subject DN will be placed in. + * @param dn_len Size of said buffer. + * + * @return 1 on failure, 0 on success + */ +int pkcs11_certificate_dn (pkcs11h_certificate_t certificate, char *dn, + size_t dn_len); + +/** + * Retrieve PKCS #11 Certificate's serial number in a printable format. + * + * @param certificate The PKCS #11 helper certificate object + * @param serial Buffer that the certificate's serial will be placed in. + * @param serial_len Size of said buffer. + * + * @return 1 on failure, 0 on success + */ +int pkcs11_certificate_serial (pkcs11h_certificate_t certificate, char *serial, + size_t serial_len); + +/** + * Load PKCS #11 Certificate's information into the given TLS context + * + * @param certificate The PKCS #11 helper certificate object + * @param ssl_ctx TLS context to use. + * + * @return 1 on failure, 0 on success + */ +int pkcs11_init_tls_session(pkcs11h_certificate_t certificate, + struct tls_root_ctx * const ssl_ctx); + +#endif /* defined(ENABLE_PKCS11) */ +#endif /* PKCS11_BACKEND_H_ */ diff --git a/pkcs11_openssl.c b/pkcs11_openssl.c new file mode 100644 index 000000000..5c99bf321 --- /dev/null +++ b/pkcs11_openssl.c @@ -0,0 +1,188 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2010 Fox Crypto B.V. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * @file PKCS #11 OpenSSL backend + */ + +#include "syshead.h" + +#ifdef ENABLE_PKCS11 + +#include "errlevel.h" +#include "pkcs11_backend.h" +#include + +int +pkcs11_init_tls_session(pkcs11h_certificate_t certificate, + struct tls_root_ctx * const ssl_ctx) +{ + int ret = 1; + + X509 *x509 = NULL; + RSA *rsa = NULL; + pkcs11h_openssl_session_t openssl_session = NULL; + + if ((openssl_session = pkcs11h_openssl_createSession (certificate)) == NULL) + { + msg (M_WARN, "PKCS#11: Cannot initialize openssl session"); + goto cleanup; + } + + /* + * Will be released by openssl_session + */ + certificate = NULL; + + if ((rsa = pkcs11h_openssl_session_getRSA (openssl_session)) == NULL) + { + msg (M_WARN, "PKCS#11: Unable get rsa object"); + goto cleanup; + } + + if ((x509 = pkcs11h_openssl_session_getX509 (openssl_session)) == NULL) + { + msg (M_WARN, "PKCS#11: Unable get certificate object"); + goto cleanup; + } + + if (!SSL_CTX_use_RSAPrivateKey (ssl_ctx->ctx, rsa)) + { + msg (M_WARN, "PKCS#11: Cannot set private key for openssl"); + goto cleanup; + } + + if (!SSL_CTX_use_certificate (ssl_ctx->ctx, x509)) + { + msg (M_WARN, "PKCS#11: Cannot set certificate for openssl"); + goto cleanup; + } + ret = 0; + +cleanup: + /* + * Certificate freeing is usually handled by openssl_session. + * If something went wrong, creating the session we have to do it manually. + */ + if (certificate != NULL) { + pkcs11h_certificate_freeCertificate (certificate); + certificate = NULL; + } + + /* + * openssl objects have reference + * count, so release them + */ + if (x509 != NULL) + { + X509_free (x509); + x509 = NULL; + } + + if (rsa != NULL) + { + RSA_free (rsa); + rsa = NULL; + } + + if (openssl_session != NULL) + { + pkcs11h_openssl_freeSession (openssl_session); + openssl_session = NULL; + } + return ret; +} + +int +pkcs11_certificate_dn (pkcs11h_certificate_t certificate, char *dn, + size_t dn_len) +{ + X509 *x509 = NULL; + int ret = 1; + + if ((x509 = pkcs11h_openssl_getX509 (certificate)) == NULL) + { + msg (M_FATAL, "PKCS#11: Cannot get X509"); + ret = 1; + goto cleanup; + } + + X509_NAME_oneline (X509_get_subject_name (x509), dn, dn_len); + + ret = 0; + +cleanup: + if (x509 != NULL) + { + X509_free (x509); + x509 = NULL; + } + + return ret; +} + +int +pkcs11_certificate_serial (pkcs11h_certificate_t certificate, char *serial, + size_t serial_len) +{ + X509 *x509 = NULL; + BIO *bio = NULL; + int ret = 1; + int n; + + if ((x509 = pkcs11h_openssl_getX509 (certificate)) == NULL) + { + msg (M_FATAL, "PKCS#11: Cannot get X509"); + goto cleanup; + } + + if ((bio = BIO_new (BIO_s_mem ())) == NULL) + { + msg (M_FATAL, "PKCS#11: Cannot create BIO"); + goto cleanup; + } + + i2a_ASN1_INTEGER(bio, X509_get_serialNumber (x509)); + n = BIO_read (bio, serial, serial_len-1); + + if (n<0) { + serial[0] = '\x0'; + } + else { + serial[n] = 0; + } + + ret = 0; + +cleanup: + + if (x509 != NULL) + { + X509_free (x509); + x509 = NULL; + } + return ret; +} +#endif /* ENABLE_PKCS11 */ diff --git a/ssl.c b/ssl.c index 516ed1a41..407eba055 100644 --- a/ssl.c +++ b/ssl.c @@ -328,8 +328,12 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) #ifdef ENABLE_PKCS11 else if (options->pkcs11_providers[0]) { - if (0 != tls_ctx_load_pkcs11(new_ctx, options->pkcs11_id_management, options->pkcs11_id)) - goto err; + if (!tls_ctx_use_pkcs11 (new_ctx, options->pkcs11_id_management, options->pkcs11_id)) + { + msg (M_WARN, "Cannot load certificate \"%s\" using PKCS#11 interface", + options->pkcs11_id); + goto err; + } } #endif #ifdef WIN32 diff --git a/ssl_backend.h b/ssl_backend.h index c532a20b6..b0c9a6d44 100644 --- a/ssl_backend.h +++ b/ssl_backend.h @@ -158,17 +158,6 @@ int tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, bool load_ca_file ); -/* - * Load PKCS #11 information for key and cert, and add to library-specific TLS - * context. - * - * TODO: document - */ -#ifdef ENABLE_PKCS11 -int tls_ctx_load_pkcs11(struct tls_root_ctx *ctx, - bool pkcs11_id_management, const char *pkcs11_id); -#endif /* ENABLE_PKCS11 */ - /** * Use Windows cryptoapi for key and cert, and add to library-specific TLS * context. diff --git a/ssl_openssl.c b/ssl_openssl.c index 2d5e914cd..f85f81a9e 100644 --- a/ssl_openssl.c +++ b/ssl_openssl.c @@ -323,23 +323,6 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, return 0; } -#ifdef ENABLE_PKCS11 -int -tls_ctx_load_pkcs11(struct tls_root_ctx *ctx, bool pkcs11_id_management, - const char *pkcs11_id) -{ - ASSERT(NULL != ctx); - - /* Load Certificate and Private Key */ - if (!SSL_CTX_use_pkcs11 (ctx->ctx, pkcs11_id_management, pkcs11_id)) - { - msg (M_WARN, "Cannot load certificate \"%s\" using PKCS#11 interface", pkcs11_id); - return 1; - } - return 0; -} -#endif /* ENABLE_PKCS11 */ - #ifdef WIN32 void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)