src/openvpn/pkcs11.c
ce98fd24
 /*
  *  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>
ce98fd24
  *
  *  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.
ce98fd24
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
ce98fd24
 #include "syshead.h"
be38c051
 
 #if defined(ENABLE_PKCS11)
 
718526e0
 #include <pkcs11-helper-1.0/pkcs11h-certificate.h>
 #include "basic.h"
 #include "error.h"
 #include "manage.h"
1bda73a7
 #include "base64.h"
ce98fd24
 #include "pkcs11.h"
efcdf594
 #include "misc.h"
 #include "otime.h"
72c7b12c
 #include "console.h"
5fe5fe9e
 #include "pkcs11_backend.h"
ce98fd24
 
 static
718526e0
 time_t
4cd4899e
 __mytime(void)
 {
81d882d5
     return openvpn_time(NULL);
718526e0
 }
 
 #if !defined(_WIN32)
 static
 int
4cd4899e
 __mygettimeofday(struct timeval *tv)
 {
81d882d5
     return gettimeofday(tv, NULL);
718526e0
 }
 #endif
 
 static
 void
4cd4899e
 __mysleep(const unsigned long usec)
 {
718526e0
 #if defined(_WIN32)
81d882d5
     Sleep(usec/1000);
718526e0
 #else
81d882d5
     usleep(usec);
718526e0
 #endif
 }
 
 
 static pkcs11h_engine_system_t s_pkcs11h_sys_engine = {
81d882d5
     malloc,
     free,
     __mytime,
     __mysleep,
718526e0
 #if defined(_WIN32)
81d882d5
     NULL
718526e0
 #else
81d882d5
     __mygettimeofday
718526e0
 #endif
 };
 
 static
18597b93
 unsigned
81d882d5
 _pkcs11_msg_pkcs112openvpn(
     const unsigned flags
4cd4899e
     )
 {
81d882d5
     unsigned openvpn_flags;
 
4cd4899e
     switch (flags)
     {
81d882d5
         case PKCS11H_LOG_DEBUG2:
             openvpn_flags = D_PKCS11_DEBUG;
             break;
 
         case PKCS11H_LOG_DEBUG1:
             openvpn_flags = D_SHOW_PKCS11;
             break;
 
         case PKCS11H_LOG_INFO:
             openvpn_flags = M_INFO;
             break;
 
         case PKCS11H_LOG_WARN:
             openvpn_flags = M_WARN;
             break;
 
         case PKCS11H_LOG_ERROR:
             openvpn_flags = M_FATAL;
             break;
 
         default:
             openvpn_flags = M_FATAL;
             break;
     }
18597b93
 
 #if defined(ENABLE_PKCS11_FORCE_DEBUG)
81d882d5
     openvpn_flags = M_INFO;
18597b93
 #endif
 
81d882d5
     return openvpn_flags;
18597b93
 }
 
 static
 unsigned
81d882d5
 _pkcs11_msg_openvpn2pkcs11(
     const unsigned flags
4cd4899e
     )
 {
81d882d5
     unsigned pkcs11_flags;
 
     if ((flags & D_PKCS11_DEBUG) != 0)
     {
         pkcs11_flags = PKCS11H_LOG_DEBUG2;
     }
     else if ((flags & D_SHOW_PKCS11) != 0)
     {
         pkcs11_flags = PKCS11H_LOG_DEBUG1;
     }
     else if ((flags & M_INFO) != 0)
     {
         pkcs11_flags = PKCS11H_LOG_INFO;
     }
     else if ((flags & M_WARN) != 0)
     {
         pkcs11_flags = PKCS11H_LOG_WARN;
     }
     else if ((flags & M_FATAL) != 0)
     {
         pkcs11_flags = PKCS11H_LOG_ERROR;
     }
     else
     {
         pkcs11_flags = PKCS11H_LOG_ERROR;
     }
18597b93
 
 #if defined(ENABLE_PKCS11_FORCE_DEBUG)
81d882d5
     pkcs11_flags = PKCS11H_LOG_DEBUG2;
18597b93
 #endif
 
81d882d5
     return pkcs11_flags;
18597b93
 }
 
 static
ce98fd24
 void
81d882d5
 _pkcs11_openvpn_log(
     void *const global_data,
     unsigned flags,
     const char *const szFormat,
     va_list args
4cd4899e
     )
 {
81d882d5
     char Buffer[10*1024];
 
     (void)global_data;
 
     vsnprintf(Buffer, sizeof(Buffer), szFormat, args);
     Buffer[sizeof(Buffer)-1] = 0;
 
     msg(_pkcs11_msg_pkcs112openvpn(flags), "%s", Buffer);
18597b93
 }
 
 static
718526e0
 PKCS11H_BOOL
81d882d5
 _pkcs11_openvpn_token_prompt(
     void *const global_data,
     void *const user_data,
     const pkcs11h_token_id_t token,
     const unsigned retry
4cd4899e
     )
 {
81d882d5
     struct user_pass token_resp;
 
     (void)global_data;
     (void)user_data;
     (void)retry;
 
     ASSERT(token!=NULL);
 
     CLEAR(token_resp);
     token_resp.defined = false;
     token_resp.nocache = true;
     openvpn_snprintf(
         token_resp.username,
         sizeof(token_resp.username),
         "Please insert %s token",
         token->label
         );
 
     if (
         !get_user_pass(
             &token_resp,
             NULL,
             "token-insertion-request",
             GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK|GET_USER_PASS_NOFATAL
             )
         )
     {
         return false;
     }
     else
     {
         return strcmp(token_resp.password, "ok") == 0;
     }
6835555e
 }
 
 static
65433d74
 PKCS11H_BOOL
81d882d5
 _pkcs11_openvpn_pin_prompt(
     void *const global_data,
     void *const user_data,
     const pkcs11h_token_id_t token,
     const unsigned retry,
     char *const pin,
     const size_t pin_max
4cd4899e
     )
 {
81d882d5
     struct user_pass token_pass;
     char prompt[1024];
 
     (void)global_data;
     (void)user_data;
     (void)retry;
 
     ASSERT(token!=NULL);
 
     openvpn_snprintf(prompt, sizeof(prompt), "%s token", token->label);
 
     token_pass.defined = false;
     token_pass.nocache = true;
 
     if (
         !get_user_pass(
             &token_pass,
             NULL,
             prompt,
             GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY|GET_USER_PASS_NOFATAL
             )
         )
     {
         return false;
     }
     else
     {
         strncpynt(pin, token_pass.password, pin_max);
         purge_user_pass(&token_pass, true);
 
         if (strlen(pin) == 0)
         {
             return false;
         }
         else
         {
             return true;
         }
     }
6835555e
 }
 
33c8c4d4
 bool
81d882d5
 pkcs11_initialize(
     const bool protected_auth,
     const int nPINCachePeriod
4cd4899e
     )
 {
81d882d5
     CK_RV rv = CKR_FUNCTION_FAILED;
 
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: pkcs11_initialize - entered"
         );
 
     if ((rv = pkcs11h_engine_setSystem(&s_pkcs11h_sys_engine)) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot initialize system engine %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if ((rv = pkcs11h_initialize()) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if ((rv = pkcs11h_setLogHook(_pkcs11_openvpn_log, NULL)) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     pkcs11h_setLogLevel(_pkcs11_msg_openvpn2pkcs11(get_debug_level()));
 
     if ((rv = pkcs11h_setForkMode(TRUE)) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot set fork mode %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if ((rv = pkcs11h_setTokenPromptHook(_pkcs11_openvpn_token_prompt, NULL)) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if ((rv = pkcs11h_setPINPromptHook(_pkcs11_openvpn_pin_prompt, NULL)) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if ((rv = pkcs11h_setProtectedAuthentication(protected_auth)) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot set protected authentication mode %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if ((rv = pkcs11h_setPINCachePeriod(nPINCachePeriod)) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot set Pcache period %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     rv = CKR_OK;
718526e0
 
 cleanup:
81d882d5
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: pkcs11_initialize - return %ld-'%s'",
         rv,
         pkcs11h_getMessage(rv)
         );
 
     return rv == CKR_OK;
6835555e
 }
 
 void
e2a0cad4
 pkcs11_terminate(void)
4cd4899e
 {
81d882d5
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: pkcs11_terminate - entered"
         );
 
     pkcs11h_terminate();
 
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: pkcs11_terminate - return"
         );
6835555e
 }
 
33c8c4d4
 bool
81d882d5
 pkcs11_addProvider(
     const char *const provider,
     const bool protected_auth,
     const unsigned private_mode,
     const bool cert_private
4cd4899e
     )
 {
81d882d5
     CK_RV rv = CKR_OK;
 
     ASSERT(provider!=NULL);
 
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: pkcs11_addProvider - entered - provider='%s', private_mode=%08x",
         provider,
         private_mode
         );
 
     msg(
         M_INFO,
         "PKCS#11: Adding PKCS#11 provider '%s'",
         provider
         );
 
     if (
         (rv = pkcs11h_addProvider(
              provider,
              provider,
              protected_auth,
              private_mode,
              PKCS11H_SLOTEVENT_METHOD_AUTO,
              0,
              cert_private
              )) != CKR_OK
         )
     {
         msg(M_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage(rv));
     }
 
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: pkcs11_addProvider - return rv=%ld-'%s'",
         rv,
         pkcs11h_getMessage(rv)
         );
 
     return rv == CKR_OK;
6835555e
 }
 
ce98fd24
 int
e2a0cad4
 pkcs11_logout(void)
4cd4899e
 {
81d882d5
     return pkcs11h_logout() == CKR_OK;
718526e0
 }
 
 int
e2a0cad4
 pkcs11_management_id_count(void)
4cd4899e
 {
81d882d5
     pkcs11h_certificate_id_list_t id_list = NULL;
     pkcs11h_certificate_id_list_t t = NULL;
     CK_RV rv = CKR_OK;
     int count = 0;
 
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: pkcs11_management_id_count - entered"
         );
 
     if (
         (rv = pkcs11h_certificate_enumCertificateIds(
              PKCS11H_ENUM_METHOD_CACHE_EXIST,
              NULL,
              PKCS11H_PROMPT_MASK_ALLOW_ALL,
              NULL,
              &id_list
              )) != CKR_OK
         )
     {
         msg(M_WARN, "PKCS#11: Cannot get certificate list %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
4cd4899e
     for (count = 0, t = id_list; t != NULL; t = t->next)
     {
81d882d5
         count++;
     }
1bda73a7
 
 cleanup:
 
81d882d5
     if (id_list != NULL)
     {
         pkcs11h_certificate_freeCertificateIdList(id_list);
         id_list = NULL;
     }
1bda73a7
 
81d882d5
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: pkcs11_management_id_count - return count=%d",
         count
         );
1bda73a7
 
81d882d5
     return count;
1bda73a7
 }
 
 bool
81d882d5
 pkcs11_management_id_get(
     const int index,
     char **id,
     char **base64
4cd4899e
     )
 {
81d882d5
     pkcs11h_certificate_id_list_t id_list = NULL;
     pkcs11h_certificate_id_list_t entry = NULL;
c373382c
 #if 0 /* certificate_id seems to be unused -- JY */
