]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Merged with Alon's r688.
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Thu, 20 Oct 2005 05:58:08 +0000 (05:58 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Thu, 20 Oct 2005 05:58:08 +0000 (05:58 +0000)
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@689 e7ae566f-a301-0410-adde-c780ea21d3b5

18 files changed:
Makefile.am
error.c
error.h
init.c
makefile.w32
makefile.w32-vc
manage.c
manage.h
misc.c
misc.h
options.c
pkcs11-helper-config.h [new file with mode: 0644]
pkcs11-helper.c [new file with mode: 0644]
pkcs11-helper.h [new file with mode: 0644]
pkcs11.c
pkcs11.h
proxy.c
ssl.c

index 6519f2aab98400ac58103ab95edd43cef25b694b..424b167d05ed9a65d447845c291eee93d9a149aa 100644 (file)
@@ -67,7 +67,7 @@ openvpn_SOURCES = \
        multi.c multi.h \
         ntlm.c ntlm.h \
        occ.c occ.h occ-inline.h \
-       pkcs11.c pkcs11.h cryptoki.h \
+       pkcs11.c pkcs11.h pkcs11-helper.c pkcs11-helper.h pkcs11-helper-config.h cryptoki.h \
        openvpn.c openvpn.h \
        openvpn-plugin.h \
        options.c options.h \
diff --git a/error.c b/error.c
index 01a620703f110ddb50bfd65e86a8a4723d0f85b1..f01dd8fc86a06a1da5b4bc71b081e31ad33b5a37 100644 (file)
--- a/error.c
+++ b/error.c
@@ -300,26 +300,29 @@ void x_msg (const unsigned int flags, const char *format, ...)
 
          if ((flags & M_NOPREFIX) || suppress_timestamps)
            {
-             fprintf (fp, "%s%s%s\n",
+             fprintf (fp, "%s%s%s%s",
                       prefix,
                       prefix_sep,
-                      m1);
+                      m1,
+                      (flags&M_NOLF) ? "" : "\n");
            }
          else
            {
 #ifdef USE_PTHREAD
-             fprintf (fp, "%s [%d] %s%s%s\n",
+             fprintf (fp, "%s [%d] %s%s%s%s",
                       time_string (0, 0, show_usec, &gc),
                       (int) openvpn_thread_self (),
                       prefix,
                       prefix_sep,
-                      m1);
+                      m1,
+                      (flags&M_NOLF) ? "" : "\n");
 #else
-             fprintf (fp, "%s %s%s%s\n",
+             fprintf (fp, "%s %s%s%s%s",
                       time_string (0, 0, show_usec, &gc),
                       prefix,
                       prefix_sep,
-                      m1);
+                      m1,
+                      (flags&M_NOLF) ? "" : "\n");
 #endif
            }
          fflush(fp);
diff --git a/error.h b/error.h
index 8bcc9095b96cb95df475ed0635b06987fe962b5c..5d2501bda01a6c31e8f8d39306eebdb99d7caad4 100644 (file)
--- a/error.h
+++ b/error.h
@@ -97,6 +97,7 @@ extern int x_msg_line_num;
 #define M_USAGE_SMALL     (1<<13)        /* fatal options error, call usage_small */
 #define M_MSG_VIRT_OUT    (1<<14)        /* output message through msg_status_output callback */
 #define M_OPTERR          (1<<15)        /* print "Options error:" prefix */
+#define M_NOLF            (1<<16)        /* don't print new line */
 
 /* flag combinations which are frequently used */
 #define M_ERR     (M_FATAL | M_ERRNO)
diff --git a/init.c b/init.c
index c2fb6cfe5f03cb02a12256a6d439d42d5a5fd94b..97d06608125ef99d515645d1999bceacb76172cd 100644 (file)
--- a/init.c
+++ b/init.c
@@ -116,12 +116,12 @@ context_init_1 (struct context *c)
 #if defined(ENABLE_PKCS11)
   {
     int i;
-    init_pkcs11 (c->options.pkcs11_pin_cache_period);
+    pkcs11_initialize (c->options.pkcs11_pin_cache_period);
     for (i=0;i<MAX_PARMS && c->options.pkcs11_providers[i] != NULL;i++)
-     add_pkcs11 (c->options.pkcs11_providers[i], c->options.pkcs11_sign_mode[i]);
+     pkcs11_addProvider (c->options.pkcs11_providers[i], c->options.pkcs11_sign_mode[i]);
   }
 #endif
-  
+
 #if P2MP
   /* Auth user/pass input */
   if (c->options.auth_user_pass_file)
@@ -236,7 +236,7 @@ uninit_static (void)
 #endif
 
 #ifdef ENABLE_PKCS11
-  free_pkcs11 ();
+  pkcs11_terminate ();
 #endif
 
 #if defined(MEASURE_TLS_HANDSHAKE_STATS) && defined(USE_CRYPTO) && defined(USE_SSL)
@@ -376,7 +376,7 @@ possibly_become_daemon (const struct options *options, const bool first_time)
        set_std_files_to_null (true);
 
 #if defined(ENABLE_PKCS11)
-      fork_fix_pkcs11 ();
+      pkcs11_forkFixup ();
 #endif
 
       ret = true;
index 0a1517c5bc97fa791368b25cfe68c9e3df0aa7d1..48cc3f13076dfea0234619efd4160edb864456d4 100755 (executable)
@@ -96,7 +96,7 @@ HEADERS = \
        ntlm.h \
        occ-inline.h \
        occ.h \
-       pkcs11.h \
+       pkcs11.h pkcs11-helper.h cryptoki.h \
         openvpn.h \
        openvpn-plugin.h \
        options.h \
@@ -151,7 +151,7 @@ OBJS =  base64.o \
        multi.o \
        ntlm.o \
        occ.o \
-       pkcs11.o \
+       pkcs11.o pkcs11-helper.o \
         openvpn.o \
        options.o \
        otime.o \
index bcd0c6205eafec1f2eb7dab5decfbd240678614e..49c103105653795080249ea47e4fa1849c96568a 100644 (file)
@@ -81,7 +81,7 @@ HEADERS = \
        ntlm.h \
        occ-inline.h \
        occ.h \
-       pkcs11.h \
+       pkcs11.h pkcs11-helper.h cryptoki.h \
         openvpn.h \
        openvpn-plugin.h \
        options.h \
@@ -136,7 +136,7 @@ OBJS =  base64.obj \
        multi.obj \
        ntlm.obj \
        occ.obj \
-       pkcs11.obj \
+       pkcs11.obj pkcs11-helper.obj \
         openvpn.obj \
        options.obj \
        otime.obj \
index 7be67fd00035a30a3c7f1c933336a1e32d3fefa2..d17d9ce7af2df811e50d862467baeec8b77425de 100644 (file)
--- a/manage.c
+++ b/manage.c
@@ -39,6 +39,7 @@
 #include "event.h"
 #include "otime.h"
 #include "integer.h"
+#include "misc.h"
 #include "manage.h"
 
 #include "memdbg.h"
@@ -74,6 +75,7 @@ man_help ()
   msg (M_CLIENT, "                         + show last N lines or 'all' for entire history.");
   msg (M_CLIENT, "mute [n]               : Set log mute level to n, or show level if n is absent.");
   msg (M_CLIENT, "net                    : (Windows only) Show network info and routing table.");
+  msg (M_CLIENT, "ok type                : Enter confirmation for NEED-OK request.");
   msg (M_CLIENT, "password type p        : Enter password p for a queried OpenVPN password.");
   msg (M_CLIENT, "signal s               : Send signal s to daemon,");
   msg (M_CLIENT, "                         s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2.");
@@ -467,6 +469,10 @@ man_up_finalize (struct management *man)
       if (strlen (man->connection.up_query.password))
        man->connection.up_query.defined = true;
       break;
+    case UP_QUERY_NEED_OK:
+      if (strlen (man->connection.up_query.password))
+       man->connection.up_query.defined = true;
+      break;
     default:
       ASSERT (0);
     }
@@ -520,6 +526,13 @@ man_query_password (struct management *man, const char *type, const char *string
   man_query_user_pass (man, type, string, needed, "password", man->connection.up_query.password, USER_PASS_LEN);
 }
 
+static void
+man_query_need_ok (struct management *man, const char *type)
+{
+  const bool needed = ((man->connection.up_query_mode == UP_QUERY_NEED_OK) && man->connection.up_query_type);
+  man_query_user_pass (man, type, "ok", needed, "ok-confirmation", man->connection.up_query.password, USER_PASS_LEN);
+}
+
 static void
 man_net (struct management *man)
 {
@@ -708,6 +721,11 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
       if (man_need (man, p, 2, 0))
        man_query_password (man, p[1], p[2]);
     }
