src/openvpn/pkcs11_openssl.c
5fe5fe9e
 /*
  *  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.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
  *  Copyright (C) 2010-2018 Fox Crypto B.V. <openvpn@fox-it.com>
5fe5fe9e
  *
  *  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.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
5fe5fe9e
  */
 
 /**
  * @file PKCS #11 OpenSSL backend
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
5fe5fe9e
 #include "syshead.h"
 
9b33b5a4
 #if defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_OPENSSL)
5fe5fe9e
 
 #include "errlevel.h"
 #include "pkcs11_backend.h"
00b973f8
 #include "ssl_verify.h"
5fe5fe9e
 #include <pkcs11-helper-1.0/pkcs11h-openssl.h>
 
 int
 pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
81d882d5
                         struct tls_root_ctx *const ssl_ctx)
5fe5fe9e
 {
81d882d5
     int ret = 1;
5fe5fe9e
 
81d882d5
     X509 *x509 = NULL;
     EVP_PKEY *evp = NULL;
     pkcs11h_openssl_session_t openssl_session = NULL;
5fe5fe9e
 
81d882d5
     if ((openssl_session = pkcs11h_openssl_createSession(certificate)) == NULL)
5fe5fe9e
     {
81d882d5
         msg(M_WARN, "PKCS#11: Cannot initialize openssl session");
         goto cleanup;
5fe5fe9e
     }
 
81d882d5
     /*
      * Will be released by openssl_session
      */
     certificate = NULL;
5fe5fe9e
 
81d882d5
     if ((evp = pkcs11h_openssl_session_getEVP(openssl_session)) == NULL)
5fe5fe9e
     {
81d882d5
         msg(M_WARN, "PKCS#11: Unable get evp object");
         goto cleanup;
5fe5fe9e
     }
 
81d882d5
     if ((x509 = pkcs11h_openssl_session_getX509(openssl_session)) == NULL)
5fe5fe9e
     {
81d882d5
         msg(M_WARN, "PKCS#11: Unable get certificate object");
         goto cleanup;
5fe5fe9e
     }
 
81d882d5
     if (!SSL_CTX_use_PrivateKey(ssl_ctx->ctx, evp))
5fe5fe9e
     {
81d882d5
         msg(M_WARN, "PKCS#11: Cannot set private key for openssl");
         goto cleanup;
5fe5fe9e
     }
 
81d882d5
     if (!SSL_CTX_use_certificate(ssl_ctx->ctx, x509))
5fe5fe9e
     {
81d882d5
         msg(M_WARN, "PKCS#11: Cannot set certificate for openssl");
         goto cleanup;
5fe5fe9e
     }
81d882d5
     ret = 0;
5fe5fe9e
 
 cleanup:
81d882d5
     /*
      * 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;
     }
5fe5fe9e
 
81d882d5
     /*
      * openssl objects have reference
      * count, so release them
      */
     if (x509 != NULL)
5fe5fe9e
     {
81d882d5
         X509_free(x509);
         x509 = NULL;
5fe5fe9e
     }
 
81d882d5
     if (evp != NULL)
5fe5fe9e
     {
81d882d5
         EVP_PKEY_free(evp);
         evp = NULL;
5fe5fe9e
     }
 
81d882d5
     if (openssl_session != NULL)
5fe5fe9e
     {
81d882d5
         pkcs11h_openssl_freeSession(openssl_session);
         openssl_session = NULL;
5fe5fe9e
     }
81d882d5
     return ret;
5fe5fe9e
 }
 
00b973f8
 char *
81d882d5
 pkcs11_certificate_dn(pkcs11h_certificate_t certificate, struct gc_arena *gc)
5fe5fe9e
 {
81d882d5
     X509 *x509 = NULL;
00b973f8
 
81d882d5
     char *dn = NULL;
5fe5fe9e
 
81d882d5
     if ((x509 = pkcs11h_openssl_getX509(certificate)) == NULL)
5fe5fe9e
     {
81d882d5
         msg(M_FATAL, "PKCS#11: Cannot get X509");
         goto cleanup;
5fe5fe9e
     }
 
81d882d5
     dn = x509_get_subject(x509, gc);
5fe5fe9e
 
 cleanup:
81d882d5
     if (x509 != NULL)
5fe5fe9e
     {
81d882d5
         X509_free(x509);
         x509 = NULL;
5fe5fe9e
     }
 
81d882d5
     return dn;
5fe5fe9e
 }
 
 int
81d882d5
 pkcs11_certificate_serial(pkcs11h_certificate_t certificate, char *serial,
                           size_t serial_len)
5fe5fe9e
 {
81d882d5
     X509 *x509 = NULL;
     BIO *bio = NULL;
     int ret = 1;
     int n;
5fe5fe9e
 
81d882d5
     if ((x509 = pkcs11h_openssl_getX509(certificate)) == NULL)
5fe5fe9e
     {
81d882d5
         msg(M_FATAL, "PKCS#11: Cannot get X509");
         goto cleanup;
5fe5fe9e
     }
 
81d882d5
     if ((bio = BIO_new(BIO_s_mem())) == NULL)
5fe5fe9e
     {
81d882d5
         msg(M_FATAL, "PKCS#11: Cannot create BIO");
         goto cleanup;
5fe5fe9e
     }
 
81d882d5
     i2a_ASN1_INTEGER(bio, X509_get_serialNumber(x509));
     n = BIO_read(bio, serial, serial_len-1);
5fe5fe9e
 
81d882d5
     if (n<0)
     {
         serial[0] = '\x0';
     }
     else
     {
         serial[n] = 0;
     }
5fe5fe9e
 
81d882d5
     ret = 0;
5fe5fe9e
 
 cleanup:
 
81d882d5
     if (x509 != NULL)
5fe5fe9e
     {
81d882d5
         X509_free(x509);
         x509 = NULL;
5fe5fe9e
     }
81d882d5
     return ret;
5fe5fe9e
 }
31ea2ee4
 #endif /* defined(ENABLE_PKCS11) && defined(ENABLE_OPENSSL) */