81d882d5
     pkcs11h_certificate_id_t certificate_id = NULL;
c373382c
 #endif
81d882d5
     pkcs11h_certificate_t certificate = NULL;
     CK_RV rv = CKR_OK;
     unsigned char *certificate_blob = NULL;
     size_t certificate_blob_size = 0;
     size_t max;
     char *internal_id = NULL;
     char *internal_base64 = NULL;
     int count = 0;
     bool success = false;
 
     ASSERT(id!=NULL);
     ASSERT(base64!=NULL);
 
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: pkcs11_management_id_get - entered index=%d",
         index
         );
 
     *id = NULL;
     *base64 = NULL;
 
     if (
         (rv = pkcs11h_certificate_enumCertificateIds(
              PKCS11H_ENUM_METHOD_CACHE_EXIST,
              NULL,
              PKCS11H_PROMPT_MASK_ALLOW_ALL,
              NULL,
              &id_list
              )) != CKR_OK
         )
     {
         msg(M_WARN, "PKCS#11: Cannot get certificate list %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     entry = id_list;
     count = 0;
4cd4899e
     while (entry != NULL && count != index)
     {
81d882d5
         count++;
         entry = entry->next;
     }
 
     if (entry == NULL)
     {
         dmsg(
             D_PKCS11_DEBUG,
             "PKCS#11: pkcs11_management_id_get - no certificate at index=%d",
             index
             );
         goto cleanup;
     }
 
     if (
         (rv = pkcs11h_certificate_serializeCertificateId(
              NULL,
              &max,
              entry->certificate_id
              )) != CKR_OK
         )
     {
         msg(M_WARN, "PKCS#11: Cannot serialize certificate id %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if ((internal_id = (char *)malloc(max)) == NULL)
     {
         msg(M_FATAL, "PKCS#11: Cannot allocate memory");
         goto cleanup;
     }
 
     if (
         (rv = pkcs11h_certificate_serializeCertificateId(
              internal_id,
              &max,
              entry->certificate_id
              )) != CKR_OK
         )
     {
         msg(M_WARN, "PKCS#11: Cannot serialize certificate id %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if (
         (rv = pkcs11h_certificate_create(
              entry->certificate_id,
              NULL,
              PKCS11H_PROMPT_MASK_ALLOW_ALL,
              PKCS11H_PIN_CACHE_INFINITE,
              &certificate
              )) != CKR_OK
         )
     {
         msg(M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if (
         (rv = pkcs11h_certificate_getCertificateBlob(
              certificate,
              NULL,
              &certificate_blob_size
              )) != CKR_OK
         )
     {
         msg(M_WARN, "PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if ((certificate_blob = (unsigned char *)malloc(certificate_blob_size)) == NULL)
     {
         msg(M_FATAL, "PKCS#11: Cannot allocate memory");
         goto cleanup;
     }
 
     if (
         (rv = pkcs11h_certificate_getCertificateBlob(
              certificate,
              certificate_blob,
              &certificate_blob_size
              )) != CKR_OK
         )
     {
         msg(M_WARN, "PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if (openvpn_base64_encode(certificate_blob, certificate_blob_size, &internal_base64) == -1)
     {
         msg(M_WARN, "PKCS#11: Cannot encode certificate");
         goto cleanup;
     }
 
     *id = internal_id;
     internal_id = NULL;
     *base64 = internal_base64;
     internal_base64 = NULL;
     success = true;
 
1bda73a7
 cleanup:
 
81d882d5
     if (id_list != NULL)
     {
         pkcs11h_certificate_freeCertificateIdList(id_list);
         id_list = NULL;
     }
 
     if (internal_id != NULL)
     {
         free(internal_id);
         internal_id = NULL;
     }
 
     if (internal_base64 != NULL)
     {
         free(internal_base64);
         internal_base64 = NULL;
     }
 
     if (certificate_blob != NULL)
     {
         free(certificate_blob);
         certificate_blob = NULL;
     }
 
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: pkcs11_management_id_get - return success=%d, id='%s'",
         success ? 1 : 0,
         *id
         );
 
     return success;
1bda73a7
 }
 
 int
81d882d5
 tls_ctx_use_pkcs11(
     struct tls_root_ctx *const ssl_ctx,
     bool pkcs11_id_management,
     const char *const pkcs11_id
4cd4899e
     )
 {
81d882d5
     pkcs11h_certificate_id_t certificate_id = NULL;
     pkcs11h_certificate_t certificate = NULL;
     CK_RV rv = CKR_OK;
 
     bool ok = false;
 
     ASSERT(ssl_ctx!=NULL);
     ASSERT(pkcs11_id_management || pkcs11_id!=NULL);
 
     dmsg(
         D_PKCS11_DEBUG,
         "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
         );
 
     if (pkcs11_id_management)
     {
         struct user_pass id_resp;
 
         CLEAR(id_resp);
 
         id_resp.defined = false;
         id_resp.nocache = true;
         openvpn_snprintf(
             id_resp.username,
             sizeof(id_resp.username),
             "Please specify PKCS#11 id to use"
             );
 
         if (
             !get_user_pass(
                 &id_resp,
                 NULL,
                 "pkcs11-id-request",
                 GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_STR|GET_USER_PASS_NOFATAL
                 )
             )
         {
             goto cleanup;
         }
 
         if (
             (rv = pkcs11h_certificate_deserializeCertificateId(
                  &certificate_id,
                  id_resp.password
                  )) != CKR_OK
             )
         {
             msg(M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage(rv));
             goto cleanup;
         }
     }
     else
     {
         if (
             (rv = pkcs11h_certificate_deserializeCertificateId(
                  &certificate_id,
                  pkcs11_id
                  )) != CKR_OK
             )
         {
             msg(M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage(rv));
             goto cleanup;
         }
     }
 
     if (
         (rv = pkcs11h_certificate_create(
              certificate_id,
              NULL,
              PKCS11H_PROMPT_MASK_ALLOW_ALL,
              PKCS11H_PIN_CACHE_INFINITE,
              &certificate
              )) != CKR_OK
         )
     {
         msg(M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if (
         (pkcs11_init_tls_session(
              certificate,
              ssl_ctx
              ))
         )
     {
         /* Handled by SSL context free */
         certificate = NULL;
         goto cleanup;
     }
 
     /* Handled by SSL context free */
     certificate = NULL;
     ok = true;
718526e0
 
 cleanup:
81d882d5
     if (certificate != NULL)
     {
         pkcs11h_certificate_freeCertificate(certificate);
         certificate = NULL;
     }
 
     if (certificate_id != NULL)
     {
         pkcs11h_certificate_freeCertificateId(certificate_id);
         certificate_id = NULL;
     }
 
     dmsg(
         D_PKCS11_DEBUG,
         "PKCS#11: tls_ctx_use_pkcs11 - return ok=%d, rv=%ld",
         ok ? 1 : 0,
         rv
         );
 
     return ok ? 1 : 0;
ce98fd24
 }
 
718526e0
 static
6eb064d8
 PKCS11H_BOOL
81d882d5
 _pkcs11_openvpn_show_pkcs11_ids_pin_prompt(
     void *const global_data,
     void *const user_data,
     const pkcs11h_token_id_t token,
     const unsigned retry,
     char *const pin,
     const size_t pin_max
4cd4899e
     )
 {
81d882d5
     struct gc_arena gc = gc_new();
     struct buffer pass_prompt = alloc_buf_gc(128, &gc);
 
     (void)global_data;
     (void)user_data;
     (void)retry;
 
     ASSERT(token!=NULL);
 
     buf_printf(&pass_prompt, "Please enter '%s' token PIN or 'cancel': ", token->display);
     if (!query_user_SINGLE(BSTR(&pass_prompt), BLEN(&pass_prompt),
                            pin, pin_max, false))
     {
         msg(M_FATAL, "Could not retrieve the PIN");
     }
 
     gc_free(&gc);
 
     if (!strcmp(pin, "cancel"))
     {
         return FALSE;
     }
     else
     {
         return TRUE;
     }
ce98fd24
 }
 
 void
81d882d5
 show_pkcs11_ids(
     const char *const provider,
     bool cert_private
4cd4899e
     )
 {
81d882d5
     struct gc_arena gc = gc_new();
     pkcs11h_certificate_id_list_t user_certificates = NULL;
     pkcs11h_certificate_id_list_t current = NULL;
     CK_RV rv = CKR_FUNCTION_FAILED;
 
     if ((rv = pkcs11h_initialize()) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if ((rv = pkcs11h_setLogHook(_pkcs11_openvpn_log, NULL)) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     pkcs11h_setLogLevel(_pkcs11_msg_openvpn2pkcs11(get_debug_level()));
 
     if ((rv = pkcs11h_setProtectedAuthentication(TRUE)) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot set protected authentication %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if ((rv = pkcs11h_setPINPromptHook(_pkcs11_openvpn_show_pkcs11_ids_pin_prompt, NULL)) != CKR_OK)
     {
         msg(M_FATAL, "PKCS#11: Cannot set PIN hook %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if (
         (rv = pkcs11h_addProvider(
              provider,
              provider,
              TRUE,
              0,
              FALSE,
              0,
              cert_private ? TRUE : FALSE
              )) != CKR_OK
         )
     {
         msg(M_FATAL, "PKCS#11: Cannot add provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     if (
         (rv = pkcs11h_certificate_enumCertificateIds(
              PKCS11H_ENUM_METHOD_CACHE_EXIST,
              NULL,
              PKCS11H_PROMPT_MASK_ALLOW_ALL,
              NULL,
              &user_certificates
              )) != CKR_OK
         )
     {
         msg(M_FATAL, "PKCS#11: Cannot enumerate certificates %ld-'%s'", rv, pkcs11h_getMessage(rv));
         goto cleanup;
     }
 
     msg(
         M_INFO|M_NOPREFIX|M_NOLF,
         (
             "\n"
             "The following objects are available for use.\n"
             "Each object shown below may be used as parameter to\n"
             "--pkcs11-id option please remember to use single quote mark.\n"
         )
         );
4cd4899e
     for (current = user_certificates; current != NULL; current = current->next)
     {
81d882d5
         pkcs11h_certificate_t certificate = NULL;
         char *dn = NULL;
         char serial[1024] = {0};
         char *ser = NULL;
         size_t ser_len = 0;
 
         if (
             (rv = pkcs11h_certificate_serializeCertificateId(
                  NULL,
                  &ser_len,
                  current->certificate_id
                  )) != CKR_OK
             )
         {
             msg(M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage(rv));
             goto cleanup1;
         }
 
         if (
             rv == CKR_OK
             && (ser = (char *)malloc(ser_len)) == NULL
             )
         {
             msg(M_FATAL, "PKCS#11: Cannot allocate memory");
             goto cleanup1;
         }
 
         if (
             (rv = pkcs11h_certificate_serializeCertificateId(
                  ser,
                  &ser_len,
                  current->certificate_id
                  )) != CKR_OK
             )
         {
             msg(M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage(rv));
             goto cleanup1;
         }
 
         if (
             (rv = pkcs11h_certificate_create(
                  current->certificate_id,
                  NULL,
                  PKCS11H_PROMPT_MASK_ALLOW_ALL,
                  PKCS11H_PIN_CACHE_INFINITE,
                  &certificate
                  ))
             )
         {
             msg(M_FATAL, "PKCS#11: Cannot create certificate %ld-'%s'", rv, pkcs11h_getMessage(rv));
             goto cleanup1;
         }
 
         if (
             (dn = pkcs11_certificate_dn(
                  certificate,
                  &gc
                  )) == NULL
             )
         {
             goto cleanup1;
         }
 
         if (
             (pkcs11_certificate_serial(
                  certificate,
                  serial,
                  sizeof(serial)
                  ))
             )
         {
             goto cleanup1;
         }
 
         msg(
             M_INFO|M_NOPREFIX|M_NOLF,
             (
                 "\n"
                 "Certificate\n"
                 "       DN:             %s\n"
                 "       Serial:         %s\n"
                 "       Serialized id:  %s\n"
             ),
             dn,
             serial,
             ser
             );
 
 cleanup1:
 
         if (certificate != NULL)
         {
             pkcs11h_certificate_freeCertificate(certificate);
             certificate = NULL;
         }
 
         if (ser != NULL)
         {
             free(ser);
             ser = NULL;
         }
     }
718526e0
 
 cleanup:
81d882d5
     if (user_certificates != NULL)
     {
         pkcs11h_certificate_freeCertificateIdList(user_certificates);
         user_certificates = NULL;
     }
 
     pkcs11h_terminate();
     gc_free(&gc);
ce98fd24
 }
 
81d882d5
 #else  /* if defined(ENABLE_PKCS11) */
eabb8eed
 #ifdef _MSC_VER  /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */
81d882d5
 static void
4cd4899e
 dummy(void)
 {
81d882d5
 }
eabb8eed
 #endif
6835555e
 #endif /* ENABLE_PKCS11 */