+  else if (streq (p[0], "ok"))
+    {
+      if (man_need (man, p, 1, 0))
+       man_query_need_ok (man, p[1]);
+    }
   else if (streq (p[0], "net"))
     {
       man_net (man);
@@ -1130,7 +1148,7 @@ man_settings_init (struct man_settings *ms,
        * Get username/password
        */
       if (pass_file)
-       get_user_pass (&ms->up, pass_file, true, "Management", 0);
+       get_user_pass (&ms->up, pass_file, "Management", GET_USER_PASS_PASSWORD_ONLY);
 
       /*
        * Should OpenVPN query the management layer for
@@ -1728,7 +1746,7 @@ bool
 management_query_user_pass (struct management *man,
                            struct user_pass *up,
                            const char *type,
-                           const bool password_only)
+                           const unsigned int flags)
 {
   struct gc_arena gc = gc_new ();
   bool ret = false;
@@ -1738,6 +1756,9 @@ management_query_user_pass (struct management *man,
       volatile int signal_received = 0;
       const bool standalone_disabled_save = man->persist.standalone_disabled;
       struct buffer alert_msg = alloc_buf_gc (128, &gc);
+      const char *alert_type = NULL;
+      const char *prefix = NULL;
+      unsigned int up_query_mode = 0;
 
       ret = true;
       man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */
@@ -1745,9 +1766,28 @@ management_query_user_pass (struct management *man,
 
       CLEAR (man->connection.up_query);
 
-      buf_printf (&alert_msg, ">PASSWORD:Need '%s' %s",
+      if (flags & GET_USER_PASS_NEED_OK)
+       {
+         up_query_mode = UP_QUERY_NEED_OK;
+         prefix= "NEED-OK";
+         alert_type = "confirmation";
+       }
+      else if (flags & GET_USER_PASS_PASSWORD_ONLY)
+       {
+         up_query_mode = UP_QUERY_PASS;
+         prefix = "PASSWORD";
+         alert_type = "password";
+       }
+      else
+       {
+         up_query_mode = UP_QUERY_USER_PASS;
+         prefix = "PASSWORD";
+         alert_type = "username/password";
+       }
+      buf_printf (&alert_msg, ">%s:Need '%s' %s",
+                 prefix,
                  type,
-                 password_only ? "password" : "username/password");
+                 alert_type);
 
       man_wait_for_client_connection (man, &signal_received, 0, MWCC_PASSWORD_WAIT);
       if (signal_received)
@@ -1759,7 +1799,7 @@ management_query_user_pass (struct management *man,
          msg (M_CLIENT, "%s", man->persist.special_state_msg);
 
          /* tell command line parser which info we need */
-         man->connection.up_query_mode = password_only ? UP_QUERY_PASS : UP_QUERY_USER_PASS;
+         man->connection.up_query_mode = up_query_mode;
          man->connection.up_query_type = type;
 
          /* run command processing event loop until we get our username/password */
index 5d059fa9dfeff02e731e8833ccca1cee1c45c10c..310f460e01da8af27f3f657e4adc5089210bd406 100644 (file)
--- a/manage.h
+++ b/manage.h
@@ -203,6 +203,7 @@ struct man_settings {
 #define UP_QUERY_DISABLED  0
 #define UP_QUERY_USER_PASS 1
 #define UP_QUERY_PASS      2
+#define UP_QUERY_NEED_OK   3
 
 /* states */
 #define MS_INITIAL          0  /* all sockets are closed */
@@ -282,7 +283,7 @@ void management_set_callback (struct management *man,
 
 void management_clear_callback (struct management *man);
 
-bool management_query_user_pass (struct management *man, struct user_pass *up, const char *type, const bool password_only);
+bool management_query_user_pass (struct management *man, struct user_pass *up, const char *type, const unsigned int flags);
 
 bool management_would_hold (struct management *man);
 bool management_hold (struct management *man);
diff --git a/misc.c b/misc.c
index f4e70799b70216c8e94018de62e4b9f997ee8325..4a79ee5d415f3dff4b2ade7c1e023a7946a47801 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -1155,7 +1155,6 @@ get_console_input (const char *prompt, const bool echo, char *input, const int c
 void
 get_user_pass (struct user_pass *up,
               const char *auth_file,
-              const bool password_only,
               const char *prefix,
               const unsigned int flags)
 {
@@ -1173,32 +1172,44 @@ get_user_pass (struct user_pass *up,
          && ((auth_file && streq (auth_file, "management")) || (from_stdin && (flags & GET_USER_PASS_MANAGEMENT)))
          && management_query_user_pass_enabled (management))
        {
-         if (!management_query_user_pass (management, up, prefix, password_only))
-           msg (M_FATAL, "ERROR: could not read %s username/password from management interface", prefix);
+         if (!management_query_user_pass (management, up, prefix, flags))
+           msg (M_FATAL, "ERROR: could not read %s username/password/ok from management interface", prefix);
        }
       else
 #endif
       /*
        * Get username/password from standard input?
        */
-      if (from_stdin)
+      if (from_stdin || (flags & GET_USER_PASS_NEED_OK))
        {
          struct buffer user_prompt = alloc_buf_gc (128, &gc);
          struct buffer pass_prompt = alloc_buf_gc (128, &gc);
 
-         buf_printf (&user_prompt, "Enter %s Username:", prefix);
-         buf_printf (&pass_prompt, "Enter %s Password:", prefix);
-
-         if (!password_only)
+         if (flags & GET_USER_PASS_NEED_OK)
            {
-             if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN))
-               msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix);
-             if (strlen (up->username) == 0)
-               msg (M_FATAL, "ERROR: %s username is empty", prefix);
+             buf_printf (&pass_prompt, "NEED-OK:%s:", prefix);
+           }
+         else
+           {
+             buf_printf (&user_prompt, "Enter %s Username:", prefix);
+             buf_printf (&pass_prompt, "Enter %s Password:", prefix);
+
+             if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
+               {
+                 if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN))
+                   msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix);
+                 if (strlen (up->username) == 0)
+                   msg (M_FATAL, "ERROR: %s username is empty", prefix);
+               }
            }
 
          if (!get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN))
-           msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix);
+           msg (M_FATAL, "ERROR: could not not read %s %s from stdin",
+                prefix,
+                (flags & GET_USER_PASS_NEED_OK) ? "ok-confirmation" : "password");
+
+         if (flags & GET_USER_PASS_NEED_OK)
+           strcpy (up->password, "ok");
        }
       else
        {
@@ -1222,7 +1233,7 @@ get_user_pass (struct user_pass *up,
          if (!fp)
            msg (M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file);
 
-         if (password_only)
+         if (flags & GET_USER_PASS_PASSWORD_ONLY)
            {
              if (fgets (up->password, USER_PASS_LEN, fp) == NULL)
                msg (M_FATAL, "Error reading password from %s authfile: %s",
@@ -1243,7 +1254,7 @@ get_user_pass (struct user_pass *up,
          chomp (up->username);
          chomp (up->password);
       
-         if (!password_only && strlen (up->username) == 0)
+         if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen (up->username) == 0)
            msg (M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file);
        }
 
diff --git a/misc.h b/misc.h
index ac8cd4227d7eb219b0c59497b75cdcb9b3257ec7..aec12c6c041cc3d9444bd0356e44e33a291f16c6 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -229,12 +229,16 @@ struct user_pass
 
 bool get_console_input (const char *prompt, const bool echo, char *input, const int capacity);
 
-#define GET_USER_PASS_MANAGEMENT  (1<<0)
-#define GET_USER_PASS_SENSITIVE   (1<<1)
+/*
+ * Flags for get_user_pass and management_query_user_pass
+ */
+#define GET_USER_PASS_MANAGEMENT    (1<<0)
+#define GET_USER_PASS_SENSITIVE     (1<<1)
+#define GET_USER_PASS_PASSWORD_ONLY (1<<2)
+#define GET_USER_PASS_NEED_OK       (1<<3)
 
 void get_user_pass (struct user_pass *up,
                    const char *auth_file,
-                   const bool password_only,
                    const char *prefix,
                    const unsigned int flags);
 
index 0a4a11396c43e1f3b37a9d348e2400ab932e1355..05a2d0fb0824ee8065ce3cbca4616972e690dc82 100644 (file)
--- a/options.c
+++ b/options.c
@@ -4896,7 +4896,7 @@ add_option (struct options *options,
     {
       char *module =  p[i++];
       VERIFY_PERMISSION (OPT_P_GENERAL);
-      show_pkcs11_slots (M_INFO|M_NOPREFIX, M_WARN|M_NOPREFIX, module);
+      show_pkcs11_slots (module);
       openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
     }
   else if (streq (p[0], "show-pkcs11-objects") && p[1] && p[2])
@@ -4916,7 +4916,7 @@ add_option (struct options *options,
       
       gc_free (&gc);
       
-      show_pkcs11_objects (M_INFO|M_NOPREFIX, M_WARN|M_NOPREFIX, provider, slot, pin);
+      show_pkcs11_objects (provider, slot, pin);
       openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
     }
   else if (streq (p[0], "pkcs11-providers") && p[1])
diff --git a/pkcs11-helper-config.h b/pkcs11-helper-config.h
new file mode 100644 (file)
index 0000000..b75e1e3
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+*  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-2005 OpenVPN Solutions LLC <info@openvpn.net>
+*
+*  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
+*/
+
+#ifndef __PKCS11_HELPER_CONFIG_H
+#define __PKCS11_HELPER_CONFIG_H
+
+#if!defined(PKCS11H_NO_NEED_INCLUDE_CONFIG)
+
+#if defined(WIN32)
+#include "config-win32.h"
+#else
+#include "config.h"
+#endif
+
+#include "syshead.h"
+
+#endif /* PKCS11H_NO_NEED_INCLUDE_CONFIG */
+
+#ifdef ENABLE_PKCS11
+#define PKCS11H_ENABLE_HELPER
+#endif
+
+#ifdef PKCS11H_ENABLE_HELPER
+
+#if defined(WIN32)
+#include "cryptoki-win32.h"
+#else
+#include "cryptoki.h"
+#endif
+
+#include "error.h"
+#include "misc.h"
+#include "ssl.h"
+
+#define PKCS11ASSERT           ASSERT
+#define PKCS11LOG              msg
+#define PKCS11_LOG_DEBUG2      D_PKCS11_DEBUG
+#define PKCS11_LOG_DEBUG1      D_SHOW_PKCS11
+#define PKCS11_LOG_INFO                M_INFO
+#define PKCS11_LOG_WARN                M_WARN
+#define PKCS11_LOG_ERROR       M_FATAL
+
+#if !defined(false)
+#define false 0
+#endif
+#if !defined(true)
+#define true (!false)
+#endif
+
+#if !defined(IN)
+#define IN
+#endif
+#if !defined(OUT)
+#define OUT
+#endif
+
+#define PKCS11_PRM_SLOT_TYPE   "--pkcs11-slot-type"
+#define PKCS11_PRM_SLOT_ID     "--pkcs11-slot"
+#define PKCS11_PRM_OBJ_TYPE    "--pkcs11-id-type"
+#define PKCS11_PRM_OBJ_ID      "--pkcs11-id"
+
+#endif         /* PKCS11H_ENABLE_HELPER */
+#endif         /* __PKCS11_HELPER_CONFIG_H */
diff --git a/pkcs11-helper.c b/pkcs11-helper.c
new file mode 100644 (file)
index 0000000..32c986d
--- /dev/null
@@ -0,0 +1,3239 @@
+/*
+ * Copyright (c) 2005 Alon Bar-Lev <alon.barlev@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The routines in this file deal with providing private key cryptography
+ * using RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki).
+ *
+ */
+
+#include "pkcs11-helper-config.h"
+
+#if defined(PKCS11H_ENABLE_HELPER)
+
+#if defined(WIN32)
+#include "cryptoki-win32.h"
+#else
+#include "cryptoki.h"
+#endif
+
+#include "pkcs11-helper.h"
+
+/*===========================================
+ * Constants
+ */
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE)
+# define RSA_get_default_method RSA_get_default_openssl_method
+#else
+# ifdef HAVE_ENGINE_GET_DEFAULT_RSA
+#  include <openssl/engine.h>
+#  if OPENSSL_VERSION_NUMBER < 0x0090704fL
+#   define BROKEN_OPENSSL_ENGINE
+#  endif
+# endif
+#endif
+
+
+/*===========================================
+ * Low level prototypes
+ */
+
+static
+void
+_pkcs11h_fixupFixedString (
+       IN const char * const szSource,
+       OUT char * const szTarget,                      /* MUST BE >= nLength+1 */
+       IN const size_t nLength                         /* FIXED STRING LENGTH */
+);
+static
+void
+_hexToBinary (
+       IN const char * const szSource,
+       OUT unsigned char * const target,
+       IN OUT size_t * const target_size
+);
+static
+CK_RV
+_pkcs11h_getSlotById (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const char * const szSlot
+);
+static
+CK_RV
+_pkcs11h_getSlotByName (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const char * const szName
+);
+static
+CK_RV
+_pkcs11h_getSlotByLabel (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const char * const szLabel
+);
+static
+CK_RV
+_pkcs11h_getObjectById (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const CK_OBJECT_CLASS class,
+       IN const unsigned char * const id,
+       IN const size_t id_size,
+       OUT CK_OBJECT_HANDLE * const handle
+);
+static
+CK_RV
+_pkcs11h_setSessionTokenInfo (
+       IN const pkcs11h_session_t pkcs11h_session
+);
+static
+CK_RV
+_pkcs11h_resetSlot (
+       IN const pkcs11h_session_t pkcs11h_session
+);
+static
+CK_RV
+_pkcs11h_loadCertificate (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const char * const szIdType,
+       IN const char * const szId
+);
+static
+CK_RV
+_pkcs11h_loadKeyProperties (
+       IN const pkcs11h_session_t pkcs11h_session
+);
+static
+bool
+_isBetterCertificate (
+       IN const unsigned char * const pCurrent,
+       IN const size_t nCurrentSize,
+       IN const unsigned char * const pNew,
+       IN const size_t nNewSize
+);
+static
+CK_RV
+_pkcs11h_validateSession (
+       IN const pkcs11h_session_t pkcs11h_session
+);
+static
+CK_RV
+_pkcs11h_login (
+       IN const pkcs11h_session_t pkcs11h_session
+);
+static
+CK_RV
+_pkcs11h_logout (
+       IN const pkcs11h_session_t pkcs11h_session
+);
+static
+int
+_pkcs11h_openssl_sign (
+       IN int type,
+       IN const unsigned char *m,
+       IN unsigned int m_len,
+       OUT unsigned char *sigret,
+       OUT unsigned int *siglen,
+       IN OUT const RSA *rsa
+);
+
+/*==========================================
+ * openssl interface
+ */
+
+static
+int
+_pkcs11h_openssl_finish (
+       IN OUT RSA *rsa
+);
+static
+int
+_pkcs11h_openssl_priv_dec (
+       IN int flen,
+       IN const unsigned char *from,
+       OUT unsigned char *to,
+       IN OUT RSA *rsa,
+       IN int padding
+);
+static
+int
+_pkcs11h_openssl_priv_enc (
+       IN int flen,
+       IN const unsigned char *from,
+       OUT unsigned char *to,
+       IN OUT RSA *rsa,
+       IN int padding
+);
+static
+pkcs11h_openssl_session_t
+_pkcs11h_openssl_get_pkcs11h_openssl_session (
+       IN OUT const RSA *rsa
+);  
+static
+pkcs11h_session_t
+_pkcs11h_openssl_get_pkcs11h_session (
+       IN OUT const RSA *rsa
+);  
+
+/*==========================================
+ * Static data
+ */
+
+pkcs11h_data_t pkcs11h_data = NULL;
+
+/*==========================================
+ * Internal utility functions
+ */
+
+static
+void
+_pkcs11h_fixupFixedString (
+       IN const char * const szSource,
+       OUT char * const szTarget,                      /* MUST BE >= nLength+1 */
+       IN const size_t nLength                         /* FIXED STRING LENGTH */
+) {
+       char *p;
+
+       PKCS11ASSERT (szSource!=NULL);
+       PKCS11ASSERT (szTarget!=NULL);
+       
+       p = szTarget+nLength;
+       memmove (szTarget, szSource, nLength);
+       *p = '\0';
+       p--;
+       while (p >= szTarget && *p == ' ') {
+               *p = '\0';
+               p--;
+       }
+}
+
+static
+void
+_hexToBinary (
+       IN const char * const szSource,
+       OUT unsigned char * const target,
+       IN OUT size_t * const target_size
+) {
+       size_t target_max_size;
+       const char *p;
+       char buf[3] = {'\0', '\0', '\0'};
+       int i = 0;
+
+       PKCS11ASSERT (szSource!=NULL);
+       PKCS11ASSERT (target!=NULL);
+       PKCS11ASSERT (target_size!=NULL);
+
+       target_max_size = *target_size;
+       p = szSource;
+       *target_size = 0;
+
+       while (*p != '\0' && *target_size < target_max_size) {
+               if (isxdigit (*p)) {
+                       buf[i%2] = *p;
+
+                       if ((i%2) == 1) {
+                               unsigned v;
+                               sscanf (buf, "%x", &v);
+                               target[*target_size] = v & 0xff;
+                               (*target_size)++;
+                       }
+
+                       i++;
+               }
+               p++;
+       }
+}
+
+static
+bool
+_isBetterCertificate (
+       IN const unsigned char * const pCurrent,
+       IN const size_t nCurrentSize,
+       IN const unsigned char * const pNew,
+       IN const size_t nNewSize
+) {
+       /*
+        * This function compare the notBefore
+        * and select the most recent certificate
+        * it does not deal with timezones...
+        * When openssl will have ASN1_TIME compare function
+        * it should be used.
+        */
+
+       X509 *x509Current = NULL, *x509New = NULL;
+       char szNotBeforeCurrent[1024], szNotBeforeNew[1024];
+       bool fBetter = false;
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _isBetterCertificate entry pCurrent=%p, nCurrentSize=%u, pNew=%p, nNewSize=%u",
+               pCurrent,
+               nCurrentSize,
+               pNew,
+               nNewSize
+       );
+
+       /*
+        * First certificae
+        * always select
+        */
+       if (nCurrentSize == 0) {
+               fBetter = true;
+       }
+       else {
+               PKCS11ASSERT (pCurrent!=NULL);
+               PKCS11ASSERT (pNew!=NULL);
+
+               szNotBeforeCurrent[0] = '\0';
+               szNotBeforeNew[0] = '\0';
+
+               x509Current = X509_new ();
+               x509New = X509_new ();
+
+               if (x509Current != NULL && x509New != NULL) {
+                       const unsigned char *p1, *p2;
+
+                       p1 = pCurrent;
+                       p2 = pNew;
+                       if (
+                               d2i_X509 (&x509Current, (unsigned char **)&p1, nCurrentSize) &&
+                               d2i_X509 (&x509New, (unsigned char **)&p2, nNewSize)
+                       ) {
+                               ASN1_TIME *notBeforeCurrent = X509_get_notBefore (x509Current);
+                               ASN1_TIME *notBeforeNew = X509_get_notBefore (x509New);
+
+                               if (
+                                       notBeforeCurrent != NULL &&
+                                       notBeforeNew != NULL &&
+                                       notBeforeCurrent->length < (int) sizeof (szNotBeforeCurrent) - 1 &&
+                                       notBeforeNew->length < (int) sizeof (szNotBeforeNew) - 1
+                               ) {
+                                       memmove (szNotBeforeCurrent, notBeforeCurrent->data, notBeforeCurrent->length);
+                                       szNotBeforeCurrent[notBeforeCurrent->length] = '\0';
+                                       memmove (szNotBeforeNew, notBeforeNew->data, notBeforeNew->length);
+                                       szNotBeforeNew[notBeforeNew->length] = '\0';
+                               }
+                       }
+               }
+
+               if (x509Current != NULL) {
+                       X509_free (x509Current);
+                       x509Current = NULL;
+               }
+               if (x509New != NULL) {
+                       X509_free (x509New);
+                       x509New = NULL;
+               }
+
+               fBetter = strcmp (szNotBeforeCurrent, szNotBeforeNew) < 0;
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _isBetterCertificate return fBetter=%d",
+               fBetter ? 1 : 0
+       );
+       
+       return fBetter;
+}
+
+/*========================================
+ * Low level PKCS#11 functions
+ */
+
+static
+CK_RV
+_pkcs11h_getSlotById (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const char * const szSlot
+) {
+       pkcs11h_provider_t provider;
+       CK_RV rv = CKR_OK;
+       int provider_number;
+       int slot_number;
+       int i;
+
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+       PKCS11ASSERT (szSlot!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_getSlotById entry pkcs11h_session=%p, szSlot=%s",
+               (void *)pkcs11h_session,
+               szSlot
+       );
+
+       if (rv == CKR_OK) {
+               if (strchr (szSlot, ':') == NULL) {
+                       provider_number = 0;
+                       slot_number = atoi (szSlot);
+               }
+               else {
+                       sscanf (szSlot, "%d:%d", &provider_number, &slot_number);
+               }
+       }
+       
+       if (rv == CKR_OK) {
+               for (
+                       i=0, provider=pkcs11h_data->providers;
+                       (
+                               i < provider_number &&
+                               provider != NULL &&
+                               rv == CKR_OK
+                       );
+                       i++, provider = provider->next
+               );
+       
+               if (
+                       provider == NULL ||
+                       (
+                               provider != NULL &&
+                               !provider->fEnabled
+                       )
+               ) {
+                       rv = CKR_SLOT_ID_INVALID;
+               }
+       }
+       
+       if (rv == CKR_OK) {
+               pkcs11h_session->provider = provider;
+               pkcs11h_session->slot = slot_number;
+       
+               PKCS11LOG (
+                       PKCS11_LOG_DEBUG1,
+                       "PKCS#11: slot selected %s-%ld",
+                       pkcs11h_session->provider->szName,
+                       pkcs11h_session->slot
+               );
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_getSlotById return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return rv;
+}
+
+static
+CK_RV
+_pkcs11h_getSlotByName (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const char * const szName
+) {
+       CK_RV rv = CKR_OK;
+
+       pkcs11h_provider_t provider;
+       bool fFound = false;
+
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+       PKCS11ASSERT (szName!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_getSlotByName entry pkcs11h_session=%p, szName=%s",
+               (void *)pkcs11h_session,
+               szName
+       );
+
+       for (
+               provider = pkcs11h_data->providers;
+               (
+                       provider != NULL &&
+                       !fFound
+               );
+               provider = provider->next
+       ) {
+               CK_SLOT_ID slots[1024];
+               CK_ULONG slotnum;
+
+               if (!provider->fEnabled) {
+                       continue;
+               }
+
+               slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
+               if (
+                       (rv = provider->f->C_GetSlotList (
+                               TRUE,
+                               slots,
+                               &slotnum
+                       )) == CKR_OK
+               ) {
+                       CK_SLOT_ID s;
+
+                       for (s=0;!fFound && s<slotnum;s++) {
+                               CK_SLOT_INFO info;
+
+                               if (
+                                       (rv = provider->f->C_GetSlotInfo (
+                                               slots[s],
+                                               &info
+                                       )) == CKR_OK
+                               ) {
+                                       char szCurrentName[sizeof (info.slotDescription)+1];
+       
+                                       _pkcs11h_fixupFixedString (
+                                               (char *)info.slotDescription,
+                                               szCurrentName,
+                                               sizeof (info.slotDescription)
+                                       );
+
+                                       if (!strcmp (szCurrentName, szName)) {
+                                               fFound = true;
+                                               pkcs11h_session->provider = provider;
+                                               pkcs11h_session->slot = slots[s];
+                                       
+                                               PKCS11LOG (
+                                                       PKCS11_LOG_DEBUG1,
+                                                       "PKCS#11: slot selected %s-%ld",
+                                                       pkcs11h_session->provider->szName,
+                                                       pkcs11h_session->slot
+                                               );
+                                       }
+                               }
+                       }
+               }
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_getSlotByName return fFound=%d-'%s'",
+               fFound ? 1 : 0,
+               pkcs11h_getMessage (rv)
+       );
+
+       return fFound ? CKR_OK : CKR_SLOT_ID_INVALID;
+}
+
+static
+CK_RV
+_pkcs11h_getSlotByLabel (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const char * const szLabel
+) {
+       CK_RV rv;
+
+       pkcs11h_provider_t provider;
+       bool fFound = false;
+
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+       PKCS11ASSERT (szLabel!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "_PKCS#11: pkcs11h_getSlotByLabel entry pkcs11h_session=%p, szName=%s",
+               (void *)pkcs11h_session,
+               szLabel
+       );
+
+       for (
+               provider = pkcs11h_data->providers;
+               (
+                       provider != NULL &&
+                       !fFound
+               );
+               provider = provider->next
+       ) {
+               CK_SLOT_ID slots[1024];
+               CK_ULONG slotnum;
+
+               if (!provider->fEnabled) {
+                       continue;
+               }
+
+               slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
+               if (
+                       (rv = provider->f->C_GetSlotList (
+                               TRUE,
+                               slots,
+                               &slotnum
+                       )) == CKR_OK
+               ) {
+                       CK_SLOT_ID s;
+
+                       for (s=0;!fFound && s<slotnum;s++) {
+                               CK_TOKEN_INFO info;
+
+                               if (
+                                       (rv = provider->f->C_GetTokenInfo (
+                                               slots[s],
+                                               &info
+                                       )) == CKR_OK
+                               ) {
+                                       char szCurrentLabel[sizeof (info.label)+1];
+                       
+                                       _pkcs11h_fixupFixedString (
+                                               (char *)info.label,
+                                               szCurrentLabel,
+                                               sizeof (info.label)
+                                       );
+
+                                       if (!strcmp (szCurrentLabel, szLabel)) {
+                                               fFound = true;
+                                               pkcs11h_session->provider = provider;
+                                               pkcs11h_session->slot = slots[s];
+                                       
+                                               PKCS11LOG (
+                                                       PKCS11_LOG_DEBUG1,
+                                                       "PKCS#11: slot selected %s-%ld",
+                                                       pkcs11h_session->provider->szName,
+                                                       pkcs11h_session->slot
+                                               );
+                                       }
+                               }
+                       }
+               }
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_getSlotByLabel return fFound=%d",
+               fFound ? 1 : 0
+       );
+
+       return fFound ? CKR_OK : CKR_SLOT_ID_INVALID;
+}
+
+static
+CK_RV
+_pkcs11h_setSessionTokenInfo (
+       IN const pkcs11h_session_t pkcs11h_session
+) {
+       CK_TOKEN_INFO info;
+       CK_RV rv;
+
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_setSessionTokenInfo entry pkcs11h_session=%p",
+               (void *)pkcs11h_session
+       );
+
+       if (
+               (rv = pkcs11h_session->provider->f->C_GetTokenInfo (
+                       pkcs11h_session->slot,
+                       &info
+               )) == CKR_OK
+       ) {
+               _pkcs11h_fixupFixedString (
+                       (char *)info.label,
+                       pkcs11h_session->szLabel,
+                       sizeof (info.label)
+               );
+               
+               memmove (
+                       pkcs11h_session->serialNumber,
+                       info.serialNumber,
+                       sizeof (pkcs11h_session->serialNumber)
+               );
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_setSessionTokenInfo return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return rv;
+}
+
+static
+CK_RV
+_pkcs11h_resetSlot (
+       IN const pkcs11h_session_t pkcs11h_session
+) {
+       CK_SLOT_ID slots[1024];
+       CK_ULONG slotnum;
+       CK_RV rv;
+       bool fFound = false;
+       bool fCancel = false;
+
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_resetSlot entry pkcs11h_session=%p",
+               (void *)pkcs11h_session
+       );
+
+       do {
+               slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
+               if (
+                       (rv = pkcs11h_session->provider->f->C_GetSlotList (
+                               TRUE,
+                               slots,
+                               &slotnum
+                       )) == CKR_OK
+               ) {
+                       CK_SLOT_ID s;
+
+                       for (s=0;!fFound && s<slotnum;s++) {
+                               CK_TOKEN_INFO info;
+
+                               if (
+                                       (rv = pkcs11h_session->provider->f->C_GetTokenInfo (
+                                               slots[s],
+                                               &info
+                                       )) == CKR_OK
+                               ) {
+                                       if (
+                                               !memcmp (
+                                                       pkcs11h_session->serialNumber,
+                                                       info.serialNumber,
+                                                       sizeof (pkcs11h_session->serialNumber)
+                                               )
+                                       ) {
+                                               pkcs11h_session->slot = slots[s];
+                                               fFound = true;
+                                       }
+                               }
+                       }
+               }
+
+               if (!fFound) {
+                       fCancel = !pkcs11h_data->hooks->card_prompt (
+                               pkcs11h_data->hooks->card_prompt_data,
+                               pkcs11h_session->szLabel
+                       );
+               }
+       } while (!fFound && !fCancel);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_resetSlot return fFound=%d",
+               fFound ? 1 : 0
+       );
+
+       return fFound ? CKR_OK : CKR_SLOT_ID_INVALID;
+}
+
+static
+CK_RV
+_pkcs11h_getObjectById (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const CK_OBJECT_CLASS class,
+       IN const unsigned char * const id,
+       IN const size_t id_size,
+       OUT CK_OBJECT_HANDLE * const handle
+) {
+       CK_ULONG count;
+       CK_RV rv = CKR_OK;
+
+       CK_ATTRIBUTE filter[] = {
+               {CKA_CLASS, (void *)&class, sizeof (class)},
+               {CKA_ID, (void *)id, id_size}
+       };
+       
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+       PKCS11ASSERT (id!=NULL);
+       PKCS11ASSERT (handle!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_getObjectById entry pkcs11h_session=%p, class=%ld, id=%p, id_size=%u, handle=%p",
+               (void *)pkcs11h_session,
+               class,
+               id,
+               id_size,
+               (void *)handle
+       );
+
+       if (rv == CKR_OK) {
+               rv = pkcs11h_session->provider->f->C_FindObjectsInit (
+                       pkcs11h_session->session,
+                       filter,
+                       sizeof (filter) / sizeof (CK_ATTRIBUTE)
+               );
+       }
+
+       if (rv == CKR_OK) {
+               rv = pkcs11h_session->provider->f->C_FindObjects (
+                       pkcs11h_session->session,
+                       handle,
+                       1,
+                       &count
+               );
+       }
+
+       if (
+               rv == CKR_OK &&
+               count == 0
+       ) {
+               rv = CKR_FUNCTION_REJECTED;
+       }
+
+       pkcs11h_session->provider->f->C_FindObjectsFinal (
+               pkcs11h_session->session
+       );
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_getObjectById return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return rv;
+}
+
+static
+CK_RV
+_pkcs11h_loadCertificate (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const char * const szIdType,
+       IN const char * const szId
+) {
+       CK_OBJECT_HANDLE objects[10];
+       CK_ULONG objects_found;
+       CK_RV rv = CKR_OK;
+
+       unsigned char selected_id[PKCS11H_MAX_ATTRIBUTE_SIZE];
+       int selected_id_size = 0;
+       unsigned char selected_certificate[PKCS11H_MAX_ATTRIBUTE_SIZE];
+       int selected_certificate_size = 0;
+
+       CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
+       unsigned char cert_filter_by[PKCS11H_MAX_ATTRIBUTE_SIZE];
+       CK_ATTRIBUTE cert_filter[] = {
+               {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)},
+               {0, cert_filter_by, 0}
+       };
+
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+       PKCS11ASSERT (szIdType!=NULL);
+       PKCS11ASSERT (szId!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_loadCertificate entry pkcs11h_session=%p, szIdType=%s, szId=%s",
+               (void *)pkcs11h_session,
+               szIdType,
+               szId
+       );
+
+       if (rv == CKR_OK) {
+               if (!strcmp (szIdType, "label")) {
+                       cert_filter[1].type = CKA_LABEL;
+                       cert_filter[1].ulValueLen = (CK_ULONG)(
+                               strlen (szId) < sizeof (cert_filter_by)  ?
+                               strlen (szId) :
+                               sizeof (cert_filter_by)
+                       );
+                       memmove (
+                               cert_filter_by,
+                               szId,
+                               cert_filter[1].ulValueLen
+                       );
+               }
+               else if (!strcmp (szIdType, "id")) {
+                       size_t s = sizeof (cert_filter_by);
+       
+                       cert_filter[1].type = CKA_ID;
+                       _hexToBinary (
+                               szId,
+                               cert_filter_by,
+                               &s
+                       );
+                       cert_filter[1].ulValueLen = s;
+               }
+               else if (!strcmp (szIdType, "subject")) {
+                       memmove (&cert_filter[1], &cert_filter[0], sizeof (CK_ATTRIBUTE));
+               }
+               else {
+                       rv = CKR_ARGUMENTS_BAD;
+               }
+       }
+       
+       if (rv == CKR_OK) {
+               rv = pkcs11h_session->provider->f->C_FindObjectsInit (
+                       pkcs11h_session->session,
+                       cert_filter,
+                       sizeof (cert_filter) / sizeof (CK_ATTRIBUTE)
+               );
+       }
+
+       if (rv == CKR_OK) {
+               while (
+                       (rv = pkcs11h_session->provider->f->C_FindObjects (
+                               pkcs11h_session->session,
+                               objects,
+                               sizeof (objects) / sizeof (CK_OBJECT_HANDLE),
+                               &objects_found
+                       )) == CKR_OK &&
+                       objects_found > 0
+               ) { 
+                       CK_ULONG i;
+                       
+                       for (i=0;i<objects_found;i++) {
+                               unsigned char attrs_id[PKCS11H_MAX_ATTRIBUTE_SIZE];
+                               unsigned char attrs_value[PKCS11H_MAX_ATTRIBUTE_SIZE];
+                               CK_ATTRIBUTE attrs[] = {
+                                       {CKA_ID, attrs_id, sizeof (attrs_id)},
+                                       {CKA_VALUE, attrs_value, sizeof (attrs_value)}
+                               };
+               
+                               if (
+                                       pkcs11h_session->provider->f->C_GetAttributeValue (
+                                               pkcs11h_session->session,
+                                               objects[i],
+                                               attrs,
+                                               sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+                                       ) == CKR_OK
+                               ) {
+                                       bool fSelected = false;
+       
+                                       if (!strcmp (szIdType, "subject")) {
+                                               X509 *x509 = NULL;
+                                               char szSubject[1024];
+                                               unsigned char *p;
+       
+                                               x509 = X509_new ();
+       
+                                               p = attrs_value;
+                                               if (d2i_X509 (&x509, &p, attrs[1].ulValueLen)) {
+                                                       X509_NAME_oneline (
+                                                               X509_get_subject_name (x509),
+                                                               szSubject,
+                                                               sizeof (szSubject)
+                                                       );
+                                                       szSubject[sizeof (szSubject) - 1] = '\0';
+                                               }
+       
+                                               if (x509 != NULL) {
+                                                       X509_free (x509);
+                                                       x509 = NULL;
+                                               }
+       
+                                               if (!strcmp (szId, szSubject)) {
+                                                       fSelected = true;
+                                               }
+                                       }
+                                       else {
+                                               fSelected = true;
+                                       }
+       
+                                       if (
+                                               fSelected &&
+                                               _isBetterCertificate (
+                                                       selected_certificate,
+                                                       selected_certificate_size,
+                                                       attrs_value,
+                                                       attrs[1].ulValueLen
+                                               )
+                                       ) {
+                                               selected_certificate_size = attrs[1].ulValueLen;
+                                               memmove (
+                                                       selected_certificate,
+                                                       attrs_value,
+                                                       selected_certificate_size
+                                               );
+                                               selected_id_size = attrs[0].ulValueLen;
+                                               memmove (
+                                                       selected_id,
+                                                       attrs_id,
+                                                       selected_id_size
+                                               );
+                                       }
+                               }
+                       }
+               }
+       
+               pkcs11h_session->provider->f->C_FindObjectsFinal (
+                       pkcs11h_session->session
+               );
+               rv = CKR_OK;
+       }
+
+       if (
+               rv == CKR_OK &&
+               selected_certificate_size == 0
+       ) {
+               rv = CKR_ATTRIBUTE_VALUE_INVALID;
+       }
+
+       if (
+               rv == CKR_OK &&
+               (pkcs11h_session->certificate = (unsigned char *)malloc (selected_certificate_size)) == NULL
+       ) {
+               rv = CKR_HOST_MEMORY;
+       }
+       
+       if (rv == CKR_OK) {
+               pkcs11h_session->certificate_size = selected_certificate_size;
+               memmove (
+                       pkcs11h_session->certificate,
+                       selected_certificate,
+                       selected_certificate_size
+               );
+       }
+       
+       if (
+               rv == CKR_OK &&
+               (pkcs11h_session->certificate_id = (unsigned char *)malloc (selected_id_size)) == NULL
+       ) {
+               rv = CKR_HOST_MEMORY;
+       }
+       
+       if (rv == CKR_OK) {
+               pkcs11h_session->certificate_id_size = selected_id_size;
+               memmove (
+                       pkcs11h_session->certificate_id,
+                       selected_id,
+                       selected_id_size
+               );
+       }
+       
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_loadCertificate return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return rv;
+}
+
+static
+CK_RV
+_pkcs11h_loadKeyProperties (
+       IN const pkcs11h_session_t pkcs11h_session
+) {
+       CK_OBJECT_HANDLE key;
+       CK_RV rv = CKR_OK;
+
+       CK_BBOOL key_attrs_sign_recover;
+       CK_BBOOL key_attrs_sign;
+       CK_ATTRIBUTE key_attrs[] = {
+               {CKA_SIGN, &key_attrs_sign_recover, sizeof (key_attrs_sign_recover)},
+               {CKA_SIGN_RECOVER, &key_attrs_sign, sizeof (key_attrs_sign)}
+       };
+
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_loadKeyProperties entry pkcs11h_session=%p",
+               (void *)pkcs11h_session
+       );
+
+       if (!strcmp (pkcs11h_session->provider->szSignMode, "recover")) {
+               pkcs11h_session->fKeySignRecover = true;
+       }
+       else if (!strcmp (pkcs11h_session->provider->szSignMode, "sign")) {
+               pkcs11h_session->fKeySignRecover = false;
+       }
+       else {
+               if (rv == CKR_OK) {
+                       rv = _pkcs11h_getObjectById (
+                               pkcs11h_session,
+                               CKO_PRIVATE_KEY,
+                               pkcs11h_session->certificate_id,
+                               pkcs11h_session->certificate_id_size,
+                               &key
+                       );
+               }
+
+               if (rv == CKR_OK) {
+                       rv = pkcs11h_session->provider->f->C_GetAttributeValue (
+                               pkcs11h_session->session,
+                               key,
+                               key_attrs,
+                               sizeof (key_attrs) / sizeof (CK_ATTRIBUTE)
+                       );
+               }
+               
+               if (rv == CKR_OK) {
+                       if (key_attrs_sign_recover != CK_FALSE) {
+                               pkcs11h_session->fKeySignRecover = true;
+                       }
+                       else if (key_attrs_sign != CK_FALSE) {
+                               pkcs11h_session->fKeySignRecover = false;
+                       }
+                       else {
+                               rv = CKR_KEY_TYPE_INCONSISTENT;
+                       }
+               }
+       }
+       
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_loadKeyProperties return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return rv;
+}
+
+static
+CK_RV
+_pkcs11h_validateSession (
+       IN const pkcs11h_session_t pkcs11h_session
+) {
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_validateSession entry pkcs11h_session=%p",
+               (void *)pkcs11h_session
+       );
+
+       if (
+               pkcs11h_session->timePINExpire != (time_t)0 &&
+               pkcs11h_session->timePINExpire < time (NULL)
+       ) {
+               _pkcs11h_logout (pkcs11h_session);
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_validateSession return"
+       );
+
+       return CKR_OK;
+}
+
+static
+CK_RV
+_pkcs11h_login (
+       IN const pkcs11h_session_t pkcs11h_session
+) {
+       CK_RV rv = CKR_OK;
+
+
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_login entry pkcs11h_session=%p",
+               (void *)pkcs11h_session
+       );
+
+       _pkcs11h_logout (pkcs11h_session);
+
+       if (rv == CKR_OK) {
+               rv = _pkcs11h_resetSlot (pkcs11h_session);
+       }
+
+       if (rv == CKR_OK) {
+               rv = pkcs11h_session->provider->f->C_OpenSession (
+                       pkcs11h_session->slot,
+                       CKF_SERIAL_SESSION,
+                       NULL_PTR,
+                       NULL_PTR,
+                       &pkcs11h_session->session
+               );
+       }
+
+       if (rv == CKR_OK) {
+               int nRetryCount = 0;
+               do {
+                       CK_UTF8CHAR_PTR utfPIN = NULL;
+                       CK_ULONG lPINLength = 0;
+                       char szPIN[1024];
+
+                       /*
+                        * Assume OK for next iteration
+                        */
+                       rv = CKR_OK;
+
+                       if (
+                               rv == CKR_OK &&
+                               !pkcs11h_session->fProtectedAuthentication
+                       ) {
+                               if (
+                                       !pkcs11h_data->hooks->pin_prompt (
+                                               pkcs11h_data->hooks->pin_prompt_data,
+                                               pkcs11h_session->szLabel,
+                                               szPIN,
+                                               sizeof (szPIN)
+                                       )
+                               ) {
+                                       rv = CKR_FUNCTION_FAILED;
+                               }
+                               else {
+                                       utfPIN = (CK_UTF8CHAR_PTR)szPIN;
+                                       lPINLength = strlen (szPIN);
+                               }
+                       }
+
+                       if (pkcs11h_data->nPINCachePeriod == -1) {
+                               pkcs11h_session->timePINExpire = 0;
+                       }
+                       else {
+                               pkcs11h_session->timePINExpire = (
+                                       time (NULL) +
+                                       (time_t)pkcs11h_data->nPINCachePeriod
+                               );
+                       }
+                       if (
+                               rv == CKR_OK &&
+                               (rv = pkcs11h_session->provider->f->C_Login (
+                                       pkcs11h_session->session,
+                                       CKU_USER,
+                                       utfPIN,
+                                       lPINLength
+                               )) != CKR_OK
+                       ) {
+                               if (rv == CKR_USER_ALREADY_LOGGED_IN) {
+                                       rv = CKR_OK;
+                               }
+                       }
+
+                       /*
+                        * Clean PIN buffer
+                        */
+                       memset (szPIN, 0, sizeof (szPIN));
+               } while (
+                       ++nRetryCount < 3 &&
+                       (
+                               rv == CKR_PIN_INCORRECT ||
+                               rv == CKR_PIN_INVALID
+                       )
+               );
+       }
+
+       if (
+               rv == CKR_OK &&
+               pkcs11h_session->certificate_id != NULL
+       ) {
+               rv = _pkcs11h_getObjectById (
+                       pkcs11h_session,
+                       CKO_PRIVATE_KEY,
+                       pkcs11h_session->certificate_id,
+                       pkcs11h_session->certificate_id_size,
+                       &pkcs11h_session->key
+               );
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_login return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return rv;
+}
+
+static
+CK_RV
+_pkcs11h_logout (
+       IN const pkcs11h_session_t pkcs11h_session
+) {
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_logout entry pkcs11h_session=%p",
+               (void *)pkcs11h_session
+       );
+
+       if (pkcs11h_session->session != (CK_SESSION_HANDLE)-1) {
+               pkcs11h_session->provider->f->C_Logout (pkcs11h_session->session);
+               pkcs11h_session->provider->f->C_CloseSession (pkcs11h_session->session);
+               pkcs11h_session->key = (CK_OBJECT_HANDLE)-1;
+               pkcs11h_session->session = (CK_SESSION_HANDLE)-1;
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_logout return"
+       );
+
+       return CKR_OK;
+}
+
+
+/*=======================================
+ * Simplified PKCS#11 functions
+ */
+
+static
+bool
+_pkcs11h_hooks_card_prompt_default (
+       IN const void * pData,
+       IN const char * const szLabel
+) {
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_hooks_card_prompt_default pData=%p, szLabel=%s",
+               pData,
+               szLabel
+       );
+
+       return false;
+}
+
+static
+bool
+_pkcs11h_hooks_pin_prompt_default (
+       IN const void * pData,
+       IN const char * const szLabel,
+       OUT char * const szPIN,
+       IN const size_t nMaxPIN
+) {
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_hooks_pin_prompt_default pData=%p, szLabel=%s",
+               pData,
+               szLabel
+       );
+       
+       return false;
+}
+
+CK_RV
+pkcs11h_initialize () {
+
+       CK_RV rv = CKR_OK;
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_initialize entry"
+       );
+
+       pkcs11h_terminate ();
+
+       if (
+               rv == CKR_OK &&
+               (pkcs11h_data = (pkcs11h_data_t)malloc (sizeof (struct pkcs11h_data_s))) == NULL
+       ) {
+               rv = CKR_HOST_MEMORY;
+       }
+
+       if (rv == CKR_OK) {
+               memset (pkcs11h_data, 0, sizeof (struct pkcs11h_data_s));
+       }
+       
+       if (
+               rv == CKR_OK &&
+               (pkcs11h_data->hooks = (pkcs11h_hooks_t)malloc (sizeof (struct pkcs11h_hooks_s))) == NULL
+       ) {
+               rv = CKR_HOST_MEMORY;
+       }
+
+       if (rv == CKR_OK) {
+               memset (pkcs11h_data->hooks, 0, sizeof (struct pkcs11h_hooks_s));
+       
+               pkcs11h_data->fInitialized = true;
+               pkcs11h_data->nPINCachePeriod = -1;
+       
+               pkcs11h_setCardPromptHook (_pkcs11h_hooks_card_prompt_default, NULL);
+               pkcs11h_setPINPromptHook (_pkcs11h_hooks_pin_prompt_default, NULL);
+       }
+       
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_initialize return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return rv;
+}
+
+CK_RV
+pkcs11h_terminate () {
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_terminate entry"
+       );
+
+       if (pkcs11h_data != NULL) {
+               pkcs11h_provider_t last = NULL;
+
+               for (
+                       ;
+                       pkcs11h_data->providers != NULL;
+                       pkcs11h_data->providers = pkcs11h_data->providers->next
+               ) {
+                       if (last != NULL) {
+                               free (last);
+                       }
+                       last = pkcs11h_data->providers;
+               
+                       if (pkcs11h_data->providers->szSignMode != NULL) {
+                               free (pkcs11h_data->providers->szSignMode);
+                               pkcs11h_data->providers->szSignMode = NULL;
+                       }
+       
+                       if (pkcs11h_data->providers->fShouldFinalize) {
+                               pkcs11h_data->providers->f->C_Finalize (NULL);
+                               pkcs11h_data->providers->fShouldFinalize = false;
+                       }
+
+                       if (pkcs11h_data->providers->f != NULL) {
+                               pkcs11h_data->providers->f = NULL;
+                       }
+       
+                       if (pkcs11h_data->providers->hLibrary != NULL) {
+#if defined(WIN32)
+                               FreeLibrary (pkcs11h_data->providers->hLibrary);
+#else
+                               dlclose (pkcs11h_data->providers->hLibrary);
+#endif
+                               pkcs11h_data->providers->hLibrary = NULL;
+                       }
+               }
+
+               if (last != NULL) {
+                       free (last);
+               }
+
+               if (pkcs11h_data->hooks != NULL) {
+                       free (pkcs11h_data->hooks);
+                       pkcs11h_data->hooks = NULL;
+               }
+
+               free (pkcs11h_data);
+               pkcs11h_data = NULL;
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_terminate return"
+       );
+
+       return CKR_OK;
+}
+
+CK_RV
+pkcs11h_setPINPromptHook (
+       IN const pkcs11h_hook_pin_prompt_t hook,
+       IN void * const pData
+) {
+       PKCS11ASSERT (pkcs11h_data!=NULL);
+       PKCS11ASSERT (pkcs11h_data->fInitialized);
+
+       pkcs11h_data->hooks->pin_prompt = hook;
+       pkcs11h_data->hooks->pin_prompt_data = pData;
+
+       return CKR_OK;
+}
+
+CK_RV
+pkcs11h_setCardPromptHook (
+       IN const pkcs11h_hook_card_prompt_t hook,
+       IN void * const pData
+) {
+       PKCS11ASSERT (pkcs11h_data!=NULL);
+       PKCS11ASSERT (pkcs11h_data->fInitialized);
+
+       pkcs11h_data->hooks->card_prompt = hook;
+       pkcs11h_data->hooks->card_prompt_data = pData;
+
+       return CKR_OK;
+}
+
+CK_RV
+pkcs11h_setPINCachePeriod (
+       IN const int nPINCachePeriod
+) {
+       PKCS11ASSERT (pkcs11h_data!=NULL);
+       PKCS11ASSERT (pkcs11h_data->fInitialized);
+
+       pkcs11h_data->nPINCachePeriod = nPINCachePeriod;
+
+       return CKR_OK;
+}
+
+CK_RV
+pkcs11h_addProvider (
+       IN const char * const szProvider,
+       IN const char * const szSignMode
+) {
+       pkcs11h_provider_t provider = NULL;
+       CK_C_GetFunctionList gfl = NULL;
+       CK_RV rv = CKR_OK;
+
+       PKCS11ASSERT (pkcs11h_data!=NULL);
+       PKCS11ASSERT (pkcs11h_data->fInitialized);
+       PKCS11ASSERT (szProvider!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_addProvider entry pid=%d, szProvider=%s, szSignMode=%s",
+#if defined(WIN32)
+               0,
+#else
+               getpid (),
+#endif         
+               szProvider,
+               szSignMode
+       );
+
+       if (
+               rv == CKR_OK &&
+               (provider = (pkcs11h_provider_t)malloc (sizeof (struct pkcs11h_provider_s))) == NULL
+       ) {
+               rv = CKR_HOST_MEMORY;
+       }
+
+       if (rv == CKR_OK) {
+               memset (provider, 0, sizeof (struct pkcs11h_provider_s));
+               provider->szName = strdup (szProvider);
+               
+               if (szSignMode == NULL) {
+                       provider->szSignMode = strdup ("auto");
+               }
+               else {
+                       provider->szSignMode = strdup (szSignMode);
+               }
+               if (provider->szSignMode == NULL) {
+                       rv = CKR_HOST_MEMORY;
+               }
+       }
+               
+       if (rv == CKR_OK) {
+#if defined(WIN32)
+               provider->hLibrary = LoadLibrary (szProvider);
+#else
+               provider->hLibrary = dlopen (szProvider, RTLD_NOW);
+#endif
+               if (provider->hLibrary == NULL) {
+                       rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       if (rv == CKR_OK) {
+#if defined(WIN32)
+               gfl = (CK_C_GetFunctionList)GetProcAddress (
+                       provider->hLibrary,
+                       "C_GetFunctionList"
+               );
+#else
+               /*
+                * Make compiler happy!
+                */
+               void *p = dlsym (
+                       provider->hLibrary,
+                       "C_GetFunctionList"
+               );
+               memmove (
+                       &gfl, 
+                       &p,
+                       sizeof (void *)
+               );
+#endif
+               if (gfl == NULL) {
+                       rv = CKR_FUNCTION_FAILED;
+               }
+       }
+
+       if (rv == CKR_OK) {
+               rv = gfl (&provider->f);
+       }
+
+       if (rv == CKR_OK) {
+               if ((rv = provider->f->C_Initialize (NULL)) != CKR_OK) {
+                       if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) {
+                               rv = CKR_OK;
+                       }
+               }
+               else {
+                       provider->fShouldFinalize = true;
+               }
+       }
+
+       if (rv == CKR_OK) {
+               provider->fEnabled = true;
+       }
+
+       if (provider != NULL) {
+               if (pkcs11h_data->providers == NULL) {
+                       pkcs11h_data->providers = provider;
+               }
+               else {
+                       pkcs11h_provider_t last = NULL;
+       
+                       for (
+                               last = pkcs11h_data->providers;
+                               last->next != NULL;
+                               last = last->next
+                       );
+                       last->next = provider;
+               }
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_addProvider return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return rv;
+}
+
+CK_RV
+pkcs11h_forkFixup () {
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_forkFixup entry pid=%d",
+#if defined(WIN32)
+               0
+#else
+               getpid ()
+#endif         
+       );
+
+       if (pkcs11h_data != NULL && pkcs11h_data->fInitialized) {
+
+               pkcs11h_provider_t current;
+
+               for (
+                       current = pkcs11h_data->providers;
+                       current != NULL;
+                       current = current->next
+               ) {
+                       if (current->fEnabled) {
+                               current->f->C_Initialize (NULL);
+                       }
+               }
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_forkFixup return"
+       );
+
+       return CKR_OK;
+}
+       
+CK_RV
+pkcs11h_createSession (
+       IN const char * const szSlotType,
+       IN const char * const szSlot,
+       IN const char * const szIdType,
+       IN const char * const szId,
+       IN const bool fProtectedAuthentication,
+       OUT pkcs11h_session_t * const p_pkcs11h_session
+) {
+       pkcs11h_session_t pkcs11h_session;
+       CK_RV rv = CKR_OK;
+
+       PKCS11ASSERT (pkcs11h_data!=NULL);
+       PKCS11ASSERT (pkcs11h_data->fInitialized);
+       PKCS11ASSERT (szSlotType!=NULL);
+       PKCS11ASSERT (szSlot!=NULL);
+       PKCS11ASSERT (szIdType!=NULL);
+       PKCS11ASSERT (szId!=NULL);
+       PKCS11ASSERT (p_pkcs11h_session!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_createSession entry szSlotType=%s, szSlot=%s, szIdType=%s, szId=%s, fProtectedAuthentication=%d, p_pkcs11h_session=%p",
+               szSlotType,
+               szSlot,
+               szIdType,
+               szId,
+               fProtectedAuthentication ? 1 : 0,
+               (void *)p_pkcs11h_session
+       );
+
+       if (
+               rv == CKR_OK &&
+               (pkcs11h_session = (pkcs11h_session_t)malloc (sizeof (struct pkcs11h_session_s))) == NULL
+       ) {
+               rv = CKR_HOST_MEMORY;
+       }
+
+       if (rv == CKR_OK) {
+               *p_pkcs11h_session = pkcs11h_session;
+               memset (pkcs11h_session, 0, sizeof (struct pkcs11h_session_s));
+       }
+       
+       if (rv == CKR_OK) {
+               pkcs11h_session->key = (CK_OBJECT_HANDLE)-1;
+               pkcs11h_session->session = (CK_SESSION_HANDLE)-1;
+               pkcs11h_session->fProtectedAuthentication = fProtectedAuthentication;
+       }
+
+       if (rv == CKR_OK) {
+               bool fCancel = false;
+
+               do {
+                       if (!strcmp (szSlotType, "id")) {
+                               rv = _pkcs11h_getSlotById (pkcs11h_session, szSlot);
+                       }
+                       else if (!strcmp (szSlotType, "name")) {
+                               rv = _pkcs11h_getSlotByName (pkcs11h_session, szSlot);
+                       }
+                       else if (!strcmp (szSlotType, "label")) {
+                               rv = _pkcs11h_getSlotByLabel (pkcs11h_session, szSlot);
+                       }
+                       else {
+                               rv = CKR_ARGUMENTS_BAD;
+                       }
+
+                       if (rv == CKR_SLOT_ID_INVALID) {
+                               char szLabel[1024];
+                               strcpy (szLabel, "SLOT(");
+                               strncat (szLabel, szSlotType, sizeof (szLabel)-1);
+                               strncat (szLabel, "=", sizeof (szLabel)-1);
+                               strncat (szLabel, szSlot, sizeof (szLabel)-1);
+                               strncat (szLabel, ")", sizeof (szLabel)-1);
+                               szLabel[sizeof (szLabel)-1] = 0;
+                               fCancel = !pkcs11h_data->hooks->card_prompt (
+                                       pkcs11h_data->hooks->card_prompt_data,
+                                       szLabel
+                               );
+                       }
+               } while (rv == CKR_SLOT_ID_INVALID && !fCancel);
+       }
+
+       if (rv == CKR_OK) {
+               rv = _pkcs11h_setSessionTokenInfo (pkcs11h_session);
+       }
+
+       if (rv == CKR_OK) {
+               rv = _pkcs11h_login (
+                       pkcs11h_session
+               );
+       }
+
+       if (rv == CKR_OK) {
+               rv = _pkcs11h_loadCertificate (
+                       pkcs11h_session,
+                       szIdType,
+                       szId
+               );
+       }
+
+       if (rv == CKR_OK) {
+               rv = _pkcs11h_loadKeyProperties (
+                       pkcs11h_session
+               );
+       }
+       
+       /*
+        * Complete missing login process
+        */
+       if (rv == CKR_OK) {
+               rv = _pkcs11h_getObjectById (
+                       pkcs11h_session,
+                       CKO_PRIVATE_KEY,
+                       pkcs11h_session->certificate_id,
+                       pkcs11h_session->certificate_id_size,
+                       &pkcs11h_session->key
+               );
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_createSession return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+       
+       return rv;
+}
+
+CK_RV
+pkcs11h_freeSession (
+       IN const pkcs11h_session_t pkcs11h_session
+) {
+       PKCS11ASSERT (pkcs11h_data!=NULL);
+       PKCS11ASSERT (pkcs11h_data->fInitialized);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_freeSession entry pkcs11h_session=%p",
+               (void *)pkcs11h_session
+       );
+
+       if (pkcs11h_session != NULL) {
+               _pkcs11h_logout (pkcs11h_session);
+
+               if (pkcs11h_session->certificate != NULL) {
+                       free (pkcs11h_session->certificate);
+               }
+               if (pkcs11h_session->certificate_id != NULL) {
+                       free (pkcs11h_session->certificate_id);
+               }
+
+               free (pkcs11h_session);
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_freeSession return"
+       );
+
+       return CKR_OK;
+}
+
+CK_RV
+pkcs11h_sign (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const CK_MECHANISM_TYPE mech_type,
+       IN const unsigned char * const source,
+       IN const size_t source_size,
+       OUT unsigned char * const target,
+       IN OUT size_t * const target_size
+) {
+       CK_MECHANISM mech = {
+               mech_type, NULL, 0
+       };
+       
+       CK_RV rv = CKR_OK;
+       bool fLogonRetry = false;
+       bool fOpSuccess = false;
+
+       PKCS11ASSERT (pkcs11h_data!=NULL);
+       PKCS11ASSERT (pkcs11h_data->fInitialized);
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+       PKCS11ASSERT (source!=NULL);
+       PKCS11ASSERT (target_size!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_sign entry pkcs11h_session=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, target_size=%p",
+               (void *)pkcs11h_session,
+               mech_type,
+               source,
+               source_size,
+               target,
+               (void *)target_size
+       );
+
+       if (rv == CKR_OK) {
+               rv = _pkcs11h_validateSession (pkcs11h_session);
+       }
+
+       while (rv == CKR_OK && !fOpSuccess) {
+               rv = pkcs11h_session->provider->f->C_SignInit (
+                       pkcs11h_session->session,
+                       &mech,
+                       pkcs11h_session->key
+               );
+
+               if (rv == CKR_OK) {
+                       fOpSuccess = true;
+               }
+               else {
+                       if (!fLogonRetry) {
+                               fLogonRetry = true;
+                               rv = _pkcs11h_login (pkcs11h_session);
+                       }
+               }
+       }
+
+       if (rv == CKR_OK) {
+               CK_ULONG size = *target_size;
+               rv = pkcs11h_session->provider->f->C_Sign (
+                       pkcs11h_session->session,
+                       (CK_BYTE_PTR)source,
+                       source_size,
+                       (CK_BYTE_PTR)target,
+                       &size
+               );
+
+               *target_size = (int)size;
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_sign return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+       
+       return rv;
+}
+
+CK_RV
+pkcs11h_signRecover (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const CK_MECHANISM_TYPE mech_type,
+       IN const unsigned char * const source,
+       IN const size_t source_size,
+       OUT unsigned char * const target,
+       IN OUT size_t * const target_size
+) {
+       CK_MECHANISM mech = {
+               mech_type, NULL, 0
+       };
+       CK_RV rv = CKR_OK;
+       bool fLogonRetry = false;
+       bool fOpSuccess = false;
+
+       PKCS11ASSERT (pkcs11h_data!=NULL);
+       PKCS11ASSERT (pkcs11h_data->fInitialized);
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+       PKCS11ASSERT (source!=NULL);
+       PKCS11ASSERT (target_size!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_signRecover entry pkcs11h_session=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, target_size=%p",
+               (void *)pkcs11h_session,
+               mech_type,
+               source,
+               source_size,
+               target,
+               (void *)target_size
+       );
+
+       if (rv == CKR_OK) {
+               rv = _pkcs11h_validateSession (pkcs11h_session);
+       }
+
+       while (rv == CKR_OK && !fOpSuccess) {
+               rv = pkcs11h_session->provider->f->C_SignRecoverInit (
+                       pkcs11h_session->session,
+                       &mech,
+                       pkcs11h_session->key
+               );
+
+               if (rv == CKR_OK) {
+                       fOpSuccess = true;
+               }
+               else {
+                       if (!fLogonRetry) {
+                               fLogonRetry = true;
+                               rv = _pkcs11h_login (pkcs11h_session);
+                       }
+               }
+       }
+
+       if (rv == CKR_OK) {
+               CK_ULONG size = *target_size;
+               rv = pkcs11h_session->provider->f->C_SignRecover (
+                       pkcs11h_session->session,
+                       (CK_BYTE_PTR)source,
+                       source_size,
+                       (CK_BYTE_PTR)target,
+                       &size
+               );
+
+               *target_size = (int)size;
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_signRecover return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return rv;
+}
+
+CK_RV
+pkcs11h_decrypt (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const CK_MECHANISM_TYPE mech_type,
+       IN const unsigned char * const source,
+       IN const size_t source_size,
+       OUT unsigned char * const target,
+       IN OUT size_t * const target_size
+) {
+       CK_MECHANISM mech = {
+               mech_type, NULL, 0
+       };
+       CK_ULONG size;
+       CK_RV rv = CKR_OK;
+       bool fLogonRetry = false;
+       bool fOpSuccess = false;
+
+       PKCS11ASSERT (pkcs11h_data!=NULL);
+       PKCS11ASSERT (pkcs11h_data->fInitialized);
+       PKCS11ASSERT (pkcs11h_session!=NULL);
+       PKCS11ASSERT (source!=NULL);
+       PKCS11ASSERT (target_size!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_decrypt entry pkcs11h_session=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, target_size=%p",
+               (void *)pkcs11h_session,
+               mech_type,
+               source,
+               source_size,
+               target,
+               (void *)target_size
+       );
+
+       if (rv != CKR_OK) {
+               rv = _pkcs11h_validateSession (pkcs11h_session);
+       }
+
+       while (rv == CKR_OK && !fOpSuccess) {
+               rv = pkcs11h_session->provider->f->C_DecryptInit (
+                       pkcs11h_session->session,
+                       &mech,
+                       pkcs11h_session->key
+               );
+
+               if (rv == CKR_OK) {
+                       fOpSuccess = true;
+               }
+               else {
+                       if (!fLogonRetry) {
+                               fLogonRetry = true;
+                               rv = _pkcs11h_login (pkcs11h_session);
+                       }
+               }
+       }
+
+       if (rv == CKR_OK) {
+               size = *target_size;
+               rv = pkcs11h_session->provider->f->C_Decrypt (
+                       pkcs11h_session->session,
+                       (CK_BYTE_PTR)source,
+                       source_size,
+                       (CK_BYTE_PTR)target,
+                       &size
+               );
+
+               *target_size = (int)size;
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_decrypt return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return rv;
+}
+
+CK_RV
+pkcs11h_getCertificate (
+       IN const pkcs11h_session_t pkcs11h_session,
+       OUT unsigned char * const certificate,
+       IN OUT size_t * const certificate_size
+) {
+       CK_RV rv = CKR_OK;
+       
+       PKCS11ASSERT (pkcs11h_data!=NULL);
+       PKCS11ASSERT (pkcs11h_data->fInitialized);
+       PKCS11ASSERT (certificate_size!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_getCertificate entry pkcs11h_session=%p, certificate=%p, certificate_size=%p",
+               (void *)pkcs11h_session,
+               certificate,
+               (void *)certificate_size
+       );
+
+       *certificate_size = pkcs11h_session->certificate_size;
+
+       if (certificate != NULL) {
+               if (
+                       rv == CKR_OK &&
+                       *certificate_size > pkcs11h_session->certificate_size
+               ) {
+                       rv = CKR_BUFFER_TOO_SMALL;
+               }
+       
+               if (rv == CKR_OK) {
+                       memmove (certificate, pkcs11h_session->certificate, *certificate_size); 
+               }
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_getCertificate return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       return CKR_OK;
+}
+
+char *
+pkcs11h_getMessage (
+       IN const int rv
+) {
+       switch (rv) {
+               case CKR_OK: return "CKR_OK";
+               case CKR_CANCEL: return "CKR_CANCEL";
+               case CKR_HOST_MEMORY: return "CKR_HOST_MEMORY";
+               case CKR_SLOT_ID_INVALID: return "CKR_SLOT_ID_INVALID";
+               case CKR_GENERAL_ERROR: return "CKR_GENERAL_ERROR";
+               case CKR_FUNCTION_FAILED: return "CKR_FUNCTION_FAILED";
+               case CKR_ARGUMENTS_BAD: return "CKR_ARGUMENTS_BAD";
+               case CKR_NO_EVENT: return "CKR_NO_EVENT";
+               case CKR_NEED_TO_CREATE_THREADS: return "CKR_NEED_TO_CREATE_THREADS";
+               case CKR_CANT_LOCK: return "CKR_CANT_LOCK";
+               case CKR_ATTRIBUTE_READ_ONLY: return "CKR_ATTRIBUTE_READ_ONLY";
+               case CKR_ATTRIBUTE_SENSITIVE: return "CKR_ATTRIBUTE_SENSITIVE";
+               case CKR_ATTRIBUTE_TYPE_INVALID: return "CKR_ATTRIBUTE_TYPE_INVALID";
+               case CKR_ATTRIBUTE_VALUE_INVALID: return "CKR_ATTRIBUTE_VALUE_INVALID";
+               case CKR_DATA_INVALID: return "CKR_DATA_INVALID";
+               case CKR_DATA_LEN_RANGE: return "CKR_DATA_LEN_RANGE";
+               case CKR_DEVICE_ERROR: return "CKR_DEVICE_ERROR";
+               case CKR_DEVICE_MEMORY: return "CKR_DEVICE_MEMORY";
+               case CKR_DEVICE_REMOVED: return "CKR_DEVICE_REMOVED";
+               case CKR_ENCRYPTED_DATA_INVALID: return "CKR_ENCRYPTED_DATA_INVALID";
+               case CKR_ENCRYPTED_DATA_LEN_RANGE: return "CKR_ENCRYPTED_DATA_LEN_RANGE";
+               case CKR_FUNCTION_CANCELED: return "CKR_FUNCTION_CANCELED";
+               case CKR_FUNCTION_NOT_PARALLEL: return "CKR_FUNCTION_NOT_PARALLEL";
+               case CKR_FUNCTION_NOT_SUPPORTED: return "CKR_FUNCTION_NOT_SUPPORTED";
+               case CKR_KEY_HANDLE_INVALID: return "CKR_KEY_HANDLE_INVALID";
+               case CKR_KEY_SIZE_RANGE: return "CKR_KEY_SIZE_RANGE";
+               case CKR_KEY_TYPE_INCONSISTENT: return "CKR_KEY_TYPE_INCONSISTENT";
+               case CKR_KEY_NOT_NEEDED: return "CKR_KEY_NOT_NEEDED";
+               case CKR_KEY_CHANGED: return "CKR_KEY_CHANGED";
+               case CKR_KEY_NEEDED: return "CKR_KEY_NEEDED";
+               case CKR_KEY_INDIGESTIBLE: return "CKR_KEY_INDIGESTIBLE";
+               case CKR_KEY_FUNCTION_NOT_PERMITTED: return "CKR_KEY_FUNCTION_NOT_PERMITTED";
+               case CKR_KEY_NOT_WRAPPABLE: return "CKR_KEY_NOT_WRAPPABLE";
+               case CKR_KEY_UNEXTRACTABLE: return "CKR_KEY_UNEXTRACTABLE";
+               case CKR_MECHANISM_INVALID: return "CKR_MECHANISM_INVALID";
+               case CKR_MECHANISM_PARAM_INVALID: return "CKR_MECHANISM_PARAM_INVALID";
+               case CKR_OBJECT_HANDLE_INVALID: return "CKR_OBJECT_HANDLE_INVALID";
+               case CKR_OPERATION_ACTIVE: return "CKR_OPERATION_ACTIVE";
+               case CKR_OPERATION_NOT_INITIALIZED: return "CKR_OPERATION_NOT_INITIALIZED";
+               case CKR_PIN_INCORRECT: return "CKR_PIN_INCORRECT";
+               case CKR_PIN_INVALID: return "CKR_PIN_INVALID";
+               case CKR_PIN_LEN_RANGE: return "CKR_PIN_LEN_RANGE";
+               case CKR_PIN_EXPIRED: return "CKR_PIN_EXPIRED";
+               case CKR_PIN_LOCKED: return "CKR_PIN_LOCKED";
+               case CKR_SESSION_CLOSED: return "CKR_SESSION_CLOSED";
+               case CKR_SESSION_COUNT: return "CKR_SESSION_COUNT";
+               case CKR_SESSION_HANDLE_INVALID: return "CKR_SESSION_HANDLE_INVALID";
+               case CKR_SESSION_PARALLEL_NOT_SUPPORTED: return "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
+               case CKR_SESSION_READ_ONLY: return "CKR_SESSION_READ_ONLY";
+               case CKR_SESSION_EXISTS: return "CKR_SESSION_EXISTS";
+               case CKR_SESSION_READ_ONLY_EXISTS: return "CKR_SESSION_READ_ONLY_EXISTS";
+               case CKR_SESSION_READ_WRITE_SO_EXISTS: return "CKR_SESSION_READ_WRITE_SO_EXISTS";
+               case CKR_SIGNATURE_INVALID: return "CKR_SIGNATURE_INVALID";
+               case CKR_SIGNATURE_LEN_RANGE: return "CKR_SIGNATURE_LEN_RANGE";
+               case CKR_TEMPLATE_INCOMPLETE: return "CKR_TEMPLATE_INCOMPLETE";
+               case CKR_TEMPLATE_INCONSISTENT: return "CKR_TEMPLATE_INCONSISTENT";
+               case CKR_TOKEN_NOT_PRESENT: return "CKR_TOKEN_NOT_PRESENT";
+               case CKR_TOKEN_NOT_RECOGNIZED: return "CKR_TOKEN_NOT_RECOGNIZED";
+               case CKR_TOKEN_WRITE_PROTECTED: return "CKR_TOKEN_WRITE_PROTECTED";
+               case CKR_UNWRAPPING_KEY_HANDLE_INVALID: return "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
+               case CKR_UNWRAPPING_KEY_SIZE_RANGE: return "CKR_UNWRAPPING_KEY_SIZE_RANGE";
+               case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT: return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
+               case CKR_USER_ALREADY_LOGGED_IN: return "CKR_USER_ALREADY_LOGGED_IN";
+               case CKR_USER_NOT_LOGGED_IN: return "CKR_USER_NOT_LOGGED_IN";
+               case CKR_USER_PIN_NOT_INITIALIZED: return "CKR_USER_PIN_NOT_INITIALIZED";
+               case CKR_USER_TYPE_INVALID: return "CKR_USER_TYPE_INVALID";
+               case CKR_USER_ANOTHER_ALREADY_LOGGED_IN: return "CKR_USER_ANOTHER_ALREADY_LOGGED_IN";
+               case CKR_USER_TOO_MANY_TYPES: return "CKR_USER_TOO_MANY_TYPES";
+               case CKR_WRAPPED_KEY_INVALID: return "CKR_WRAPPED_KEY_INVALID";
+               case CKR_WRAPPED_KEY_LEN_RANGE: return "CKR_WRAPPED_KEY_LEN_RANGE";
+               case CKR_WRAPPING_KEY_HANDLE_INVALID: return "CKR_WRAPPING_KEY_HANDLE_INVALID";
+               case CKR_WRAPPING_KEY_SIZE_RANGE: return "CKR_WRAPPING_KEY_SIZE_RANGE";
+               case CKR_WRAPPING_KEY_TYPE_INCONSISTENT: return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
+               case CKR_RANDOM_SEED_NOT_SUPPORTED: return "CKR_RANDOM_SEED_NOT_SUPPORTED";
+               case CKR_RANDOM_NO_RNG: return "CKR_RANDOM_NO_RNG";
+               case CKR_DOMAIN_PARAMS_INVALID: return "CKR_DOMAIN_PARAMS_INVALID";
+               case CKR_BUFFER_TOO_SMALL: return "CKR_BUFFER_TOO_SMALL";
+               case CKR_SAVED_STATE_INVALID: return "CKR_SAVED_STATE_INVALID";
+               case CKR_INFORMATION_SENSITIVE: return "CKR_INFORMATION_SENSITIVE";
+               case CKR_STATE_UNSAVEABLE: return "CKR_STATE_UNSAVEABLE";
+               case CKR_CRYPTOKI_NOT_INITIALIZED: return "CKR_CRYPTOKI_NOT_INITIALIZED";
+               case CKR_CRYPTOKI_ALREADY_INITIALIZED: return "CKR_CRYPTOKI_ALREADY_INITIALIZED";
+               case CKR_MUTEX_BAD: return "CKR_MUTEX_BAD";
+               case CKR_MUTEX_NOT_LOCKED: return "CKR_MUTEX_NOT_LOCKED";
+               case CKR_FUNCTION_REJECTED: return "CKR_FUNCTION_REJECTED";
+               case CKR_VENDOR_DEFINED: return "CKR_VENDOR_DEFINED";
+               default: return "Unknown PKCS#11 error";
+       }
+}
+
+/*==========================================
+ * openssl interface
+ */
+
+static
+pkcs11h_openssl_session_t
+_pkcs11h_openssl_get_pkcs11h_openssl_session (
+       IN OUT const RSA *rsa
+) {
+       pkcs11h_openssl_session_t session;
+               
+       PKCS11ASSERT (rsa!=NULL);
+       session = (pkcs11h_openssl_session_t)RSA_get_app_data (rsa);
+       PKCS11ASSERT (session!=NULL);
+
+       return session;
+}
+
+static
+pkcs11h_session_t
+_pkcs11h_openssl_get_pkcs11h_session (
+       IN OUT const RSA *rsa
+) {
+       pkcs11h_openssl_session_t session;
+       
+       PKCS11ASSERT (rsa!=NULL);
+       session = (pkcs11h_openssl_session_t)RSA_get_app_data (rsa);
+       PKCS11ASSERT (session!=NULL);
+       PKCS11ASSERT (session->pkcs11h_session!=NULL);
+
+       return session->pkcs11h_session;
+}
+
+static
+int
+_pkcs11h_openssl_priv_enc (
+       IN int flen,
+       IN const unsigned char *from,
+       OUT unsigned char *to,
+       IN OUT RSA *rsa,
+       IN int padding
+) {
+       PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Private key encryption not supported");
+       return -1;
+}
+
+static
+int
+_pkcs11h_openssl_priv_dec (
+       IN int flen,
+       IN const unsigned char *from,
+       OUT unsigned char *to,
+       IN OUT RSA *rsa,
+       IN int padding
+) {
+       pkcs11h_session_t pkcs11h_session = _pkcs11h_openssl_get_pkcs11h_session (rsa);
+       CK_RV rv = CKR_OK;
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_openssl_priv_dec entered - flen=%d, from=%p, to=%p, rsa=%p, padding=%d",
+               flen,
+               from,
+               to,
+               (void *)rsa,
+               padding
+       );
+
+       PKCS11ASSERT (from!=NULL);
+       PKCS11ASSERT (to!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG1,      
+               "PKCS#11: Performing decryption using private key"
+       );
+
+       if (padding != RSA_PKCS1_PADDING) {
+               rv = CKR_ARGUMENTS_BAD;
+       }
+
+       if (
+               rv == CKR_OK &&
+               (rv = pkcs11h_decrypt (
+                       pkcs11h_session,
+                       CKM_RSA_PKCS,
+                       from,
+                       flen,
+                       to,
+                       (size_t *)&flen
+               )) != CKR_OK
+       ) {
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot decrypt using private key %ld:'%s'", rv, pkcs11h_getMessage (rv));
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_openssl_priv_dec - return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+       
+       return rv == CKR_OK ? 1 : -1; 
+}
+
+static
+int
+_pkcs11h_openssl_sign (
+       IN int type,
+       IN const unsigned char *m,
+       IN unsigned int m_len,
+       OUT unsigned char *sigret,
+       OUT unsigned int *siglen,
+       IN OUT const RSA *rsa
+) {
+       pkcs11h_openssl_session_t pkcs11h_openssl_session = _pkcs11h_openssl_get_pkcs11h_openssl_session (rsa);
+       pkcs11h_session_t pkcs11h_session = _pkcs11h_openssl_get_pkcs11h_session (rsa);
+       CK_RV rv = CKR_OK;
+
+       int myrsa_size = 0;
+       
+       unsigned char *enc_alloc = NULL;
+       unsigned char *enc;
+       int enc_len = 0;
+       
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_openssl_sign entered - type=%d, m=%p, m_len=%u, signret=%p, signlen=%p, rsa=%p",
+               type,
+               m,
+               m_len,
+               sigret,
+               (void *)siglen,
+               (void *)rsa
+       );
+
+       PKCS11ASSERT (m!=NULL);
+       PKCS11ASSERT (sigret!=NULL);
+       PKCS11ASSERT (siglen!=NULL);
+
+       if (rv == CKR_OK) {
+               myrsa_size=RSA_size(rsa);
+       }
+
+       if (pkcs11h_openssl_session->fShouldPadSign) {
+               X509_SIG sig;
+               ASN1_TYPE parameter;
+               X509_ALGOR algor;
+               ASN1_OCTET_STRING digest;
+
+               if (
+                       rv == CKR_OK &&
+                       (enc=enc_alloc=(unsigned char *)malloc ((unsigned int)myrsa_size+1)) == NULL
+               ) {
+                       rv = CKR_HOST_MEMORY;
+               }
+               
+               if (rv == CKR_OK) {
+                       sig.algor= &algor;
+               }
+
+               if (
+                       rv == CKR_OK &&
+                       (sig.algor->algorithm=OBJ_nid2obj(type)) == NULL
+               ) {
+                       rv = CKR_FUNCTION_FAILED;
+               }
+       
+               if (
+                       rv == CKR_OK &&
+                       sig.algor->algorithm->length == 0
+               ) {
+                       rv = CKR_KEY_SIZE_RANGE;
+               }
+       
+               if (rv == CKR_OK) {
+                       parameter.type=V_ASN1_NULL;
+                       parameter.value.ptr=NULL;
+       
+                       sig.algor->parameter= &parameter;
+
+                       sig.digest=&digest;
+                       sig.digest->data=(unsigned char *)m;
+                       sig.digest->length=m_len;
+               }
+       
+               if (
+                       rv == CKR_OK &&
+                       (enc_len=i2d_X509_SIG(&sig,NULL)) < 0
+               ) {
+                       rv = CKR_FUNCTION_FAILED;
+               }
+       
+               if (
+                       rv == CKR_OK &&
+                       enc_len > (myrsa_size-RSA_PKCS1_PADDING_SIZE)
+               ) {
+                       rv = CKR_KEY_SIZE_RANGE;
+               }
+       
+               if (rv == CKR_OK) {
+                       unsigned char *p=enc;
+                       i2d_X509_SIG(&sig,&p);
+               }
+       }
+       else {
+               if (rv == CKR_OK) {
+                       enc = (unsigned char *)m;
+                       enc_len = m_len;
+               }
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG1,
+               "PKCS#11: Performing signature"
+       );
+
+       *siglen = myrsa_size;
+
+       if (pkcs11h_session->fKeySignRecover) {
+               if (
+                       (rv = pkcs11h_signRecover (
+                               pkcs11h_session,
+                               CKM_RSA_PKCS,
+                               enc,
+                               enc_len,
+                               sigret,
+                               siglen
+                       )) != CKR_OK
+               ) {
+                       PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot perform signature-recover %ld:'%s'", rv, pkcs11h_getMessage (rv));
+               }
+       }
+       else {
+               if (
+                       (rv = pkcs11h_sign (
+                               pkcs11h_session,
+                               CKM_RSA_PKCS,
+                               enc,
+                               enc_len,
+                               sigret,
+                               siglen
+                       )) != CKR_OK
+               ) {
+                       PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot perform signature %ld:'%s'", rv, pkcs11h_getMessage (rv));
+               }
+       }
+       
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_openssl_sign - return rv=%ld-'%s'",
+               rv,
+               pkcs11h_getMessage (rv)
+       );
+
+       if (enc_alloc != NULL) {
+               free (enc_alloc);
+       }
+       
+       return rv == CKR_OK ? 1 : -1; 
+}
+
+static
+int
+_pkcs11h_openssl_finish (
+       IN OUT RSA *rsa
+) {
+       pkcs11h_openssl_session_t pkcs11h_openssl_session = _pkcs11h_openssl_get_pkcs11h_openssl_session (rsa);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_openssl_finish - entered rsa=%p",
+               (void *)rsa
+       );
+
+       RSA_set_app_data (rsa, NULL);
+       
+       if (pkcs11h_openssl_session->orig_finish != NULL) {
+               pkcs11h_openssl_session->orig_finish (rsa);
+
+#ifdef BROKEN_OPENSSL_ENGINE
+               {
+                       /* We get called TWICE here, once for
+                        * releasing the key and also for
+                        * releasing the engine.
+                        * To prevent endless recursion, FIRST
+                        * clear rsa->engine, THEN call engine->finish
+                        */
+                       ENGINE *e = rsa->engine;
+                       rsa->engine = NULL;
+                       if (e) {
+                               ENGINE_finish(e);
+                       }
+               }
+#endif
+       }
+
+       pkcs11h_openssl_freeSession (pkcs11h_openssl_session);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: _pkcs11h_openssl_finish - return"
+       );
+       
+       return 1;
+}
+
+pkcs11h_openssl_session_t
+pkcs11h_openssl_createSession (
+       IN const bool fShouldPadSign
+) {
+       pkcs11h_openssl_session_t pkcs11h_openssl_session = NULL;
+       bool fOK = true;
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_openssl_createSession - entry fShouldPadSign=%d",
+               fShouldPadSign ? 1 : 0
+       );
+
+       if (
+               fOK &&
+               (pkcs11h_openssl_session = (pkcs11h_openssl_session_t)malloc (sizeof (struct pkcs11h_openssl_session_s))) == NULL
+       ) {
+               fOK = false;
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot allocate memory");
+       }
+
+       if (fOK) {
+               memset (pkcs11h_openssl_session, 0, sizeof (struct pkcs11h_openssl_session_s));
+       }
+
+       if (fOK) {
+               pkcs11h_openssl_session->fShouldPadSign = fShouldPadSign;
+               pkcs11h_openssl_session->nReferenceCount = 1;
+       }
+
+       if (!fOK) {
+               free (pkcs11h_openssl_session);
+               pkcs11h_openssl_session = NULL;
+       }
+       
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_openssl_createSession - return pkcs11h_openssl_session=%p",
+               (void *)pkcs11h_openssl_session
+       );
+
+       return pkcs11h_openssl_session;
+}
+
+void
+pkcs11h_openssl_freeSession (
+       IN const pkcs11h_openssl_session_t pkcs11h_openssl_session
+) {
+       PKCS11ASSERT (pkcs11h_openssl_session!=NULL);
+       PKCS11ASSERT (pkcs11h_openssl_session->nReferenceCount>0);
+       
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_openssl_freeSession - entry pkcs11h_openssl_session=%p, count=%d",
+               (void *)pkcs11h_openssl_session,
+               pkcs11h_openssl_session->nReferenceCount
+       );
+
+       pkcs11h_openssl_session->nReferenceCount--;
+       
+       if (pkcs11h_openssl_session->nReferenceCount == 0) {
+               if (pkcs11h_openssl_session->x509) {
+                       X509_free (pkcs11h_openssl_session->x509);
+                       pkcs11h_openssl_session->x509 = NULL;
+               }
+               if (pkcs11h_openssl_session->pkcs11h_session != NULL) {
+                       pkcs11h_freeSession (pkcs11h_openssl_session->pkcs11h_session);
+                       pkcs11h_openssl_session->pkcs11h_session = NULL;
+               }
+               
+               free (pkcs11h_openssl_session);
+       }
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_openssl_freeSession - return"
+       );
+}
+
+RSA *
+pkcs11h_openssl_getRSA (
+       IN const pkcs11h_openssl_session_t pkcs11h_openssl_session
+) {
+       X509 *x509 = NULL;
+       RSA *rsa = NULL;
+       EVP_PKEY *pubkey = NULL;
+       CK_RV rv = CKR_OK;
+
+       unsigned char certificate[10*1024];
+       size_t certificate_size;
+       unsigned char *p;
+       bool fOK = true;
+
+       PKCS11ASSERT (pkcs11h_openssl_session!=NULL);
+       PKCS11ASSERT (!pkcs11h_openssl_session->fInitialized);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_openssl_getRSA - entry pkcs11h_openssl_session=%p",
+               (void *)pkcs11h_openssl_session
+       );
+
+       if (
+               fOK &&
+               (x509 = X509_new ()) == NULL
+       ) {
+               fOK = false;
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Unable to allocate certificate object");
+       }
+
+       certificate_size = sizeof (certificate);
+       if (
+               fOK &&
+               (rv = pkcs11h_getCertificate (
+                       pkcs11h_openssl_session->pkcs11h_session,
+                       certificate,
+                       &certificate_size
+               )) != CKR_OK
+       ) { 
+               fOK = false;
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11h_getMessage (rv));
+       }
+
+       p = certificate;
+       if (
+               fOK &&
+               !d2i_X509 (&x509, &p, certificate_size)
+       ) {
+               fOK = false;
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Unable to parse X.509 certificate");
+       }
+
+       if (
+               fOK &&
+               (pubkey = X509_get_pubkey (x509)) == NULL
+       ) {
+               fOK = false;
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot get public key");
+       }
+       
+       if (
+               fOK &&
+               pubkey->type != EVP_PKEY_RSA
+       ) {
+               fOK = false;
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Invalid public key algorithm");
+       }
+
+       if (
+               fOK &&
+               (rsa = EVP_PKEY_get1_RSA (pubkey)) == NULL
+       ) {
+               fOK = false;
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot get RSA key");
+       }
+
+       if (fOK) {
+               const RSA_METHOD *def = RSA_get_default_method();
+
+               memmove (&pkcs11h_openssl_session->smart_rsa, def, sizeof(RSA_METHOD));
+
+               pkcs11h_openssl_session->orig_finish = def->finish;
+
+               pkcs11h_openssl_session->smart_rsa.name = "pkcs11";
+               pkcs11h_openssl_session->smart_rsa.rsa_priv_enc = _pkcs11h_openssl_priv_enc;
+               pkcs11h_openssl_session->smart_rsa.rsa_priv_dec = _pkcs11h_openssl_priv_dec;
+               pkcs11h_openssl_session->smart_rsa.rsa_sign = _pkcs11h_openssl_sign;
+               pkcs11h_openssl_session->smart_rsa.finish = _pkcs11h_openssl_finish;
+               pkcs11h_openssl_session->smart_rsa.flags  = RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY;
+
+               RSA_set_method (rsa, &pkcs11h_openssl_session->smart_rsa);
+               RSA_set_app_data (rsa, pkcs11h_openssl_session);
+               pkcs11h_openssl_session->nReferenceCount++;
+       }
+       
+#ifdef BROKEN_OPENSSL_ENGINE
+       if (fOK) {
+               if (!rsa->engine)
+                       rsa->engine = ENGINE_get_default_RSA();
+
+               ENGINE_set_RSA(ENGINE_get_default_RSA(), &pkcs11h_openssl_session->smart_rsa);
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: OpenSSL engine support is broken! Workaround enabled");
+       }
+#endif
+               
+       if (fOK) {
+               /*
+                       So that it won't hold RSA
+               */
+               pkcs11h_openssl_session->x509 = X509_dup (x509);
+               rsa->flags |= RSA_FLAG_SIGN_VER;
+               pkcs11h_openssl_session->fInitialized = true;
+       }
+       else {
+               if (rsa != NULL) {
+                       RSA_free (rsa);
+                       rsa = NULL;
+               }
+       }
+
+       /*
+        * openssl objects have reference
+        * count, so release them
+        */
+       if (pubkey != NULL) {
+               EVP_PKEY_free (pubkey);
+               pubkey = NULL;
+       }
+
+       if (x509 != NULL) {
+               X509_free (x509);
+               x509 = NULL;
+       }
+       
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_openssl_getRSA - return rsa=%p",
+               (void *)rsa
+       );
+
+       return rsa;
+}
+
+X509 *
+pkcs11h_openssl_getX509 (
+       IN const pkcs11h_openssl_session_t pkcs11h_openssl_session
+) {
+       X509 *x509 = NULL;
+       
+       PKCS11ASSERT (pkcs11h_openssl_session!=NULL);
+
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_openssl_getX509 - entry pkcs11h_openssl_session=%p",
+               (void *)pkcs11h_openssl_session
+       );
+
+       if (pkcs11h_openssl_session->x509 != NULL) {
+               x509 = X509_dup (pkcs11h_openssl_session->x509);
+       }
+       
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11h_openssl_getX509 - return x509=%p",
+               (void *)x509
+       );
+
+       return x509;
+}
+
+
+void
+pkcs11h_standalone_dump_slots (
+       IN const pkcs11h_output_print_t my_output,
+       IN const void *pData,
+       IN const char * const provider
+) {
+       CK_RV rv = CKR_OK;
+
+       pkcs11h_provider_t pkcs11h_provider;
+
+       PKCS11ASSERT (provider!=NULL);
+
+       if (
+               rv == CKR_OK &&
+               (rv = pkcs11h_initialize ()) != CKR_OK
+       ) {
+               my_output (pData, "PKCS#11: Cannot initialize interface %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+       }
+
+       if (
+               rv == CKR_OK &&
+               (rv = pkcs11h_addProvider (provider, NULL)) != CKR_OK
+       ) {
+               my_output (pData, "PKCS#11: Cannot initialize provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+       }
+
+       /*
+        * our provider is head
+        */
+       if (rv == CKR_OK) {
+               pkcs11h_provider = pkcs11h_data->providers;
+               if (pkcs11h_provider == NULL || !pkcs11h_provider->fEnabled) {
+                       my_output (pData, "PKCS#11: Cannot get provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+                       rv = CKR_GENERAL_ERROR;
+               }
+       }
+
+       if (rv == CKR_OK) {
+               CK_INFO info;
+               
+               if ((rv = pkcs11h_provider->f->C_GetInfo (&info)) != CKR_OK) {
+                       my_output (pData, "PKCS#11: Cannot get PKCS#11 provider information %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+                       rv = CKR_OK;
+               }
+               else {
+                       char szManufacturerID[sizeof (info.manufacturerID)+1];
+       
+                       _pkcs11h_fixupFixedString (
+                               (char *)info.manufacturerID,
+                               szManufacturerID,
+                               sizeof (info.manufacturerID)
+                       );
+       
+                       my_output (
+                               pData,
+                               (
+                                       "Provider Information:\n"
+                                       "\tcryptokiVersion:\t%u.%u\n"
+                                       "\tmanufacturerID:\t\t%s\n"
+                                       "\tflags:\t\t\t%d\n"
+                                       "\n"
+                               ),
+                               info.cryptokiVersion.major,
+                               info.cryptokiVersion.minor,
+                               szManufacturerID,
+                               (unsigned)info.flags
+                       );
+               }
+       }
+       
+       if (rv == CKR_OK) {
+               CK_SLOT_ID slots[1024];
+               CK_ULONG slotnum;
+               CK_SLOT_ID s;
+               
+               slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
+               if (
+                       (rv = pkcs11h_provider->f->C_GetSlotList (
+                               FALSE,
+                               slots,
+                               &slotnum
+                       )) != CKR_OK
+               ) {
+                       my_output (pData, "PKCS#11: Cannot get slot list %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+               }
+               else {
+                       my_output (
+                               pData,
+                               (
+                                       "The following slots are available for use with this provider.\n"
+                                       "Each slot shown below may be used as a parameter to a\n"
+                                       "%s and %s options.\n"
+                                       "\n"
+                                       "Slots: (id - name)\n"
+                               ),
+                               PKCS11_PRM_SLOT_TYPE,
+                               PKCS11_PRM_SLOT_ID
+                       );
+                       for (s=0;s<slotnum;s++) {
+                               CK_SLOT_INFO info;
+       
+                               if (
+                                       (rv = pkcs11h_provider->f->C_GetSlotInfo (
+                                               slots[s],
+                                               &info
+                                       )) == CKR_OK
+                               ) {
+                                       char szCurrentName[sizeof (info.slotDescription)+1];
+                               
+                                       _pkcs11h_fixupFixedString (
+                                               (char *)info.slotDescription,
+                                               szCurrentName,
+                                               sizeof (info.slotDescription)
+                                       );
+       
+                                       my_output (pData, "\t%lu - %s\n", slots[s], szCurrentName);
+                               }
+                       }
+               }
+       }
+       
+       pkcs11h_terminate ();
+}
+
+static
+bool
+_pkcs11h_standalone_dump_objects_pin_prompt (
+       IN const void *pData,
+       IN const char * const szLabel,
+       OUT char * const szPIN,
+       IN const size_t nMaxPIN
+) {
+       strncpy (szPIN, (char *)pData, nMaxPIN);
+       return true;
+}
+
+void
+pkcs11h_standalone_dump_objects (
+       IN const pkcs11h_output_print_t my_output,
+       IN const void *pData,
+       IN const char * const provider,
+       IN const char * const slot,
+       IN const char * const pin
+) {
+       CK_SLOT_ID s;
+       CK_RV rv = CKR_OK;
+
+       pkcs11h_provider_t pkcs11h_provider;
+
+       PKCS11ASSERT (provider!=NULL);
+       PKCS11ASSERT (slot!=NULL);
+       PKCS11ASSERT (pin!=NULL);
+
+       s = atoi (slot);
+
+       if (
+               rv == CKR_OK &&
+               (rv = pkcs11h_initialize ()) != CKR_OK
+       ) {
+               my_output (pData, "PKCS#11: Cannot initialize interface %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+       }
+
+       if (
+               rv == CKR_OK &&
+               (rv = pkcs11h_setPINPromptHook (_pkcs11h_standalone_dump_objects_pin_prompt, (void *)pin)) != CKR_OK
+       ) {
+               my_output (pData, "PKCS#11: Cannot set hooks %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+       }
+
+       if (
+               rv == CKR_OK &&
+               (rv = pkcs11h_addProvider (provider, NULL)) != CKR_OK
+       ) {
+               my_output (pData, "PKCS#11: Cannot initialize provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+       }
+
+       /*
+        * our provider is head
+        */
+       if (rv == CKR_OK) {
+               pkcs11h_provider = pkcs11h_data->providers;
+               if (pkcs11h_provider == NULL || !pkcs11h_provider->fEnabled) {
+                       my_output (pData, "PKCS#11: Cannot get provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+                       rv = CKR_GENERAL_ERROR;
+               }
+       }
+
+       if (rv == CKR_OK) {
+               CK_TOKEN_INFO info;
+               
+               if (
+                       (rv = pkcs11h_provider->f->C_GetTokenInfo (
+                               s,
+                               &info
+                       )) != CKR_OK
+               ) {
+                       my_output (pData, "PKCS#11: Cannot get token information for slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv));
+                       rv = CKR_OK;
+               }
+               else {
+                       char szLabel[sizeof (info.label)+1];
+                       char szManufacturerID[sizeof (info.manufacturerID)+1];
+                       char szModel[sizeof (info.model)+1];
+                       char szSerialNumber[sizeof (info.serialNumber)+1];
+                       
+                       _pkcs11h_fixupFixedString (
+                               (char *)info.label,
+                               szLabel,
+                               sizeof (info.label)
+                       );
+                       _pkcs11h_fixupFixedString (
+                               (char *)info.manufacturerID,
+                               szManufacturerID,
+                               sizeof (info.manufacturerID)
+                       );
+                       _pkcs11h_fixupFixedString (
+                               (char *)info.model,
+                               szModel,
+                               sizeof (info.model)
+                       );
+                       _pkcs11h_fixupFixedString (
+                               (char *)info.serialNumber,
+                               szSerialNumber,
+                               sizeof (info.serialNumber)
+                       );
+       
+                       my_output (
+                               pData,
+                               (
+                                       "Token Information:\n"
+                                       "\tlabel:\t\t%s\n"
+                                       "\tmanufacturerID:\t%s\n"
+                                       "\tmodel:\t\t%s\n"
+                                       "\tserialNumber:\t%s\n"
+                                       "\tflags:\t\t%08x\n"
+                                       "\n"
+                                       "You can access this token using\n"
+                                       "%s \"label\" %s \"%s\" options.\n"
+                                       "\n"
+                               ),
+                               szLabel,
+                               szManufacturerID,
+                               szModel,
+                               szSerialNumber,
+                               (unsigned)info.flags,
+                               PKCS11_PRM_SLOT_TYPE,
+                               PKCS11_PRM_SLOT_ID,
+                               szLabel
+                       );
+               }
+       }
+
+       if (rv == CKR_OK) {
+               CK_SESSION_HANDLE session;
+               
+               if (
+                       (rv = pkcs11h_provider->f->C_OpenSession (
+                               s,
+                               CKF_SERIAL_SESSION,
+                               NULL_PTR,
+                               NULL_PTR,
+                               &session
+                       )) != CKR_OK
+               ) {
+                       my_output (pData, "PKCS#11: Cannot open session to slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv));
+                       rv = CKR_OK;
+               }
+               else {
+                       CK_OBJECT_HANDLE objects[10];
+                       CK_ULONG objects_found;
+       
+                       if (
+                               (rv = pkcs11h_provider->f->C_Login (
+                                       session,
+                                       CKU_USER,
+                                       (CK_CHAR_PTR)pin,
+                                       (CK_ULONG)strlen (pin)
+                               )) != CKR_OK &&
+                               rv != CKR_USER_ALREADY_LOGGED_IN
+                       ) {
+                               my_output (pData, "PKCS#11: Cannot login to token on slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv));
+                       }
+               
+                       if (
+                               (rv = pkcs11h_provider->f->C_FindObjectsInit (
+                                       session,
+                                       NULL,
+                                       0
+                               )) != CKR_OK
+                       ) {
+                               my_output (pData, "PKCS#11: Cannot query objects for token on slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv));
+                       }
+               
+                       my_output (
+                               pData,
+                               (
+                                       "The following objects are available for use with this token.\n"
+                                       "Each object shown below may be used as a parameter to\n"
+                                       "%s and %s options.\n"
+                                       "\n"
+                               ),
+                               PKCS11_PRM_OBJ_TYPE,
+                               PKCS11_PRM_OBJ_ID
+                       );
+               
+                       while (
+                               (rv = pkcs11h_provider->f->C_FindObjects (
+                                       session,
+                                       objects,
+                                       sizeof (objects) / sizeof (CK_OBJECT_HANDLE),
+                                       &objects_found
+                               )) == CKR_OK &&
+                               objects_found > 0
+                       ) { 
+                               CK_ULONG i;
+                               
+                               for (i=0;i<objects_found;i++) {
+                                       CK_OBJECT_CLASS attrs_class;
+                                       unsigned char attrs_id[PKCS11H_MAX_ATTRIBUTE_SIZE];
+                                       unsigned char attrs_label[PKCS11H_MAX_ATTRIBUTE_SIZE];
+                                       CK_ATTRIBUTE attrs[] = {
+                                               {CKA_CLASS, &attrs_class, sizeof (attrs_class)},
+                                               {CKA_ID, attrs_id, sizeof (attrs_id)},
+                                               {CKA_LABEL, attrs_label, sizeof (attrs_label)-1}
+                                       };
+                       
+                                       if (
+                                               pkcs11h_provider->f->C_GetAttributeValue (
+                                                       session,
+                                                       objects[i],
+                                                       attrs,
+                                                       sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+                                               ) == CKR_OK
+                                       ) {
+                                               int id_len = attrs[1].ulValueLen;
+                                               int j;
+                                                       
+                                               attrs_label[attrs[2].ulValueLen] = 0;
+               
+                                               my_output (
+                                                       pData,
+                                                       (
+                                                               "Object\n"
+                                                               "\tLabel:\t\t%s\n"
+                                                               "\tId:\n"
+                                                       ),
+                                                       attrs_label
+                                               );
+               
+                                                       
+                                               for (j=0;j<id_len;j+=16) {
+                                                       char szLine[3*16+1];
+                                                       int k;
+               
+                                                       szLine[0] = '\0';
+                                                       for (k=0;k<16 && j+k<id_len;k++) {
+                                                               sprintf (szLine+strlen (szLine), "%02x ", attrs_id[j+k]);
+                                                       }
+               
+                                                       my_output (pData, "\t\t%s\n", szLine);
+                                               }
+               
+                                               if (attrs_class == CKO_CERTIFICATE) {
+                                                       unsigned char certificate[PKCS11H_MAX_ATTRIBUTE_SIZE];
+                                                       CK_ATTRIBUTE attrs_cert[] = {
+                                                               {CKA_VALUE, certificate, sizeof (certificate)}
+                                                       };
+               
+                                                       my_output (pData, "\tType:\t\tCertificate\n");
+               
+                                                       if (
+                                                               pkcs11h_provider->f->C_GetAttributeValue (
+                                                                       session,
+                                                                       objects[i],
+                                                                       attrs_cert,
+                                                                       sizeof (attrs_cert) / sizeof (CK_ATTRIBUTE)
+                                                               ) == CKR_OK
+                                                       ) {
+                                                               X509 *x509 = NULL;
+                                                               BIO *bioSerial = NULL;
+               
+                                                               char szSubject[1024];
+                                                               char szSerial[1024];
+                                                               char szNotBefore[1024];
+               
+                                                               szSubject[0] = '\0';
+                                                               szSerial[0] = '\0';
+                                                               szNotBefore[0] = '\0';
+               
+                                                               if ((x509 = X509_new ()) == NULL) {
+                                                                       my_output (pData, "Cannot create x509 context\n");
+                                                               }
+                                                               else {
+                                                                       unsigned char *p;
+               
+                                                                       p = certificate;
+                                                                       if (d2i_X509 (&x509, &p, attrs_cert[0].ulValueLen)) {
+               
+                                                                               ASN1_TIME *notBefore = X509_get_notBefore (x509);
+                                                                               if (notBefore != NULL && notBefore->length < (int) sizeof (szNotBefore) - 1) {
+                                                                                       memmove (szNotBefore, notBefore->data, notBefore->length);
+                                                                                       szNotBefore[notBefore->length] = '\0';
+                                                                               }
+               
+                                                                               X509_NAME_oneline (
+                                                                                       X509_get_subject_name (x509),
+                                                                                       szSubject,
+                                                                                       sizeof (szSubject)
+                                                                               );
+                                                                               szSubject[sizeof (szSubject) - 1] = '\0';
+                                                                       }
+                                                               }
+               
+                                                               if ((bioSerial = BIO_new (BIO_s_mem ())) == NULL) {
+                                                                       my_output (pData, "Cannot create BIO context\n");
+                                                               }
+                                                               else {
+                                                                       int n;
+               
+                                                                       i2a_ASN1_INTEGER(bioSerial, X509_get_serialNumber (x509));
+                                                                       n = BIO_read (bioSerial, szSerial, sizeof (szSerial)-1);
+                                                                       if (n<0) {
+                                                                               szSerial[0] = '\0';
+                                                                       }
+                                                                       else {
+                                                                               szSerial[n] = '\0';
+                                                                       }
+                                                               }
+               
+               
+                                                               if (x509 != NULL) {
+                                                                       X509_free (x509);
+                                                                       x509 = NULL;
+                                                               }
+                                                               if (bioSerial != NULL) {
+                                                                       BIO_free_all (bioSerial);
+                                                                       bioSerial = NULL;
+                                                               }
+               
+                                                               my_output (
+                                                                       pData,
+                                                                       (
+                                                                               "\tsubject:\t%s\n"
+                                                                               "\tserialNumber:\t%s\n"
+                                                                               "\tnotBefore:\t%s\n"
+                                                                       ),
+                                                                       szSubject,
+                                                                       szSerial,
+                                                                       szNotBefore
+                                                               );
+                                                       }
+                                               }
+                                               else if (attrs_class == CKO_PRIVATE_KEY) {
+                                                       CK_BBOOL sign_recover;
+                                                       CK_BBOOL sign;
+                                                       CK_ATTRIBUTE attrs_key[] = {
+                                                               {CKA_SIGN, &sign_recover, sizeof (sign_recover)},
+                                                               {CKA_SIGN_RECOVER, &sign, sizeof (sign)}
+                                                       };
+               
+                                                       my_output (pData, "\tType:\t\tPrivate Key\n");
+               
+                                                       if (
+                                                               pkcs11h_provider->f->C_GetAttributeValue (
+                                                                       session,
+                                                                       objects[i],
+                                                                       attrs_key,
+                                                                       sizeof (attrs_key) / sizeof (CK_ATTRIBUTE)
+                                                               ) == CKR_OK
+                                                       ) {
+                                                               my_output (
+                                                                       pData,
+                                                                       (
+                                                                               "\tSign:\t\t%s\n"
+                                                                               "\tSign Recover:\t%s\n"
+                                                                       ),
+                                                                       sign ? "TRUE" : "FALSE",
+                                                                       sign_recover ? "TRUE" : "FALSE"
+                                                               );
+                                                       }
+                                               }
+                                               else {
+                                                       my_output (pData, "\tType:\t\tUnsupported\n");
+                                               }
+                                       }
+                               }
+                       
+                               pkcs11h_provider->f->C_FindObjectsFinal (session);
+                               pkcs11h_provider->f->C_Logout (session);
+                               pkcs11h_provider->f->C_CloseSession (session);
+                       }
+               }
+       }
+       
+       pkcs11h_terminate ();
+}
+
+#ifdef BROKEN_OPENSSL_ENGINE
+static void broken_openssl_init() __attribute__ ((constructor));
+static void  broken_openssl_init()
+{
+       SSL_library_init();
+       ENGINE_load_openssl();
+       ENGINE_register_all_RSA();
+}
+#endif
+
+#else
+static void dummy (void) {}
+#endif /* PKCS11_HELPER_ENABLE */
diff --git a/pkcs11-helper.h b/pkcs11-helper.h
new file mode 100644 (file)
index 0000000..10a3a6f
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2005 Alon Bar-Lev <alon.barlev@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The routines in this file deal with providing private key cryptography
+ * using RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki).
+ *
+ */
+
+#ifndef __PKCS11_HELPER_H
+#define __PKCS11_HELPER_H
+
+#include "pkcs11-helper-config.h"
+
+#define PKCS11H_MAX_ATTRIBUTE_SIZE (10*1024)
+
+typedef void (*pkcs11h_output_print_t)(
+       IN const void *pData,
+       IN const char * const szFormat,
+       IN ...
+);
+
+typedef bool (*pkcs11h_hook_card_prompt_t)(
+       IN const void *pData,
+       IN const char * const szLabel
+);
+
+typedef bool (*pkcs11h_hook_pin_prompt_t)(
+       IN const void *pData,
+       IN const char * const szLabel,
+       OUT char * const szPIN,
+       IN const size_t nMaxPIN
+);
+
+
+typedef struct pkcs11h_hooks_s {
+       void *card_prompt_data;
+       void *pin_prompt_data;
+       pkcs11h_hook_card_prompt_t card_prompt;
+       pkcs11h_hook_pin_prompt_t pin_prompt;
+} *pkcs11h_hooks_t;
+
+typedef struct pkcs11h_provider_s {
+       struct pkcs11h_provider_s *next;
+
+       bool fEnabled;
+       char *szName;
+       
+#if defined(WIN32)
+       HANDLE hLibrary;
+#else
+       void *hLibrary;
+#endif
+       CK_FUNCTION_LIST_PTR f;
+       bool fShouldFinalize;
+       char *szSignMode;
+
+} *pkcs11h_provider_t;
+
+typedef struct pkcs11h_session_s {
+
+       pkcs11h_provider_t provider;
+
+       bool fProtectedAuthentication;
+
+       char szLabel[sizeof (((CK_TOKEN_INFO *)NULL)->label)+1];
+       CK_CHAR serialNumber[sizeof (((CK_TOKEN_INFO *)NULL)->serialNumber)];
+       
+       unsigned char *certificate;
+       size_t certificate_size;
+       unsigned char *certificate_id;
+       size_t certificate_id_size;
+
+       CK_SLOT_ID slot;
+       bool fKeySignRecover;
+
+       CK_SESSION_HANDLE session;
+       CK_OBJECT_HANDLE key;
+
+       time_t timePINExpire;
+} *pkcs11h_session_t;
+
+typedef struct pkcs11h_data_s {
+       bool fInitialized;
+       int nPINCachePeriod;
+       pkcs11h_provider_t providers;
+       pkcs11h_hooks_t hooks;
+} *pkcs11h_data_t;
+
+typedef struct pkcs11h_openssl_session_s {
+       int nReferenceCount;
+       bool fInitialized;
+       bool fShouldPadSign;
+       X509 *x509;
+       RSA_METHOD smart_rsa;
+       int (*orig_finish)(RSA *rsa);
+       pkcs11h_session_t pkcs11h_session;
+} *pkcs11h_openssl_session_t;
+
+CK_RV
+pkcs11h_initialize ();
+
+CK_RV
+pkcs11h_terminate ();
+
+CK_RV
+pkcs11h_setCardPromptHook (
+       IN const pkcs11h_hook_card_prompt_t hook,
+       IN void * const pData
+);
+
+CK_RV
+pkcs11h_setPINPromptHook (
+       IN const pkcs11h_hook_pin_prompt_t hook,
+       IN void * const pData
+);
+
+CK_RV
+pkcs11h_setPINCachePeriod (
+       IN const int nPINCachePeriod
+);
+
+CK_RV
+pkcs11h_addProvider (
+       IN const char * const szProvider,
+       IN const char * const szSignMode
+);
+
+CK_RV
+pkcs11h_forkFixup ();
+
+CK_RV
+pkcs11h_createSession (
+       IN const char * const szSlotType,
+       IN const char * const szSlot,
+       IN const char * const szIdType,
+       IN const char * const szId,
+       IN const bool fProtectedAuthentication,
+       OUT pkcs11h_session_t * const pkcs11h_session
+);
+
+CK_RV
+pkcs11h_freeSession (
+       IN const pkcs11h_session_t pkcs11h_session
+);
+
+CK_RV
+pkcs11h_sign (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const CK_MECHANISM_TYPE mech_type,
+       IN const unsigned char * const source,
+       IN const size_t source_size,
+       OUT unsigned char * const target,
+       IN OUT size_t * const target_size
+);
+
+CK_RV
+pkcs11h_signRecover (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const CK_MECHANISM_TYPE mech_type,
+       IN const unsigned char * const source,
+       IN const size_t source_size,
+       OUT unsigned char * const target,
+       IN OUT size_t * const target_size
+);
+
+CK_RV
+pkcs11h_decrypt (
+       IN const pkcs11h_session_t pkcs11h_session,
+       IN const CK_MECHANISM_TYPE mech_type,
+       IN const unsigned char * const source,
+       IN const size_t source_size,
+       OUT unsigned char * const target,
+       IN OUT size_t * const target_size
+);
+
+CK_RV
+pkcs11h_getCertificate (
+       IN const pkcs11h_session_t pkcs11h_session,
+       OUT unsigned char * const certificate,
+       IN OUT size_t * const certificate_size
+);
+
+char *
+pkcs11h_getMessage (
+       IN const int rv
+);
+
+pkcs11h_openssl_session_t
+pkcs11h_openssl_createSession (
+       IN const bool fShouldPadSign
+);
+
+void
+pkcs11h_openssl_freeSession (
+       IN const pkcs11h_openssl_session_t pkcs11h_openssl_session
+);
+
+RSA *
+pkcs11h_openssl_getRSA (
+       IN const pkcs11h_openssl_session_t pkcs11h_openssl_session
+);
+
+X509 *
+pkcs11h_openssl_getX509 (
+       IN const pkcs11h_openssl_session_t pkcs11h_openssl_session
+);
+
+void
+pkcs11h_standalone_dump_slots (
+       IN const pkcs11h_output_print_t my_output,
+       IN const void *pData,
+       IN const char * const provider
+);
+
+void
+pkcs11h_standalone_dump_objects (
+       IN const pkcs11h_output_print_t my_output,
+       IN const void *pData,
+       IN const char * const provider,
+       IN const char * const slot,
+       IN const char * const pin
+);
+
+#endif
index 8dd9dfef95c6148e35a416abb37ff6505fafc38a..84d663b82a41ceffe85391e9799446fb6d991c7f 100644 (file)
--- a/pkcs11.c
+++ b/pkcs11.c
 
 #if defined(ENABLE_PKCS11)
 
-#include "error.h"
-#include "misc.h"
-#include "ssl.h"
+#define PKCS11H_NO_NEED_INCLUDE_CONFIG
 
-#if !defined(IN)
-#define IN
-#endif
-#if !defined(OUT)
-#define OUT
-#endif
-
-#if defined(WIN32)
-#include "cryptoki-win32.h"
-#else
-#include "cryptoki.h"
-#endif
-
-#include "pkcs11.h"
-
-/*===========================================
- * MACROS
- */
-
-#define snprintf openvpn_snprintf
-
-/*===========================================
- * Constants
- */
-
-#if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE)
-# define RSA_get_default_method RSA_get_default_openssl_method
-#else
-# ifdef HAVE_ENGINE_GET_DEFAULT_RSA
-#  include <openssl/engine.h>
-#  if OPENSSL_VERSION_NUMBER < 0x0090704fL
-#   define BROKEN_OPENSSL_ENGINE
-#  endif
-# endif
-#endif
-
-#define PKCS11_MAX_ATTRIBUTE_SIZE (10*1024)
-
-/*===========================================
- * Types
- */
-
-typedef bool (*pkcs11_hook_card_prompt_t)(
-       IN const void *pData,
-       IN const char * const szLabel
-);
-
-typedef bool (*pkcs11_hook_pin_prompt_t)(
-       IN const void *pData,
-       IN const char * const szLabel,
-       OUT char * const szPIN,
-       IN const size_t nMaxPIN
-);
-       
-typedef struct pkcs11_hooks_s {
-       void *card_prompt_data;
-       void *pin_prompt_data;
-       pkcs11_hook_card_prompt_t card_prompt;
-       pkcs11_hook_pin_prompt_t pin_prompt;
-} *pkcs11_hooks_t;
-
-typedef struct pkcs11_provider_s {
-       struct pkcs11_provider_s *next;
-
-       bool fEnabled;
-       
-#if defined(WIN32)
-       HANDLE hLibrary;
-#else
-       void *hLibrary;
-#endif
-       CK_FUNCTION_LIST_PTR f;
-       bool fShouldFinalize;
-       char *szSignMode;
-
-} *pkcs11_provider_t;
-
-typedef struct pkcs11_session_s {
-
-       pkcs11_provider_t provider;
-
-       bool fProtectedAuthentication;
-
-       char szLabel[sizeof (((CK_TOKEN_INFO *)NULL)->label)+1];
-       CK_CHAR serialNumber[sizeof (((CK_TOKEN_INFO *)NULL)->serialNumber)];
-       
-       unsigned char *certificate;
-       size_t certificate_size;
-       unsigned char *certificate_id;
-       size_t certificate_id_size;
-
-       CK_SLOT_ID slot;
-       bool fKeySignRecover;
-
-       CK_SESSION_HANDLE session;
-       CK_OBJECT_HANDLE key;
-
-       time_t timePINExpire;
-} *pkcs11_session_t;
-
-typedef struct pkcs11_data_s {
-       bool fInitialized;
-       int nPINCachePeriod;
-       pkcs11_provider_t providers;
-       pkcs11_hooks_t hooks;
-} *pkcs11_data_t;
-
-/*===========================================
- * Low level prototypes
- */
-
-static
-void
-_fixupFixedString (
-       IN const char * const szSource,
-       OUT char * const szTarget,                      /* MUST BE >= nLength+1 */
-       IN const size_t nLength                         /* FIXED STRING LENGTH */
-);
-static
-void
-_hexToBinary (
-       IN const char * const szSource,
-       OUT unsigned char * const target,
-       IN OUT size_t * const target_size
-);
-static
-CK_RV
-_pkcs11_getSlotById (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const char * const szSlot
-);
-static
-CK_RV
-_pkcs11_getSlotByName (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const char * const szName
-);
-static
-CK_RV
-_pkcs11_getSlotByLabel (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const char * const szLabel
-);
-static
-CK_RV
-_pkcs11_getObjectById (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const CK_OBJECT_CLASS class,
-       IN const unsigned char * const id,
-       IN const size_t id_size,
-       OUT CK_OBJECT_HANDLE * const handle
-);
-static
-CK_RV
-_pkcs11_setSessionTokenInfo (
-       IN const pkcs11_session_t pkcs11_session
-);
-static
-CK_RV
-_pkcs11_resetSlot (
-       IN const pkcs11_session_t pkcs11_session
-);
-static
-CK_RV
-_pkcs11_loadCertificate (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const char * const szIdType,
-       IN const char * const szId
-);
-static
-CK_RV
-_pkcs11_loadKeyProperties (
-       IN const pkcs11_session_t pkcs11_session
-);
-static
-bool
-_isBetterCertificate (
-       IN const unsigned char * const pCurrent,
-       IN const size_t nCurrentSize,
-       IN const unsigned char * const pNew,
-       IN const size_t nNewSize
-);
-static
-CK_RV
-_pkcs11_validateSession (
-       IN const pkcs11_session_t pkcs11_session
-);
-static
-CK_RV
-_pkcs11_login (
-       IN const pkcs11_session_t pkcs11_session
-);
-static
-CK_RV
-_pkcs11_logout (
-       IN const pkcs11_session_t pkcs11_session
-);
-
-/*=========================================
- * Simplified functions prototypes
- */
-static
-bool
-_pkcs11_hooks_card_prompt_default (
-       IN const void *pData,
-       IN const char * const szLabel
-);
-static
-bool
-_pkcs11_hooks_pin_prompt_default (
-       IN const void *pData,
-       IN const char * const szLabel,
-       OUT char * const szPIN,
-       IN const size_t nMaxPIN
-);
-static
-CK_RV
-pkcs11_initialize ();
-static
-CK_RV
-pkcs11_terminate ();
-static
-CK_RV
-pkcs11_setCardPromptHook (
-       IN const pkcs11_hook_card_prompt_t hook,
-       IN void * const pData
-);
-static
-CK_RV
-pkcs11_setPINPromptHook (
-       IN const pkcs11_hook_pin_prompt_t hook,
-       IN void * const pData
-);
-static
-CK_RV
-pkcs11_setPINCachePeriod (
-       IN const int nPINCachePeriod
-);
-static
-CK_RV
-pkcs11_addProvider (
-       IN const char * const szProvider,
-       IN const char * const szSignMode
-);
-static
-CK_RV
-pkcs11_forkFixup ();
-static
-CK_RV
-pkcs11_createSession (
-       IN const char * const szSlotType,
-       IN const char * const szSlot,
-       IN const char * const szIdType,
-       IN const char * const szId,
-       IN const bool fProtectedAuthentication,
-       OUT pkcs11_session_t * const pkcs11_session
-);
-static
-CK_RV
-pkcs11_freeSession (
-       IN const pkcs11_session_t pkcs11_session
-);
-static
-CK_RV
-pkcs11_sign (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const CK_MECHANISM_TYPE mech_type,
-       IN const unsigned char * const source,
-       IN const size_t source_size,
-       OUT unsigned char * const target,
-       IN OUT size_t * const target_size
-);
-static
-CK_RV
-pkcs11_signRecover (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const CK_MECHANISM_TYPE mech_type,
-       IN const unsigned char * const source,
-       IN const size_t source_size,
-       OUT unsigned char * const target,
-       IN OUT size_t * const target_size
-);
-static
-CK_RV
-pkcs11_decrypt (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const CK_MECHANISM_TYPE mech_type,
-       IN const unsigned char * const source,
-       IN const size_t source_size,
-       OUT unsigned char * const target,
-       IN OUT size_t * const target_size
-);
-static
-CK_RV
-pkcs11_getCertificate (
-       IN const pkcs11_session_t pkcs11_session,
-       OUT unsigned char * const certificate,
-       IN OUT size_t * const certificate_size
-);
-static
-char *
-pkcs11_getMessage (
-       IN const int rv
-);
-
-/*==========================================
- * Static data
- */
-
-static pkcs11_data_t pkcs11_data = NULL;
-
-/*==========================================
- * Internal utility functions
- */
-
-static
-void
-_fixupFixedString (
-       IN const char * const szSource,
-       OUT char * const szTarget,                      /* MUST BE >= nLength+1 */
-       IN const size_t nLength                         /* FIXED STRING LENGTH */
-) {
-       char *p;
-
-       ASSERT (szSource!=NULL);
-       ASSERT (szTarget!=NULL);
-       
-       p = szTarget+nLength;
-       memmove (szTarget, szSource, nLength);
-       *p = '\0';
-       p--;
-       while (p >= szTarget && *p == ' ') {
-               *p = '\0';
-               p--;
-       }
-}
-
-static
-void
-_hexToBinary (
-       IN const char * const szSource,
-       OUT unsigned char * const target,
-       IN OUT size_t * const target_size
-) {
-       size_t target_max_size;
-       const char *p;
-       char buf[3] = {'\0', '\0', '\0'};
-       int i = 0;
-
-       ASSERT (szSource!=NULL);
-       ASSERT (target!=NULL);
-       ASSERT (target_size!=NULL);
-
-       target_max_size = *target_size;
-       p = szSource;
-       *target_size = 0;
-
-       while (*p != '\0' && *target_size < target_max_size) {
-               if (isxdigit (*p)) {
-                       buf[i%2] = *p;
-
-                       if ((i%2) == 1) {
-                               unsigned v;
-                               sscanf (buf, "%x", &v);
-                               target[*target_size] = v & 0xff;
-                               (*target_size)++;
-                       }
-
-                       i++;
-               }
-               p++;
-       }
-}
-
-static
-bool
-_isBetterCertificate (
-       IN const unsigned char * const pCurrent,
-       IN const size_t nCurrentSize,
-       IN const unsigned char * const pNew,
-       IN const size_t nNewSize
-) {
-       /*
-        * This function compare the notBefore
-        * and select the most recent certificate
-        * it does not deal with timezones...
-        * When openssl will have ASN1_TIME compare function
-        * it should be used.
-        */
-
-       X509 *x509Current = NULL, *x509New = NULL;
-       char szNotBeforeCurrent[1024], szNotBeforeNew[1024];
-
-       /*
-        * First certificae
-        * always select
-        */
-       if (nCurrentSize == 0) {
-               return true;
-       }
-
-       szNotBeforeCurrent[0] = '\0';
-       szNotBeforeNew[0] = '\0';
-
-       x509Current = X509_new ();
-       x509New = X509_new ();
-
-       if (x509Current != NULL && x509New != NULL) {
-               const unsigned char *p1, *p2;
-
-               p1 = pCurrent;
-               p2 = pNew;
-               if (
-                       d2i_X509 (&x509Current, (unsigned char **)&p1, nCurrentSize) &&
-                       d2i_X509 (&x509New, (unsigned char **)&p2, nNewSize)
-               ) {
-                       ASN1_TIME *notBeforeCurrent = X509_get_notBefore (x509Current);
-                       ASN1_TIME *notBeforeNew = X509_get_notBefore (x509New);
-
-                       if (
-                               notBeforeCurrent != NULL &&
-                               notBeforeNew != NULL &&
-                               notBeforeCurrent->length < (int) sizeof (szNotBeforeCurrent) - 1 &&
-                               notBeforeNew->length < (int) sizeof (szNotBeforeNew) - 1
-                       ) {
-                               memmove (szNotBeforeCurrent, notBeforeCurrent->data, notBeforeCurrent->length);
-                               szNotBeforeCurrent[notBeforeCurrent->length] = '\0';
-                               memmove (szNotBeforeNew, notBeforeNew->data, notBeforeNew->length);
-                               szNotBeforeNew[notBeforeNew->length] = '\0';
-                       }
-               }
-       }
-
-       if (x509Current != NULL) {
-               X509_free (x509Current);
-               x509Current = NULL;
-       }
-       if (x509New != NULL) {
-               X509_free (x509New);
-               x509New = NULL;
-       }
-
-       return strcmp (szNotBeforeCurrent, szNotBeforeNew) < 0;
-}
-
-/*========================================
- * Low level PKCS#11 functions
- */
-
-static
-CK_RV
-_pkcs11_getSlotById (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const char * const szSlot
-) {
-       pkcs11_provider_t provider;
-       int provider_number;
-       int slot_number;
-       int i;
-
-       ASSERT (pkcs11_session!=NULL);
-       ASSERT (szSlot!=NULL);
-
-       if (strchr (szSlot, ':') == NULL) {
-               provider_number = 0;
-               slot_number = atoi (szSlot);
-       }
-       else {
-               sscanf (szSlot, "%d:%d", &provider_number, &slot_number);
-       }
-
-       for (
-               i=0, provider=pkcs11_data->providers;
-               i < provider_number && provider != NULL;
-               i++, provider = provider->next
-       );
-
-       if (
-               provider == NULL ||
-               (
-                       provider != NULL &&
-                       !provider->fEnabled
-               )
-       ) {
-               return CKR_SLOT_ID_INVALID;
-       }
-
-       pkcs11_session->provider = provider;
-       pkcs11_session->slot = slot_number;
-       return CKR_OK;
-}
-
-static
-CK_RV
-_pkcs11_getSlotByName (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const char * const szName
-) {
-       CK_RV rv;
-
-       pkcs11_provider_t provider;
-       bool fFound = false;
-
-       ASSERT (pkcs11_session!=NULL);
-       ASSERT (szName!=NULL);
-
-       for (
-               provider = pkcs11_data->providers;
-               (
-                       provider != NULL &&
-                       !fFound
-               );
-               provider = provider->next
-       ) {
-               CK_SLOT_ID slots[1024];
-               CK_ULONG slotnum;
-
-               if (!provider->fEnabled) {
-                       continue;
-               }
-
-               slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
-               if (
-                       (rv = provider->f->C_GetSlotList (
-                               TRUE,
-                               slots,
-                               &slotnum
-                       )) == CKR_OK
-               ) {
-                       CK_SLOT_ID s;
-
-                       for (s=0;!fFound && s<slotnum;s++) {
-                               CK_SLOT_INFO info;
-
-                               if (
-                                       (rv = provider->f->C_GetSlotInfo (
-                                               slots[s],
-                                               &info
-                                       )) == CKR_OK
-                               ) {
-                                       char szCurrentName[sizeof (info.slotDescription)+1];
-       
-                                       _fixupFixedString (
-                                               (char *)info.slotDescription,
-                                               szCurrentName,
-                                               sizeof (info.slotDescription)
-                                       );
-
-                                       if (!strcmp (szCurrentName, szName)) {
-                                               fFound = true;
-                                               pkcs11_session->provider = provider;
-                                               pkcs11_session->slot = slots[s];
-                                       }
-                               }
-                       }
-               }
-       }
-
-       return fFound ? CKR_OK : CKR_SLOT_ID_INVALID;
-}
-
-static
-CK_RV
-_pkcs11_getSlotByLabel (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const char * const szLabel
-) {
-       CK_RV rv;
-
-       pkcs11_provider_t provider;
-       bool fFound = false;
-
-       ASSERT (pkcs11_session!=NULL);
-       ASSERT (szLabel!=NULL);
-
-       for (
-               provider = pkcs11_data->providers;
-               (
-                       provider != NULL &&
-                       !fFound
-               );
-               provider = provider->next
-       ) {
-               CK_SLOT_ID slots[1024];
-               CK_ULONG slotnum;
-
-               if (!provider->fEnabled) {
-                       continue;
-               }
-
-               slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
-               if (
-                       (rv = provider->f->C_GetSlotList (
-                               TRUE,
-                               slots,
-                               &slotnum
-                       )) == CKR_OK
-               ) {
-                       CK_SLOT_ID s;
-
-                       for (s=0;!fFound && s<slotnum;s++) {
-                               CK_TOKEN_INFO info;
-
-                               if (
-                                       (rv = provider->f->C_GetTokenInfo (
-                                               slots[s],
-                                               &info
-                                       )) == CKR_OK
-                               ) {
-                                       char szCurrentLabel[sizeof (info.label)+1];
-                       
-                                       _fixupFixedString (
-                                               (char *)info.label,
-                                               szCurrentLabel,
-                                               sizeof (info.label)
-                                       );
-
-                                       if (!strcmp (szCurrentLabel, szLabel)) {
-                                               fFound = true;
-                                               pkcs11_session->provider = provider;
-                                               pkcs11_session->slot = slots[s];
-                                       }
-                               }
-                       }
-               }
-       }
-
-       return fFound ? CKR_OK : CKR_SLOT_ID_INVALID;
-}
-
-static
-CK_RV
-_pkcs11_setSessionTokenInfo (
-       IN const pkcs11_session_t pkcs11_session
-) {
-       CK_TOKEN_INFO info;
-       CK_RV rv;
-
-       ASSERT (pkcs11_session!=NULL);
-
-       if (
-               (rv = pkcs11_session->provider->f->C_GetTokenInfo (
-                       pkcs11_session->slot,
-                       &info
-               )) == CKR_OK
-       ) {
-               _fixupFixedString (
-                       (char *)info.label,
-                       pkcs11_session->szLabel,
-                       sizeof (info.label)
-               );
-               
-               memmove (
-                       pkcs11_session->serialNumber,
-                       info.serialNumber,
-                       sizeof (pkcs11_session->serialNumber)
-               );
-       }
-
-       return rv;
-}
-
-static
-CK_RV
-_pkcs11_resetSlot (
-       IN const pkcs11_session_t pkcs11_session
-) {
-       CK_SLOT_ID slots[1024];
-       CK_ULONG slotnum;
-       CK_RV rv;
-       bool fFound = false;
-       bool fCancel = false;
-
-       ASSERT (pkcs11_session!=NULL);
-
-       do {
-               slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
-               if (
-                       (rv = pkcs11_session->provider->f->C_GetSlotList (
-                               TRUE,
-                               slots,
-                               &slotnum
-                       )) == CKR_OK
-               ) {
-                       CK_SLOT_ID s;
-
-                       for (s=0;!fFound && s<slotnum;s++) {
-                               CK_TOKEN_INFO info;
-
-                               if (
-                                       (rv = pkcs11_session->provider->f->C_GetTokenInfo (
-                                               slots[s],
-                                               &info
-                                       )) == CKR_OK
-                               ) {
-                                       if (
-                                               !memcmp (
-                                                       pkcs11_session->serialNumber,
-                                                       info.serialNumber,
-                                                       sizeof (pkcs11_session->serialNumber)
-                                               )
-                                       ) {
-                                               pkcs11_session->slot = slots[s];
-                                               fFound = true;
-                                       }
-                               }
-                       }
-               }
-
-               if (!fFound) {
-                       fCancel = !pkcs11_data->hooks->card_prompt (
-                               pkcs11_data->hooks->card_prompt_data,
-                               pkcs11_session->szLabel
-                       );
-               }
-       } while (!fFound && !fCancel);
-
-       return fFound ? CKR_OK : CKR_SLOT_ID_INVALID;
-}
-
-static
-CK_RV
-_pkcs11_getObjectById (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const CK_OBJECT_CLASS class,
-       IN const unsigned char * const id,
-       IN const size_t id_size,
-       OUT CK_OBJECT_HANDLE * const handle
-) {
-       CK_ULONG count;
-       CK_RV rv = CKR_OK;
-
-       CK_ATTRIBUTE filter[] = {
-               {CKA_CLASS, (void *)&class, sizeof (class)},
-               {CKA_ID, (void *)id, id_size}
-       };
-       
-       ASSERT (pkcs11_session!=NULL);
-       ASSERT (id!=NULL);
-       ASSERT (handle!=NULL);
-
-       if (rv == CKR_OK) {
-               rv = pkcs11_session->provider->f->C_FindObjectsInit (
-                       pkcs11_session->session,
-                       filter,
-                       sizeof (filter) / sizeof (CK_ATTRIBUTE)
-               );
-       }
-
-       if (rv == CKR_OK) {
-               rv = pkcs11_session->provider->f->C_FindObjects (
-                       pkcs11_session->session,
-                       handle,
-                       1,
-                       &count
-               );
-       }
-
-       if (
-               rv == CKR_OK &&
-               count == 0
-       ) {
-               rv = CKR_FUNCTION_REJECTED;
-       }
-
-       pkcs11_session->provider->f->C_FindObjectsFinal (
-               pkcs11_session->session
-       );
-
-       return rv;
-}
-
-static
-CK_RV
-_pkcs11_loadCertificate (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const char * const szIdType,
-       IN const char * const szId
-) {
-       CK_OBJECT_HANDLE objects[10];
-       CK_ULONG objects_found;
-       CK_RV rv;
-
-       unsigned char selected_id[PKCS11_MAX_ATTRIBUTE_SIZE];
-       int selected_id_size = 0;
-       unsigned char selected_certificate[PKCS11_MAX_ATTRIBUTE_SIZE];
-       int selected_certificate_size = 0;
-
-       CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
-       unsigned char cert_filter_by[PKCS11_MAX_ATTRIBUTE_SIZE];
-       CK_ATTRIBUTE cert_filter[] = {
-               {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)},
-               {0, cert_filter_by, 0}
-       };
-
-       ASSERT (pkcs11_session!=NULL);
-       ASSERT (szIdType!=NULL);
-       ASSERT (szId!=NULL);
-
-       if (!strcmp (szIdType, "label")) {
-               cert_filter[1].type = CKA_LABEL;
-               cert_filter[1].ulValueLen = (CK_ULONG)(
-                       strlen (szId) < sizeof (cert_filter_by)  ?
-                       strlen (szId) :
-                       sizeof (cert_filter_by)
-               );
-               memmove (
-                       cert_filter_by,
-                       szId,
-                       cert_filter[1].ulValueLen
-               );
-       }
-       else if (!strcmp (szIdType, "id")) {
-               size_t s = sizeof (cert_filter_by);
-
-               cert_filter[1].type = CKA_ID;
-               _hexToBinary (
-                       szId,
-                       cert_filter_by,
-                       &s
-               );
-               cert_filter[1].ulValueLen = s;
-       }
-       else if (!strcmp (szIdType, "subject")) {
-               memmove (&cert_filter[1], &cert_filter[0], sizeof (CK_ATTRIBUTE));
-       }
-       else {
-               return CKR_ARGUMENTS_BAD;
-       }
-
-       if (
-               (rv = pkcs11_session->provider->f->C_FindObjectsInit (
-                       pkcs11_session->session,
-                       cert_filter,
-                       sizeof (cert_filter) / sizeof (CK_ATTRIBUTE)
-               )) != CKR_OK
-       ) {
-               return rv;
-       }
-
-       while (
-               (rv = pkcs11_session->provider->f->C_FindObjects (
-                       pkcs11_session->session,
-                       objects,
-                       sizeof (objects) / sizeof (CK_OBJECT_HANDLE),
-                       &objects_found
-               )) == CKR_OK &&
-               objects_found > 0
-       ) { 
-               CK_ULONG i;
-               
-               for (i=0;i<objects_found;i++) {
-                       unsigned char attrs_id[PKCS11_MAX_ATTRIBUTE_SIZE];
-                       unsigned char attrs_value[PKCS11_MAX_ATTRIBUTE_SIZE];
-                       CK_ATTRIBUTE attrs[] = {
-                               {CKA_ID, attrs_id, sizeof (attrs_id)},
-                               {CKA_VALUE, attrs_value, sizeof (attrs_value)}
-                       };
-       
-                       if (
-                               pkcs11_session->provider->f->C_GetAttributeValue (
-                                       pkcs11_session->session,
-                                       objects[i],
-                                       attrs,
-                                       sizeof (attrs) / sizeof (CK_ATTRIBUTE)
-                               ) == CKR_OK
-                       ) {
-                               bool fSelected = false;
-
-                               if (!strcmp (szIdType, "subject")) {
-                                       X509 *x509 = NULL;
-                                       char szSubject[1024];
-                                       unsigned char *p;
-
-                                       x509 = X509_new ();
-
-                                       p = attrs_value;
-                                       if (d2i_X509 (&x509, &p, attrs[1].ulValueLen)) {
-                                               X509_NAME_oneline (
-                                                       X509_get_subject_name (x509),
-                                                       szSubject,
-                                                       sizeof (szSubject)
-                                               );
-                                               szSubject[sizeof (szSubject) - 1] = '\0';
-                                       }
-
-                                       if (x509 != NULL) {
-                                               X509_free (x509);
-                                               x509 = NULL;
-                                       }
-
-                                       if (!strcmp (szId, szSubject)) {
-                                               fSelected = true;
-                                       }
-                               }
-                               else {
-                                       fSelected = true;
-                               }
-
-                               if (
-                                       fSelected &&
-                                       _isBetterCertificate (
-                                               selected_certificate,
-                                               selected_certificate_size,
-                                               attrs_value,
-                                               attrs[1].ulValueLen
-                                       )
-                               ) {
-                                       selected_certificate_size = attrs[1].ulValueLen;
-                                       memmove (
-                                               selected_certificate,
-                                               attrs_value,
-                                               selected_certificate_size
-                                       );
-                                       selected_id_size = attrs[0].ulValueLen;
-                                       memmove (
-                                               selected_id,
-                                               attrs_id,
-                                               selected_id_size
-                                       );
-                               }
-                       }
-               }
-       }
-
-       pkcs11_session->provider->f->C_FindObjectsFinal (
-               pkcs11_session->session
-       );
-
-       if (selected_certificate_size == 0) {
-               return CKR_ATTRIBUTE_VALUE_INVALID;
-       }
-
-       if ((pkcs11_session->certificate = (unsigned char *)malloc (selected_certificate_size)) == NULL) {
-               return CKR_HOST_MEMORY;
-       }
-       pkcs11_session->certificate_size = selected_certificate_size;
-       memmove (
-               pkcs11_session->certificate,
-               selected_certificate,
-               selected_certificate_size
-       );
-       if ((pkcs11_session->certificate_id = (unsigned char *)malloc (selected_id_size)) == NULL) {
-               return CKR_HOST_MEMORY;
-       }
-       pkcs11_session->certificate_id_size = selected_id_size;
-       memmove (
-               pkcs11_session->certificate_id,
-               selected_id,
-               selected_id_size
-       );
-
-       return CKR_OK;
-}
-
-static
-CK_RV
-_pkcs11_loadKeyProperties (
-       IN const pkcs11_session_t pkcs11_session
-) {
-       CK_OBJECT_HANDLE key;
-       CK_RV rv;
-
-       CK_BBOOL key_attrs_sign_recover;
-       CK_BBOOL key_attrs_sign;
-       CK_ATTRIBUTE key_attrs[] = {
-               {CKA_SIGN, &key_attrs_sign_recover, sizeof (key_attrs_sign_recover)},
-               {CKA_SIGN_RECOVER, &key_attrs_sign, sizeof (key_attrs_sign)}
-       };
-
-       ASSERT (pkcs11_session!=NULL);
-
-       if (!strcmp (pkcs11_session->provider->szSignMode, "recover")) {
-               pkcs11_session->fKeySignRecover = true;
-       }
-       else if (!strcmp (pkcs11_session->provider->szSignMode, "sign")) {
-               pkcs11_session->fKeySignRecover = false;
-       }
-       else {
-               if (
-                       (rv = _pkcs11_getObjectById (
-                               pkcs11_session,
-                               CKO_PRIVATE_KEY,
-                               pkcs11_session->certificate_id,
-                               pkcs11_session->certificate_id_size,
-                               &key
-                       )) != CKR_OK
-               ) {
-                       return rv;
-               }
-
-               if (
-                       pkcs11_session->provider->f->C_GetAttributeValue (
-                               pkcs11_session->session,
-                               key,
-                               key_attrs,
-                               sizeof (key_attrs) / sizeof (CK_ATTRIBUTE)
-                       ) == CKR_OK
-               ) {
-                       if (key_attrs_sign_recover != CK_FALSE) {
-                               pkcs11_session->fKeySignRecover = true;
-                       }
-                       else if (key_attrs_sign != CK_FALSE) {
-                               pkcs11_session->fKeySignRecover = false;
-                       }
-                       else {
-                               return CKR_KEY_TYPE_INCONSISTENT;
-                       }
-               }
-
-       }
-
-       return CKR_OK;
-}
-
-static
-CK_RV
-_pkcs11_validateSession (
-       IN const pkcs11_session_t pkcs11_session
-) {
-       if (
-               pkcs11_session->timePINExpire != (time_t)0 &&
-               pkcs11_session->timePINExpire < time (NULL)
-       ) {
-               _pkcs11_logout (pkcs11_session);
-       }
-       return CKR_OK;
-}
-
-static
-CK_RV
-_pkcs11_login (
-       IN const pkcs11_session_t pkcs11_session
-) {
-       CK_RV rv = CKR_OK;
-
-
-       ASSERT (pkcs11_session!=NULL);
-
-       _pkcs11_logout (pkcs11_session);
-
-       if (rv == CKR_OK) {
-               rv = _pkcs11_resetSlot (pkcs11_session);
-       }
-
-       if (rv == CKR_OK) {
-               rv = pkcs11_session->provider->f->C_OpenSession (
-                       pkcs11_session->slot,
-                       CKF_SERIAL_SESSION,
-                       NULL_PTR,
-                       NULL_PTR,
-                       &pkcs11_session->session
-               );
-       }
-
-       if (rv == CKR_OK) {
-               int nRetryCount = 0;
-               do {
-                       CK_UTF8CHAR_PTR utfPIN = NULL;
-                       CK_ULONG lPINLength = 0;
-                       char szPIN[1024];
-
-                       /*
-                        * Assume OK for next iteration
-                        */
-                       rv = CKR_OK;
-
-                       if (
-                               rv == CKR_OK &&
-                               !pkcs11_session->fProtectedAuthentication
-                       ) {
-                               if (
-                                       !pkcs11_data->hooks->pin_prompt (
-                                               pkcs11_data->hooks->pin_prompt_data,
-                                               pkcs11_session->szLabel,
-                                               szPIN,
-                                               sizeof (szPIN)
-                                       )
-                               ) {
-                                       rv = CKR_FUNCTION_FAILED;
-                               }
-                               else {
-                                       utfPIN = (CK_UTF8CHAR_PTR)szPIN;
-                                       lPINLength = strlen (szPIN);
-                               }
-                       }
-
-                       if (pkcs11_data->nPINCachePeriod == -1) {
-                               pkcs11_session->timePINExpire = 0;
-                       }
-                       else {
-                               pkcs11_session->timePINExpire = (
-                                       time (NULL) +
-                                       (time_t)pkcs11_data->nPINCachePeriod
-                               );
-                       }
-                       if (
-                               rv == CKR_OK &&
-                               (rv = pkcs11_session->provider->f->C_Login (
-                                       pkcs11_session->session,
-                                       CKU_USER,
-                                       utfPIN,
-                                       lPINLength
-                               )) != CKR_OK
-                       ) {
-                               if (rv == CKR_USER_ALREADY_LOGGED_IN) {
-                                       rv = CKR_OK;
-                               }
-                       }
-
-                       /*
-                        * Clean PIN buffer
-                        */
-                       memset (szPIN, 0, sizeof (szPIN));
-               } while (
-                       ++nRetryCount < 3 &&
-                       (
-                               rv == CKR_PIN_INCORRECT ||
-                               rv == CKR_PIN_INVALID
-                       )
-               );
-       }
-
-       if (
-               rv == CKR_OK &&
-               pkcs11_session->certificate_id != NULL
-       ) {
-               rv = _pkcs11_getObjectById (
-                       pkcs11_session,
-                       CKO_PRIVATE_KEY,
-                       pkcs11_session->certificate_id,
-                       pkcs11_session->certificate_id_size,
-                       &pkcs11_session->key
-               );
-       }
-
-       return rv;
-}
-
-static
-CK_RV
-_pkcs11_logout (
-       IN const pkcs11_session_t pkcs11_session
-) {
-       ASSERT (pkcs11_session!=NULL);
-
-       if (pkcs11_session->session != (CK_SESSION_HANDLE)-1) {
-               pkcs11_session->provider->f->C_Logout (pkcs11_session->session);
-               pkcs11_session->provider->f->C_CloseSession (pkcs11_session->session);
-               pkcs11_session->key = (CK_OBJECT_HANDLE)-1;
-               pkcs11_session->session = (CK_SESSION_HANDLE)-1;
-       }
-
-       return CKR_OK;
-}
-
-
-/*=======================================
- * Simplified PKCS#11 functions
- */
-
-static
-bool
-_pkcs11_hooks_card_prompt_default (
-       IN const void * pData,
-       IN const char * const szLabel
-) {
-       return false;
-}
-
-static
-bool
-_pkcs11_hooks_pin_prompt_default (
-       IN const void * pData,
-       IN const char * const szLabel,
-       OUT char * const szPIN,
-       IN const size_t nMaxPIN
-) {
-       return false;
-}
-
-static
-CK_RV
-pkcs11_initialize () {
-
-       pkcs11_terminate ();
-
-       pkcs11_data = (pkcs11_data_t)malloc (sizeof (struct pkcs11_data_s));
-       if (pkcs11_data == NULL) {
-               return CKR_HOST_MEMORY;
-       }
-
-       memset (pkcs11_data, 0, sizeof (struct pkcs11_data_s));
-
-       pkcs11_data->nPINCachePeriod = -1;
-
-       pkcs11_data->hooks = (pkcs11_hooks_t)malloc (sizeof (struct pkcs11_hooks_s));
-       if (pkcs11_data->hooks == NULL) {
-               return CKR_HOST_MEMORY;
-       }
-
-       memset (pkcs11_data->hooks, 0, sizeof (struct pkcs11_hooks_s));
-
-       pkcs11_data->fInitialized = true;
-
-       pkcs11_setCardPromptHook (_pkcs11_hooks_card_prompt_default, NULL);
-       pkcs11_setPINPromptHook (_pkcs11_hooks_pin_prompt_default, NULL);
-
-       return CKR_OK;
-}
-
-static
-CK_RV
-pkcs11_terminate () {
-
-       if (pkcs11_data != NULL) {
-               pkcs11_provider_t last = NULL;
-
-               for (
-                       ;
-                       pkcs11_data->providers != NULL;
-                       pkcs11_data->providers = pkcs11_data->providers->next
-               ) {
-                       if (last != NULL) {
-                               free (last);
-                       }
-                       last = pkcs11_data->providers;
-               
-                       if (pkcs11_data->providers->szSignMode != NULL) {
-                               free (pkcs11_data->providers->szSignMode);
-                               pkcs11_data->providers->szSignMode = NULL;
-                       }
-       
-                       if (pkcs11_data->providers->fShouldFinalize) {
-                               pkcs11_data->providers->f->C_Finalize (NULL);
-                               pkcs11_data->providers->fShouldFinalize = false;
-                       }
-
-                       if (pkcs11_data->providers->f != NULL) {
-                               pkcs11_data->providers->f = NULL;
-                       }
-       
-                       if (pkcs11_data->providers->hLibrary != NULL) {
-#if defined(WIN32)
-                               FreeLibrary (pkcs11_data->providers->hLibrary);
-#else
-                               dlclose (pkcs11_data->providers->hLibrary);
-#endif
-                               pkcs11_data->providers->hLibrary = NULL;
-                       }
-               }
-
-               if (last != NULL) {
-                       free (last);
-               }
-
-               if (pkcs11_data->hooks != NULL) {
-                       free (pkcs11_data->hooks);
-                       pkcs11_data->hooks = NULL;
-               }
-
-               free (pkcs11_data);
-               pkcs11_data = NULL;
-       }
-
-       return CKR_OK;
-}
-
-static
-CK_RV
-pkcs11_setPINPromptHook (
-       IN const pkcs11_hook_pin_prompt_t hook,
-       IN void * const pData
-) {
-       ASSERT (pkcs11_data!=NULL);
-       ASSERT (pkcs11_data->fInitialized);
-
-       pkcs11_data->hooks->pin_prompt = hook;
-       pkcs11_data->hooks->pin_prompt_data = pData;
-
-       return CKR_OK;
-}
-
-static
-CK_RV
-pkcs11_setCardPromptHook (
-       IN const pkcs11_hook_card_prompt_t hook,
-       IN void * const pData
-) {
-       ASSERT (pkcs11_data!=NULL);
-       ASSERT (pkcs11_data->fInitialized);
-
-       pkcs11_data->hooks->card_prompt = hook;
-       pkcs11_data->hooks->card_prompt_data = pData;
-
-       return CKR_OK;
-}
-
-static
-CK_RV
-pkcs11_setPINCachePeriod (
-       IN const int nPINCachePeriod
-) {
-       ASSERT (pkcs11_data!=NULL);
-       ASSERT (pkcs11_data->fInitialized);
-
-       pkcs11_data->nPINCachePeriod = nPINCachePeriod;
-
-       return CKR_OK;
-}
-
-static
-CK_RV
-pkcs11_addProvider (
-       IN const char * const szProvider,
-       IN const char * const szSignMode
-) {
-       pkcs11_provider_t provider = NULL;
-       CK_C_GetFunctionList gfl = NULL;
-       CK_RV rv = CKR_OK;
-
-       ASSERT (pkcs11_data!=NULL);
-       ASSERT (pkcs11_data->fInitialized);
-       ASSERT (szProvider!=NULL);
-
-       if (
-               rv == CKR_OK &&
-               (provider = (pkcs11_provider_t)malloc (sizeof (struct pkcs11_provider_s))) == NULL
-       ) {
-               rv = CKR_HOST_MEMORY;
-       }
-
-       if (rv == CKR_OK) {
-               memset (provider, 0, sizeof (struct pkcs11_provider_s));
-               if (szSignMode == NULL) {
-                       provider->szSignMode = strdup ("auto");
-               }
-               else {
-                       provider->szSignMode = strdup (szSignMode);
-               }
-               if (provider->szSignMode == NULL) {
-                       rv = CKR_HOST_MEMORY;
-               }
-       }
-               
-       if (rv == CKR_OK) {
-#if defined(WIN32)
-               provider->hLibrary = LoadLibrary (szProvider);
-#else
-               provider->hLibrary = dlopen (szProvider, RTLD_NOW);
-#endif
-               if (provider->hLibrary == NULL) {
-                       rv = CKR_FUNCTION_FAILED;
-               }
-       }
-
-       if (rv == CKR_OK) {
-#if defined(WIN32)
-               gfl = (CK_C_GetFunctionList)GetProcAddress (
-                       provider->hLibrary,
-                       "C_GetFunctionList"
-               );
-#else
-               /*
-                * Make compiler happy!
-                */
-               void *p = dlsym (
-                       provider->hLibrary,
-                       "C_GetFunctionList"
-               );
-               memmove (
-                       &gfl, 
-                       &p,
-                       sizeof (void *)
-               );
-#endif
-               if (gfl == NULL) {
-                       rv = CKR_FUNCTION_FAILED;
-               }
-       }
-
-       if (rv == CKR_OK) {
-               rv = gfl (&provider->f);
-       }
-
-       if (rv == CKR_OK) {
-               if ((rv = provider->f->C_Initialize (NULL)) != CKR_OK) {
-                       if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) {
-                               rv = CKR_OK;
-                       }
-               }
-               else {
-                       provider->fShouldFinalize = true;
-               }
-       }
-
-       if (rv == CKR_OK) {
-               provider->fEnabled = true;
-       }
-
-       if (provider != NULL) {
-               if (pkcs11_data->providers == NULL) {
-                       pkcs11_data->providers = provider;
-               }
-               else {
-                       pkcs11_provider_t last = NULL;
-       
-                       for (
-                               last = pkcs11_data->providers;
-                               last->next != NULL;
-                               last = last->next
-                       );
-                       last->next = provider;
-               }
-       }
-
-       return rv;
-}
-
-static
-CK_RV
-pkcs11_forkFixup () {
-
-       if (pkcs11_data != NULL && pkcs11_data->fInitialized) {
-
-               pkcs11_provider_t current;
-
-               for (
-                       current = pkcs11_data->providers;
-                       current != NULL;
-                       current = current->next
-               ) {
-                       if (current->fEnabled) {
-                               current->f->C_Initialize (NULL);
-                       }
-               }
-       }
-
-       return CKR_OK;
-}
-       
-static
-CK_RV
-pkcs11_createSession (
-       IN const char * const szSlotType,
-       IN const char * const szSlot,
-       IN const char * const szIdType,
-       IN const char * const szId,
-       IN const bool fProtectedAuthentication,
-       OUT pkcs11_session_t * const p_pkcs11_session
-) {
-       pkcs11_session_t pkcs11_session;
-       CK_RV rv = CKR_OK;
-
-       ASSERT (pkcs11_data!=NULL);
-       ASSERT (pkcs11_data->fInitialized);
-       ASSERT (szSlotType!=NULL);
-       ASSERT (szSlot!=NULL);
-       ASSERT (szIdType!=NULL);
-       ASSERT (szId!=NULL);
-       ASSERT (p_pkcs11_session!=NULL);
-       
-       if (
-               rv == CKR_OK &&
-               (pkcs11_session = (pkcs11_session_t)malloc (sizeof (struct pkcs11_session_s))) == NULL
-       ) {
-               rv = CKR_HOST_MEMORY;
-       }
-
-       if (rv == CKR_OK) {
-               *p_pkcs11_session = pkcs11_session;
-               memset (pkcs11_session, 0, sizeof (struct pkcs11_session_s));
-       }
-       
-       if (rv == CKR_OK) {
-               pkcs11_session->key = (CK_OBJECT_HANDLE)-1;
-               pkcs11_session->session = (CK_SESSION_HANDLE)-1;
-               pkcs11_session->fProtectedAuthentication = fProtectedAuthentication;
-       }
-
-       if (rv == CKR_OK) {
-               bool fCancel = false;
-
-               do {
-                       if (!strcmp (szSlotType, "id")) {
-                               rv = _pkcs11_getSlotById (pkcs11_session, szSlot);
-                       }
-                       else if (!strcmp (szSlotType, "name")) {
-                               rv = _pkcs11_getSlotByName (pkcs11_session, szSlot);
-                       }
-                       else if (!strcmp (szSlotType, "label")) {
-                               rv = _pkcs11_getSlotByLabel (pkcs11_session, szSlot);
-                       }
-                       else {
-                               rv = CKR_ARGUMENTS_BAD;
-                       }
-
-                       if (rv == CKR_SLOT_ID_INVALID) {
-                               char szLabel[1024];
-                               snprintf (szLabel, sizeof (szLabel), "SLOT(%s=%s)", szSlotType, szSlot);
-                               fCancel = !pkcs11_data->hooks->card_prompt (
-                                       pkcs11_data->hooks->card_prompt_data,
-                                       szLabel
-                               );
-                       }
-               } while (rv == CKR_SLOT_ID_INVALID && !fCancel);
-       }
-
-       if (rv == CKR_OK) {
-               rv = _pkcs11_setSessionTokenInfo (pkcs11_session);
-       }
-
-       if (rv == CKR_OK) {
-               rv = _pkcs11_login (
-                       pkcs11_session
-               );
-       }
-
-       if (rv == CKR_OK) {
-               rv = _pkcs11_loadCertificate (
-                       pkcs11_session,
-                       szIdType,
-                       szId
-               );
-       }
-
-       if (rv == CKR_OK) {
-               rv = _pkcs11_loadKeyProperties (
-                       pkcs11_session
-               );
-       }
-       
-       /*
-        * Complete missing login process
-        */
-       if (rv == CKR_OK) {
-               rv = _pkcs11_getObjectById (
-                       pkcs11_session,
-                       CKO_PRIVATE_KEY,
-                       pkcs11_session->certificate_id,
-                       pkcs11_session->certificate_id_size,
-                       &pkcs11_session->key
-               );
-       }
-
-       return rv;
-}
-
-CK_RV
-pkcs11_freeSession (
-       IN const pkcs11_session_t pkcs11_session
-) {
-       ASSERT (pkcs11_data!=NULL);
-       ASSERT (pkcs11_data->fInitialized);
-
-       if (pkcs11_session != NULL) {
-               _pkcs11_logout (pkcs11_session);
-
-               if (pkcs11_session->certificate != NULL) {
-                       free (pkcs11_session->certificate);
-               }
-               if (pkcs11_session->certificate_id != NULL) {
-                       free (pkcs11_session->certificate_id);
-               }
-
-               free (pkcs11_session);
-       }
-
-       return CKR_OK;
-}
-
-static
-CK_RV
-pkcs11_sign (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const CK_MECHANISM_TYPE mech_type,
-       IN const unsigned char * const source,
-       IN const size_t source_size,
-       OUT unsigned char * const target,
-       IN OUT size_t * const target_size
-) {
-       CK_MECHANISM mech = {
-               mech_type, NULL, 0
-       };
-       CK_RV rv = CKR_OK;
-       bool fLogonRetry = false;
-       bool fOpSuccess = false;
-
-       ASSERT (pkcs11_data!=NULL);
-       ASSERT (pkcs11_data->fInitialized);
-       ASSERT (pkcs11_session!=NULL);
-       ASSERT (source!=NULL);
-       ASSERT (target_size!=NULL);
-
-       rv = _pkcs11_validateSession (pkcs11_session);
-
-       while (rv == CKR_OK && !fOpSuccess) {
-               rv = pkcs11_session->provider->f->C_SignInit (
-                       pkcs11_session->session,
-                       &mech,
-                       pkcs11_session->key
-               );
-
-               if (rv == CKR_OK) {
-                       fOpSuccess = true;
-               }
-               else {
-                       if (!fLogonRetry) {
-                               fLogonRetry = true;
-                               rv = _pkcs11_login (pkcs11_session);
-                       }
-               }
-       }
-
-       if (rv == CKR_OK) {
-               CK_ULONG size = *target_size;
-               rv = pkcs11_session->provider->f->C_Sign (
-                       pkcs11_session->session,
-                       (CK_BYTE_PTR)source,
-                       source_size,
-                       (CK_BYTE_PTR)target,
-                       &size
-               );
-
-               *target_size = (int)size;
-       }
-
-       return rv;
-}
-
-static
-CK_RV
-pkcs11_signRecover (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const CK_MECHANISM_TYPE mech_type,
-       IN const unsigned char * const source,
-       IN const size_t source_size,
-       OUT unsigned char * const target,
-       IN OUT size_t * const target_size
-) {
-       CK_MECHANISM mech = {
-               mech_type, NULL, 0
-       };
-       CK_RV rv = CKR_OK;
-       bool fLogonRetry = false;
-       bool fOpSuccess = false;
-
-       ASSERT (pkcs11_data!=NULL);
-       ASSERT (pkcs11_data->fInitialized);
-       ASSERT (pkcs11_session!=NULL);
-       ASSERT (source!=NULL);
-       ASSERT (target_size!=NULL);
-
-       rv = _pkcs11_validateSession (pkcs11_session);
-
-       while (rv == CKR_OK && !fOpSuccess) {
-               rv = pkcs11_session->provider->f->C_SignRecoverInit (
-                       pkcs11_session->session,
-                       &mech,
-                       pkcs11_session->key
-               );
-
-               if (rv == CKR_OK) {
-                       fOpSuccess = true;
-               }
-               else {
-                       if (!fLogonRetry) {
-                               fLogonRetry = true;
-                               rv = _pkcs11_login (pkcs11_session);
-                       }
-               }
-       }
-
-       if (rv == CKR_OK) {
-               CK_ULONG size = *target_size;
-               rv = pkcs11_session->provider->f->C_SignRecover (
-                       pkcs11_session->session,
-                       (CK_BYTE_PTR)source,
-                       source_size,
-                       (CK_BYTE_PTR)target,
-                       &size
-               );
-
-               *target_size = (int)size;
-       }
-
-       return rv;
-}
-
-static
-CK_RV
-pkcs11_decrypt (
-       IN const pkcs11_session_t pkcs11_session,
-       IN const CK_MECHANISM_TYPE mech_type,
-       IN const unsigned char * const source,
-       IN const size_t source_size,
-       OUT unsigned char * const target,
-       IN OUT size_t * const target_size
-) {
-       CK_MECHANISM mech = {
-               mech_type, NULL, 0
-       };
-       CK_ULONG size;
-       CK_RV rv = CKR_OK;
-       bool fLogonRetry = false;
-       bool fOpSuccess = false;
-
-       ASSERT (pkcs11_data!=NULL);
-       ASSERT (pkcs11_data->fInitialized);
-       ASSERT (pkcs11_session!=NULL);
-       ASSERT (source!=NULL);
-       ASSERT (target_size!=NULL);
-
-       rv = _pkcs11_validateSession (pkcs11_session);
-
-       while (rv == CKR_OK && !fOpSuccess) {
-               rv = pkcs11_session->provider->f->C_DecryptInit (
-                       pkcs11_session->session,
-                       &mech,
-                       pkcs11_session->key
-               );
-
-               if (rv == CKR_OK) {
-                       fOpSuccess = true;
-               }
-               else {
-                       if (!fLogonRetry) {
-                               fLogonRetry = true;
-                               rv = _pkcs11_login (pkcs11_session);
-                       }
-               }
-       }
-
-       if (rv == CKR_OK) {
-               size = *target_size;
-               rv = pkcs11_session->provider->f->C_Decrypt (
-                       pkcs11_session->session,
-                       (CK_BYTE_PTR)source,
-                       source_size,
-                       (CK_BYTE_PTR)target,
-                       &size
-               );
-
-               *target_size = (int)size;
-       }
-
-       return rv;
-}
-
-static
-CK_RV
-pkcs11_getCertificate (
-       IN const pkcs11_session_t pkcs11_session,
-       OUT unsigned char * const certificate,
-       IN OUT size_t * const certificate_size
-) {
-       ASSERT (pkcs11_data!=NULL);
-       ASSERT (pkcs11_data->fInitialized);
-       ASSERT (certificate_size!=NULL);
-
-       *certificate_size = pkcs11_session->certificate_size;
-
-       if (certificate == NULL) {
-               return CKR_OK;
-       }
-
-       if (*certificate_size > pkcs11_session->certificate_size) {
-               return CKR_BUFFER_TOO_SMALL;
-       }
-
-       memmove (certificate, pkcs11_session->certificate, *certificate_size);  
-
-       return CKR_OK;
-}
-
-static
-char *
-pkcs11_getMessage (
-       IN const int rv
-) {
-       switch (rv) {
-               case CKR_OK: return "CKR_OK";
-               case CKR_CANCEL: return "CKR_CANCEL";
-               case CKR_HOST_MEMORY: return "CKR_HOST_MEMORY";
-               case CKR_SLOT_ID_INVALID: return "CKR_SLOT_ID_INVALID";
-               case CKR_GENERAL_ERROR: return "CKR_GENERAL_ERROR";
-               case CKR_FUNCTION_FAILED: return "CKR_FUNCTION_FAILED";
-               case CKR_ARGUMENTS_BAD: return "CKR_ARGUMENTS_BAD";
-               case CKR_NO_EVENT: return "CKR_NO_EVENT";
-               case CKR_NEED_TO_CREATE_THREADS: return "CKR_NEED_TO_CREATE_THREADS";
-               case CKR_CANT_LOCK: return "CKR_CANT_LOCK";
-               case CKR_ATTRIBUTE_READ_ONLY: return "CKR_ATTRIBUTE_READ_ONLY";
-               case CKR_ATTRIBUTE_SENSITIVE: return "CKR_ATTRIBUTE_SENSITIVE";
-               case CKR_ATTRIBUTE_TYPE_INVALID: return "CKR_ATTRIBUTE_TYPE_INVALID";
-               case CKR_ATTRIBUTE_VALUE_INVALID: return "CKR_ATTRIBUTE_VALUE_INVALID";
-               case CKR_DATA_INVALID: return "CKR_DATA_INVALID";
-               case CKR_DATA_LEN_RANGE: return "CKR_DATA_LEN_RANGE";
-               case CKR_DEVICE_ERROR: return "CKR_DEVICE_ERROR";
-               case CKR_DEVICE_MEMORY: return "CKR_DEVICE_MEMORY";
-               case CKR_DEVICE_REMOVED: return "CKR_DEVICE_REMOVED";
-               case CKR_ENCRYPTED_DATA_INVALID: return "CKR_ENCRYPTED_DATA_INVALID";
-               case CKR_ENCRYPTED_DATA_LEN_RANGE: return "CKR_ENCRYPTED_DATA_LEN_RANGE";
-               case CKR_FUNCTION_CANCELED: return "CKR_FUNCTION_CANCELED";
-               case CKR_FUNCTION_NOT_PARALLEL: return "CKR_FUNCTION_NOT_PARALLEL";
-               case CKR_FUNCTION_NOT_SUPPORTED: return "CKR_FUNCTION_NOT_SUPPORTED";
-               case CKR_KEY_HANDLE_INVALID: return "CKR_KEY_HANDLE_INVALID";
-               case CKR_KEY_SIZE_RANGE: return "CKR_KEY_SIZE_RANGE";
-               case CKR_KEY_TYPE_INCONSISTENT: return "CKR_KEY_TYPE_INCONSISTENT";
-               case CKR_KEY_NOT_NEEDED: return "CKR_KEY_NOT_NEEDED";
-               case CKR_KEY_CHANGED: return "CKR_KEY_CHANGED";
-               case CKR_KEY_NEEDED: return "CKR_KEY_NEEDED";
-               case CKR_KEY_INDIGESTIBLE: return "CKR_KEY_INDIGESTIBLE";
-               case CKR_KEY_FUNCTION_NOT_PERMITTED: return "CKR_KEY_FUNCTION_NOT_PERMITTED";
-               case CKR_KEY_NOT_WRAPPABLE: return "CKR_KEY_NOT_WRAPPABLE";
-               case CKR_KEY_UNEXTRACTABLE: return "CKR_KEY_UNEXTRACTABLE";
-               case CKR_MECHANISM_INVALID: return "CKR_MECHANISM_INVALID";
-               case CKR_MECHANISM_PARAM_INVALID: return "CKR_MECHANISM_PARAM_INVALID";
-               case CKR_OBJECT_HANDLE_INVALID: return "CKR_OBJECT_HANDLE_INVALID";
-               case CKR_OPERATION_ACTIVE: return "CKR_OPERATION_ACTIVE";
-               case CKR_OPERATION_NOT_INITIALIZED: return "CKR_OPERATION_NOT_INITIALIZED";
-               case CKR_PIN_INCORRECT: return "CKR_PIN_INCORRECT";
-               case CKR_PIN_INVALID: return "CKR_PIN_INVALID";
-               case CKR_PIN_LEN_RANGE: return "CKR_PIN_LEN_RANGE";
-               case CKR_PIN_EXPIRED: return "CKR_PIN_EXPIRED";
-               case CKR_PIN_LOCKED: return "CKR_PIN_LOCKED";
-               case CKR_SESSION_CLOSED: return "CKR_SESSION_CLOSED";
-               case CKR_SESSION_COUNT: return "CKR_SESSION_COUNT";
-               case CKR_SESSION_HANDLE_INVALID: return "CKR_SESSION_HANDLE_INVALID";
-               case CKR_SESSION_PARALLEL_NOT_SUPPORTED: return "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
-               case CKR_SESSION_READ_ONLY: return "CKR_SESSION_READ_ONLY";
-               case CKR_SESSION_EXISTS: return "CKR_SESSION_EXISTS";
-               case CKR_SESSION_READ_ONLY_EXISTS: return "CKR_SESSION_READ_ONLY_EXISTS";
-               case CKR_SESSION_READ_WRITE_SO_EXISTS: return "CKR_SESSION_READ_WRITE_SO_EXISTS";
-               case CKR_SIGNATURE_INVALID: return "CKR_SIGNATURE_INVALID";
-               case CKR_SIGNATURE_LEN_RANGE: return "CKR_SIGNATURE_LEN_RANGE";
-               case CKR_TEMPLATE_INCOMPLETE: return "CKR_TEMPLATE_INCOMPLETE";
-               case CKR_TEMPLATE_INCONSISTENT: return "CKR_TEMPLATE_INCONSISTENT";
-               case CKR_TOKEN_NOT_PRESENT: return "CKR_TOKEN_NOT_PRESENT";
-               case CKR_TOKEN_NOT_RECOGNIZED: return "CKR_TOKEN_NOT_RECOGNIZED";
-               case CKR_TOKEN_WRITE_PROTECTED: return "CKR_TOKEN_WRITE_PROTECTED";
-               case CKR_UNWRAPPING_KEY_HANDLE_INVALID: return "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
-               case CKR_UNWRAPPING_KEY_SIZE_RANGE: return "CKR_UNWRAPPING_KEY_SIZE_RANGE";
-               case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT: return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
-               case CKR_USER_ALREADY_LOGGED_IN: return "CKR_USER_ALREADY_LOGGED_IN";
-               case CKR_USER_NOT_LOGGED_IN: return "CKR_USER_NOT_LOGGED_IN";
-               case CKR_USER_PIN_NOT_INITIALIZED: return "CKR_USER_PIN_NOT_INITIALIZED";
-               case CKR_USER_TYPE_INVALID: return "CKR_USER_TYPE_INVALID";
-               case CKR_USER_ANOTHER_ALREADY_LOGGED_IN: return "CKR_USER_ANOTHER_ALREADY_LOGGED_IN";
-               case CKR_USER_TOO_MANY_TYPES: return "CKR_USER_TOO_MANY_TYPES";
-               case CKR_WRAPPED_KEY_INVALID: return "CKR_WRAPPED_KEY_INVALID";
-               case CKR_WRAPPED_KEY_LEN_RANGE: return "CKR_WRAPPED_KEY_LEN_RANGE";
-               case CKR_WRAPPING_KEY_HANDLE_INVALID: return "CKR_WRAPPING_KEY_HANDLE_INVALID";
-               case CKR_WRAPPING_KEY_SIZE_RANGE: return "CKR_WRAPPING_KEY_SIZE_RANGE";
-               case CKR_WRAPPING_KEY_TYPE_INCONSISTENT: return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
-               case CKR_RANDOM_SEED_NOT_SUPPORTED: return "CKR_RANDOM_SEED_NOT_SUPPORTED";
-               case CKR_RANDOM_NO_RNG: return "CKR_RANDOM_NO_RNG";
-               case CKR_DOMAIN_PARAMS_INVALID: return "CKR_DOMAIN_PARAMS_INVALID";
-               case CKR_BUFFER_TOO_SMALL: return "CKR_BUFFER_TOO_SMALL";
-               case CKR_SAVED_STATE_INVALID: return "CKR_SAVED_STATE_INVALID";
-               case CKR_INFORMATION_SENSITIVE: return "CKR_INFORMATION_SENSITIVE";
-               case CKR_STATE_UNSAVEABLE: return "CKR_STATE_UNSAVEABLE";
-               case CKR_CRYPTOKI_NOT_INITIALIZED: return "CKR_CRYPTOKI_NOT_INITIALIZED";
-               case CKR_CRYPTOKI_ALREADY_INITIALIZED: return "CKR_CRYPTOKI_ALREADY_INITIALIZED";
-               case CKR_MUTEX_BAD: return "CKR_MUTEX_BAD";
-               case CKR_MUTEX_NOT_LOCKED: return "CKR_MUTEX_NOT_LOCKED";
-               case CKR_FUNCTION_REJECTED: return "CKR_FUNCTION_REJECTED";
-               case CKR_VENDOR_DEFINED: return "CKR_VENDOR_DEFINED";
-               default: return "Unknown PKCS#11 error";
-       }
-}
-
-/*==========================================
- * openssl interface
- */
-
-typedef struct openssl_session_s {
-       RSA_METHOD smart_rsa;
-       int (*orig_finish)(RSA *rsa);
-       pkcs11_session_t pkcs11_session;
-} *openssl_session_t;
-
-static
-pkcs11_session_t
-_openssl_get_pkcs11_session (const RSA *rsa) {
-       openssl_session_t session;
-       
-       ASSERT (rsa!=NULL);
-       session = (openssl_session_t)RSA_get_app_data (rsa);
-       ASSERT (session!=NULL);
-       ASSERT (session->pkcs11_session!=NULL);
-
-       return session->pkcs11_session;
-}
-
-static
-int
-openssl_pkcs11_priv_enc (
-       int flen,
-       const unsigned char *from,
-       unsigned char *to,
-       RSA *rsa,
-       int padding
-) {
-       msg(M_WARN, "PKCS#11: Private key encryption not supported");
-       return -1;
-}
-
-static
-int
-openssl_pkcs11_priv_dec (
-       int flen, const unsigned char *from,
-       unsigned char *to,
-       RSA *rsa,
-       int padding
-) {
-       pkcs11_session_t pkcs11_session = _openssl_get_pkcs11_session (rsa);
-       CK_RV rv = CKR_OK;
-
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: openssl_pkcs11_priv_dec entered - flen=%d, from=%p, to=%p, rsa=%p, padding=%d",
-               flen,
-               from,
-               to,
-               (void *)rsa,
-               padding
-       );
-
-       ASSERT (from!=NULL);
-       ASSERT (to!=NULL);
-
-       msg (
-               D_SHOW_PKCS11,
-               "PKCS#11: Performing decryption using private key"
-       );
-
-       if (padding != RSA_PKCS1_PADDING) {
-               rv = CKR_ARGUMENTS_BAD;
-       }
-
-       if (
-               rv == CKR_OK &&
-               (rv = pkcs11_decrypt (
-                       pkcs11_session,
-                       CKM_RSA_PKCS,
-                       from,
-                       flen,
-                       to,
-                       (size_t *)&flen
-               )) != CKR_OK
-       ) {
-               msg (M_WARN, "PKCS#11: Cannot decrypt using private key %ld:'%s'", rv, pkcs11_getMessage (rv));
-       }
+#include "pkcs11-helper.h"
+#include "pkcs11.h"
 
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: openssl_pkcs11_priv_dec - return rv=%ld",
-               rv
-       );
-       
-       return rv == CKR_OK ? 1 : -1; 
-}
+#define snprintf openvpn_snprintf
 
 static
-int
-openssl_pkcs11_sign (
-       int type,
-       const unsigned char *m,
-       unsigned int m_len,
-       unsigned char *sigret,
-       unsigned int *siglen,
-       const RSA *rsa
+void
+_pkcs11_openvpn_print (
+       IN const void *pData,
+       IN const char * const szFormat,
+       IN ...
 ) {
-       pkcs11_session_t pkcs11_session = _openssl_get_pkcs11_session (rsa);
-       CK_RV rv = CKR_OK;
-
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: openssl_pkcs11_priv_sign entered - type=%d, m=%p, m_len=%u, signret=%p, signlen=%p, rsa=%p",
-               type,
-               m,
-               m_len,
-               sigret,
-               (void *)siglen,
-               (void *)rsa
-       );
-
-       ASSERT (m!=NULL);
-       ASSERT (siglen!=NULL);
-
-       msg (
-               D_SHOW_PKCS11,
-               "PKCS#11: Performing signature"
-       );
-
-       *siglen = RSA_size(rsa);
-
-       if (pkcs11_session->fKeySignRecover) {
-               if (
-                       (rv = pkcs11_signRecover (
-                               pkcs11_session,
-                               CKM_RSA_PKCS,
-                               m,
-                               m_len,
-                               sigret,
-                               siglen
-                       )) != CKR_OK
-               ) {
-                       msg (M_WARN, "PKCS#11: Cannot perform signature-recover %ld:'%s'", rv, pkcs11_getMessage (rv));
-               }
-       }
-       else {
-               if (
-                       (rv = pkcs11_sign (
-                               pkcs11_session,
-                               CKM_RSA_PKCS,
-                               m,
-                               m_len,
-                               sigret,
-                               siglen
-                       )) != CKR_OK
-               ) {
-                       msg (M_WARN, "PKCS#11: Cannot perform signature %ld:'%s'", rv, pkcs11_getMessage (rv));
-               }
-       }
-
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: openssl_pkcs11_priv_sign - return rv=%ld",
-               rv
-       );
-       
-       return rv == CKR_OK ? 1 : -1; 
-}
-
-static
-int
-openssl_pkcs11_finish(RSA *rsa) {
-       pkcs11_session_t pkcs11_session = _openssl_get_pkcs11_session (rsa);
-       openssl_session_t openssl_session;
-
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: openssl_pkcs11_finish - entered rsa=%p",
-               (void *)rsa
-       );
-
-       openssl_session = (openssl_session_t)RSA_get_app_data (rsa);
-
-       RSA_set_app_data (rsa, NULL);
-       pkcs11_freeSession (pkcs11_session);
-       
-       if (openssl_session->orig_finish != NULL) {
-               openssl_session->orig_finish (rsa);
-
-#ifdef BROKEN_OPENSSL_ENGINE
-               {
-                       /* We get called TWICE here, once for
-                        * releasing the key and also for
-                        * releasing the engine.
-                        * To prevent endless recursion, FIRST
-                        * clear rsa->engine, THEN call engine->finish
-                        */
-                       ENGINE *e = rsa->engine;
-                       rsa->engine = NULL;
-                       if (e) {
-                               ENGINE_finish(e);
-                       }
-               }
-#endif
-       }
-
-       free  (openssl_session);
-
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: openssl_pkcs11_finish - return"
-       );
+       char Buffer[10*1024];
+       va_list args;
        
-       return 1;
-}
-
-void
-openssl_pkcs11_set_rsa(const openssl_session_t openssl_session, RSA *rsa)
-{
-       const RSA_METHOD *def = RSA_get_default_method();
-
-       ASSERT (openssl_session!=NULL);
-       ASSERT (rsa!=NULL);
-
-       memmove (&openssl_session->smart_rsa, def, sizeof(RSA_METHOD));
-
-       openssl_session->orig_finish = def->finish;
-
-       openssl_session->smart_rsa.name = "pkcs11";
-       openssl_session->smart_rsa.rsa_priv_enc = openssl_pkcs11_priv_enc;
-       openssl_session->smart_rsa.rsa_priv_dec = openssl_pkcs11_priv_dec;
-       openssl_session->smart_rsa.rsa_sign = openssl_pkcs11_sign;
-       openssl_session->smart_rsa.finish = openssl_pkcs11_finish;
-       openssl_session->smart_rsa.flags  = RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY;
-
-       RSA_set_method (rsa, &openssl_session->smart_rsa);
-       RSA_set_app_data (rsa, openssl_session);
+       va_start (args, szFormat);
+       vsnprintf (Buffer, sizeof (Buffer), szFormat, args);
+       va_end (args);
+       Buffer[sizeof (Buffer)-1] = 0;
        
-#ifdef BROKEN_OPENSSL_ENGINE
-       if (fOK) {
-               if (!rsa->engine)
-                       rsa->engine = ENGINE_get_default_RSA();
-
-               ENGINE_set_RSA(ENGINE_get_default_RSA(), openssl_session->smart_rsa);
-               msg(M_WARN, "PKCS#11: OpenSSL engine support is broken! Workaround enabled");
-       }
-#endif
+       msg (M_INFO|M_NOPREFIX|M_NOLF, "%s", Buffer);
 }
 
-
-#ifdef BROKEN_OPENSSL_ENGINE
-static void broken_openssl_init() __attribute__ ((constructor));
-static void  broken_openssl_init()
-{
-       SSL_library_init();
-       ENGINE_load_openssl();
-       ENGINE_register_all_RSA();
-}
-#endif
-
-/*==========================================
- * openvpn interface
- */
-
 static
 bool
-_openvpn_pkcs11_card_prompt (
+_pkcs11_openvpn_card_prompt (
        IN const void *pData,
        IN const char * const szLabel
 ) {
@@ -2184,11 +75,11 @@ _openvpn_pkcs11_card_prompt (
 
        ASSERT (szLabel!=NULL);
 
-       openvpn_snprintf (szPrompt, sizeof (szPrompt), "INSERT");
+       openvpn_snprintf (szPrompt, sizeof (szPrompt), "Please insert %s token", szLabel);
 
        token_pass.defined = false;
        token_pass.nocache = true;
-       get_user_pass (&token_pass, NULL, true, szPrompt, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE);
+       get_user_pass (&token_pass, NULL, szPrompt, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK);
        strncpynt (szTemp, token_pass.password, sizeof (szTemp));
        purge_user_pass (&token_pass, true);
 
@@ -2202,7 +93,7 @@ _openvpn_pkcs11_card_prompt (
 
 static
 bool
-_openvpn_pkcs11_pin_prompt (
+_pkcs11_openvpn_pin_prompt (
        IN const void *pData,
        IN const char * const szLabel,
        OUT char * const szPIN,
@@ -2217,7 +108,7 @@ _openvpn_pkcs11_pin_prompt (
 
        token_pass.defined = false;
        token_pass.nocache = true;
-       get_user_pass (&token_pass, NULL, true, szPrompt, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE);
+       get_user_pass (&token_pass, NULL, szPrompt, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY);
        strncpynt (szPIN, token_pass.password, nMaxPIN);
        purge_user_pass (&token_pass, true);
 
@@ -2230,213 +121,166 @@ _openvpn_pkcs11_pin_prompt (
 }
 
 void
-init_pkcs11 (
+pkcs11_initialize (
        const int nPINCachePeriod
 ) {
        CK_RV rv;
 
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: init_pkcs11 - entered"
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11_initialize - entered"
        );
 
-       if ((rv = pkcs11_initialize ()) != CKR_OK) {
-               msg (M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11_getMessage (rv));
+       if ((rv = pkcs11h_initialize ()) != CKR_OK) {
+               PKCS11LOG (PKCS11_LOG_ERROR, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage (rv));
        }
-/*Until REQUEST/REPLY interface.
-       if ((rv = pkcs11_setCardPromptHook (_openvpn_pkcs11_card_prompt, NULL)) != CKR_OK) {
-               msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11_getMessage (rv));
+
+       if ((rv = pkcs11h_setCardPromptHook (_pkcs11_openvpn_card_prompt, NULL)) != CKR_OK) {
+               PKCS11LOG (PKCS11_LOG_ERROR, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
        }
-*/
-       if ((rv = pkcs11_setPINPromptHook (_openvpn_pkcs11_pin_prompt, NULL)) != CKR_OK) {
-               msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11_getMessage (rv));
+
+       if ((rv = pkcs11h_setPINPromptHook (_pkcs11_openvpn_pin_prompt, NULL)) != CKR_OK) {
+               PKCS11LOG (PKCS11_LOG_ERROR, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
        }
 
-       if ((rv = pkcs11_setPINCachePeriod (nPINCachePeriod)) != CKR_OK) {
-               msg (M_FATAL, "PKCS#11: Cannot set PIN cache period %ld-'%s'", rv, pkcs11_getMessage (rv));
+       if ((rv = pkcs11h_setPINCachePeriod (nPINCachePeriod)) != CKR_OK) {
+               PKCS11LOG (PKCS11_LOG_ERROR, "PKCS#11: Cannot set PIN cache period %ld-'%s'", rv, pkcs11h_getMessage (rv));
        }
 
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: init_pkcs11 - return"
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11_initialize - return"
        );
 }
 
 void
-free_pkcs11 () {
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: free_pkcs11 - entered"
+pkcs11_terminate () {
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11_terminate - entered"
        );
 
-       pkcs11_terminate ();
+       pkcs11h_terminate ();
 
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: free_pkcs11 - return"
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11_terminate - return"
        );
 }
 
 void
-fork_fix_pkcs11 () {
-       pkcs11_forkFixup ();
+pkcs11_forkFixup () {
+       pkcs11h_forkFixup ();
 }
 
 void
-add_pkcs11 (
+pkcs11_addProvider (
        IN const char * const provider,
        IN const char * const sign_mode
 ) {
        CK_RV rv;
 
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: add_pkcs11 - entered - provider='%s', sign_mode='%s'",
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11_addProvider - entered - provider='%s', sign_mode='%s'",
                provider,
                sign_mode == NULL ? "default" : sign_mode
        );
 
-       msg (
-               M_INFO,
+       PKCS11LOG (
+               PKCS11_LOG_INFO,
                "PKCS#11: Adding PKCS#11 provider '%s'",
                provider
        );
 
-       if ((rv = pkcs11_addProvider (provider, sign_mode)) != CKR_OK) {
-               msg (M_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11_getMessage (rv));
+       if ((rv = pkcs11h_addProvider (provider, sign_mode)) != CKR_OK) {
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage (rv));
        }
 
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: add_pkcs11 - return"
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: pkcs11_addProvider - return"
        );
 }
 
 int
 SSL_CTX_use_pkcs11 (
        IN OUT SSL_CTX * const ssl_ctx,
-       IN const char * const pkcs11_slot_type,
-       IN const char * const pkcs11_slot,
-       IN const char * const pkcs11_id_type,
-       IN const char * const pkcs11_id,
-       IN const bool pkcs11_protected_authentication
+       IN const char * const pkcs11h_slot_type,
+       IN const char * const pkcs11h_slot,
+       IN const char * const pkcs11h_id_type,
+       IN const char * const pkcs11h_id,
+       IN const bool pkcs11h_protected_authentication
 ) {
        X509 *x509 = NULL;
        RSA *rsa = NULL;
-       EVP_PKEY *pubkey = NULL;
-       openssl_session_t openssl_session = NULL;
-       bool fShouldFreeOpenSSLSession = true;
+       pkcs11h_openssl_session_t pkcs11h_openssl_session = NULL;
        CK_RV rv = CKR_OK;
 
-       unsigned char certificate[10*1024];
-       size_t certificate_size;
-       unsigned char *p;
        bool fOK = true;
 
-       msg (
-               D_PKCS11_DEBUG,
-               "PKCS#11: SSL_CTX_use_pkcs11 - entered - ssl_ctx=%p, pkcs11_slot_type='%s', pkcs11_slot='%s', pkcs11_id_type='%s', pkcs11_id='%s', pkcs11_protected_authentication=%d",
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
+               "PKCS#11: SSL_CTX_use_pkcs11 - entered - ssl_ctx=%p, pkcs11h_slot_type='%s', pkcs11h_slot='%s', pkcs11h_id_type='%s', pkcs11h_id='%s', pkcs11h_protected_authentication=%d",
                (void *)ssl_ctx,
-               pkcs11_slot_type,
-               pkcs11_slot,
-               pkcs11_id_type,
-               pkcs11_id,
-               pkcs11_protected_authentication ? 1 : 0
+               pkcs11h_slot_type,
+               pkcs11h_slot,
+               pkcs11h_id_type,
+               pkcs11h_id,
+               pkcs11h_protected_authentication ? 1 : 0
        );
 
-       ASSERT (ssl_ctx!=NULL);
-       ASSERT (pkcs11_slot_type!=NULL);
-       ASSERT (pkcs11_slot!=NULL);
-       ASSERT (pkcs11_id_type!=NULL);
-       ASSERT (pkcs11_id!=NULL);
+       PKCS11ASSERT (ssl_ctx!=NULL);
+       PKCS11ASSERT (pkcs11h_slot_type!=NULL);
+       PKCS11ASSERT (pkcs11h_slot!=NULL);
+       PKCS11ASSERT (pkcs11h_id_type!=NULL);
+       PKCS11ASSERT (pkcs11h_id!=NULL);
 
        if (
                fOK &&
-               (openssl_session = (openssl_session_t)malloc (sizeof (struct openssl_session_s))) == NULL
+               (pkcs11h_openssl_session = pkcs11h_openssl_createSession (false)) == NULL
        ) {
                fOK = false;
-               msg (M_WARN, "PKCS#11: Cannot allocate memory");
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot initialize openssh session");
        }
 
-       if (fOK) {
-               memset (openssl_session, 0, sizeof (struct openssl_session_s));
-       }
-       
        if (
                fOK &&
-               (rv = pkcs11_createSession (
-                       pkcs11_slot_type,
-                       pkcs11_slot,
-                       pkcs11_id_type,
-                       pkcs11_id,
-                       pkcs11_protected_authentication,
-                       &openssl_session->pkcs11_session
+               (rv = pkcs11h_createSession (
+                       pkcs11h_slot_type,
+                       pkcs11h_slot,
+                       pkcs11h_id_type,
+                       pkcs11h_id,
+                       pkcs11h_protected_authentication,
+                       &pkcs11h_openssl_session->pkcs11h_session
                )) != CKR_OK
        ) {
                fOK = false;
-               msg (M_WARN, "PKCS#11: Cannot set parameters %ld-'%s'", rv, pkcs11_getMessage (rv));
-       }
-
-       if (
-               fOK &&
-               (x509 = X509_new ()) == NULL
-       ) {
-               fOK = false;
-               msg (M_WARN, "PKCS#11: Unable to allocate certificate object");
-       }
-
-       certificate_size = sizeof (certificate);
-       if (
-               fOK &&
-               (rv = pkcs11_getCertificate (
-                       openssl_session->pkcs11_session,
-                       certificate,
-                       &certificate_size
-               )) != CKR_OK
-       ) { 
-               fOK = false;
-               msg (M_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11_getMessage (rv));
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot set parameters %ld-'%s'", rv, pkcs11h_getMessage (rv));
        }
 
-       p = certificate;
        if (
                fOK &&
-               !d2i_X509 (&x509, &p, certificate_size)
+               (rsa = pkcs11h_openssl_getRSA (pkcs11h_openssl_session)) == NULL
        ) {
                fOK = false;
-               msg (M_WARN, "PKCS#11: Unable to parse X.509 certificate");
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Unable get rsa object");
        }
 
        if (
                fOK &&
-               (pubkey = X509_get_pubkey (x509)) == NULL
-       ) {
-               fOK = false;
-               msg (M_WARN, "PKCS#11: Cannot get public key");
-       }
-       
-       if (
-               fOK &&
-               pubkey->type != EVP_PKEY_RSA
+               (x509 = pkcs11h_openssl_getX509 (pkcs11h_openssl_session)) == NULL
        ) {
                fOK = false;
-               msg (M_WARN, "PKCS#11: Invalid public key algorithm");
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Unable get certificate object");
        }
 
        if (
                fOK &&
-               (rsa = EVP_PKEY_get1_RSA (pubkey)) == NULL
+               !SSL_CTX_use_RSAPrivateKey (ssl_ctx, rsa)
        ) {
                fOK = false;
-               msg (M_WARN, "PKCS#11: Cannot get RSA key");
-       }
-
-       if (fOK) {
-               openssl_pkcs11_set_rsa (openssl_session, rsa);
-               rsa->flags |= RSA_FLAG_SIGN_VER;
-
-               /* it will be freed when rsa usage count will be zero */
-               fShouldFreeOpenSSLSession = false;
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot set private key for openssl");
        }
 
        if (
@@ -2444,25 +288,13 @@ SSL_CTX_use_pkcs11 (
                !SSL_CTX_use_certificate (ssl_ctx, x509)
        ) {
                fOK = false;
-               msg (M_WARN, "PKCS#11: Cannot set certificate for openssl");
-       }
-
-       if (
-               fOK &&
-               !SSL_CTX_use_RSAPrivateKey (ssl_ctx, rsa)
-       ) {
-               fOK = false;
-               msg (M_WARN, "PKCS#11: Cannot set private key for openssl");
+               PKCS11LOG (PKCS11_LOG_WARN, "PKCS#11: Cannot set certificate for openssl");
        }
 
        /*
         * openssl objects have reference
         * count, so release them
         */
-       if (pubkey != NULL) {
-               EVP_PKEY_free (pubkey);
-               pubkey = NULL;
-       }
 
        if (x509 != NULL) {
                X509_free (x509);
@@ -2473,19 +305,14 @@ SSL_CTX_use_pkcs11 (
                RSA_free (rsa);
                rsa = NULL;
        }
-
-       if (fShouldFreeOpenSSLSession) {
-               if (openssl_session != NULL) {
-                       if (openssl_session->pkcs11_session != NULL) {
-                               pkcs11_freeSession (openssl_session->pkcs11_session);
-                       }
-                       free (openssl_session);
-                       openssl_session = NULL;
-               }
+       
+       if (pkcs11h_openssl_session != NULL) {
+               pkcs11h_openssl_freeSession (pkcs11h_openssl_session);
+               pkcs11h_openssl_session = NULL;
        }
 
-       msg (
-               D_PKCS11_DEBUG,
+       PKCS11LOG (
+               PKCS11_LOG_DEBUG2,
                "PKCS#11: SSL_CTX_use_pkcs11 - return fOK=%d, rv=%ld",
                fOK ? 1 : 0,
                rv
@@ -2496,460 +323,28 @@ SSL_CTX_use_pkcs11 (
 
 void
 show_pkcs11_slots (
-       IN const int msglev,
-       IN const int warnlev,
-       IN const char * const provider
-) {
-       CK_INFO info;
-       CK_SLOT_ID slots[1024];
-       CK_ULONG slotnum;
-       CK_SLOT_ID s;
-       CK_RV rv;
-
-       pkcs11_provider_t pkcs11_provider;
-
-       ASSERT (provider!=NULL);
-
-       if (
-               (rv = pkcs11_initialize ()) != CKR_OK
-       ) {
-               msg (M_FATAL, "PKCS#11: Cannot initialize interface %ld-'%s'", rv, pkcs11_getMessage (rv));
-       }
-
-       if (
-               (rv = pkcs11_addProvider (provider, NULL)) != CKR_OK
-       ) {
-               msg (M_FATAL, "PKCS#11: Cannot initialize provider %ld-'%s'", rv, pkcs11_getMessage (rv));
-       }
-
-       /*
-        * our provider is head
-        */
-       pkcs11_provider = pkcs11_data->providers;
-       if (pkcs11_provider == NULL || !pkcs11_provider->fEnabled) {
-               msg (M_FATAL, "PKCS#11: Cannot get provider %ld-'%s'", rv, pkcs11_getMessage (rv));
-       }
-
-       if (
-               (rv = pkcs11_provider->f->C_GetInfo (&info)) != CKR_OK
-       ) {
-               msg (warnlev, "PKCS#11: Cannot get PKCS#11 provider information %ld-'%s'", rv, pkcs11_getMessage (rv));
-       }
-       else {
-               char szManufacturerID[sizeof (info.manufacturerID)+1];
-
-               _fixupFixedString (
-                       (char *)info.manufacturerID,
-                       szManufacturerID,
-                       sizeof (info.manufacturerID)
-               );
-
-               msg (
-                       msglev,
-                       (
-                               "Provider Information:\n"
-                               "\tcryptokiVersion: %u.%u\n"
-                               "\tmanufacturerID: %s\n"
-                               "\tflags: %d\n"
-                       ),
-                       info.cryptokiVersion.major,
-                       info.cryptokiVersion.minor,
-                       szManufacturerID,
-                       (unsigned)info.flags
-               );
-       }
-       
-       slotnum = sizeof (slots) / sizeof (CK_SLOT_ID);
-       if (
-               (rv = pkcs11_provider->f->C_GetSlotList (
-                       FALSE,
-                       slots,
-                       &slotnum
-               )) != CKR_OK
-       ) {
-               msg (warnlev, "PKCS#11: Cannot get slot list %ld-'%s'", rv, pkcs11_getMessage (rv));
-       }
-       else {
-               msg (
-                       msglev,
-                       (
-                               "The following slots are available for use with this provider.\n"
-                               "Each slot shown below may be used as a parameter to a\n"
-                               "--pkcs11-slot-type and --pkcs11-slot options.\n"
-                               "\n"
-                               "Slots: (id - name)"
-                       )
-               );
-               for (s=0;s<slotnum;s++) {
-                       CK_SLOT_INFO info;
-
-                       if (
-                               (rv = pkcs11_provider->f->C_GetSlotInfo (
-                                       slots[s],
-                                       &info
-                               )) == CKR_OK
-                       ) {
-                               char szCurrentName[sizeof (info.slotDescription)+1];
-                       
-                               _fixupFixedString (
-                                       (char *)info.slotDescription,
-                                       szCurrentName,
-                                       sizeof (info.slotDescription)
-                               );
-
-                               msg (msglev, "\t%lu - %s", slots[s], szCurrentName);
-                       }
-               }
-       }
-
-       pkcs11_terminate ();
-}
-
-static
-bool
-_show_pkcs11_objects_pin_prompt (
-       IN const void *pData,
-       IN const char * const szLabel,
-       OUT char * const szPIN,
-       IN const size_t nMaxPIN
+       const char * const provider
 ) {
-       strncpy (szPIN, (char *)pData, nMaxPIN);
-       return true;
+       pkcs11h_standalone_dump_slots (
+               _pkcs11_openvpn_print,
+               NULL,
+               provider
+       );
 }
 
 void
 show_pkcs11_objects (
-       IN const int msglev,
-       IN const int warnlev,
-       IN const char * const provider,
-       IN const char * const slot,
-       IN const char * const pin
+       const char * const provider,
+       const char * const slot,
+       const char * const pin
 ) {
-       CK_OBJECT_HANDLE objects[10];
-       CK_SESSION_HANDLE session;
-       CK_ULONG objects_found;
-       CK_TOKEN_INFO info;
-       CK_SLOT_ID s;
-       CK_RV rv;
-
-       pkcs11_provider_t pkcs11_provider;
-
-       ASSERT (provider!=NULL);
-       ASSERT (slot!=NULL);
-       ASSERT (pin!=NULL);
-
-       s = atoi (slot);
-
-       if (
-               (rv = pkcs11_initialize ()) != CKR_OK
-       ) {
-               msg (M_FATAL, "PKCS#11: Cannot initialize interface %ld-'%s'", rv, pkcs11_getMessage (rv));
-       }
-
-       if (
-               (rv = pkcs11_setPINPromptHook (_show_pkcs11_objects_pin_prompt, (void *)pin)) != CKR_OK
-       ) {
-               msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11_getMessage (rv));
-       }
-
-       if (
-               (rv = pkcs11_addProvider (provider, NULL)) != CKR_OK
-       ) {
-               msg (M_FATAL, "PKCS#11: Cannot initialize provider %ld-'%s'", rv, pkcs11_getMessage (rv));
-       }
-
-       /*
-        * our provider is head
-        */
-       pkcs11_provider = pkcs11_data->providers;
-       if (pkcs11_provider == NULL || !pkcs11_provider->fEnabled) {
-               msg (M_FATAL, "PKCS#11: Cannot get provider %ld-'%s'", rv, pkcs11_getMessage (rv));
-       }
-
-       if (
-               (rv = pkcs11_provider->f->C_GetTokenInfo (
-                       s,
-                       &info
-               )) != CKR_OK
-       ) {
-               msg (warnlev, "PKCS#11: Cannot get token information for slot %ld %ld-'%s'", s, rv, pkcs11_getMessage (rv));
-       }
-       else {
-               char szLabel[sizeof (info.label)+1];
-               char szManufacturerID[sizeof (info.manufacturerID)+1];
-               char szModel[sizeof (info.model)+1];
-               char szSerialNumber[sizeof (info.serialNumber)+1];
-               
-               _fixupFixedString (
-                       (char *)info.label,
-                       szLabel,
-                       sizeof (info.label)
-               );
-               _fixupFixedString (
-                       (char *)info.manufacturerID,
-                       szManufacturerID,
-                       sizeof (info.manufacturerID)
-               );
-               _fixupFixedString (
-                       (char *)info.model,
-                       szModel,
-                       sizeof (info.model)
-               );
-               _fixupFixedString (
-                       (char *)info.serialNumber,
-                       szSerialNumber,
-                       sizeof (info.serialNumber)
-               );
-
-               msg (
-                       msglev,
-                       (
-                               "Token Information:\n"
-                               "\tlabel:\t\t%s\n"
-                               "\tmanufacturerID:\t%s\n"
-                               "\tmodel:\t\t%s\n"
-                               "\tserialNumber:\t%s\n"
-                               "\tflags:\t\t%08x\n"
-                               "\n"
-                               "You can access this token using\n"
-                               "--pkcs11-slot-type \"label\" --pkcs11-slot \"%s\" options.\n"
-                       ),
-                       szLabel,
-                       szManufacturerID,
-                       szModel,
-                       szSerialNumber,
-                       (unsigned)info.flags,
-                       szLabel
-               );
-       }
-
-       if (
-               (rv = pkcs11_provider->f->C_OpenSession (
-                       s,
-                       CKF_SERIAL_SESSION,
-                       NULL_PTR,
-                       NULL_PTR,
-                       &session
-               )) != CKR_OK
-       ) {
-               msg (M_FATAL, "PKCS#11: Cannot open session to slot %ld %ld-'%s'", s, rv, pkcs11_getMessage (rv));
-       }
-
-       if (
-               (rv = pkcs11_provider->f->C_Login (
-                       session,
-                       CKU_USER,
-                       (CK_CHAR_PTR)pin,
-                       (CK_ULONG)strlen (pin)
-               )) != CKR_OK &&
-               rv != CKR_USER_ALREADY_LOGGED_IN
-       ) {
-               msg (M_FATAL, "PKCS#11: Cannot login to token on slot %ld %ld-'%s'", s, rv, pkcs11_getMessage (rv));
-       }
-
-       if (
-               (rv = pkcs11_provider->f->C_FindObjectsInit (
-                       session,
-                       NULL,
-                       0
-               )) != CKR_OK
-       ) {
-               msg (M_FATAL, "PKCS#11: Cannot query objects for token on slot %ld %ld-'%s'", s, rv, pkcs11_getMessage (rv));
-       }
-
-       msg (
-               msglev,
-               "The following objects are available for use with this token.\n"
-               "Each object shown below may be used as a parameter to\n"
-               "--pkcs11-id-type and --pkcs11-id options.\n"
+       pkcs11h_standalone_dump_objects (
+               _pkcs11_openvpn_print,
+               NULL,
+               provider,
+               slot,
+               pin
        );
-
-       while (
-               (rv = pkcs11_provider->f->C_FindObjects (
-                       session,
-                       objects,
-                       sizeof (objects) / sizeof (CK_OBJECT_HANDLE),
-                       &objects_found
-               )) == CKR_OK &&
-               objects_found > 0
-       ) { 
-               CK_ULONG i;
-               
-               for (i=0;i<objects_found;i++) {
-                       CK_OBJECT_CLASS attrs_class;
-                       unsigned char attrs_id[PKCS11_MAX_ATTRIBUTE_SIZE];
-                       unsigned char attrs_label[PKCS11_MAX_ATTRIBUTE_SIZE];
-                       CK_ATTRIBUTE attrs[] = {
-                               {CKA_CLASS, &attrs_class, sizeof (attrs_class)},
-                               {CKA_ID, attrs_id, sizeof (attrs_id)},
-                               {CKA_LABEL, attrs_label, sizeof (attrs_label)-1}
-                       };
-       
-                       if (
-                               pkcs11_provider->f->C_GetAttributeValue (
-                                       session,
-                                       objects[i],
-                                       attrs,
-                                       sizeof (attrs) / sizeof (CK_ATTRIBUTE)
-                               ) == CKR_OK
-                       ) {
-                               int id_len = attrs[1].ulValueLen;
-                               int j;
-                                       
-                               attrs_label[attrs[2].ulValueLen] = 0;
-
-                               msg (
-                                       msglev,
-                                       (
-                                               "Object\n"
-                                               "\tLabel:\t\t%s\n"
-                                               "\tId:"
-                                       ),
-                                       attrs_label
-                               );
-
-                                       
-                               for (j=0;j<id_len;j+=16) {
-                                       char szLine[3*16+1];
-                                       int k;
-
-                                       szLine[0] = '\0';
-                                       for (k=0;k<16 && j+k<id_len;k++) {
-                                               sprintf (szLine+strlen (szLine), "%02x ", attrs_id[j+k]);
-                                       }
-
-                                       msg (msglev, "\t\t%s", szLine);
-                               }
-
-                               if (attrs_class == CKO_CERTIFICATE) {
-                                       unsigned char certificate[PKCS11_MAX_ATTRIBUTE_SIZE];
-                                       CK_ATTRIBUTE attrs_cert[] = {
-                                               {CKA_VALUE, certificate, sizeof (certificate)}
-                                       };
-
-                                       msg (msglev, "\tType:\t\tCertificate");
-
-                                       if (
-                                               pkcs11_provider->f->C_GetAttributeValue (
-                                                       session,
-                                                       objects[i],
-                                                       attrs_cert,
-                                                       sizeof (attrs_cert) / sizeof (CK_ATTRIBUTE)
-                                               ) == CKR_OK
-                                       ) {
-                                               X509 *x509 = NULL;
-                                               BIO *bioSerial = NULL;
-
-                                               char szSubject[1024];
-                                               char szSerial[1024];
-                                               char szNotBefore[1024];
-
-                                               szSubject[0] = '\0';
-                                               szSerial[0] = '\0';
-                                               szNotBefore[0] = '\0';
-
-                                               if ((x509 = X509_new ()) == NULL) {
-                                                       msg (warnlev, "Cannot create x509 context");
-                                               }
-                                               else {
-                                                       unsigned char *p;
-
-                                                       p = certificate;
-                                                       if (d2i_X509 (&x509, &p, attrs_cert[0].ulValueLen)) {
-
-                                                               ASN1_TIME *notBefore = X509_get_notBefore (x509);
-                                                               if (notBefore != NULL && notBefore->length < (int) sizeof (szNotBefore) - 1) {
-                                                                       memmove (szNotBefore, notBefore->data, notBefore->length);
-                                                                       szNotBefore[notBefore->length] = '\0';
-                                                               }
-
-                                                               X509_NAME_oneline (
-                                                                       X509_get_subject_name (x509),
-                                                                       szSubject,
-                                                                       sizeof (szSubject)
-                                                               );
-                                                               szSubject[sizeof (szSubject) - 1] = '\0';
-                                                       }
-                                               }
-
-                                               if ((bioSerial = BIO_new (BIO_s_mem ())) == NULL) {
-                                                       msg (warnlev, "Cannot create BIO context");
-                                               }
-                                               else {
-                                                       int n;
-
-                                                       i2a_ASN1_INTEGER(bioSerial, X509_get_serialNumber (x509));
-                                                       n = BIO_read (bioSerial, szSerial, sizeof (szSerial)-1);
-                                                       if (n<0) {
-                                                               szSerial[0] = '\0';
-                                                       }
-                                                       else {
-                                                               szSerial[n] = '\0';
-                                                       }
-                                               }
-
-
-                                               if (x509 != NULL) {
-                                                       X509_free (x509);
-                                                       x509 = NULL;
-                                               }
-                                               if (bioSerial != NULL) {
-                                                       BIO_free_all (bioSerial);
-                                                       bioSerial = NULL;
-                                               }
-
-                                               msg (
-                                                       msglev,
-                                                       (
-                                                               "\tsubject:\t%s\n"
-                                                               "\tserialNumber:\t%s\n"
-                                                               "\tnotBefore:\t%s"
-                                                       ),
-                                                       szSubject,
-                                                       szSerial,
-                                                       szNotBefore
-                                               );
-                                       }
-                               }
-                               else if (attrs_class == CKO_PRIVATE_KEY) {
-                                       CK_BBOOL sign_recover;
-                                       CK_BBOOL sign;
-                                       CK_ATTRIBUTE attrs_key[] = {
-                                               {CKA_SIGN, &sign_recover, sizeof (sign_recover)},
-                                               {CKA_SIGN_RECOVER, &sign, sizeof (sign)}
-                                       };
-
-                                       msg (msglev, "\tType:\t\tPrivate Key");
-
-                                       if (
-                                               pkcs11_provider->f->C_GetAttributeValue (
-                                                       session,
-                                                       objects[i],
-                                                       attrs_key,
-                                                       sizeof (attrs_key) / sizeof (CK_ATTRIBUTE)
-                                               ) == CKR_OK
-                                       ) {
-                                               msg (
-                                                       msglev,
-                                                       (
-                                                               "\tSign:\t\t%s\n"
-                                                               "\tSign Recover:\t%s"
-                                                       ),
-                                                       sign ? "TRUE" : "FALSE",
-                                                       sign_recover ? "TRUE" : "FALSE"
-                                               );
-                                       }
-                               }
-                               else {
-                                       msg (msglev, "\tType:\t\tUnsupported");
-                               }
-                       }
-               }
-       }
-       pkcs11_provider->f->C_FindObjectsFinal (session);
-       pkcs11_provider->f->C_Logout (session);
-       pkcs11_provider->f->C_CloseSession (session);
-       pkcs11_terminate ();
 }
 
 #else
index a6f0f8954d3ea0e04a5748872f28a3c636fa6349..4e4a95b85312e49935e7c7147691e43acefb453e 100644 (file)
--- a/pkcs11.h
+++ b/pkcs11.h
 #include <openssl/ssl.h>
 
 void
-init_pkcs11 (
+pkcs11_initialize (
        const int nPINCachePeriod
 );
 
 void
-free_pkcs11 ();
+pkcs11_terminate ();
 
 void
-fork_fix_pkcs11 ();
+pkcs11_forkFixup ();
 
 void
-add_pkcs11 (
+pkcs11_addProvider (
        const char * const provider,
        const char * const sign_mode
 );
@@ -58,15 +58,11 @@ SSL_CTX_use_pkcs11 (
 
 void
 show_pkcs11_slots (
-       const int msglev,
-       const int warnlev,
        const char * const provider
 );
 
 void
 show_pkcs11_objects (
-       const int msglev,
-       const int warnlev,
        const char * const provider,
        const char * const slot,
        const char * const pin
diff --git a/proxy.c b/proxy.c
index 5c8521aba9eab869479713fe4b5fbb54b4c4f6f1..091173357c1354d1e1e69ccd7145f7de2d35795f 100644 (file)
--- a/proxy.c
+++ b/proxy.c
@@ -280,7 +280,6 @@ new_http_proxy (const struct http_proxy_options *o,
     {
       get_user_pass (&static_proxy_user_pass,
                     o->auth_file,
-                    false,
                     "HTTP Proxy",
                     GET_USER_PASS_MANAGEMENT);
       p->up = static_proxy_user_pass;
diff --git a/ssl.c b/ssl.c
index dc2381ead43e775bc446b9834405645575f7622a..8a7f0a321999b8186f92da732d02d1de5f43b76d 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -266,7 +266,7 @@ void
 pem_password_setup (const char *auth_file)
 {
   if (!strlen (passbuf.password))
-    get_user_pass (&passbuf, auth_file, true, UP_TYPE_PRIVATE_KEY, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE);
+    get_user_pass (&passbuf, auth_file, UP_TYPE_PRIVATE_KEY, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_PASSWORD_ONLY);
 }
 
 int
@@ -296,7 +296,7 @@ auth_user_pass_setup (const char *auth_file)
 {
   auth_user_pass_enabled = true;
   if (!auth_user_pass.defined)
-    get_user_pass (&auth_user_pass, auth_file, false, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE);
+    get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE);
 }
 
 /*