+diff -urNp openssh-4.4p1/authfd.c openssh-4.4p1+pkcs11-0.17/authfd.c
+--- openssh-4.4p1/authfd.c 2006-09-01 08:38:36.000000000 +0300
++++ openssh-4.4p1+pkcs11-0.17/authfd.c 2006-10-12 13:59:59.000000000 +0200
+@@ -669,3 +669,79 @@ decode_reply(int type)
+ /* NOTREACHED */
+ return 0;
+ }
++
++#ifndef SSH_PKCS11_DISABLED
++
++int
++ssh_pkcs11_add_provider (AuthenticationConnection *auth, const char *provider,
++ int protected_authentication, const char *sign_mode, int cert_private)
++{
++ Buffer msg;
++ int type;
++ int code;
++
++ code = SSH_AGENTC_PKCS11_ADD_PROVIDER;
++
++ buffer_init(&msg);
++ buffer_put_char(&msg, code);
++ buffer_put_cstring(&msg, provider);
++ buffer_put_int(&msg, protected_authentication);
++ buffer_put_cstring(&msg, sign_mode == NULL ? "auto" : sign_mode);
++ buffer_put_int(&msg, cert_private);
++
++ if (ssh_request_reply(auth, &msg, &msg) == 0) {
++ buffer_free(&msg);
++ return 0;
++ }
++ type = buffer_get_char(&msg);
++ buffer_free(&msg);
++ return decode_reply(type);
++}
++
++int
++ssh_pkcs11_id (AuthenticationConnection *auth, const pkcs11_identity *id, int remove)
++{
++ Buffer msg;
++ int type;
++ int code;
++
++ code = remove ? SSH_AGENTC_PKCS11_REMOVE_ID : SSH_AGENTC_PKCS11_ADD_ID;
++
++ buffer_init(&msg);
++ buffer_put_char(&msg, code);
++ buffer_put_cstring(&msg, id->id);
++ buffer_put_int(&msg, id->pin_cache_period);
++ buffer_put_cstring(&msg, id->cert_file == NULL ? "" : id->cert_file);
++
++ if (ssh_request_reply(auth, &msg, &msg) == 0) {
++ buffer_free(&msg);
++ return 0;
++ }
++ type = buffer_get_char(&msg);
++ buffer_free(&msg);
++ return decode_reply(type);
++}
++
++int
++ssh_pkcs11_set_ask_pin (AuthenticationConnection *auth, const char *pin_prog)
++{
++ Buffer msg;
++ int type;
++ int code;
++
++ code = SSH_AGENTC_PKCS11_SET_ASK_PIN;
++
++ buffer_init(&msg);
++ buffer_put_char(&msg, code);
++ buffer_put_cstring(&msg, pin_prog);
++
++ if (ssh_request_reply(auth, &msg, &msg) == 0) {
++ buffer_free(&msg);
++ return 0;
++ }
++ type = buffer_get_char(&msg);
++ buffer_free(&msg);
++ return decode_reply(type);
++}
++
++#endif /* SSH_PKCS11_DISABLED */
+diff -urNp openssh-4.4p1/authfd.h openssh-4.4p1+pkcs11-0.17/authfd.h
+--- openssh-4.4p1/authfd.h 2006-08-05 05:39:39.000000000 +0300
++++ openssh-4.4p1+pkcs11-0.17/authfd.h 2006-10-12 13:57:49.000000000 +0200
+@@ -16,6 +16,8 @@
+ #ifndef AUTHFD_H
+ #define AUTHFD_H
+
++#include "pkcs11.h"
++
+ /* Messages for the authentication agent connection. */
+ #define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
+ #define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
+@@ -49,6 +51,11 @@
+ #define SSH2_AGENTC_ADD_ID_CONSTRAINED 25
+ #define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
+
++#define SSH_AGENTC_PKCS11_ADD_PROVIDER 27
++#define SSH_AGENTC_PKCS11_ADD_ID 28
++#define SSH_AGENTC_PKCS11_REMOVE_ID 29
++#define SSH_AGENTC_PKCS11_SET_ASK_PIN 30
++
+ #define SSH_AGENT_CONSTRAIN_LIFETIME 1
+ #define SSH_AGENT_CONSTRAIN_CONFIRM 2
+
+@@ -92,4 +99,11 @@ int
+ ssh_agent_sign(AuthenticationConnection *, Key *, u_char **, u_int *, u_char *,
+ u_int);
+
++#ifndef SSH_PKCS11_DISABLED
++int ssh_pkcs11_add_provider (AuthenticationConnection *, const char *,
++ int, const char *, int);
++int ssh_pkcs11_id (AuthenticationConnection *, const pkcs11_identity *, int remove);
++int ssh_pkcs11_set_ask_pin (AuthenticationConnection *, const char *);
++#endif /* SSH_PKCS11_DISABLED */
++
+ #endif /* AUTHFD_H */
+diff -urNp openssh-4.4p1/ChangeLog.pkcs11 openssh-4.4p1+pkcs11-0.17/ChangeLog.pkcs11
+--- openssh-4.4p1/ChangeLog.pkcs11 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/ChangeLog.pkcs11 2006-10-23 17:36:52.000000000 +0200
+@@ -0,0 +1,49 @@
++20061023
++ - (alonbl) Removed logit from ssh-agent, thanks to Denniston, Todd.
++ - (alonbl) Release 0.17
++
++20061020
++ - (alonbl) Major modification of ssh-add command-line parameters.
++ Now, a complete serialized certificate needs to be specified, this
++ in order to allow people to add id without forcing card to be available.
++ But to allow complete silent addition a certificate file also needed.
++ --pkcs11-show-ids is used in order to get a list of resources.
++ --pkcs11-add-id --pkcs11-id <serialized id> \
++ [--pkcs11-cert-file <cert_file>]
++ - (alonbl) PKCS#11 release 0.16
++
++20061012
++ - (alonbl) OpenSC bug workaround.
++ - (alonbl) PKCS#11 release 0.15
++
++20060930
++ - (alonbl) Some pkcs11-helper updates.
++ - (alonbl) Rebase against 4.4p1.
++ - (alonbl) PKCS#11 release 0.14
++
++20060709
++ - (alonbl) PKCS#11 fixed handling multiproviders.
++ - (alonbl) PKCS#11 release 0.13
++
++20060608
++ - (alonbl) PKCS#11 modifed to match X.509-5.5 patch, works OK with focing
++ ssh-rsa id.
++ - (alonbl) PKCS#11 removed --pkcs11-x509-force-ssh argument.
++ - (alonbl) PKCS#11 release 0.12
++
++20060527
++ - (alonbl) PKCS#11 fix issues with gcc-2
++ - (alonbl) PKCS#11 fix issues with openssl-0.9.6 (first) version.
++ - (alonbl) PKCS#11 modified to match X.509-5.4 patch.
++ - (alonbl) PKCS#11 add --pkcs11-x509-force-ssh argument to force ssh id out
++ of X.509 certificate.
++ - (alonbl) PKCS#11 release 0.11
++
++20060419
++ - (alonbl) PKCS#11 fix handling empty attributes.
++ - (alonbl) PKCS#11 release 0.10
++
++20060404
++ - (alonbl) PKCS#11 code sync.
++ - (alonbl) PKCS#11 release 0.09
++
+diff -urNp openssh-4.4p1/config.h.in openssh-4.4p1+pkcs11-0.17/config.h.in
+--- openssh-4.4p1/config.h.in 2006-09-26 14:03:33.000000000 +0300
++++ openssh-4.4p1+pkcs11-0.17/config.h.in 2006-09-28 16:31:03.000000000 +0300
+@@ -1217,6 +1217,12 @@
+ /* Use audit debugging module */
+ #undef SSH_AUDIT_EVENTS
+
++/* Define if you don't want use PKCS#11 */
++#undef SSH_PKCS11_DISABLED
++
++/* Define if you don't want use X509 with PKCS#11 */
++#undef SSH_PKCS11_X509_DISABLED
++
+ /* non-privileged user for privilege separation */
+ #undef SSH_PRIVSEP_USER
+
+diff -urNp openssh-4.4p1/configure openssh-4.4p1+pkcs11-0.17/configure
+--- openssh-4.4p1/configure 2006-09-26 14:03:41.000000000 +0300
++++ openssh-4.4p1+pkcs11-0.17/configure 2006-09-28 16:33:53.000000000 +0300
+@@ -1307,6 +1307,7 @@ Optional Features:
+ --disable-libutil disable use of libutil (login() etc.) no
+ --disable-pututline disable use of pututline() etc. (uwtmp) no
+ --disable-pututxline disable use of pututxline() etc. (uwtmpx) no
++ --disable-pkcs11 Disable PKCS#11 support
+
+ Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+@@ -32163,6 +32164,33 @@ if test ! -z "$blibpath" ; then
+ echo "$as_me: WARNING: Please check and edit blibpath in LDFLAGS in Makefile" >&2;}
+ fi
+
++ssh_pkcs11="yes"
++ssh_pkcs11_x509="yes"
++# Check whether --enable-pkcs11 was given.
++if test "${enable_pkcs11+set}" = set; then
++ enableval=$enable_pkcs11;
++ if test "x$enableval" = "xno"; then
++ ssh_pkcs11="no"
++ fi
++
++
++fi
++
++if test "x$ssh_pkcs11" = "xno"; then
++
++cat >>confdefs.h <<_ACEOF
++#define SSH_PKCS11_DISABLED 1
++_ACEOF
++
++fi
++if test "x$ssh_x509" = "x"; then
++
++cat >>confdefs.h <<_ACEOF
++#define SSH_PKCS11_X509_DISABLED 1
++_ACEOF
++
++fi
++
+ CFLAGS="$CFLAGS $werror_flags"
+
+
+@@ -33415,6 +33443,7 @@ echo " IP address in \$DISPLAY hac
+ echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
+ echo " BSD Auth support: $BSD_AUTH_MSG"
+ echo " Random number source: $RAND_MSG"
++echo " PKCS#11 support: $ssh_pkcs11"
+ if test ! -z "$USE_RAND_HELPER" ; then
+ echo " ssh-rand-helper collects from: $RAND_HELPER_MSG"
+ fi
+diff -urNp openssh-4.4p1/configure.ac openssh-4.4p1+pkcs11-0.17/configure.ac
+--- openssh-4.4p1/configure.ac 2006-09-24 22:08:59.000000000 +0300
++++ openssh-4.4p1+pkcs11-0.17/configure.ac 2006-09-28 08:05:35.000000000 +0300
+@@ -3912,6 +3912,27 @@ if test ! -z "$blibpath" ; then
+ AC_MSG_WARN([Please check and edit blibpath in LDFLAGS in Makefile])
+ fi
+
++ssh_pkcs11="yes"
++ssh_pkcs11_x509="yes"
++AC_ARG_ENABLE(pkcs11,
++ [ --disable-pkcs11 Disable PKCS#11 support],
++ [
++ if test "x$enableval" = "xno"; then
++ ssh_pkcs11="no"
++ fi
++ ]
++)
++if test "x$ssh_pkcs11" = "xno"; then
++ AC_DEFINE_UNQUOTED(
++ SSH_PKCS11_DISABLED, 1,
++ [Define if you don't want use PKCS#11])
++fi
++if test "x$ssh_x509" = "x"; then
++ AC_DEFINE_UNQUOTED(
++ SSH_PKCS11_X509_DISABLED, 1,
++ [Define if you don't want use X509 with PKCS#11])
++fi
++
+ dnl Adding -Werror to CFLAGS early prevents configure tests from running.
+ dnl Add now.
+ CFLAGS="$CFLAGS $werror_flags"
+@@ -3973,6 +3994,7 @@ echo " IP address in \$DISPLAY hac
+ echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
+ echo " BSD Auth support: $BSD_AUTH_MSG"
+ echo " Random number source: $RAND_MSG"
++echo " PKCS#11 support: $ssh_pkcs11"
+ if test ! -z "$USE_RAND_HELPER" ; then
+ echo " ssh-rand-helper collects from: $RAND_HELPER_MSG"
+ fi
+diff -urNp openssh-4.4p1/cryptoki.h openssh-4.4p1+pkcs11-0.17/cryptoki.h
+--- openssh-4.4p1/cryptoki.h 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/cryptoki.h 2006-09-28 08:05:35.000000000 +0300
+@@ -0,0 +1,35 @@
++/* cryptoki.h include file for PKCS #11. */
++/* $Revision: 1.4 $ */
++
++/* License to copy and use this software is granted provided that it is
++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
++ * (Cryptoki)" in all material mentioning or referencing this software.
++
++ * License is also granted to make and use derivative works provided that
++ * such works are identified as "derived from the RSA Security Inc. PKCS #11
++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
++ * referencing the derived work.
++
++ * RSA Security Inc. makes no representations concerning either the
++ * merchantability of this software or the suitability of this software for
++ * any particular purpose. It is provided "as is" without express or implied
++ * warranty of any kind.
++ */
++
++#ifndef ___CRYPTOKI_H_INC___
++#define ___CRYPTOKI_H_INC___
++
++#define CK_PTR *
++
++#define CK_DEFINE_FUNCTION(returnType, name) returnType name
++#define CK_DECLARE_FUNCTION(returnType, name) returnType name
++#define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType (* name)
++#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name)
++
++#ifndef NULL_PTR
++#define NULL_PTR 0
++#endif
++
++#include "pkcs11-headers/pkcs11.h"
++
++#endif /* ___CRYPTOKI_H_INC___ */
+diff -urNp openssh-4.4p1/cryptoki-win32.h openssh-4.4p1+pkcs11-0.17/cryptoki-win32.h
+--- openssh-4.4p1/cryptoki-win32.h 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/cryptoki-win32.h 2006-09-28 08:05:35.000000000 +0300
+@@ -0,0 +1,66 @@
++/* cryptoki.h include file for PKCS #11. */
++/* $Revision: 1.4 $ */
++
++/* License to copy and use this software is granted provided that it is
++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
++ * (Cryptoki)" in all material mentioning or referencing this software.
++
++ * License is also granted to make and use derivative works provided that
++ * such works are identified as "derived from the RSA Security Inc. PKCS #11
++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
++ * referencing the derived work.
++
++ * RSA Security Inc. makes no representations concerning either the
++ * merchantability of this software or the suitability of this software for
++ * any particular purpose. It is provided "as is" without express or implied
++ * warranty of any kind.
++ */
++
++/* This is a sample file containing the top level include directives
++ * for building Win32 Cryptoki libraries and applications.
++ */
++
++#ifndef ___CRYPTOKI_H_INC___
++#define ___CRYPTOKI_H_INC___
++
++#pragma pack(push, cryptoki, 1)
++
++/* Specifies that the function is a DLL entry point. */
++#define CK_IMPORT_SPEC __declspec(dllimport)
++
++/* Define CRYPTOKI_EXPORTS during the build of cryptoki libraries. Do
++ * not define it in applications.
++ */
++#ifdef CRYPTOKI_EXPORTS
++/* Specified that the function is an exported DLL entry point. */
++#define CK_EXPORT_SPEC __declspec(dllexport)
++#else
++#define CK_EXPORT_SPEC CK_IMPORT_SPEC
++#endif
++
++/* Ensures the calling convention for Win32 builds */
++#define CK_CALL_SPEC __cdecl
++
++#define CK_PTR *
++
++#define CK_DEFINE_FUNCTION(returnType, name) \
++ returnType CK_EXPORT_SPEC CK_CALL_SPEC name
++
++#define CK_DECLARE_FUNCTION(returnType, name) \
++ returnType CK_EXPORT_SPEC CK_CALL_SPEC name
++
++#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
++ returnType CK_IMPORT_SPEC (CK_CALL_SPEC CK_PTR name)
++
++#define CK_CALLBACK_FUNCTION(returnType, name) \
++ returnType (CK_CALL_SPEC CK_PTR name)
++
++#ifndef NULL_PTR
++#define NULL_PTR 0
++#endif
++
++#include "pkcs11-headers/pkcs11.h"
++
++#pragma pack(pop, cryptoki)
++
++#endif /* ___CRYPTOKI_H_INC___ */
+diff -urNp openssh-4.4p1/LICENCE openssh-4.4p1+pkcs11-0.17/LICENCE
+--- openssh-4.4p1/LICENCE 2006-08-30 20:24:41.000000000 +0300
++++ openssh-4.4p1+pkcs11-0.17/LICENCE 2006-09-28 08:05:35.000000000 +0300
+@@ -332,6 +332,9 @@ OpenSSH contains no GPL code.
+ * authorization. *
+ ****************************************************************************/
+
++ d) PKCS #11: Cryptographic Token Interface Standard
++
++ This software uses RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki).
+
+ ------
+ $OpenBSD: LICENCE,v 1.19 2004/08/30 09:18:08 markus Exp $
+diff -urNp openssh-4.4p1/Makefile.in openssh-4.4p1+pkcs11-0.17/Makefile.in
+--- openssh-4.4p1/Makefile.in 2006-09-12 14:54:10.000000000 +0300
++++ openssh-4.4p1+pkcs11-0.17/Makefile.in 2006-09-28 08:05:35.000000000 +0300
+@@ -66,6 +66,7 @@ TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-a
+
+ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
+ canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
++ pkcs11.o pkcs11-helper.o \
+ cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
+ compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \
+ log.o match.o md-sha256.o moduli.o nchan.o packet.o \
+diff -urNp openssh-4.4p1/pkcs11.c openssh-4.4p1+pkcs11-0.17/pkcs11.c
+--- openssh-4.4p1/pkcs11.c 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/pkcs11.c 2006-10-23 17:35:54.000000000 +0200
+@@ -0,0 +1,1139 @@
++/*
++ * Copyright (c) 2005-2006 Alon Bar-Lev. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 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 "includes.h"
++#include <sys/wait.h>
++#include <errno.h>
++
++#if !defined(SSH_PKCS11_DISABLED)
++
++#include "pkcs11-helper.h"
++#include "pkcs11.h"
++#include "openssl/pem.h"
++#include "misc.h"
++
++static
++char *
++ssh_from_x509 (X509 *x509);
++
++static char *s_szSetPINProg = NULL;
++
++static
++unsigned
++_pkcs11_msg_pkcs112openssh (
++ IN const unsigned flags
++) {
++ unsigned openssh_flags;
++
++ switch (flags) {
++ case PKCS11H_LOG_DEBUG2:
++ openssh_flags = SYSLOG_LEVEL_DEBUG3;
++ break;
++ case PKCS11H_LOG_DEBUG1:
++ openssh_flags = SYSLOG_LEVEL_DEBUG2;
++ break;
++ case PKCS11H_LOG_INFO:
++ openssh_flags = SYSLOG_LEVEL_INFO;
++ break;
++ case PKCS11H_LOG_WARN:
++ openssh_flags = SYSLOG_LEVEL_ERROR;
++ break;
++ case PKCS11H_LOG_ERROR:
++ openssh_flags = SYSLOG_LEVEL_FATAL;
++ break;
++ default:
++ openssh_flags = SYSLOG_LEVEL_FATAL;
++ break;
++ }
++
++ return openssh_flags;
++}
++
++static
++unsigned
++_pkcs11_msg_openssh2pkcs11 (
++ IN const unsigned flags
++) {
++ unsigned pkcs11_flags;
++
++ switch (flags) {
++ case SYSLOG_LEVEL_DEBUG3:
++ pkcs11_flags = PKCS11H_LOG_DEBUG2;
++ break;
++ case SYSLOG_LEVEL_DEBUG2:
++ pkcs11_flags = PKCS11H_LOG_DEBUG1;
++ break;
++ case SYSLOG_LEVEL_INFO:
++ pkcs11_flags = PKCS11H_LOG_INFO;
++ break;
++ case SYSLOG_LEVEL_ERROR:
++ pkcs11_flags = PKCS11H_LOG_WARN;
++ break;
++ case SYSLOG_LEVEL_FATAL:
++ pkcs11_flags = PKCS11H_LOG_ERROR;
++ break;
++ default:
++ pkcs11_flags = PKCS11H_LOG_ERROR;
++ break;
++ }
++
++ return pkcs11_flags;
++}
++
++static
++void
++_pkcs11_openssh_log (
++ IN void * const pData,
++ IN unsigned flags,
++ IN const char * const szFormat,
++ IN va_list args
++) {
++ do_log (_pkcs11_msg_pkcs112openssh (flags), szFormat, args);
++}
++
++static
++int
++_pkcs11_ssh_prompt (
++ IN const char * const szType,
++ IN const char * const szPrompt,
++ OUT char * const szInput,
++ IN const int nMaxInput
++) {
++ pid_t pid = -1;
++ int fds[2] = {-1, -1};
++ int fOK = TRUE;
++
++ /*
++ * Make sure we don't reuse PIN
++ */
++ if (fOK) {
++ memset (szInput, 0, nMaxInput);
++ }
++
++ if (fOK && s_szSetPINProg == NULL) {
++ fOK = FALSE;
++ }
++
++ if (fOK && pipe (fds) == -1) {
++ fOK = FALSE;
++ }
++
++ if (fOK && (pid = fork ()) == -1) {
++ fOK = FALSE;
++ }
++
++ if (fOK) {
++ if (pid == 0) {
++ close (fds[0]);
++ fds[0] = -1;
++
++ if (fOK && dup2 (fds[1], 1) == -1) {
++ fOK = FALSE;
++ }
++ if (fOK) {
++ close (fds[1]);
++ fds[1] = -1;
++ }
++
++ if (fOK) {
++ execl (
++ s_szSetPINProg,
++ s_szSetPINProg,
++ "-t",
++ szType,
++ szPrompt,
++ NULL
++ );
++ }
++
++ exit (1);
++ }
++ else {
++ int status;
++ int r = 0;
++
++ close (fds[1]);
++ fds[1] = -1;
++
++ if (fOK) {
++ while (
++ (r=waitpid (pid, &status, 0)) == 0 ||
++ (r == -1 && errno == EINTR)
++ );
++
++ if (r == -1) {
++ fOK = FALSE;
++ }
++ }
++
++ if (fOK && !WIFEXITED (status)) {
++ fOK = FALSE;
++ }
++
++ if (fOK && WEXITSTATUS (status) != 0) {
++ fOK = FALSE;
++ }
++
++ if (fOK) {
++ if (!strcmp (szType, "password")) {
++ if ((r = read (fds[0], szInput, nMaxInput)) == -1) {
++ fOK = FALSE;
++ r = 0;
++ }
++ }
++ else {
++ r = 0;
++ }
++ szInput[r] = '\0';
++ }
++
++ if (fOK) {
++ if (strlen (szInput) > 0 && szInput[strlen (szInput)-1] == '\n') {
++ szInput[strlen (szInput)-1] = '\0';
++ }
++ /*
++ * for DOS compatability
++ */
++ if (strlen (szInput) > 0 && szInput[strlen (szInput)-1] == '\r') {
++ szInput[strlen (szInput)-1] = '\0';
++ }
++ }
++ }
++ }
++
++ if (fds[0] != -1) {
++ close (fds[0]);
++ fds[0] = -1;
++ }
++
++ if (fds[1] != -1) {
++ close (fds[1]);
++ fds[1] = -1;
++ }
++
++ return fOK;
++}
++
++static
++void
++_pkcs11_ssh_print (
++ IN void * const pData,
++ IN const char * const szFormat,
++ IN ...
++) {
++ va_list args;
++
++ va_start (args, szFormat);
++ vprintf (szFormat, args);
++ va_end (args);
++}
++
++static
++PKCS11H_BOOL
++_pkcs11_ssh_token_prompt (
++ IN void * const pData1,
++ IN void * const pData2,
++ IN const pkcs11h_token_id_t token,
++ IN const unsigned retry
++) {
++ char szPrompt[1024];
++ char szPIN[1024];
++
++ snprintf (szPrompt, sizeof (szPrompt), "Please insert token '%s' or cancel", token->display);
++ return _pkcs11_ssh_prompt ("okcancel", szPrompt, szPIN, sizeof (szPIN));
++}
++
++static
++PKCS11H_BOOL
++_pkcs11_ssh_pin_prompt (
++ IN void * const pData1,
++ IN void * const pData2,
++ IN const pkcs11h_token_id_t token,
++ IN const unsigned retry,
++ OUT char * const szPIN,
++ IN const size_t nMaxPIN
++) {
++ char szPrompt[1024];
++
++ snprintf (szPrompt, sizeof (szPrompt), "Please enter PIN for token '%s'", token->display);
++ return _pkcs11_ssh_prompt ("password", szPrompt, szPIN, nMaxPIN);
++}
++
++static
++PKCS11H_BOOL
++_pkcs11_ssh_pin_prompt_cli (
++ IN void * const pData1,
++ IN void * const pData2,
++ IN const pkcs11h_token_id_t token,
++ IN const unsigned retry,
++ OUT char * const szPIN,
++ IN const size_t nMaxPIN
++) {
++ char szPrompt[1024];
++ snprintf (szPrompt, sizeof (szPrompt), "Please enter '%s' PIN or 'cancel': ", token->display);
++ char *p = getpass (szPrompt);
++
++ strncpy (szPIN, p, nMaxPIN);
++ szPIN[nMaxPIN-1] = '\0';
++
++ return strcmp (szPIN, "cancel") != 0;
++}
++
++void
++_pkcs11_do_log (
++ IN LogLevel l,
++ IN const char *f,
++ IN ...
++) {
++ va_list args;
++ va_start (args, f);
++ do_log (l, f, args);
++ va_end (args);
++}
++
++int
++pkcs11_initialize (
++ const int fProtectedAuthentication,
++ const int nPINCachePeriod
++) {
++ CK_RV rv = CKR_OK;
++
++ debug3 (
++ "PKCS#11: pkcs11_initialize - entered fProtectedAuthentication=%d, nPINCachePeriod=%d",
++ fProtectedAuthentication,
++ nPINCachePeriod
++ );
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_initialize ()) != CKR_OK
++ ) {
++ error ("PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_setLogHook (_pkcs11_openssh_log, NULL)) != CKR_OK
++ ) {
++ error ("PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ /*
++ * WARNING!!!
++ * There is no way to get log level,
++ * so set to minimum.
++ * After fix in log.c it can be fixed.
++ */
++ if (rv == CKR_OK) {
++ pkcs11h_setLogLevel (_pkcs11_msg_openssh2pkcs11 (SYSLOG_LEVEL_DEBUG3));
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_setTokenPromptHook (_pkcs11_ssh_token_prompt, NULL)) != CKR_OK
++ ) {
++ error ("PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_setPINPromptHook (_pkcs11_ssh_pin_prompt, NULL)) != CKR_OK
++ ) {
++ error ("PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_setProtectedAuthentication (fProtectedAuthentication)) != CKR_OK
++ ) {
++ error ("PKCS#11: Cannot set protected authentication mode %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_setPINCachePeriod (nPINCachePeriod)) != CKR_OK
++ ) {
++ error ("PKCS#11: Cannot set PIN cache period %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ debug3 (
++ "PKCS#11: pkcs11_initialize - return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv == CKR_OK;
++}
++
++void
++pkcs11_terminate () {
++ debug3 ("PKCS#11: pkcs11_terminate - entered");
++
++ pkcs11h_terminate ();
++
++ debug3 ("PKCS#11: pkcs11_terminate - return");
++}
++
++void
++pkcs11_forkFix () {
++ pkcs11h_forkFixup ();
++}
++
++int
++pkcs11_setAskPIN (
++ const char * const pin_prog
++) {
++ if (pin_prog != NULL) {
++ if (s_szSetPINProg != NULL) {
++ xfree (s_szSetPINProg);
++ s_szSetPINProg = NULL;
++ }
++
++ s_szSetPINProg = xstrdup (pin_prog);
++ }
++
++ return 1;
++}
++
++int
++pkcs11_addProvider (
++ const char * const provider,
++ const int fProtectedAuthentication,
++ const char * const sign_mode,
++ const int fCertIsPrivate
++) {
++ unsigned maskSignMode = 0;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (provider != NULL);
++ PKCS11H_ASSERT (sign_mode != NULL);
++
++ debug3 (
++ "PKCS#11: pkcs11_addProvider - entered - provider='%s', fProtectedAuthentication=%d, sign_mode='%s', fCertIsPrivate=%d",
++ provider,
++ fProtectedAuthentication ? 1 : 0,
++ sign_mode == NULL ? "default" : sign_mode,
++ fCertIsPrivate ? 1 : 0
++ );
++
++ debug (
++ "PKCS#11: Adding PKCS#11 provider '%s'",
++ provider
++ );
++
++ if (rv == CKR_OK) {
++ if (sign_mode == NULL || !strcmp (sign_mode, "auto")) {
++ maskSignMode = 0;
++ }
++ else if (!strcmp (sign_mode, "sign")) {
++ maskSignMode = PKCS11H_SIGNMODE_MASK_SIGN;
++ }
++ else if (!strcmp (sign_mode, "recover")) {
++ maskSignMode = PKCS11H_SIGNMODE_MASK_RECOVER;
++ }
++ else if (!strcmp (sign_mode, "any")) {
++ maskSignMode = (
++ PKCS11H_SIGNMODE_MASK_SIGN |
++ PKCS11H_SIGNMODE_MASK_RECOVER
++ );
++ }
++ else {
++ error ("PKCS#11: Invalid sign mode '%s'", sign_mode);
++ rv = CKR_ARGUMENTS_BAD;
++ }
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_addProvider (
++ provider,
++ provider,
++ fProtectedAuthentication,
++ maskSignMode,
++ PKCS11H_SLOTEVENT_METHOD_AUTO,
++ 0,
++ fCertIsPrivate
++ )) != CKR_OK
++ ) {
++ error ("PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage (rv));
++ }
++
++ debug3 (
++ "PKCS#11: pkcs11_addProvider - return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv == CKR_OK;
++}
++
++pkcs11_identity *
++pkcs11_identity_new () {
++ pkcs11_identity *id = xmalloc (sizeof (struct pkcs11_identity_s));
++ if (id != NULL) {
++ memset (id, 0, sizeof (struct pkcs11_identity_s));
++ }
++ return id;
++}
++
++void
++pkcs11_identity_free (
++ const pkcs11_identity * const id
++) {
++ if (id != NULL) {
++ xfree ((void *)id);
++ }
++}
++
++void
++pkcs11_getKey (
++ IN const pkcs11_identity * const id,
++ OUT Key ** const sshkey,
++ OUT char * const szComment,
++ IN const int nCommentMax
++) {
++ X509 *x509 = NULL;
++ RSA *rsa = NULL;
++ pkcs11h_certificate_id_t certificate_id = NULL;
++ pkcs11h_certificate_t certificate = NULL;
++ pkcs11h_openssl_session_t openssl_session = NULL;
++ size_t temp;
++ CK_RV rv = CKR_OK;
++
++ int fOK = TRUE;
++
++ debug3 (
++ "PKCS#11: pkcs11_getKey - entered - id=%p, sshkey=%p, szComment=%p, nCommentMax=%d",
++ (void *)id,
++ (void *)sshkey,
++ (void *)szComment,
++ nCommentMax
++ );
++
++ PKCS11H_ASSERT (id != NULL);
++ PKCS11H_ASSERT (sshkey!=NULL);
++ PKCS11H_ASSERT (szComment!=NULL);
++
++ debug3 (
++ "PKCS#11: pkcs11_getKey - id - id=%s, pin_cache_period=%d, cert_file=%s",
++ id->id,
++ id->pin_cache_period,
++ id->cert_file
++ );
++
++ PKCS11H_ASSERT (id->id);
++
++ if (
++ fOK &&
++ pkcs11h_certificate_deserializeCertificateId (&certificate_id, id->id)
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (
++ fOK &&
++ id->cert_file != NULL &&
++ id->cert_file[0] != '\x0'
++ ) {
++ X509 *x509 = NULL;
++ unsigned char *p = NULL;
++ unsigned char *certificate_blob = NULL;
++ size_t certificate_blob_size = 0;
++ FILE *fp = NULL;
++
++ if (
++ fOK &&
++ (fp = fopen (id->cert_file, "r")) == NULL
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Cannot open file '%s'", id->cert_file);
++ }
++
++ if (
++ fOK &&
++ !PEM_read_X509 (
++ fp,
++ &x509,
++ NULL,
++ 0
++ )
++ ) {
++ x509 = NULL;
++ fOK = FALSE;
++ error ("PKCS#11: Cannot read PEM from file '%s'", id->cert_file);
++ }
++
++ if (
++ fOK &&
++ (certificate_blob_size = i2d_X509 (x509, NULL)) < 0
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Cannot read decode certificate");
++ }
++
++ if (
++ fOK &&
++ (certificate_blob = (unsigned char *)xmalloc (certificate_blob_size)) == NULL
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Cannot allocate memory");
++ }
++
++ /*
++ * i2d_X509 increments p!!!
++ */
++ p = certificate_blob;
++
++ if (
++ fOK &&
++ (certificate_blob_size = i2d_X509 (x509, &p)) < 0
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Cannot read decode certificate");
++ }
++
++ if (
++ fOK &&
++ pkcs11h_certificate_setCertificateIdCertificateBlob (
++ certificate_id,
++ certificate_blob,
++ certificate_blob_size
++ ) != CKR_OK
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Cannot set certificate blob %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (x509 != NULL) {
++ X509_free (x509);
++ x509 = NULL;
++ }
++
++ if (certificate_blob != NULL) {
++ xfree (certificate_blob);
++ certificate_blob = NULL;
++ }
++
++ if (fp != NULL) {
++ fclose (fp);
++ fp = NULL;
++ }
++ }
++
++ if (
++ fOK &&
++ (rv = pkcs11h_certificate_create (
++ certificate_id,
++ NULL,
++ PKCS11H_PROMPT_MASK_ALLOW_ALL,
++ id->pin_cache_period,
++ &certificate
++ )) != CKR_OK
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (certificate_id != NULL){
++ pkcs11h_certificate_freeCertificateId (certificate_id);
++ certificate_id = NULL;
++ }
++
++ /*
++ * Is called so next certificate_id will
++ * contain a proper description
++ */
++ if (
++ fOK &&
++ (rv = pkcs11h_certificate_getCertificateBlob (
++ certificate,
++ NULL,
++ &temp
++ )) != CKR_OK
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (
++ fOK &&
++ (rv = pkcs11h_certificate_getCertificateId (
++ certificate,
++ &certificate_id
++ )) != CKR_OK
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Cannot get certificate_id %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (fOK) {
++ strncpy (szComment, certificate_id->displayName, nCommentMax);
++ szComment[nCommentMax - 1] = '\0';
++ }
++
++ if (
++ fOK &&
++ (openssl_session = pkcs11h_openssl_createSession (certificate)) == NULL
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Cannot initialize openssl session");
++ }
++
++ if (fOK) {
++ /*
++ * will be release by openssl_session
++ */
++ certificate = NULL;
++ }
++
++ if (
++ fOK &&
++ (rsa = pkcs11h_openssl_session_getRSA (openssl_session)) == NULL
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Unable get rsa object");
++ }
++
++ if (
++ fOK &&
++ (x509 = pkcs11h_openssl_session_getX509 (openssl_session)) == NULL
++ ) {
++ fOK = FALSE;
++ error ("PKCS#11: Unable get certificate object");
++ }
++
++ if (fOK) {
++ *sshkey = key_new_private (KEY_UNSPEC);
++ (*sshkey)->rsa = rsa;
++ rsa = NULL;
++#if defined(SSH_PKCS11_X509_DISABLED)
++ (*sshkey)->type = KEY_RSA;
++#else
++ (*sshkey)->type = KEY_X509_RSA;
++ (*sshkey)->x509 = x509;
++ x509 = NULL;
++#endif
++ }
++
++ if (x509 != NULL) {
++ X509_free (x509);
++ x509 = NULL;
++ }
++
++ if (openssl_session != NULL) {
++ pkcs11h_openssl_freeSession (openssl_session);
++ openssl_session = NULL;
++ }
++
++ if (certificate != NULL) {
++ pkcs11h_certificate_freeCertificate (certificate);
++ certificate = NULL;
++ }
++
++ if (certificate_id != NULL) {
++ pkcs11h_certificate_freeCertificateId (certificate_id);
++ certificate_id = NULL;
++ }
++
++ debug3 (
++ "PKCS#11: pkcs11_getKey - return fOK=%d, rv=%ld",
++ fOK ? 1 : 0,
++ rv
++ );
++}
++
++void
++pkcs11_show_ids (
++ const char * const provider,
++ int allow_protected_auth,
++ int cert_is_private
++) {
++ pkcs11h_certificate_id_list_t user_certificates = NULL;
++ pkcs11h_certificate_id_list_t current = NULL;
++ CK_RV rv = CKR_OK;
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_initialize ();
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_setLogHook (_pkcs11_openssh_log, NULL);
++ }
++
++ if (rv == CKR_OK) {
++ pkcs11h_setLogLevel (_pkcs11_msg_openssh2pkcs11 (SYSLOG_LEVEL_DEBUG3));
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_setPINPromptHook (_pkcs11_ssh_pin_prompt_cli, NULL);
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_setProtectedAuthentication (TRUE);
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_addProvider (
++ provider,
++ provider,
++ allow_protected_auth ? TRUE : FALSE,
++ 0,
++ FALSE,
++ 0,
++ cert_is_private ? TRUE : FALSE
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_certificate_enumCertificateIds (
++ PKCS11H_ENUM_METHOD_CACHE_EXIST,
++ NULL,
++ PKCS11H_PROMPT_MASK_ALLOW_ALL,
++ NULL,
++ &user_certificates
++ );
++ }
++
++ for (current = user_certificates; rv == CKR_OK && current != NULL; current = current->next) {
++ pkcs11h_certificate_t certificate = NULL;
++ X509 *x509 = NULL;
++ char dn[1024] = {0};
++ char *ser = NULL;
++ char *ssh_key = NULL;
++ size_t ser_len = 0;
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_certificate_serializeCertificateId (NULL, &ser_len, current->certificate_id);
++ }
++
++ if (
++ rv == CKR_OK &&
++ (ser = (char *)xmalloc (ser_len)) == NULL
++ ) {
++ rv = CKR_HOST_MEMORY;
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_certificate_serializeCertificateId (ser, &ser_len, current->certificate_id);
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_certificate_create (
++ current->certificate_id,
++ NULL,
++ PKCS11H_PROMPT_MASK_ALLOW_ALL,
++ PKCS11H_PIN_CACHE_INFINITE,
++ &certificate
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ (x509 = pkcs11h_openssl_getX509 (certificate)) == NULL
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++
++ if (rv == CKR_OK) {
++ X509_NAME_oneline (
++ X509_get_subject_name (x509),
++ dn,
++ sizeof (dn)
++ );
++ printf (
++ (
++ "\n"
++ "********************************************\n"
++ "IDENTITY:\n"
++ " DN: %s\n"
++ " Serialized id: %s\n"
++ "\n"
++ " Certificate:\n"
++ ),
++ dn,
++ ser
++ );
++ PEM_write_X509 (stdout, x509);
++ }
++
++ if (
++ rv == CKR_OK &&
++ (ssh_key = ssh_from_x509 (x509)) != NULL
++ ) {
++ printf (
++ (
++ "\n"
++ " SSH:\n"
++ "%s\n"
++ ),
++ ssh_key
++ );
++
++ xfree (ssh_key);
++ }
++
++ if (x509 != NULL) {
++ X509_free (x509);
++ x509 = NULL;
++ }
++
++ if (certificate != NULL) {
++ pkcs11h_certificate_freeCertificate (certificate);
++ certificate = NULL;
++ }
++
++ if (ser != NULL) {
++ xfree (ser);
++ ser = NULL;
++ }
++
++ /*
++ * Ignore error
++ */
++ if (rv != CKR_OK) {
++ error ("PKCS#11: Failed to get id %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ rv = CKR_OK;
++ }
++ }
++
++ if (user_certificates != NULL) {
++ pkcs11h_certificate_freeCertificateIdList (user_certificates);
++ user_certificates = NULL;
++ }
++
++ pkcs11h_terminate ();
++}
++
++void
++pkcs11_dump_slots (
++ const char * const provider
++) {
++ pkcs11h_standalone_dump_slots (
++ _pkcs11_ssh_print,
++ NULL,
++ provider
++ );
++}
++
++void
++pkcs11_dump_objects (
++ const char * const provider,
++ const char * const slot,
++ const char * const pin
++) {
++ pkcs11h_standalone_dump_objects (
++ _pkcs11_ssh_print,
++ NULL,
++ provider,
++ slot,
++ pin
++ );
++}
++
++/*
++ * The ssh_from_x509 is dirived of Tatu and Markus work.
++ *
++ * Copyright (c) 2006 Alon bar-Lev <alon.barlev@gmail.com>. All rights reserved.
++ * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
++ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
++ */
++
++#define PUT_32BIT(cp, value) ( \
++ (cp)[0] = (value) >> 24, \
++ (cp)[1] = (value) >> 16, \
++ (cp)[2] = (value) >> 8, \
++ (cp)[3] = (value) )
++
++static
++char *
++ssh_from_x509 (X509 *x509) {
++
++ EVP_PKEY *pubkey = NULL;
++ BIO *bio = NULL, *bio2 = NULL, *bio64 = NULL;
++ unsigned char *blob = NULL, *buffer = NULL;
++ char *ret = NULL;
++ int blobsize = 0, retsize = 0;
++ int bytes_name = 0, bytes_exponent = 0, bytes_modulus = 0;
++ unsigned char *bp;
++ char *p;
++ int n;
++ const char *keyname = NULL;
++ int ok = 1;
++
++ if (ok && (pubkey = X509_get_pubkey (x509)) == NULL) {
++ ok = 0;
++ }
++
++ if (ok && (bio64 = BIO_new (BIO_f_base64 ())) == NULL) {
++ ok = 0;
++ }
++
++ if (ok && (bio = BIO_new (BIO_s_mem ())) == NULL) {
++ ok = 0;
++ }
++
++ if (ok && (bio2 = BIO_push (bio64, bio)) == NULL) {
++ ok = 0;
++ }
++
++ if (ok && pubkey->type != EVP_PKEY_RSA) {
++ ok = 0;
++ }
++
++ if (ok) {
++ keyname = "ssh-rsa";
++ }
++
++ if (ok) {
++ bytes_name = strlen (keyname);
++ bytes_exponent = BN_num_bytes (pubkey->pkey.rsa->e);
++ bytes_modulus = BN_num_bytes (pubkey->pkey.rsa->n);
++
++ blobsize = (
++ 4 + bytes_name +
++ 4 + (bytes_exponent + 1) +
++ 4 + (bytes_modulus + 1) +
++ 1
++ );
++ }
++
++ if (ok && (blob = (unsigned char *)xmalloc (blobsize)) == NULL) {
++ ok = 0;
++ }
++
++ if (ok && (buffer = (unsigned char *)xmalloc (blobsize)) == NULL) {
++ ok = 0;
++ }
++
++ if (ok) {
++ bp = blob;
++
++ PUT_32BIT (bp, bytes_name), bp += 4;
++ memcpy (bp, keyname, bytes_name), bp += bytes_name;
++
++ BN_bn2bin (pubkey->pkey.rsa->e, buffer);
++ if (buffer[0] & 0x80) {
++ // highest bit set would indicate a negative number.
++ // to avoid this, we have to spend an extra byte:
++ PUT_32BIT (bp, bytes_exponent+1), bp += 4;
++ *(bp++) = 0;
++ } else {
++ PUT_32BIT (bp, bytes_exponent), bp += 4;
++ }
++ memcpy (bp, buffer, bytes_exponent), bp += bytes_exponent;
++
++ BN_bn2bin (pubkey->pkey.rsa->n, buffer);
++ if (buffer[0] & 0x80) {
++ PUT_32BIT (bp, bytes_modulus+1), bp += 4;
++ *(bp++) = 0;
++ } else {
++ PUT_32BIT( bp, bytes_modulus ), bp += 4;
++ }
++ memcpy (bp, buffer, bytes_modulus), bp += bytes_modulus;
++ }
++
++
++ if (ok && BIO_write (bio2, blob, bp-blob) == -1) {
++ ok = 0;
++ }
++
++ if (ok && BIO_flush (bio2) == -1) {
++ ok = 0;
++ }
++
++ /*
++ * Allocate the newline too... We will remove them later
++ * For MS, allocate return as well.
++ */
++ if (ok) {
++ retsize = strlen (keyname) + 1 + (blobsize * 4 / 3) + (blobsize * 2 / 50) + 10 + 1;
++ }
++
++ if (ok && (ret = xmalloc (retsize)) == NULL) {
++ ok = 0;
++ }
++
++ if (ok) {
++ strcpy (ret, keyname);
++ strcat (ret, " ");
++ }
++
++ if (ok && (n = BIO_read (bio, ret + strlen (ret), retsize - strlen (ret) - 1)) == -1) {
++ ok = 0;
++ }
++
++ if (ok) {
++ ret[strlen (keyname) + 1 + n] = '\x0';
++ }
++
++ if (ok) {
++ while ((p = strchr (ret, '\n')) != NULL) {
++ memmove (p, p+1, strlen (p)+1);
++ }
++ while ((p = strchr (ret, '\r')) != NULL) {
++ memmove (p, p+1, strlen (p)+1);
++ }
++
++ }
++
++ if (bio != NULL) {
++ BIO_free_all (bio);
++ bio = NULL;
++ }
++
++ if (pubkey != NULL) {
++ EVP_PKEY_free (pubkey);
++ pubkey = NULL;
++ }
++
++ if (buffer != NULL) {
++ xfree (buffer);
++ buffer = NULL;
++ }
++
++ if (blob != NULL) {
++ xfree (blob);
++ blob = NULL;
++ }
++
++ if (!ok) {
++ if (ret != NULL) {
++ xfree (ret);
++ ret = NULL;
++ }
++ }
++
++ return ret;
++}
++
++#else
++static void dummy (void) {}
++#endif /* SSH_PKCS11_DISABLED */
+diff -urNp openssh-4.4p1/pkcs11.h openssh-4.4p1+pkcs11-0.17/pkcs11.h
+--- openssh-4.4p1/pkcs11.h 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/pkcs11.h 2006-10-12 13:55:28.000000000 +0200
+@@ -0,0 +1,100 @@
++/*
++ * Copyright (c) 2005-2006 Alon Bar-Lev. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 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.
++ */
++
++#ifndef SSH_PKCS11_H
++#define SSH_PKCS11_H
++
++#if !defined(SSH_PKCS11_DISABLED)
++
++#include "key.h"
++
++typedef struct pkcs11_identity_s {
++ char *id;
++ int pin_cache_period;
++ char *cert_file;
++} pkcs11_identity;
++
++int
++pkcs11_initialize (
++ const int fProtectedAuthentication,
++ const int nPINCachePeriod
++);
++
++void
++pkcs11_terminate ();
++
++void
++pkcs11_forkFix ();
++
++int
++pkcs11_setAskPIN (
++ const char * const pin_prog
++);
++
++int
++pkcs11_addProvider (
++ const char * const provider,
++ const int fProtectedAuthentication,
++ const char * const sign_mode,
++ const int fCertIsPrivate
++);
++
++pkcs11_identity *
++pkcs11_identity_new ();
++
++void
++pkcs11_identity_free (
++ const pkcs11_identity * const id
++);
++
++void
++pkcs11_getKey (
++ const pkcs11_identity * const id,
++ Key ** const sshkey,
++ char * const szComment,
++ const int nCommentMax
++);
++
++void
++pkcs11_show_ids (
++ const char * const provider,
++ int allow_protected_auth,
++ int cert_is_private
++);
++
++void
++pkcs11_dump_slots (
++ const char * const provider
++);
++
++void
++pkcs11_dump_objects (
++ const char * const provider,
++ const char * const slot,
++ const char * const pin
++);
++
++#endif /* SSH_PKCS11_DISABLED */
++
++#endif /* OPENSSH_PKCS11_H */
+diff -urNp openssh-4.4p1/pkcs11-headers/pkcs11f.h openssh-4.4p1+pkcs11-0.17/pkcs11-headers/pkcs11f.h
+--- openssh-4.4p1/pkcs11-headers/pkcs11f.h 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/pkcs11-headers/pkcs11f.h 2006-09-28 08:05:35.000000000 +0300
+@@ -0,0 +1,912 @@
++/* pkcs11f.h include file for PKCS #11. */
++/* $Revision: 1.4 $ */
++
++/* License to copy and use this software is granted provided that it is
++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
++ * (Cryptoki)" in all material mentioning or referencing this software.
++
++ * License is also granted to make and use derivative works provided that
++ * such works are identified as "derived from the RSA Security Inc. PKCS #11
++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
++ * referencing the derived work.
++
++ * RSA Security Inc. makes no representations concerning either the
++ * merchantability of this software or the suitability of this software for
++ * any particular purpose. It is provided "as is" without express or implied
++ * warranty of any kind.
++ */
++
++/* This header file contains pretty much everything about all the */
++/* Cryptoki function prototypes. Because this information is */
++/* used for more than just declaring function prototypes, the */
++/* order of the functions appearing herein is important, and */
++/* should not be altered. */
++
++/* General-purpose */
++
++/* C_Initialize initializes the Cryptoki library. */
++CK_PKCS11_FUNCTION_INFO(C_Initialize)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
++ * cast to CK_C_INITIALIZE_ARGS_PTR
++ * and dereferenced */
++);
++#endif
++
++
++/* C_Finalize indicates that an application is done with the
++ * Cryptoki library. */
++CK_PKCS11_FUNCTION_INFO(C_Finalize)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
++);
++#endif
++
++
++/* C_GetInfo returns general information about Cryptoki. */
++CK_PKCS11_FUNCTION_INFO(C_GetInfo)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_INFO_PTR pInfo /* location that receives information */
++);
++#endif
++
++
++/* C_GetFunctionList returns the function list. */
++CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
++ * function list */
++);
++#endif
++
++
++
++/* Slot and token management */
++
++/* C_GetSlotList obtains a list of slots in the system. */
++CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_BBOOL tokenPresent, /* only slots with tokens? */
++ CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
++ CK_ULONG_PTR pulCount /* receives number of slots */
++);
++#endif
++
++
++/* C_GetSlotInfo obtains information about a particular slot in
++ * the system. */
++CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SLOT_ID slotID, /* the ID of the slot */
++ CK_SLOT_INFO_PTR pInfo /* receives the slot information */
++);
++#endif
++
++
++/* C_GetTokenInfo obtains information about a particular token
++ * in the system. */
++CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SLOT_ID slotID, /* ID of the token's slot */
++ CK_TOKEN_INFO_PTR pInfo /* receives the token information */
++);
++#endif
++
++
++/* C_GetMechanismList obtains a list of mechanism types
++ * supported by a token. */
++CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SLOT_ID slotID, /* ID of token's slot */
++ CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
++ CK_ULONG_PTR pulCount /* gets # of mechs. */
++);
++#endif
++
++
++/* C_GetMechanismInfo obtains information about a particular
++ * mechanism possibly supported by a token. */
++CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SLOT_ID slotID, /* ID of the token's slot */
++ CK_MECHANISM_TYPE type, /* type of mechanism */
++ CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
++);
++#endif
++
++
++/* C_InitToken initializes a token. */
++CK_PKCS11_FUNCTION_INFO(C_InitToken)
++#ifdef CK_NEED_ARG_LIST
++/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
++(
++ CK_SLOT_ID slotID, /* ID of the token's slot */
++ CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */
++ CK_ULONG ulPinLen, /* length in bytes of the PIN */
++ CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */
++);
++#endif
++
++
++/* C_InitPIN initializes the normal user's PIN. */
++CK_PKCS11_FUNCTION_INFO(C_InitPIN)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */
++ CK_ULONG ulPinLen /* length in bytes of the PIN */
++);
++#endif
++
++
++/* C_SetPIN modifies the PIN of the user who is logged in. */
++CK_PKCS11_FUNCTION_INFO(C_SetPIN)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_UTF8CHAR_PTR pOldPin, /* the old PIN */
++ CK_ULONG ulOldLen, /* length of the old PIN */
++ CK_UTF8CHAR_PTR pNewPin, /* the new PIN */
++ CK_ULONG ulNewLen /* length of the new PIN */
++);
++#endif
++
++
++
++/* Session management */
++
++/* C_OpenSession opens a session between an application and a
++ * token. */
++CK_PKCS11_FUNCTION_INFO(C_OpenSession)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SLOT_ID slotID, /* the slot's ID */
++ CK_FLAGS flags, /* from CK_SESSION_INFO */
++ CK_VOID_PTR pApplication, /* passed to callback */
++ CK_NOTIFY Notify, /* callback function */
++ CK_SESSION_HANDLE_PTR phSession /* gets session handle */
++);
++#endif
++
++
++/* C_CloseSession closes a session between an application and a
++ * token. */
++CK_PKCS11_FUNCTION_INFO(C_CloseSession)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession /* the session's handle */
++);
++#endif
++
++
++/* C_CloseAllSessions closes all sessions with a token. */
++CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SLOT_ID slotID /* the token's slot */
++);
++#endif
++
++
++/* C_GetSessionInfo obtains information about the session. */
++CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_SESSION_INFO_PTR pInfo /* receives session info */
++);
++#endif
++
++
++/* C_GetOperationState obtains the state of the cryptographic operation
++ * in a session. */
++CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_BYTE_PTR pOperationState, /* gets state */
++ CK_ULONG_PTR pulOperationStateLen /* gets state length */
++);
++#endif
++
++
++/* C_SetOperationState restores the state of the cryptographic
++ * operation in a session. */
++CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_BYTE_PTR pOperationState, /* holds state */
++ CK_ULONG ulOperationStateLen, /* holds state length */
++ CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
++ CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
++);
++#endif
++
++
++/* C_Login logs a user into a token. */
++CK_PKCS11_FUNCTION_INFO(C_Login)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_USER_TYPE userType, /* the user type */
++ CK_UTF8CHAR_PTR pPin, /* the user's PIN */
++ CK_ULONG ulPinLen /* the length of the PIN */
++);
++#endif
++
++
++/* C_Logout logs a user out from a token. */
++CK_PKCS11_FUNCTION_INFO(C_Logout)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession /* the session's handle */
++);
++#endif
++
++
++
++/* Object management */
++
++/* C_CreateObject creates a new object. */
++CK_PKCS11_FUNCTION_INFO(C_CreateObject)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
++ CK_ULONG ulCount, /* attributes in template */
++ CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
++);
++#endif
++
++
++/* C_CopyObject copies an object, creating a new object for the
++ * copy. */
++CK_PKCS11_FUNCTION_INFO(C_CopyObject)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_OBJECT_HANDLE hObject, /* the object's handle */
++ CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
++ CK_ULONG ulCount, /* attributes in template */
++ CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
++);
++#endif
++
++
++/* C_DestroyObject destroys an object. */
++CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_OBJECT_HANDLE hObject /* the object's handle */
++);
++#endif
++
++
++/* C_GetObjectSize gets the size of an object in bytes. */
++CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_OBJECT_HANDLE hObject, /* the object's handle */
++ CK_ULONG_PTR pulSize /* receives size of object */
++);
++#endif
++
++
++/* C_GetAttributeValue obtains the value of one or more object
++ * attributes. */
++CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_OBJECT_HANDLE hObject, /* the object's handle */
++ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
++ CK_ULONG ulCount /* attributes in template */
++);
++#endif
++
++
++/* C_SetAttributeValue modifies the value of one or more object
++ * attributes */
++CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_OBJECT_HANDLE hObject, /* the object's handle */
++ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
++ CK_ULONG ulCount /* attributes in template */
++);
++#endif
++
++
++/* C_FindObjectsInit initializes a search for token and session
++ * objects that match a template. */
++CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
++ CK_ULONG ulCount /* attrs in search template */
++);
++#endif
++
++
++/* C_FindObjects continues a search for token and session
++ * objects that match a template, obtaining additional object
++ * handles. */
++CK_PKCS11_FUNCTION_INFO(C_FindObjects)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
++ CK_ULONG ulMaxObjectCount, /* max handles to get */
++ CK_ULONG_PTR pulObjectCount /* actual # returned */
++);
++#endif
++
++
++/* C_FindObjectsFinal finishes a search for token and session
++ * objects. */
++CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession /* the session's handle */
++);
++#endif
++
++
++
++/* Encryption and decryption */
++
++/* C_EncryptInit initializes an encryption operation. */
++CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
++ CK_OBJECT_HANDLE hKey /* handle of encryption key */
++);
++#endif
++
++
++/* C_Encrypt encrypts single-part data. */
++CK_PKCS11_FUNCTION_INFO(C_Encrypt)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_BYTE_PTR pData, /* the plaintext data */
++ CK_ULONG ulDataLen, /* bytes of plaintext */
++ CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
++ CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
++);
++#endif
++
++
++/* C_EncryptUpdate continues a multiple-part encryption
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_BYTE_PTR pPart, /* the plaintext data */
++ CK_ULONG ulPartLen, /* plaintext data len */
++ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
++ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
++);
++#endif
++
++
++/* C_EncryptFinal finishes a multiple-part encryption
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session handle */
++ CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
++ CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
++);
++#endif
++
++
++/* C_DecryptInit initializes a decryption operation. */
++CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
++ CK_OBJECT_HANDLE hKey /* handle of decryption key */
++);
++#endif
++
++
++/* C_Decrypt decrypts encrypted data in a single part. */
++CK_PKCS11_FUNCTION_INFO(C_Decrypt)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_BYTE_PTR pEncryptedData, /* ciphertext */
++ CK_ULONG ulEncryptedDataLen, /* ciphertext length */
++ CK_BYTE_PTR pData, /* gets plaintext */
++ CK_ULONG_PTR pulDataLen /* gets p-text size */
++);
++#endif
++
++
++/* C_DecryptUpdate continues a multiple-part decryption
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_BYTE_PTR pEncryptedPart, /* encrypted data */
++ CK_ULONG ulEncryptedPartLen, /* input length */
++ CK_BYTE_PTR pPart, /* gets plaintext */
++ CK_ULONG_PTR pulPartLen /* p-text size */
++);
++#endif
++
++
++/* C_DecryptFinal finishes a multiple-part decryption
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pLastPart, /* gets plaintext */
++ CK_ULONG_PTR pulLastPartLen /* p-text size */
++);
++#endif
++
++
++
++/* Message digesting */
++
++/* C_DigestInit initializes a message-digesting operation. */
++CK_PKCS11_FUNCTION_INFO(C_DigestInit)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
++);
++#endif
++
++
++/* C_Digest digests data in a single part. */
++CK_PKCS11_FUNCTION_INFO(C_Digest)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pData, /* data to be digested */
++ CK_ULONG ulDataLen, /* bytes of data to digest */
++ CK_BYTE_PTR pDigest, /* gets the message digest */
++ CK_ULONG_PTR pulDigestLen /* gets digest length */
++);
++#endif
++
++
++/* C_DigestUpdate continues a multiple-part message-digesting
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pPart, /* data to be digested */
++ CK_ULONG ulPartLen /* bytes of data to be digested */
++);
++#endif
++
++
++/* C_DigestKey continues a multi-part message-digesting
++ * operation, by digesting the value of a secret key as part of
++ * the data already digested. */
++CK_PKCS11_FUNCTION_INFO(C_DigestKey)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_OBJECT_HANDLE hKey /* secret key to digest */
++);
++#endif
++
++
++/* C_DigestFinal finishes a multiple-part message-digesting
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pDigest, /* gets the message digest */
++ CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
++);
++#endif
++
++
++
++/* Signing and MACing */
++
++/* C_SignInit initializes a signature (private key encryption)
++ * operation, where the signature is (will be) an appendix to
++ * the data, and plaintext cannot be recovered from the
++ *signature. */
++CK_PKCS11_FUNCTION_INFO(C_SignInit)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
++ CK_OBJECT_HANDLE hKey /* handle of signature key */
++);
++#endif
++
++
++/* C_Sign signs (encrypts with private key) data in a single
++ * part, where the signature is (will be) an appendix to the
++ * data, and plaintext cannot be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_Sign)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pData, /* the data to sign */
++ CK_ULONG ulDataLen, /* count of bytes to sign */
++ CK_BYTE_PTR pSignature, /* gets the signature */
++ CK_ULONG_PTR pulSignatureLen /* gets signature length */
++);
++#endif
++
++
++/* C_SignUpdate continues a multiple-part signature operation,
++ * where the signature is (will be) an appendix to the data,
++ * and plaintext cannot be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pPart, /* the data to sign */
++ CK_ULONG ulPartLen /* count of bytes to sign */
++);
++#endif
++
++
++/* C_SignFinal finishes a multiple-part signature operation,
++ * returning the signature. */
++CK_PKCS11_FUNCTION_INFO(C_SignFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pSignature, /* gets the signature */
++ CK_ULONG_PTR pulSignatureLen /* gets signature length */
++);
++#endif
++
++
++/* C_SignRecoverInit initializes a signature operation, where
++ * the data can be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
++ CK_OBJECT_HANDLE hKey /* handle of the signature key */
++);
++#endif
++
++
++/* C_SignRecover signs data in a single operation, where the
++ * data can be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_SignRecover)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pData, /* the data to sign */
++ CK_ULONG ulDataLen, /* count of bytes to sign */
++ CK_BYTE_PTR pSignature, /* gets the signature */
++ CK_ULONG_PTR pulSignatureLen /* gets signature length */
++);
++#endif
++
++
++
++/* Verifying signatures and MACs */
++
++/* C_VerifyInit initializes a verification operation, where the
++ * signature is an appendix to the data, and plaintext cannot
++ * cannot be recovered from the signature (e.g. DSA). */
++CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
++ CK_OBJECT_HANDLE hKey /* verification key */
++);
++#endif
++
++
++/* C_Verify verifies a signature in a single-part operation,
++ * where the signature is an appendix to the data, and plaintext
++ * cannot be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_Verify)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pData, /* signed data */
++ CK_ULONG ulDataLen, /* length of signed data */
++ CK_BYTE_PTR pSignature, /* signature */
++ CK_ULONG ulSignatureLen /* signature length*/
++);
++#endif
++
++
++/* C_VerifyUpdate continues a multiple-part verification
++ * operation, where the signature is an appendix to the data,
++ * and plaintext cannot be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pPart, /* signed data */
++ CK_ULONG ulPartLen /* length of signed data */
++);
++#endif
++
++
++/* C_VerifyFinal finishes a multiple-part verification
++ * operation, checking the signature. */
++CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pSignature, /* signature to verify */
++ CK_ULONG ulSignatureLen /* signature length */
++);
++#endif
++
++
++/* C_VerifyRecoverInit initializes a signature verification
++ * operation, where the data is recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
++ CK_OBJECT_HANDLE hKey /* verification key */
++);
++#endif
++
++
++/* C_VerifyRecover verifies a signature in a single-part
++ * operation, where the data is recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pSignature, /* signature to verify */
++ CK_ULONG ulSignatureLen, /* signature length */
++ CK_BYTE_PTR pData, /* gets signed data */
++ CK_ULONG_PTR pulDataLen /* gets signed data len */
++);
++#endif
++
++
++
++/* Dual-function cryptographic operations */
++
++/* C_DigestEncryptUpdate continues a multiple-part digesting
++ * and encryption operation. */
++CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_BYTE_PTR pPart, /* the plaintext data */
++ CK_ULONG ulPartLen, /* plaintext length */
++ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
++ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
++);
++#endif
++
++
++/* C_DecryptDigestUpdate continues a multiple-part decryption and
++ * digesting operation. */
++CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
++ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
++ CK_BYTE_PTR pPart, /* gets plaintext */
++ CK_ULONG_PTR pulPartLen /* gets plaintext len */
++);
++#endif
++
++
++/* C_SignEncryptUpdate continues a multiple-part signing and
++ * encryption operation. */
++CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_BYTE_PTR pPart, /* the plaintext data */
++ CK_ULONG ulPartLen, /* plaintext length */
++ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
++ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
++);
++#endif
++
++
++/* C_DecryptVerifyUpdate continues a multiple-part decryption and
++ * verify operation. */
++CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
++ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
++ CK_BYTE_PTR pPart, /* gets plaintext */
++ CK_ULONG_PTR pulPartLen /* gets p-text length */
++);
++#endif
++
++
++
++/* Key management */
++
++/* C_GenerateKey generates a secret key, creating a new key
++ * object. */
++CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_MECHANISM_PTR pMechanism, /* key generation mech. */
++ CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
++ CK_ULONG ulCount, /* # of attrs in template */
++ CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
++);
++#endif
++
++
++/* C_GenerateKeyPair generates a public-key/private-key pair,
++ * creating new key objects. */
++CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session
++ * handle */
++ CK_MECHANISM_PTR pMechanism, /* key-gen
++ * mech. */
++ CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template
++ * for pub.
++ * key */
++ CK_ULONG ulPublicKeyAttributeCount, /* # pub.
++ * attrs. */
++ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template
++ * for priv.
++ * key */
++ CK_ULONG ulPrivateKeyAttributeCount, /* # priv.
++ * attrs. */
++ CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub.
++ * key
++ * handle */
++ CK_OBJECT_HANDLE_PTR phPrivateKey /* gets
++ * priv. key
++ * handle */
++);
++#endif
++
++
++/* C_WrapKey wraps (i.e., encrypts) a key. */
++CK_PKCS11_FUNCTION_INFO(C_WrapKey)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
++ CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
++ CK_OBJECT_HANDLE hKey, /* key to be wrapped */
++ CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
++ CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
++);
++#endif
++
++
++/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
++ * key object. */
++CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
++ CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
++ CK_BYTE_PTR pWrappedKey, /* the wrapped key */
++ CK_ULONG ulWrappedKeyLen, /* wrapped key len */
++ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
++ CK_ULONG ulAttributeCount, /* template length */
++ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
++);
++#endif
++
++
++/* C_DeriveKey derives a key from a base key, creating a new key
++ * object. */
++CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* session's handle */
++ CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
++ CK_OBJECT_HANDLE hBaseKey, /* base key */
++ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
++ CK_ULONG ulAttributeCount, /* template length */
++ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
++);
++#endif
++
++
++
++/* Random number generation */
++
++/* C_SeedRandom mixes additional seed material into the token's
++ * random number generator. */
++CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR pSeed, /* the seed material */
++ CK_ULONG ulSeedLen /* length of seed material */
++);
++#endif
++
++
++/* C_GenerateRandom generates random data. */
++CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_BYTE_PTR RandomData, /* receives the random data */
++ CK_ULONG ulRandomLen /* # of bytes to generate */
++);
++#endif
++
++
++
++/* Parallel function management */
++
++/* C_GetFunctionStatus is a legacy function; it obtains an
++ * updated status of a function running in parallel with an
++ * application. */
++CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession /* the session's handle */
++);
++#endif
++
++
++/* C_CancelFunction is a legacy function; it cancels a function
++ * running in parallel. */
++CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE hSession /* the session's handle */
++);
++#endif
++
++
++
++/* Functions added in for Cryptoki Version 2.01 or later */
++
++/* C_WaitForSlotEvent waits for a slot event (token insertion,
++ * removal, etc.) to occur. */
++CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_FLAGS flags, /* blocking/nonblocking flag */
++ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
++ CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
++);
++#endif
+diff -urNp openssh-4.4p1/pkcs11-headers/pkcs11.h openssh-4.4p1+pkcs11-0.17/pkcs11-headers/pkcs11.h
+--- openssh-4.4p1/pkcs11-headers/pkcs11.h 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/pkcs11-headers/pkcs11.h 2006-09-28 08:05:35.000000000 +0300
+@@ -0,0 +1,299 @@
++/* pkcs11.h include file for PKCS #11. */
++/* $Revision: 1.4 $ */
++
++/* License to copy and use this software is granted provided that it is
++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
++ * (Cryptoki)" in all material mentioning or referencing this software.
++
++ * License is also granted to make and use derivative works provided that
++ * such works are identified as "derived from the RSA Security Inc. PKCS #11
++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
++ * referencing the derived work.
++
++ * RSA Security Inc. makes no representations concerning either the
++ * merchantability of this software or the suitability of this software for
++ * any particular purpose. It is provided "as is" without express or implied
++ * warranty of any kind.
++ */
++
++#ifndef _PKCS11_H_
++#define _PKCS11_H_ 1
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* Before including this file (pkcs11.h) (or pkcs11t.h by
++ * itself), 6 platform-specific macros must be defined. These
++ * macros are described below, and typical definitions for them
++ * are also given. Be advised that these definitions can depend
++ * on both the platform and the compiler used (and possibly also
++ * on whether a Cryptoki library is linked statically or
++ * dynamically).
++ *
++ * In addition to defining these 6 macros, the packing convention
++ * for Cryptoki structures should be set. The Cryptoki
++ * convention on packing is that structures should be 1-byte
++ * aligned.
++ *
++ * If you're using Microsoft Developer Studio 5.0 to produce
++ * Win32 stuff, this might be done by using the following
++ * preprocessor directive before including pkcs11.h or pkcs11t.h:
++ *
++ * #pragma pack(push, cryptoki, 1)
++ *
++ * and using the following preprocessor directive after including
++ * pkcs11.h or pkcs11t.h:
++ *
++ * #pragma pack(pop, cryptoki)
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to produce Win16 stuff, this might be done by using
++ * the following preprocessor directive before including
++ * pkcs11.h or pkcs11t.h:
++ *
++ * #pragma pack(1)
++ *
++ * In a UNIX environment, you're on your own for this. You might
++ * not need to do (or be able to do!) anything.
++ *
++ *
++ * Now for the macros:
++ *
++ *
++ * 1. CK_PTR: The indirection string for making a pointer to an
++ * object. It can be used like this:
++ *
++ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
++ *
++ * If you're using Microsoft Developer Studio 5.0 to produce
++ * Win32 stuff, it might be defined by:
++ *
++ * #define CK_PTR *
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to produce Win16 stuff, it might be defined by:
++ *
++ * #define CK_PTR far *
++ *
++ * In a typical UNIX environment, it might be defined by:
++ *
++ * #define CK_PTR *
++ *
++ *
++ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
++ * an exportable Cryptoki library function definition out of a
++ * return type and a function name. It should be used in the
++ * following fashion to define the exposed Cryptoki functions in
++ * a Cryptoki library:
++ *
++ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
++ * CK_VOID_PTR pReserved
++ * )
++ * {
++ * ...
++ * }
++ *
++ * If you're using Microsoft Developer Studio 5.0 to define a
++ * function in a Win32 Cryptoki .dll, it might be defined by:
++ *
++ * #define CK_DEFINE_FUNCTION(returnType, name) \
++ * returnType __declspec(dllexport) name
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to define a function in a Win16 Cryptoki .dll, it
++ * might be defined by:
++ *
++ * #define CK_DEFINE_FUNCTION(returnType, name) \
++ * returnType __export _far _pascal name
++ *
++ * In a UNIX environment, it might be defined by:
++ *
++ * #define CK_DEFINE_FUNCTION(returnType, name) \
++ * returnType name
++ *
++ *
++ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
++ * an importable Cryptoki library function declaration out of a
++ * return type and a function name. It should be used in the
++ * following fashion:
++ *
++ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
++ * CK_VOID_PTR pReserved
++ * );
++ *
++ * If you're using Microsoft Developer Studio 5.0 to declare a
++ * function in a Win32 Cryptoki .dll, it might be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION(returnType, name) \
++ * returnType __declspec(dllimport) name
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to declare a function in a Win16 Cryptoki .dll, it
++ * might be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION(returnType, name) \
++ * returnType __export _far _pascal name
++ *
++ * In a UNIX environment, it might be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION(returnType, name) \
++ * returnType name
++ *
++ *
++ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
++ * which makes a Cryptoki API function pointer declaration or
++ * function pointer type declaration out of a return type and a
++ * function name. It should be used in the following fashion:
++ *
++ * // Define funcPtr to be a pointer to a Cryptoki API function
++ * // taking arguments args and returning CK_RV.
++ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
++ *
++ * or
++ *
++ * // Define funcPtrType to be the type of a pointer to a
++ * // Cryptoki API function taking arguments args and returning
++ * // CK_RV, and then define funcPtr to be a variable of type
++ * // funcPtrType.
++ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
++ * funcPtrType funcPtr;
++ *
++ * If you're using Microsoft Developer Studio 5.0 to access
++ * functions in a Win32 Cryptoki .dll, in might be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
++ * returnType __declspec(dllimport) (* name)
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to access functions in a Win16 Cryptoki .dll, it might
++ * be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
++ * returnType __export _far _pascal (* name)
++ *
++ * In a UNIX environment, it might be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
++ * returnType (* name)
++ *
++ *
++ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
++ * a function pointer type for an application callback out of
++ * a return type for the callback and a name for the callback.
++ * It should be used in the following fashion:
++ *
++ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
++ *
++ * to declare a function pointer, myCallback, to a callback
++ * which takes arguments args and returns a CK_RV. It can also
++ * be used like this:
++ *
++ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
++ * myCallbackType myCallback;
++ *
++ * If you're using Microsoft Developer Studio 5.0 to do Win32
++ * Cryptoki development, it might be defined by:
++ *
++ * #define CK_CALLBACK_FUNCTION(returnType, name) \
++ * returnType (* name)
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to do Win16 development, it might be defined by:
++ *
++ * #define CK_CALLBACK_FUNCTION(returnType, name) \
++ * returnType _far _pascal (* name)
++ *
++ * In a UNIX environment, it might be defined by:
++ *
++ * #define CK_CALLBACK_FUNCTION(returnType, name) \
++ * returnType (* name)
++ *
++ *
++ * 6. NULL_PTR: This macro is the value of a NULL pointer.
++ *
++ * In any ANSI/ISO C environment (and in many others as well),
++ * this should best be defined by
++ *
++ * #ifndef NULL_PTR
++ * #define NULL_PTR 0
++ * #endif
++ */
++
++
++/* All the various Cryptoki types and #define'd values are in the
++ * file pkcs11t.h. */
++#include "pkcs11t.h"
++
++#define __PASTE(x,y) x##y
++
++
++/* ==============================================================
++ * Define the "extern" form of all the entry points.
++ * ==============================================================
++ */
++
++#define CK_NEED_ARG_LIST 1
++#define CK_PKCS11_FUNCTION_INFO(name) \
++ extern CK_DECLARE_FUNCTION(CK_RV, name)
++
++/* pkcs11f.h has all the information about the Cryptoki
++ * function prototypes. */
++#include "pkcs11f.h"
++
++#undef CK_NEED_ARG_LIST
++#undef CK_PKCS11_FUNCTION_INFO
++
++
++/* ==============================================================
++ * Define the typedef form of all the entry points. That is, for
++ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
++ * a pointer to that kind of function.
++ * ==============================================================
++ */
++
++#define CK_NEED_ARG_LIST 1
++#define CK_PKCS11_FUNCTION_INFO(name) \
++ typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
++
++/* pkcs11f.h has all the information about the Cryptoki
++ * function prototypes. */
++#include "pkcs11f.h"
++
++#undef CK_NEED_ARG_LIST
++#undef CK_PKCS11_FUNCTION_INFO
++
++
++/* ==============================================================
++ * Define structed vector of entry points. A CK_FUNCTION_LIST
++ * contains a CK_VERSION indicating a library's Cryptoki version
++ * and then a whole slew of function pointers to the routines in
++ * the library. This type was declared, but not defined, in
++ * pkcs11t.h.
++ * ==============================================================
++ */
++
++#define CK_PKCS11_FUNCTION_INFO(name) \
++ __PASTE(CK_,name) name;
++
++struct CK_FUNCTION_LIST {
++
++ CK_VERSION version; /* Cryptoki version */
++
++/* Pile all the function pointers into the CK_FUNCTION_LIST. */
++/* pkcs11f.h has all the information about the Cryptoki
++ * function prototypes. */
++#include "pkcs11f.h"
++
++};
++
++#undef CK_PKCS11_FUNCTION_INFO
++
++
++#undef __PASTE
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+diff -urNp openssh-4.4p1/pkcs11-headers/pkcs11t.h openssh-4.4p1+pkcs11-0.17/pkcs11-headers/pkcs11t.h
+--- openssh-4.4p1/pkcs11-headers/pkcs11t.h 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/pkcs11-headers/pkcs11t.h 2006-09-28 08:05:35.000000000 +0300
+@@ -0,0 +1,1685 @@
++/* pkcs11t.h include file for PKCS #11. */
++/* $Revision: 1.6 $ */
++
++/* License to copy and use this software is granted provided that it is
++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
++ * (Cryptoki)" in all material mentioning or referencing this software.
++
++ * License is also granted to make and use derivative works provided that
++ * such works are identified as "derived from the RSA Security Inc. PKCS #11
++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
++ * referencing the derived work.
++
++ * RSA Security Inc. makes no representations concerning either the
++ * merchantability of this software or the suitability of this software for
++ * any particular purpose. It is provided "as is" without express or implied
++ * warranty of any kind.
++ */
++
++/* See top of pkcs11.h for information about the macros that
++ * must be defined and the structure-packing conventions that
++ * must be set before including this file. */
++
++#ifndef _PKCS11T_H_
++#define _PKCS11T_H_ 1
++
++#define CK_TRUE 1
++#define CK_FALSE 0
++
++#ifndef CK_DISABLE_TRUE_FALSE
++#ifndef FALSE
++#define FALSE CK_FALSE
++#endif
++
++#ifndef TRUE
++#define TRUE CK_TRUE
++#endif
++#endif
++
++/* an unsigned 8-bit value */
++typedef unsigned char CK_BYTE;
++
++/* an unsigned 8-bit character */
++typedef CK_BYTE CK_CHAR;
++
++/* an 8-bit UTF-8 character */
++typedef CK_BYTE CK_UTF8CHAR;
++
++/* a BYTE-sized Boolean flag */
++typedef CK_BYTE CK_BBOOL;
++
++/* an unsigned value, at least 32 bits long */
++typedef unsigned long int CK_ULONG;
++
++/* a signed value, the same size as a CK_ULONG */
++/* CK_LONG is new for v2.0 */
++typedef long int CK_LONG;
++
++/* at least 32 bits; each bit is a Boolean flag */
++typedef CK_ULONG CK_FLAGS;
++
++
++/* some special values for certain CK_ULONG variables */
++#define CK_UNAVAILABLE_INFORMATION (~0UL)
++#define CK_EFFECTIVELY_INFINITE 0
++
++
++typedef CK_BYTE CK_PTR CK_BYTE_PTR;
++typedef CK_CHAR CK_PTR CK_CHAR_PTR;
++typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR;
++typedef CK_ULONG CK_PTR CK_ULONG_PTR;
++typedef void CK_PTR CK_VOID_PTR;
++
++/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
++typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
++
++
++/* The following value is always invalid if used as a session */
++/* handle or object handle */
++#define CK_INVALID_HANDLE 0
++
++
++typedef struct CK_VERSION {
++ CK_BYTE major; /* integer portion of version number */
++ CK_BYTE minor; /* 1/100ths portion of version number */
++} CK_VERSION;
++
++typedef CK_VERSION CK_PTR CK_VERSION_PTR;
++
++
++typedef struct CK_INFO {
++ /* manufacturerID and libraryDecription have been changed from
++ * CK_CHAR to CK_UTF8CHAR for v2.10 */
++ CK_VERSION cryptokiVersion; /* Cryptoki interface ver */
++ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
++ CK_FLAGS flags; /* must be zero */
++
++ /* libraryDescription and libraryVersion are new for v2.0 */
++ CK_UTF8CHAR libraryDescription[32]; /* blank padded */
++ CK_VERSION libraryVersion; /* version of library */
++} CK_INFO;
++
++typedef CK_INFO CK_PTR CK_INFO_PTR;
++
++
++/* CK_NOTIFICATION enumerates the types of notifications that
++ * Cryptoki provides to an application */
++/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG
++ * for v2.0 */
++typedef CK_ULONG CK_NOTIFICATION;
++#define CKN_SURRENDER 0
++
++
++typedef CK_ULONG CK_SLOT_ID;
++
++typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
++
++
++/* CK_SLOT_INFO provides information about a slot */
++typedef struct CK_SLOT_INFO {
++ /* slotDescription and manufacturerID have been changed from
++ * CK_CHAR to CK_UTF8CHAR for v2.10 */
++ CK_UTF8CHAR slotDescription[64]; /* blank padded */
++ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
++ CK_FLAGS flags;
++
++ /* hardwareVersion and firmwareVersion are new for v2.0 */
++ CK_VERSION hardwareVersion; /* version of hardware */
++ CK_VERSION firmwareVersion; /* version of firmware */
++} CK_SLOT_INFO;
++
++/* flags: bit flags that provide capabilities of the slot
++ * Bit Flag Mask Meaning
++ */
++#define CKF_TOKEN_PRESENT 0x00000001 /* a token is there */
++#define CKF_REMOVABLE_DEVICE 0x00000002 /* removable devices*/
++#define CKF_HW_SLOT 0x00000004 /* hardware slot */
++
++typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
++
++
++/* CK_TOKEN_INFO provides information about a token */
++typedef struct CK_TOKEN_INFO {
++ /* label, manufacturerID, and model have been changed from
++ * CK_CHAR to CK_UTF8CHAR for v2.10 */
++ CK_UTF8CHAR label[32]; /* blank padded */
++ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
++ CK_UTF8CHAR model[16]; /* blank padded */
++ CK_CHAR serialNumber[16]; /* blank padded */
++ CK_FLAGS flags; /* see below */
++
++ /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount,
++ * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been
++ * changed from CK_USHORT to CK_ULONG for v2.0 */
++ CK_ULONG ulMaxSessionCount; /* max open sessions */
++ CK_ULONG ulSessionCount; /* sess. now open */
++ CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */
++ CK_ULONG ulRwSessionCount; /* R/W sess. now open */
++ CK_ULONG ulMaxPinLen; /* in bytes */
++ CK_ULONG ulMinPinLen; /* in bytes */
++ CK_ULONG ulTotalPublicMemory; /* in bytes */
++ CK_ULONG ulFreePublicMemory; /* in bytes */
++ CK_ULONG ulTotalPrivateMemory; /* in bytes */
++ CK_ULONG ulFreePrivateMemory; /* in bytes */
++
++ /* hardwareVersion, firmwareVersion, and time are new for
++ * v2.0 */
++ CK_VERSION hardwareVersion; /* version of hardware */
++ CK_VERSION firmwareVersion; /* version of firmware */
++ CK_CHAR utcTime[16]; /* time */
++} CK_TOKEN_INFO;
++
++/* The flags parameter is defined as follows:
++ * Bit Flag Mask Meaning
++ */
++#define CKF_RNG 0x00000001 /* has random #
++ * generator */
++#define CKF_WRITE_PROTECTED 0x00000002 /* token is
++ * write-
++ * protected */
++#define CKF_LOGIN_REQUIRED 0x00000004 /* user must
++ * login */
++#define CKF_USER_PIN_INITIALIZED 0x00000008 /* normal user's
++ * PIN is set */
++
++/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0. If it is set,
++ * that means that *every* time the state of cryptographic
++ * operations of a session is successfully saved, all keys
++ * needed to continue those operations are stored in the state */
++#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020
++
++/* CKF_CLOCK_ON_TOKEN is new for v2.0. If it is set, that means
++ * that the token has some sort of clock. The time on that
++ * clock is returned in the token info structure */
++#define CKF_CLOCK_ON_TOKEN 0x00000040
++
++/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0. If it is
++ * set, that means that there is some way for the user to login
++ * without sending a PIN through the Cryptoki library itself */
++#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100
++
++/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0. If it is true,
++ * that means that a single session with the token can perform
++ * dual simultaneous cryptographic operations (digest and
++ * encrypt; decrypt and digest; sign and encrypt; and decrypt
++ * and sign) */
++#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200
++
++/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the
++ * token has been initialized using C_InitializeToken or an
++ * equivalent mechanism outside the scope of PKCS #11.
++ * Calling C_InitializeToken when this flag is set will cause
++ * the token to be reinitialized. */
++#define CKF_TOKEN_INITIALIZED 0x00000400
++
++/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is
++ * true, the token supports secondary authentication for
++ * private key objects. This flag is deprecated in v2.11 and
++ onwards. */
++#define CKF_SECONDARY_AUTHENTICATION 0x00000800
++
++/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an
++ * incorrect user login PIN has been entered at least once
++ * since the last successful authentication. */
++#define CKF_USER_PIN_COUNT_LOW 0x00010000
++
++/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true,
++ * supplying an incorrect user PIN will it to become locked. */
++#define CKF_USER_PIN_FINAL_TRY 0x00020000
++
++/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the
++ * user PIN has been locked. User login to the token is not
++ * possible. */
++#define CKF_USER_PIN_LOCKED 0x00040000
++
++/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
++ * the user PIN value is the default value set by token
++ * initialization or manufacturing, or the PIN has been
++ * expired by the card. */
++#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000
++
++/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an
++ * incorrect SO login PIN has been entered at least once since
++ * the last successful authentication. */
++#define CKF_SO_PIN_COUNT_LOW 0x00100000
++
++/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true,
++ * supplying an incorrect SO PIN will it to become locked. */
++#define CKF_SO_PIN_FINAL_TRY 0x00200000
++
++/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO
++ * PIN has been locked. SO login to the token is not possible.
++ */
++#define CKF_SO_PIN_LOCKED 0x00400000
++
++/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
++ * the SO PIN value is the default value set by token
++ * initialization or manufacturing, or the PIN has been
++ * expired by the card. */
++#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000
++
++typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
++
++
++/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
++ * identifies a session */
++typedef CK_ULONG CK_SESSION_HANDLE;
++
++typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
++
++
++/* CK_USER_TYPE enumerates the types of Cryptoki users */
++/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for
++ * v2.0 */
++typedef CK_ULONG CK_USER_TYPE;
++/* Security Officer */
++#define CKU_SO 0
++/* Normal user */
++#define CKU_USER 1
++/* Context specific (added in v2.20) */
++#define CKU_CONTEXT_SPECIFIC 2
++
++/* CK_STATE enumerates the session states */
++/* CK_STATE has been changed from an enum to a CK_ULONG for
++ * v2.0 */
++typedef CK_ULONG CK_STATE;
++#define CKS_RO_PUBLIC_SESSION 0
++#define CKS_RO_USER_FUNCTIONS 1
++#define CKS_RW_PUBLIC_SESSION 2
++#define CKS_RW_USER_FUNCTIONS 3
++#define CKS_RW_SO_FUNCTIONS 4
++
++
++/* CK_SESSION_INFO provides information about a session */
++typedef struct CK_SESSION_INFO {
++ CK_SLOT_ID slotID;
++ CK_STATE state;
++ CK_FLAGS flags; /* see below */
++
++ /* ulDeviceError was changed from CK_USHORT to CK_ULONG for
++ * v2.0 */
++ CK_ULONG ulDeviceError; /* device-dependent error code */
++} CK_SESSION_INFO;
++
++/* The flags are defined in the following table:
++ * Bit Flag Mask Meaning
++ */
++#define CKF_RW_SESSION 0x00000002 /* session is r/w */
++#define CKF_SERIAL_SESSION 0x00000004 /* no parallel */
++
++typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
++
++
++/* CK_OBJECT_HANDLE is a token-specific identifier for an
++ * object */
++typedef CK_ULONG CK_OBJECT_HANDLE;
++
++typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
++
++
++/* CK_OBJECT_CLASS is a value that identifies the classes (or
++ * types) of objects that Cryptoki recognizes. It is defined
++ * as follows: */
++/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for
++ * v2.0 */
++typedef CK_ULONG CK_OBJECT_CLASS;
++
++/* The following classes of objects are defined: */
++/* CKO_HW_FEATURE is new for v2.10 */
++/* CKO_DOMAIN_PARAMETERS is new for v2.11 */
++/* CKO_MECHANISM is new for v2.20 */
++#define CKO_DATA 0x00000000
++#define CKO_CERTIFICATE 0x00000001
++#define CKO_PUBLIC_KEY 0x00000002
++#define CKO_PRIVATE_KEY 0x00000003
++#define CKO_SECRET_KEY 0x00000004
++#define CKO_HW_FEATURE 0x00000005
++#define CKO_DOMAIN_PARAMETERS 0x00000006
++#define CKO_MECHANISM 0x00000007
++#define CKO_VENDOR_DEFINED 0x80000000
++
++typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
++
++/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a
++ * value that identifies the hardware feature type of an object
++ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
++typedef CK_ULONG CK_HW_FEATURE_TYPE;
++
++/* The following hardware feature types are defined */
++/* CKH_USER_INTERFACE is new for v2.20 */
++#define CKH_MONOTONIC_COUNTER 0x00000001
++#define CKH_CLOCK 0x00000002
++#define CKH_USER_INTERFACE 0x00000003
++#define CKH_VENDOR_DEFINED 0x80000000
++
++/* CK_KEY_TYPE is a value that identifies a key type */
++/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */
++typedef CK_ULONG CK_KEY_TYPE;
++
++/* the following key types are defined: */
++#define CKK_RSA 0x00000000
++#define CKK_DSA 0x00000001
++#define CKK_DH 0x00000002
++
++/* CKK_ECDSA and CKK_KEA are new for v2.0 */
++/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */
++#define CKK_ECDSA 0x00000003
++#define CKK_EC 0x00000003
++#define CKK_X9_42_DH 0x00000004
++#define CKK_KEA 0x00000005
++
++#define CKK_GENERIC_SECRET 0x00000010
++#define CKK_RC2 0x00000011
++#define CKK_RC4 0x00000012
++#define CKK_DES 0x00000013
++#define CKK_DES2 0x00000014
++#define CKK_DES3 0x00000015
++
++/* all these key types are new for v2.0 */
++#define CKK_CAST 0x00000016
++#define CKK_CAST3 0x00000017
++/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */
++#define CKK_CAST5 0x00000018
++#define CKK_CAST128 0x00000018
++#define CKK_RC5 0x00000019
++#define CKK_IDEA 0x0000001A
++#define CKK_SKIPJACK 0x0000001B
++#define CKK_BATON 0x0000001C
++#define CKK_JUNIPER 0x0000001D
++#define CKK_CDMF 0x0000001E
++#define CKK_AES 0x0000001F
++
++/* BlowFish and TwoFish are new for v2.20 */
++#define CKK_BLOWFISH 0x00000020
++#define CKK_TWOFISH 0x00000021
++
++#define CKK_VENDOR_DEFINED 0x80000000
++
++
++/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
++ * type */
++/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG
++ * for v2.0 */
++typedef CK_ULONG CK_CERTIFICATE_TYPE;
++
++/* The following certificate types are defined: */
++/* CKC_X_509_ATTR_CERT is new for v2.10 */
++/* CKC_WTLS is new for v2.20 */
++#define CKC_X_509 0x00000000
++#define CKC_X_509_ATTR_CERT 0x00000001
++#define CKC_WTLS 0x00000002
++#define CKC_VENDOR_DEFINED 0x80000000
++
++
++/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
++ * type */
++/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for
++ * v2.0 */
++typedef CK_ULONG CK_ATTRIBUTE_TYPE;
++
++/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
++ consists of an array of values. */
++#define CKF_ARRAY_ATTRIBUTE 0x40000000
++
++/* The following attribute types are defined: */
++#define CKA_CLASS 0x00000000
++#define CKA_TOKEN 0x00000001
++#define CKA_PRIVATE 0x00000002
++#define CKA_LABEL 0x00000003
++#define CKA_APPLICATION 0x00000010
++#define CKA_VALUE 0x00000011
++
++/* CKA_OBJECT_ID is new for v2.10 */
++#define CKA_OBJECT_ID 0x00000012
++
++#define CKA_CERTIFICATE_TYPE 0x00000080
++#define CKA_ISSUER 0x00000081
++#define CKA_SERIAL_NUMBER 0x00000082
++
++/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new
++ * for v2.10 */
++#define CKA_AC_ISSUER 0x00000083
++#define CKA_OWNER 0x00000084
++#define CKA_ATTR_TYPES 0x00000085
++
++/* CKA_TRUSTED is new for v2.11 */
++#define CKA_TRUSTED 0x00000086
++
++/* CKA_CERTIFICATE_CATEGORY ...
++ * CKA_CHECK_VALUE are new for v2.20 */
++#define CKA_CERTIFICATE_CATEGORY 0x00000087
++#define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088
++#define CKA_URL 0x00000089
++#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008A
++#define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008B
++#define CKA_CHECK_VALUE 0x00000090
++
++#define CKA_KEY_TYPE 0x00000100
++#define CKA_SUBJECT 0x00000101
++#define CKA_ID 0x00000102
++#define CKA_SENSITIVE 0x00000103
++#define CKA_ENCRYPT 0x00000104
++#define CKA_DECRYPT 0x00000105
++#define CKA_WRAP 0x00000106
++#define CKA_UNWRAP 0x00000107
++#define CKA_SIGN 0x00000108
++#define CKA_SIGN_RECOVER 0x00000109
++#define CKA_VERIFY 0x0000010A
++#define CKA_VERIFY_RECOVER 0x0000010B
++#define CKA_DERIVE 0x0000010C
++#define CKA_START_DATE 0x00000110
++#define CKA_END_DATE 0x00000111
++#define CKA_MODULUS 0x00000120
++#define CKA_MODULUS_BITS 0x00000121
++#define CKA_PUBLIC_EXPONENT 0x00000122
++#define CKA_PRIVATE_EXPONENT 0x00000123
++#define CKA_PRIME_1 0x00000124
++#define CKA_PRIME_2 0x00000125
++#define CKA_EXPONENT_1 0x00000126
++#define CKA_EXPONENT_2 0x00000127
++#define CKA_COEFFICIENT 0x00000128
++#define CKA_PRIME 0x00000130
++#define CKA_SUBPRIME 0x00000131
++#define CKA_BASE 0x00000132
++
++/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */
++#define CKA_PRIME_BITS 0x00000133
++#define CKA_SUBPRIME_BITS 0x00000134
++#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS
++/* (To retain backwards-compatibility) */
++
++#define CKA_VALUE_BITS 0x00000160
++#define CKA_VALUE_LEN 0x00000161
++
++/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE,
++ * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS,
++ * and CKA_EC_POINT are new for v2.0 */
++#define CKA_EXTRACTABLE 0x00000162
++#define CKA_LOCAL 0x00000163
++#define CKA_NEVER_EXTRACTABLE 0x00000164
++#define CKA_ALWAYS_SENSITIVE 0x00000165
++
++/* CKA_KEY_GEN_MECHANISM is new for v2.11 */
++#define CKA_KEY_GEN_MECHANISM 0x00000166
++
++#define CKA_MODIFIABLE 0x00000170
++
++/* CKA_ECDSA_PARAMS is deprecated in v2.11,
++ * CKA_EC_PARAMS is preferred. */
++#define CKA_ECDSA_PARAMS 0x00000180
++#define CKA_EC_PARAMS 0x00000180
++
++#define CKA_EC_POINT 0x00000181
++
++/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
++ * are new for v2.10. Deprecated in v2.11 and onwards. */
++#define CKA_SECONDARY_AUTH 0x00000200
++#define CKA_AUTH_PIN_FLAGS 0x00000201
++
++/* CKA_ALWAYS_AUTHENTICATE ...
++ * CKA_UNWRAP_TEMPLATE are new for v2.20 */
++#define CKA_ALWAYS_AUTHENTICATE 0x00000202
++
++#define CKA_WRAP_WITH_TRUSTED 0x00000210
++#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211)
++#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212)
++
++/* CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET
++ * are new for v2.10 */
++#define CKA_HW_FEATURE_TYPE 0x00000300
++#define CKA_RESET_ON_INIT 0x00000301
++#define CKA_HAS_RESET 0x00000302
++
++/* The following attributes are new for v2.20 */
++#define CKA_PIXEL_X 0x00000400
++#define CKA_PIXEL_Y 0x00000401
++#define CKA_RESOLUTION 0x00000402
++#define CKA_CHAR_ROWS 0x00000403
++#define CKA_CHAR_COLUMNS 0x00000404
++#define CKA_COLOR 0x00000405
++#define CKA_BITS_PER_PIXEL 0x00000406
++#define CKA_CHAR_SETS 0x00000480
++#define CKA_ENCODING_METHODS 0x00000481
++#define CKA_MIME_TYPES 0x00000482
++#define CKA_MECHANISM_TYPE 0x00000500
++#define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501
++#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502
++#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503
++#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600)
++
++#define CKA_VENDOR_DEFINED 0x80000000
++
++
++/* CK_ATTRIBUTE is a structure that includes the type, length
++ * and value of an attribute */
++typedef struct CK_ATTRIBUTE {
++ CK_ATTRIBUTE_TYPE type;
++ CK_VOID_PTR pValue;
++
++ /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */
++ CK_ULONG ulValueLen; /* in bytes */
++} CK_ATTRIBUTE;
++
++typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
++
++
++/* CK_DATE is a structure that defines a date */
++typedef struct CK_DATE{
++ CK_CHAR year[4]; /* the year ("1900" - "9999") */
++ CK_CHAR month[2]; /* the month ("01" - "12") */
++ CK_CHAR day[2]; /* the day ("01" - "31") */
++} CK_DATE;
++
++
++/* CK_MECHANISM_TYPE is a value that identifies a mechanism
++ * type */
++/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for
++ * v2.0 */
++typedef CK_ULONG CK_MECHANISM_TYPE;
++
++/* the following mechanism types are defined: */
++#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000
++#define CKM_RSA_PKCS 0x00000001
++#define CKM_RSA_9796 0x00000002
++#define CKM_RSA_X_509 0x00000003
++
++/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS
++ * are new for v2.0. They are mechanisms which hash and sign */
++#define CKM_MD2_RSA_PKCS 0x00000004
++#define CKM_MD5_RSA_PKCS 0x00000005
++#define CKM_SHA1_RSA_PKCS 0x00000006
++
++/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and
++ * CKM_RSA_PKCS_OAEP are new for v2.10 */
++#define CKM_RIPEMD128_RSA_PKCS 0x00000007
++#define CKM_RIPEMD160_RSA_PKCS 0x00000008
++#define CKM_RSA_PKCS_OAEP 0x00000009
++
++/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31,
++ * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */
++#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A
++#define CKM_RSA_X9_31 0x0000000B
++#define CKM_SHA1_RSA_X9_31 0x0000000C
++#define CKM_RSA_PKCS_PSS 0x0000000D
++#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E
++
++#define CKM_DSA_KEY_PAIR_GEN 0x00000010
++#define CKM_DSA 0x00000011
++#define CKM_DSA_SHA1 0x00000012
++#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020
++#define CKM_DH_PKCS_DERIVE 0x00000021
++
++/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE,
++ * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for
++ * v2.11 */
++#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030
++#define CKM_X9_42_DH_DERIVE 0x00000031
++#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032
++#define CKM_X9_42_MQV_DERIVE 0x00000033
++
++/* CKM_SHA256/384/512 are new for v2.20 */
++#define CKM_SHA256_RSA_PKCS 0x00000040
++#define CKM_SHA384_RSA_PKCS 0x00000041
++#define CKM_SHA512_RSA_PKCS 0x00000042
++#define CKM_SHA256_RSA_PKCS_PSS 0x00000043
++#define CKM_SHA384_RSA_PKCS_PSS 0x00000044
++#define CKM_SHA512_RSA_PKCS_PSS 0x00000045
++
++#define CKM_RC2_KEY_GEN 0x00000100
++#define CKM_RC2_ECB 0x00000101
++#define CKM_RC2_CBC 0x00000102
++#define CKM_RC2_MAC 0x00000103
++
++/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */
++#define CKM_RC2_MAC_GENERAL 0x00000104
++#define CKM_RC2_CBC_PAD 0x00000105
++
++#define CKM_RC4_KEY_GEN 0x00000110
++#define CKM_RC4 0x00000111
++#define CKM_DES_KEY_GEN 0x00000120
++#define CKM_DES_ECB 0x00000121
++#define CKM_DES_CBC 0x00000122
++#define CKM_DES_MAC 0x00000123
++
++/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */
++#define CKM_DES_MAC_GENERAL 0x00000124
++#define CKM_DES_CBC_PAD 0x00000125
++
++#define CKM_DES2_KEY_GEN 0x00000130
++#define CKM_DES3_KEY_GEN 0x00000131
++#define CKM_DES3_ECB 0x00000132
++#define CKM_DES3_CBC 0x00000133
++#define CKM_DES3_MAC 0x00000134
++
++/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN,
++ * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC,
++ * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */
++#define CKM_DES3_MAC_GENERAL 0x00000135
++#define CKM_DES3_CBC_PAD 0x00000136
++#define CKM_CDMF_KEY_GEN 0x00000140
++#define CKM_CDMF_ECB 0x00000141
++#define CKM_CDMF_CBC 0x00000142
++#define CKM_CDMF_MAC 0x00000143
++#define CKM_CDMF_MAC_GENERAL 0x00000144
++#define CKM_CDMF_CBC_PAD 0x00000145
++
++/* the following four DES mechanisms are new for v2.20 */
++#define CKM_DES_OFB64 0x00000150
++#define CKM_DES_OFB8 0x00000151
++#define CKM_DES_CFB64 0x00000152
++#define CKM_DES_CFB8 0x00000153
++
++#define CKM_MD2 0x00000200
++
++/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */
++#define CKM_MD2_HMAC 0x00000201
++#define CKM_MD2_HMAC_GENERAL 0x00000202
++
++#define CKM_MD5 0x00000210
++
++/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */
++#define CKM_MD5_HMAC 0x00000211
++#define CKM_MD5_HMAC_GENERAL 0x00000212
++
++#define CKM_SHA_1 0x00000220
++
++/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */
++#define CKM_SHA_1_HMAC 0x00000221
++#define CKM_SHA_1_HMAC_GENERAL 0x00000222
++
++/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC,
++ * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC,
++ * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */
++#define CKM_RIPEMD128 0x00000230
++#define CKM_RIPEMD128_HMAC 0x00000231
++#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232
++#define CKM_RIPEMD160 0x00000240
++#define CKM_RIPEMD160_HMAC 0x00000241
++#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242
++
++/* CKM_SHA256/384/512 are new for v2.20 */
++#define CKM_SHA256 0x00000250
++#define CKM_SHA256_HMAC 0x00000251
++#define CKM_SHA256_HMAC_GENERAL 0x00000252
++#define CKM_SHA384 0x00000260
++#define CKM_SHA384_HMAC 0x00000261
++#define CKM_SHA384_HMAC_GENERAL 0x00000262
++#define CKM_SHA512 0x00000270
++#define CKM_SHA512_HMAC 0x00000271
++#define CKM_SHA512_HMAC_GENERAL 0x00000272
++
++/* All of the following mechanisms are new for v2.0 */
++/* Note that CAST128 and CAST5 are the same algorithm */
++#define CKM_CAST_KEY_GEN 0x00000300
++#define CKM_CAST_ECB 0x00000301
++#define CKM_CAST_CBC 0x00000302
++#define CKM_CAST_MAC 0x00000303
++#define CKM_CAST_MAC_GENERAL 0x00000304
++#define CKM_CAST_CBC_PAD 0x00000305
++#define CKM_CAST3_KEY_GEN 0x00000310
++#define CKM_CAST3_ECB 0x00000311
++#define CKM_CAST3_CBC 0x00000312
++#define CKM_CAST3_MAC 0x00000313
++#define CKM_CAST3_MAC_GENERAL 0x00000314
++#define CKM_CAST3_CBC_PAD 0x00000315
++#define CKM_CAST5_KEY_GEN 0x00000320
++#define CKM_CAST128_KEY_GEN 0x00000320
++#define CKM_CAST5_ECB 0x00000321
++#define CKM_CAST128_ECB 0x00000321
++#define CKM_CAST5_CBC 0x00000322
++#define CKM_CAST128_CBC 0x00000322
++#define CKM_CAST5_MAC 0x00000323
++#define CKM_CAST128_MAC 0x00000323
++#define CKM_CAST5_MAC_GENERAL 0x00000324
++#define CKM_CAST128_MAC_GENERAL 0x00000324
++#define CKM_CAST5_CBC_PAD 0x00000325
++#define CKM_CAST128_CBC_PAD 0x00000325
++#define CKM_RC5_KEY_GEN 0x00000330
++#define CKM_RC5_ECB 0x00000331
++#define CKM_RC5_CBC 0x00000332
++#define CKM_RC5_MAC 0x00000333
++#define CKM_RC5_MAC_GENERAL 0x00000334
++#define CKM_RC5_CBC_PAD 0x00000335
++#define CKM_IDEA_KEY_GEN 0x00000340
++#define CKM_IDEA_ECB 0x00000341
++#define CKM_IDEA_CBC 0x00000342
++#define CKM_IDEA_MAC 0x00000343
++#define CKM_IDEA_MAC_GENERAL 0x00000344
++#define CKM_IDEA_CBC_PAD 0x00000345
++#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350
++#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360
++#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362
++#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363
++#define CKM_XOR_BASE_AND_DATA 0x00000364
++#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365
++#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370
++#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371
++#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372
++
++/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN,
++ * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and
++ * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */
++#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373
++#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374
++#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375
++#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376
++#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377
++
++/* CKM_TLS_PRF is new for v2.20 */
++#define CKM_TLS_PRF 0x00000378
++
++#define CKM_SSL3_MD5_MAC 0x00000380
++#define CKM_SSL3_SHA1_MAC 0x00000381
++#define CKM_MD5_KEY_DERIVATION 0x00000390
++#define CKM_MD2_KEY_DERIVATION 0x00000391
++#define CKM_SHA1_KEY_DERIVATION 0x00000392
++
++/* CKM_SHA256/384/512 are new for v2.20 */
++#define CKM_SHA256_KEY_DERIVATION 0x00000393
++#define CKM_SHA384_KEY_DERIVATION 0x00000394
++#define CKM_SHA512_KEY_DERIVATION 0x00000395
++
++#define CKM_PBE_MD2_DES_CBC 0x000003A0
++#define CKM_PBE_MD5_DES_CBC 0x000003A1
++#define CKM_PBE_MD5_CAST_CBC 0x000003A2
++#define CKM_PBE_MD5_CAST3_CBC 0x000003A3
++#define CKM_PBE_MD5_CAST5_CBC 0x000003A4
++#define CKM_PBE_MD5_CAST128_CBC 0x000003A4
++#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5
++#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5
++#define CKM_PBE_SHA1_RC4_128 0x000003A6
++#define CKM_PBE_SHA1_RC4_40 0x000003A7
++#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8
++#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9
++#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA
++#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB
++
++/* CKM_PKCS5_PBKD2 is new for v2.10 */
++#define CKM_PKCS5_PBKD2 0x000003B0
++
++#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0
++
++/* WTLS mechanisms are new for v2.20 */
++#define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0
++#define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1
++#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2
++#define CKM_WTLS_PRF 0x000003D3
++#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4
++#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5
++
++#define CKM_KEY_WRAP_LYNKS 0x00000400
++#define CKM_KEY_WRAP_SET_OAEP 0x00000401
++
++/* CKM_CMS_SIG is new for v2.20 */
++#define CKM_CMS_SIG 0x00000500
++
++/* Fortezza mechanisms */
++#define CKM_SKIPJACK_KEY_GEN 0x00001000
++#define CKM_SKIPJACK_ECB64 0x00001001
++#define CKM_SKIPJACK_CBC64 0x00001002
++#define CKM_SKIPJACK_OFB64 0x00001003
++#define CKM_SKIPJACK_CFB64 0x00001004
++#define CKM_SKIPJACK_CFB32 0x00001005
++#define CKM_SKIPJACK_CFB16 0x00001006
++#define CKM_SKIPJACK_CFB8 0x00001007
++#define CKM_SKIPJACK_WRAP 0x00001008
++#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009
++#define CKM_SKIPJACK_RELAYX 0x0000100a
++#define CKM_KEA_KEY_PAIR_GEN 0x00001010
++#define CKM_KEA_KEY_DERIVE 0x00001011
++#define CKM_FORTEZZA_TIMESTAMP 0x00001020
++#define CKM_BATON_KEY_GEN 0x00001030
++#define CKM_BATON_ECB128 0x00001031
++#define CKM_BATON_ECB96 0x00001032
++#define CKM_BATON_CBC128 0x00001033
++#define CKM_BATON_COUNTER 0x00001034
++#define CKM_BATON_SHUFFLE 0x00001035
++#define CKM_BATON_WRAP 0x00001036
++
++/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11,
++ * CKM_EC_KEY_PAIR_GEN is preferred */
++#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040
++#define CKM_EC_KEY_PAIR_GEN 0x00001040
++
++#define CKM_ECDSA 0x00001041
++#define CKM_ECDSA_SHA1 0x00001042
++
++/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE
++ * are new for v2.11 */
++#define CKM_ECDH1_DERIVE 0x00001050
++#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051
++#define CKM_ECMQV_DERIVE 0x00001052
++
++#define CKM_JUNIPER_KEY_GEN 0x00001060
++#define CKM_JUNIPER_ECB128 0x00001061
++#define CKM_JUNIPER_CBC128 0x00001062
++#define CKM_JUNIPER_COUNTER 0x00001063
++#define CKM_JUNIPER_SHUFFLE 0x00001064
++#define CKM_JUNIPER_WRAP 0x00001065
++#define CKM_FASTHASH 0x00001070
++
++/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC,
++ * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN,
++ * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are
++ * new for v2.11 */
++#define CKM_AES_KEY_GEN 0x00001080
++#define CKM_AES_ECB 0x00001081
++#define CKM_AES_CBC 0x00001082
++#define CKM_AES_MAC 0x00001083
++#define CKM_AES_MAC_GENERAL 0x00001084
++#define CKM_AES_CBC_PAD 0x00001085
++
++/* BlowFish and TwoFish are new for v2.20 */
++#define CKM_BLOWFISH_KEY_GEN 0x00001090
++#define CKM_BLOWFISH_CBC 0x00001091
++#define CKM_TWOFISH_KEY_GEN 0x00001092
++#define CKM_TWOFISH_CBC 0x00001093
++
++
++/* CKM_xxx_ENCRYPT_DATA mechanisms are new for v2.20 */
++#define CKM_DES_ECB_ENCRYPT_DATA 0x00001100
++#define CKM_DES_CBC_ENCRYPT_DATA 0x00001101
++#define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102
++#define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103
++#define CKM_AES_ECB_ENCRYPT_DATA 0x00001104
++#define CKM_AES_CBC_ENCRYPT_DATA 0x00001105
++
++#define CKM_DSA_PARAMETER_GEN 0x00002000
++#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001
++#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002
++
++#define CKM_VENDOR_DEFINED 0x80000000
++
++typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
++
++
++/* CK_MECHANISM is a structure that specifies a particular
++ * mechanism */
++typedef struct CK_MECHANISM {
++ CK_MECHANISM_TYPE mechanism;
++ CK_VOID_PTR pParameter;
++
++ /* ulParameterLen was changed from CK_USHORT to CK_ULONG for
++ * v2.0 */
++ CK_ULONG ulParameterLen; /* in bytes */
++} CK_MECHANISM;
++
++typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
++
++
++/* CK_MECHANISM_INFO provides information about a particular
++ * mechanism */
++typedef struct CK_MECHANISM_INFO {
++ CK_ULONG ulMinKeySize;
++ CK_ULONG ulMaxKeySize;
++ CK_FLAGS flags;
++} CK_MECHANISM_INFO;
++
++/* The flags are defined as follows:
++ * Bit Flag Mask Meaning */
++#define CKF_HW 0x00000001 /* performed by HW */
++
++/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN,
++ * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER,
++ * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP,
++ * and CKF_DERIVE are new for v2.0. They specify whether or not
++ * a mechanism can be used for a particular task */
++#define CKF_ENCRYPT 0x00000100
++#define CKF_DECRYPT 0x00000200
++#define CKF_DIGEST 0x00000400
++#define CKF_SIGN 0x00000800
++#define CKF_SIGN_RECOVER 0x00001000
++#define CKF_VERIFY 0x00002000
++#define CKF_VERIFY_RECOVER 0x00004000
++#define CKF_GENERATE 0x00008000
++#define CKF_GENERATE_KEY_PAIR 0x00010000
++#define CKF_WRAP 0x00020000
++#define CKF_UNWRAP 0x00040000
++#define CKF_DERIVE 0x00080000
++
++/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE,
++ * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They
++ * describe a token's EC capabilities not available in mechanism
++ * information. */
++#define CKF_EC_F_P 0x00100000
++#define CKF_EC_F_2M 0x00200000
++#define CKF_EC_ECPARAMETERS 0x00400000
++#define CKF_EC_NAMEDCURVE 0x00800000
++#define CKF_EC_UNCOMPRESS 0x01000000
++#define CKF_EC_COMPRESS 0x02000000
++
++#define CKF_EXTENSION 0x80000000 /* FALSE for this version */
++
++typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
++
++
++/* CK_RV is a value that identifies the return value of a
++ * Cryptoki function */
++/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */
++typedef CK_ULONG CK_RV;
++
++#define CKR_OK 0x00000000
++#define CKR_CANCEL 0x00000001
++#define CKR_HOST_MEMORY 0x00000002
++#define CKR_SLOT_ID_INVALID 0x00000003
++
++/* CKR_FLAGS_INVALID was removed for v2.0 */
++
++/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */
++#define CKR_GENERAL_ERROR 0x00000005
++#define CKR_FUNCTION_FAILED 0x00000006
++
++/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS,
++ * and CKR_CANT_LOCK are new for v2.01 */
++#define CKR_ARGUMENTS_BAD 0x00000007
++#define CKR_NO_EVENT 0x00000008
++#define CKR_NEED_TO_CREATE_THREADS 0x00000009
++#define CKR_CANT_LOCK 0x0000000A
++
++#define CKR_ATTRIBUTE_READ_ONLY 0x00000010
++#define CKR_ATTRIBUTE_SENSITIVE 0x00000011
++#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012
++#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013
++#define CKR_DATA_INVALID 0x00000020
++#define CKR_DATA_LEN_RANGE 0x00000021
++#define CKR_DEVICE_ERROR 0x00000030
++#define CKR_DEVICE_MEMORY 0x00000031
++#define CKR_DEVICE_REMOVED 0x00000032
++#define CKR_ENCRYPTED_DATA_INVALID 0x00000040
++#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041
++#define CKR_FUNCTION_CANCELED 0x00000050
++#define CKR_FUNCTION_NOT_PARALLEL 0x00000051
++
++/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */
++#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054
++
++#define CKR_KEY_HANDLE_INVALID 0x00000060
++
++/* CKR_KEY_SENSITIVE was removed for v2.0 */
++
++#define CKR_KEY_SIZE_RANGE 0x00000062
++#define CKR_KEY_TYPE_INCONSISTENT 0x00000063
++
++/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED,
++ * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED,
++ * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for
++ * v2.0 */
++#define CKR_KEY_NOT_NEEDED 0x00000064
++#define CKR_KEY_CHANGED 0x00000065
++#define CKR_KEY_NEEDED 0x00000066
++#define CKR_KEY_INDIGESTIBLE 0x00000067
++#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068
++#define CKR_KEY_NOT_WRAPPABLE 0x00000069
++#define CKR_KEY_UNEXTRACTABLE 0x0000006A
++
++#define CKR_MECHANISM_INVALID 0x00000070
++#define CKR_MECHANISM_PARAM_INVALID 0x00000071
++
++/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID
++ * were removed for v2.0 */
++#define CKR_OBJECT_HANDLE_INVALID 0x00000082
++#define CKR_OPERATION_ACTIVE 0x00000090
++#define CKR_OPERATION_NOT_INITIALIZED 0x00000091
++#define CKR_PIN_INCORRECT 0x000000A0
++#define CKR_PIN_INVALID 0x000000A1
++#define CKR_PIN_LEN_RANGE 0x000000A2
++
++/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */
++#define CKR_PIN_EXPIRED 0x000000A3
++#define CKR_PIN_LOCKED 0x000000A4
++
++#define CKR_SESSION_CLOSED 0x000000B0
++#define CKR_SESSION_COUNT 0x000000B1
++#define CKR_SESSION_HANDLE_INVALID 0x000000B3
++#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4
++#define CKR_SESSION_READ_ONLY 0x000000B5
++#define CKR_SESSION_EXISTS 0x000000B6
++
++/* CKR_SESSION_READ_ONLY_EXISTS and
++ * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */
++#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7
++#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8
++
++#define CKR_SIGNATURE_INVALID 0x000000C0
++#define CKR_SIGNATURE_LEN_RANGE 0x000000C1
++#define CKR_TEMPLATE_INCOMPLETE 0x000000D0
++#define CKR_TEMPLATE_INCONSISTENT 0x000000D1
++#define CKR_TOKEN_NOT_PRESENT 0x000000E0
++#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1
++#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2
++#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0
++#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1
++#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2
++#define CKR_USER_ALREADY_LOGGED_IN 0x00000100
++#define CKR_USER_NOT_LOGGED_IN 0x00000101
++#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102
++#define CKR_USER_TYPE_INVALID 0x00000103
++
++/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES
++ * are new to v2.01 */
++#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104
++#define CKR_USER_TOO_MANY_TYPES 0x00000105
++
++#define CKR_WRAPPED_KEY_INVALID 0x00000110
++#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112
++#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113
++#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114
++#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115
++#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120
++
++/* These are new to v2.0 */
++#define CKR_RANDOM_NO_RNG 0x00000121
++
++/* These are new to v2.11 */
++#define CKR_DOMAIN_PARAMS_INVALID 0x00000130
++
++/* These are new to v2.0 */
++#define CKR_BUFFER_TOO_SMALL 0x00000150
++#define CKR_SAVED_STATE_INVALID 0x00000160
++#define CKR_INFORMATION_SENSITIVE 0x00000170
++#define CKR_STATE_UNSAVEABLE 0x00000180
++
++/* These are new to v2.01 */
++#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190
++#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191
++#define CKR_MUTEX_BAD 0x000001A0
++#define CKR_MUTEX_NOT_LOCKED 0x000001A1
++
++/* This is new to v2.20 */
++#define CKR_FUNCTION_REJECTED 0x00000200
++
++#define CKR_VENDOR_DEFINED 0x80000000
++
++
++/* CK_NOTIFY is an application callback that processes events */
++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
++ CK_SESSION_HANDLE hSession, /* the session's handle */
++ CK_NOTIFICATION event,
++ CK_VOID_PTR pApplication /* passed to C_OpenSession */
++);
++
++
++/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
++ * version and pointers of appropriate types to all the
++ * Cryptoki functions */
++/* CK_FUNCTION_LIST is new for v2.0 */
++typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
++
++typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
++
++typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
++
++
++/* CK_CREATEMUTEX is an application callback for creating a
++ * mutex object */
++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
++ CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */
++);
++
++
++/* CK_DESTROYMUTEX is an application callback for destroying a
++ * mutex object */
++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
++ CK_VOID_PTR pMutex /* pointer to mutex */
++);
++
++
++/* CK_LOCKMUTEX is an application callback for locking a mutex */
++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
++ CK_VOID_PTR pMutex /* pointer to mutex */
++);
++
++
++/* CK_UNLOCKMUTEX is an application callback for unlocking a
++ * mutex */
++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
++ CK_VOID_PTR pMutex /* pointer to mutex */
++);
++
++
++/* CK_C_INITIALIZE_ARGS provides the optional arguments to
++ * C_Initialize */
++typedef struct CK_C_INITIALIZE_ARGS {
++ CK_CREATEMUTEX CreateMutex;
++ CK_DESTROYMUTEX DestroyMutex;
++ CK_LOCKMUTEX LockMutex;
++ CK_UNLOCKMUTEX UnlockMutex;
++ CK_FLAGS flags;
++ CK_VOID_PTR pReserved;
++} CK_C_INITIALIZE_ARGS;
++
++/* flags: bit flags that provide capabilities of the slot
++ * Bit Flag Mask Meaning
++ */
++#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001
++#define CKF_OS_LOCKING_OK 0x00000002
++
++typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
++
++
++/* additional flags for parameters to functions */
++
++/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
++#define CKF_DONT_BLOCK 1
++
++/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10.
++ * CK_RSA_PKCS_OAEP_MGF_TYPE is used to indicate the Message
++ * Generation Function (MGF) applied to a message block when
++ * formatting a message block for the PKCS #1 OAEP encryption
++ * scheme. */
++typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
++
++typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
++
++/* The following MGFs are defined */
++/* CKG_MGF1_SHA256, CKG_MGF1_SHA384, and CKG_MGF1_SHA512
++ * are new for v2.20 */
++#define CKG_MGF1_SHA1 0x00000001
++#define CKG_MGF1_SHA256 0x00000002
++#define CKG_MGF1_SHA384 0x00000003
++#define CKG_MGF1_SHA512 0x00000004
++
++/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10.
++ * CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source
++ * of the encoding parameter when formatting a message block
++ * for the PKCS #1 OAEP encryption scheme. */
++typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
++
++typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
++
++/* The following encoding parameter sources are defined */
++#define CKZ_DATA_SPECIFIED 0x00000001
++
++/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10.
++ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
++ * CKM_RSA_PKCS_OAEP mechanism. */
++typedef struct CK_RSA_PKCS_OAEP_PARAMS {
++ CK_MECHANISM_TYPE hashAlg;
++ CK_RSA_PKCS_MGF_TYPE mgf;
++ CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
++ CK_VOID_PTR pSourceData;
++ CK_ULONG ulSourceDataLen;
++} CK_RSA_PKCS_OAEP_PARAMS;
++
++typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
++
++/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11.
++ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
++ * CKM_RSA_PKCS_PSS mechanism(s). */
++typedef struct CK_RSA_PKCS_PSS_PARAMS {
++ CK_MECHANISM_TYPE hashAlg;
++ CK_RSA_PKCS_MGF_TYPE mgf;
++ CK_ULONG sLen;
++} CK_RSA_PKCS_PSS_PARAMS;
++
++typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
++
++/* CK_EC_KDF_TYPE is new for v2.11. */
++typedef CK_ULONG CK_EC_KDF_TYPE;
++
++/* The following EC Key Derivation Functions are defined */
++#define CKD_NULL 0x00000001
++#define CKD_SHA1_KDF 0x00000002
++
++/* CK_ECDH1_DERIVE_PARAMS is new for v2.11.
++ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
++ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
++ * where each party contributes one key pair.
++ */
++typedef struct CK_ECDH1_DERIVE_PARAMS {
++ CK_EC_KDF_TYPE kdf;
++ CK_ULONG ulSharedDataLen;
++ CK_BYTE_PTR pSharedData;
++ CK_ULONG ulPublicDataLen;
++ CK_BYTE_PTR pPublicData;
++} CK_ECDH1_DERIVE_PARAMS;
++
++typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
++
++
++/* CK_ECDH2_DERIVE_PARAMS is new for v2.11.
++ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
++ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */
++typedef struct CK_ECDH2_DERIVE_PARAMS {
++ CK_EC_KDF_TYPE kdf;
++ CK_ULONG ulSharedDataLen;
++ CK_BYTE_PTR pSharedData;
++ CK_ULONG ulPublicDataLen;
++ CK_BYTE_PTR pPublicData;
++ CK_ULONG ulPrivateDataLen;
++ CK_OBJECT_HANDLE hPrivateData;
++ CK_ULONG ulPublicDataLen2;
++ CK_BYTE_PTR pPublicData2;
++} CK_ECDH2_DERIVE_PARAMS;
++
++typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
++
++typedef struct CK_ECMQV_DERIVE_PARAMS {
++ CK_EC_KDF_TYPE kdf;
++ CK_ULONG ulSharedDataLen;
++ CK_BYTE_PTR pSharedData;
++ CK_ULONG ulPublicDataLen;
++ CK_BYTE_PTR pPublicData;
++ CK_ULONG ulPrivateDataLen;
++ CK_OBJECT_HANDLE hPrivateData;
++ CK_ULONG ulPublicDataLen2;
++ CK_BYTE_PTR pPublicData2;
++ CK_OBJECT_HANDLE publicKey;
++} CK_ECMQV_DERIVE_PARAMS;
++
++typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
++
++/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
++ * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */
++typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
++typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
++
++/* The following X9.42 DH key derivation functions are defined
++ (besides CKD_NULL already defined : */
++#define CKD_SHA1_KDF_ASN1 0x00000003
++#define CKD_SHA1_KDF_CONCATENATE 0x00000004
++
++/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11.
++ * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
++ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
++ * contributes one key pair */
++typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
++ CK_X9_42_DH_KDF_TYPE kdf;
++ CK_ULONG ulOtherInfoLen;
++ CK_BYTE_PTR pOtherInfo;
++ CK_ULONG ulPublicDataLen;
++ CK_BYTE_PTR pPublicData;
++} CK_X9_42_DH1_DERIVE_PARAMS;
++
++typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
++
++/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11.
++ * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
++ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
++ * mechanisms, where each party contributes two key pairs */
++typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
++ CK_X9_42_DH_KDF_TYPE kdf;
++ CK_ULONG ulOtherInfoLen;
++ CK_BYTE_PTR pOtherInfo;
++ CK_ULONG ulPublicDataLen;
++ CK_BYTE_PTR pPublicData;
++ CK_ULONG ulPrivateDataLen;
++ CK_OBJECT_HANDLE hPrivateData;
++ CK_ULONG ulPublicDataLen2;
++ CK_BYTE_PTR pPublicData2;
++} CK_X9_42_DH2_DERIVE_PARAMS;
++
++typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
++
++typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
++ CK_X9_42_DH_KDF_TYPE kdf;
++ CK_ULONG ulOtherInfoLen;
++ CK_BYTE_PTR pOtherInfo;
++ CK_ULONG ulPublicDataLen;
++ CK_BYTE_PTR pPublicData;
++ CK_ULONG ulPrivateDataLen;
++ CK_OBJECT_HANDLE hPrivateData;
++ CK_ULONG ulPublicDataLen2;
++ CK_BYTE_PTR pPublicData2;
++ CK_OBJECT_HANDLE publicKey;
++} CK_X9_42_MQV_DERIVE_PARAMS;
++
++typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
++
++/* CK_KEA_DERIVE_PARAMS provides the parameters to the
++ * CKM_KEA_DERIVE mechanism */
++/* CK_KEA_DERIVE_PARAMS is new for v2.0 */
++typedef struct CK_KEA_DERIVE_PARAMS {
++ CK_BBOOL isSender;
++ CK_ULONG ulRandomLen;
++ CK_BYTE_PTR pRandomA;
++ CK_BYTE_PTR pRandomB;
++ CK_ULONG ulPublicDataLen;
++ CK_BYTE_PTR pPublicData;
++} CK_KEA_DERIVE_PARAMS;
++
++typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
++
++
++/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
++ * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just
++ * holds the effective keysize */
++typedef CK_ULONG CK_RC2_PARAMS;
++
++typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
++
++
++/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
++ * mechanism */
++typedef struct CK_RC2_CBC_PARAMS {
++ /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for
++ * v2.0 */
++ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
++
++ CK_BYTE iv[8]; /* IV for CBC mode */
++} CK_RC2_CBC_PARAMS;
++
++typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
++
++
++/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
++ * CKM_RC2_MAC_GENERAL mechanism */
++/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */
++typedef struct CK_RC2_MAC_GENERAL_PARAMS {
++ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
++ CK_ULONG ulMacLength; /* Length of MAC in bytes */
++} CK_RC2_MAC_GENERAL_PARAMS;
++
++typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
++ CK_RC2_MAC_GENERAL_PARAMS_PTR;
++
++
++/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
++ * CKM_RC5_MAC mechanisms */
++/* CK_RC5_PARAMS is new for v2.0 */
++typedef struct CK_RC5_PARAMS {
++ CK_ULONG ulWordsize; /* wordsize in bits */
++ CK_ULONG ulRounds; /* number of rounds */
++} CK_RC5_PARAMS;
++
++typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
++
++
++/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
++ * mechanism */
++/* CK_RC5_CBC_PARAMS is new for v2.0 */
++typedef struct CK_RC5_CBC_PARAMS {
++ CK_ULONG ulWordsize; /* wordsize in bits */
++ CK_ULONG ulRounds; /* number of rounds */
++ CK_BYTE_PTR pIv; /* pointer to IV */
++ CK_ULONG ulIvLen; /* length of IV in bytes */
++} CK_RC5_CBC_PARAMS;
++
++typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
++
++
++/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
++ * CKM_RC5_MAC_GENERAL mechanism */
++/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */
++typedef struct CK_RC5_MAC_GENERAL_PARAMS {
++ CK_ULONG ulWordsize; /* wordsize in bits */
++ CK_ULONG ulRounds; /* number of rounds */
++ CK_ULONG ulMacLength; /* Length of MAC in bytes */
++} CK_RC5_MAC_GENERAL_PARAMS;
++
++typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
++ CK_RC5_MAC_GENERAL_PARAMS_PTR;
++
++
++/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
++ * ciphers' MAC_GENERAL mechanisms. Its value is the length of
++ * the MAC */
++/* CK_MAC_GENERAL_PARAMS is new for v2.0 */
++typedef CK_ULONG CK_MAC_GENERAL_PARAMS;
++
++typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
++
++/* CK_DES/AES_ECB/CBC_ENCRYPT_DATA_PARAMS are new for v2.20 */
++typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
++ CK_BYTE iv[8];
++ CK_BYTE_PTR pData;
++ CK_ULONG length;
++} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
++
++typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
++
++typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
++ CK_BYTE iv[16];
++ CK_BYTE_PTR pData;
++ CK_ULONG length;
++} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
++
++typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
++
++/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
++ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */
++/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */
++typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
++ CK_ULONG ulPasswordLen;
++ CK_BYTE_PTR pPassword;
++ CK_ULONG ulPublicDataLen;
++ CK_BYTE_PTR pPublicData;
++ CK_ULONG ulPAndGLen;
++ CK_ULONG ulQLen;
++ CK_ULONG ulRandomLen;
++ CK_BYTE_PTR pRandomA;
++ CK_BYTE_PTR pPrimeP;
++ CK_BYTE_PTR pBaseG;
++ CK_BYTE_PTR pSubprimeQ;
++} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
++
++typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
++ CK_SKIPJACK_PRIVATE_WRAP_PTR;
++
++
++/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
++ * CKM_SKIPJACK_RELAYX mechanism */
++/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */
++typedef struct CK_SKIPJACK_RELAYX_PARAMS {
++ CK_ULONG ulOldWrappedXLen;
++ CK_BYTE_PTR pOldWrappedX;
++ CK_ULONG ulOldPasswordLen;
++ CK_BYTE_PTR pOldPassword;
++ CK_ULONG ulOldPublicDataLen;
++ CK_BYTE_PTR pOldPublicData;
++ CK_ULONG ulOldRandomLen;
++ CK_BYTE_PTR pOldRandomA;
++ CK_ULONG ulNewPasswordLen;
++ CK_BYTE_PTR pNewPassword;
++ CK_ULONG ulNewPublicDataLen;
++ CK_BYTE_PTR pNewPublicData;
++ CK_ULONG ulNewRandomLen;
++ CK_BYTE_PTR pNewRandomA;
++} CK_SKIPJACK_RELAYX_PARAMS;
++
++typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
++ CK_SKIPJACK_RELAYX_PARAMS_PTR;
++
++
++typedef struct CK_PBE_PARAMS {
++ CK_BYTE_PTR pInitVector;
++ CK_UTF8CHAR_PTR pPassword;
++ CK_ULONG ulPasswordLen;
++ CK_BYTE_PTR pSalt;
++ CK_ULONG ulSaltLen;
++ CK_ULONG ulIteration;
++} CK_PBE_PARAMS;
++
++typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
++
++
++/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
++ * CKM_KEY_WRAP_SET_OAEP mechanism */
++/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */
++typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
++ CK_BYTE bBC; /* block contents byte */
++ CK_BYTE_PTR pX; /* extra data */
++ CK_ULONG ulXLen; /* length of extra data in bytes */
++} CK_KEY_WRAP_SET_OAEP_PARAMS;
++
++typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \
++ CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
++
++
++typedef struct CK_SSL3_RANDOM_DATA {
++ CK_BYTE_PTR pClientRandom;
++ CK_ULONG ulClientRandomLen;
++ CK_BYTE_PTR pServerRandom;
++ CK_ULONG ulServerRandomLen;
++} CK_SSL3_RANDOM_DATA;
++
++
++typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
++ CK_SSL3_RANDOM_DATA RandomInfo;
++ CK_VERSION_PTR pVersion;
++} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
++
++typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
++ CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
++
++
++typedef struct CK_SSL3_KEY_MAT_OUT {
++ CK_OBJECT_HANDLE hClientMacSecret;
++ CK_OBJECT_HANDLE hServerMacSecret;
++ CK_OBJECT_HANDLE hClientKey;
++ CK_OBJECT_HANDLE hServerKey;
++ CK_BYTE_PTR pIVClient;
++ CK_BYTE_PTR pIVServer;
++} CK_SSL3_KEY_MAT_OUT;
++
++typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
++
++
++typedef struct CK_SSL3_KEY_MAT_PARAMS {
++ CK_ULONG ulMacSizeInBits;
++ CK_ULONG ulKeySizeInBits;
++ CK_ULONG ulIVSizeInBits;
++ CK_BBOOL bIsExport;
++ CK_SSL3_RANDOM_DATA RandomInfo;
++ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
++} CK_SSL3_KEY_MAT_PARAMS;
++
++typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
++
++/* CK_TLS_PRF_PARAMS is new for version 2.20 */
++typedef struct CK_TLS_PRF_PARAMS {
++ CK_BYTE_PTR pSeed;
++ CK_ULONG ulSeedLen;
++ CK_BYTE_PTR pLabel;
++ CK_ULONG ulLabelLen;
++ CK_BYTE_PTR pOutput;
++ CK_ULONG_PTR pulOutputLen;
++} CK_TLS_PRF_PARAMS;
++
++typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
++
++/* WTLS is new for version 2.20 */
++typedef struct CK_WTLS_RANDOM_DATA {
++ CK_BYTE_PTR pClientRandom;
++ CK_ULONG ulClientRandomLen;
++ CK_BYTE_PTR pServerRandom;
++ CK_ULONG ulServerRandomLen;
++} CK_WTLS_RANDOM_DATA;
++
++typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
++
++typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
++ CK_MECHANISM_TYPE DigestMechanism;
++ CK_WTLS_RANDOM_DATA RandomInfo;
++ CK_BYTE_PTR pVersion;
++} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
++
++typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
++ CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
++
++typedef struct CK_WTLS_PRF_PARAMS {
++ CK_MECHANISM_TYPE DigestMechanism;
++ CK_BYTE_PTR pSeed;
++ CK_ULONG ulSeedLen;
++ CK_BYTE_PTR pLabel;
++ CK_ULONG ulLabelLen;
++ CK_BYTE_PTR pOutput;
++ CK_ULONG_PTR pulOutputLen;
++} CK_WTLS_PRF_PARAMS;
++
++typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
++
++typedef struct CK_WTLS_KEY_MAT_OUT {
++ CK_OBJECT_HANDLE hMacSecret;
++ CK_OBJECT_HANDLE hKey;
++ CK_BYTE_PTR pIV;
++} CK_WTLS_KEY_MAT_OUT;
++
++typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
++
++typedef struct CK_WTLS_KEY_MAT_PARAMS {
++ CK_MECHANISM_TYPE DigestMechanism;
++ CK_ULONG ulMacSizeInBits;
++ CK_ULONG ulKeySizeInBits;
++ CK_ULONG ulIVSizeInBits;
++ CK_ULONG ulSequenceNumber;
++ CK_BBOOL bIsExport;
++ CK_WTLS_RANDOM_DATA RandomInfo;
++ CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
++} CK_WTLS_KEY_MAT_PARAMS;
++
++typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
++
++/* CMS is new for version 2.20 */
++typedef struct CK_CMS_SIG_PARAMS {
++ CK_OBJECT_HANDLE certificateHandle;
++ CK_MECHANISM_PTR pSigningMechanism;
++ CK_MECHANISM_PTR pDigestMechanism;
++ CK_UTF8CHAR_PTR pContentType;
++ CK_BYTE_PTR pRequestedAttributes;
++ CK_ULONG ulRequestedAttributesLen;
++ CK_BYTE_PTR pRequiredAttributes;
++ CK_ULONG ulRequiredAttributesLen;
++} CK_CMS_SIG_PARAMS;
++
++typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR;
++
++typedef struct CK_KEY_DERIVATION_STRING_DATA {
++ CK_BYTE_PTR pData;
++ CK_ULONG ulLen;
++} CK_KEY_DERIVATION_STRING_DATA;
++
++typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
++ CK_KEY_DERIVATION_STRING_DATA_PTR;
++
++
++/* The CK_EXTRACT_PARAMS is used for the
++ * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit
++ * of the base key should be used as the first bit of the
++ * derived key */
++/* CK_EXTRACT_PARAMS is new for v2.0 */
++typedef CK_ULONG CK_EXTRACT_PARAMS;
++
++typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
++
++/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10.
++ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
++ * indicate the Pseudo-Random Function (PRF) used to generate
++ * key bits using PKCS #5 PBKDF2. */
++typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
++
++typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
++
++/* The following PRFs are defined in PKCS #5 v2.0. */
++#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001
++
++
++/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10.
++ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
++ * source of the salt value when deriving a key using PKCS #5
++ * PBKDF2. */
++typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
++
++typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
++
++/* The following salt value sources are defined in PKCS #5 v2.0. */
++#define CKZ_SALT_SPECIFIED 0x00000001
++
++/* CK_PKCS5_PBKD2_PARAMS is new for v2.10.
++ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the
++ * parameters to the CKM_PKCS5_PBKD2 mechanism. */
++typedef struct CK_PKCS5_PBKD2_PARAMS {
++ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
++ CK_VOID_PTR pSaltSourceData;
++ CK_ULONG ulSaltSourceDataLen;
++ CK_ULONG iterations;
++ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
++ CK_VOID_PTR pPrfData;
++ CK_ULONG ulPrfDataLen;
++ CK_UTF8CHAR_PTR pPassword;
++ CK_ULONG_PTR ulPasswordLen;
++} CK_PKCS5_PBKD2_PARAMS;
++
++typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
++
++#endif
+diff -urNp openssh-4.4p1/pkcs11-helper.c openssh-4.4p1+pkcs11-0.17/pkcs11-helper.c
+--- openssh-4.4p1/pkcs11-helper.c 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/pkcs11-helper.c 2006-10-22 17:11:50.000000000 +0200
+@@ -0,0 +1,11337 @@
++/*
++ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev@gmail.com>
++ * All rights reserved.
++ *
++ * This software is available to you under a choice of one of two
++ * licenses. You may choose to be licensed under the terms of the GNU
++ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
++ *
++ * GNU General Public License (GPL) Version 2
++ * ===========================================
++ * 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[.GPL2] included with this
++ * distribution); if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * OpenIB.org BSD license
++ * =======================
++ * 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).
++ *
++ */
++
++/*
++ * Changelog
++ *
++ * 2006.09.24
++ * - (alonbl) Fix invalid certificate max size handling (Zeljko Vrba).
++ * - (alonbl) Added object serialization.
++ * - (alonbl) Added user data to hooks.
++ * - (alonbl) Added a force login method.
++ * - (alonbl) Added support for gnutls in addition to openssl.
++ * - (alonbl) Fixup threading lock issues.
++ * - (alonbl) Added support for duplicate serial tokens, based on label.
++ * - (alonbl) Added workaround for OpenSC cards, OpenSC bug#108, thanks to Kaupo Arulo.
++ * - (alonbl) Added a methods to lock session between two sign/decrypt operations.
++ * - (alonbl) Modified openssl interface.
++ * - (alonbl) Release 01.02.
++ *
++ * 2006.06.26
++ * - (alonbl) Fix handling mutiple providers.
++ * - (alonbl) Release 01.01.
++ *
++ * 2006.05.14
++ * - (alonbl) First stable release.
++ * - (alonbl) Release 01.00.
++ *
++ */
++
++#include "pkcs11-helper-config.h"
++
++#if defined(ENABLE_PKCS11H_HELPER)
++
++#include "pkcs11-helper.h"
++
++/*===========================================
++ * Constants
++ */
++
++#if defined(USE_PKCS11H_OPENSSL)
++
++#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
++
++#if OPENSSL_VERSION_NUMBER < 0x00907000L
++#if !defined(RSA_PKCS1_PADDING_SIZE)
++#define RSA_PKCS1_PADDING_SIZE 11
++#endif
++#endif
++
++#endif
++
++#define PKCS11H_INVALID_SLOT_ID ((CK_SLOT_ID)-1)
++#define PKCS11H_INVALID_SESSION_HANDLE ((CK_SESSION_HANDLE)-1)
++#define PKCS11H_INVALID_OBJECT_HANDLE ((CK_OBJECT_HANDLE)-1)
++
++#define PKCS11H_DEFAULT_SLOTEVENT_POLL 5000
++#define PKCS11H_DEFAULT_MAX_LOGIN_RETRY 3
++#define PKCS11H_DEFAULT_PIN_CACHE_PERIOD PKCS11H_PIN_CACHE_INFINITE
++
++#define PKCS11H_SERIALIZE_INVALID_CHARS "\\/\"'%&#@!?$* <>{}[]()`|"
++
++enum _pkcs11h_private_op_e {
++ _pkcs11h_private_op_sign=0,
++ _pkcs11h_private_op_sign_recover,
++ _pkcs11h_private_op_decrypt
++};
++
++/*===========================================
++ * Macros
++ */
++
++#define PKCS11H_MSG_LEVEL_TEST(flags) (((unsigned int)flags) <= s_pkcs11h_loglevel)
++
++#if defined(HAVE_CPP_VARARG_MACRO_ISO) && !defined(__LCLINT__)
++# define PKCS11H_LOG(flags, ...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), __VA_ARGS__); } while (FALSE)
++# ifdef ENABLE_PKCS11H_DEBUG
++# define PKCS11H_DEBUG(flags, ...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), __VA_ARGS__); } while (FALSE)
++# else
++# define PKCS11H_DEBUG(flags, ...)
++# endif
++#elif defined(HAVE_CPP_VARARG_MACRO_GCC) && !defined(__LCLINT__)
++# define PKCS11H_LOG(flags, args...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), args); } while (FALSE)
++# ifdef ENABLE_PKCS11H_DEBUG
++# define PKCS11H_DEBUG(flags, args...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), args); } while (FALSE)
++# else
++# define PKCS11H_DEBUG(flags, args...)
++# endif
++#else
++# define PKCS11H_LOG _pkcs11h_log
++# define PKCS11H_DEBUG _pkcs11h_log
++#endif
++
++/*===========================================
++ * Types
++ */
++
++struct pkcs11h_provider_s;
++struct pkcs11h_session_s;
++struct pkcs11h_data_s;
++typedef struct pkcs11h_provider_s *pkcs11h_provider_t;
++typedef struct pkcs11h_session_s *pkcs11h_session_t;
++typedef struct pkcs11h_data_s *pkcs11h_data_t;
++
++#if defined(USE_PKCS11H_OPENSSL)
++
++#if OPENSSL_VERSION_NUMBER < 0x00908000L
++typedef unsigned char *pkcs11_openssl_d2i_t;
++#else
++typedef const unsigned char *pkcs11_openssl_d2i_t;
++#endif
++
++#endif
++
++#if defined(ENABLE_PKCS11H_THREADING)
++
++#define PKCS11H_COND_INFINITE 0xffffffff
++
++#if defined(WIN32)
++#define PKCS11H_THREAD_NULL NULL
++typedef HANDLE pkcs11h_cond_t;
++typedef HANDLE pkcs11h_mutex_t;
++typedef HANDLE pkcs11h_thread_t;
++#else
++#define PKCS11H_THREAD_NULL 0l
++typedef pthread_mutex_t pkcs11h_mutex_t;
++typedef pthread_t pkcs11h_thread_t;
++
++typedef struct {
++ pthread_cond_t cond;
++ pthread_mutex_t mut;
++} pkcs11h_cond_t;
++
++typedef struct __pkcs11h_threading_mutex_entry_s {
++ struct __pkcs11h_threading_mutex_entry_s *next;
++ pkcs11h_mutex_t *p_mutex;
++ PKCS11H_BOOL locked;
++} *__pkcs11h_threading_mutex_entry_t;
++#endif
++
++typedef void * (*pkcs11h_thread_start_t)(void *);
++
++typedef struct {
++ pkcs11h_thread_start_t start;
++ void *data;
++} __pkcs11h_thread_data_t;
++
++#endif /* ENABLE_PKCS11H_THREADING */
++
++struct pkcs11h_provider_s {
++ pkcs11h_provider_t next;
++
++ PKCS11H_BOOL enabled;
++ char reference[1024];
++ char manufacturerID[sizeof (((CK_TOKEN_INFO *)NULL)->manufacturerID)+1];
++
++#if defined(WIN32)
++ HANDLE handle;
++#else
++ void *handle;
++#endif
++
++ CK_FUNCTION_LIST_PTR f;
++ PKCS11H_BOOL should_finalize;
++ PKCS11H_BOOL allow_protected_auth;
++ PKCS11H_BOOL cert_is_private;
++ unsigned mask_sign_mode;
++ int slot_event_method;
++ int slot_poll_interval;
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++ pkcs11h_thread_t slotevent_thread;
++#endif
++};
++
++struct pkcs11h_session_s {
++ pkcs11h_session_t next;
++
++ int reference_count;
++ PKCS11H_BOOL valid;
++
++ pkcs11h_provider_t provider;
++
++ pkcs11h_token_id_t token_id;
++
++ CK_SESSION_HANDLE session_handle;
++
++ PKCS11H_BOOL allow_protected_auth_supported;
++ int pin_cache_period;
++ time_t pin_expire_time;
++
++#if defined(ENABLE_PKCS11H_ENUM)
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++ pkcs11h_certificate_id_list_t cached_certs;
++ PKCS11H_BOOL touch;
++#endif
++#endif
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ pkcs11h_mutex_t mutex;
++#endif
++};
++
++#if defined (ENABLE_PKCS11H_CERTIFICATE)
++
++struct pkcs11h_certificate_s {
++
++ pkcs11h_certificate_id_t id;
++ int pin_cache_period;
++ PKCS11H_BOOL pin_cache_populated_to_session;
++
++ unsigned mask_sign_mode;
++
++ pkcs11h_session_t session;
++ CK_OBJECT_HANDLE key_handle;
++
++ PKCS11H_BOOL operation_active;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ pkcs11h_mutex_t mutex;
++#endif
++
++ unsigned mask_prompt;
++ void * user_data;
++};
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++struct pkcs11h_data_s {
++ PKCS11H_BOOL initialized;
++ int pin_cache_period;
++
++ pkcs11h_provider_t providers;
++ pkcs11h_session_t sessions;
++
++ struct {
++ void * log_data;
++ void * slotevent_data;
++ void * token_prompt_data;
++ void * pin_prompt_data;
++ pkcs11h_hook_log_t log;
++ pkcs11h_hook_slotevent_t slotevent;
++ pkcs11h_hook_token_prompt_t token_prompt;
++ pkcs11h_hook_pin_prompt_t pin_prompt;
++ } hooks;
++
++ PKCS11H_BOOL allow_protected_auth;
++ unsigned max_retries;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ struct {
++ pkcs11h_mutex_t global;
++ pkcs11h_mutex_t session;
++ pkcs11h_mutex_t cache;
++ } mutexes;
++#endif
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++ struct {
++ PKCS11H_BOOL initialized;
++ PKCS11H_BOOL should_terminate;
++ PKCS11H_BOOL skip_event;
++ pkcs11h_cond_t cond_event;
++ pkcs11h_thread_t thread;
++ } slotevent;
++#endif
++};
++
++#if defined(ENABLE_PKCS11H_OPENSSL)
++struct pkcs11h_openssl_session_s {
++ int reference_count;
++ PKCS11H_BOOL initialized;
++ X509 *x509;
++ RSA_METHOD smart_rsa;
++ int (*orig_finish)(RSA *rsa);
++ pkcs11h_certificate_t certificate;
++ pkcs11h_hook_openssl_cleanup_t cleanup_hook;
++};
++#endif
++
++/*======================================================================*
++ * MEMORY INTERFACE
++ *======================================================================*/
++
++static
++CK_RV
++_pkcs11h_mem_malloc (
++ OUT const void * * const p,
++ IN const size_t s
++);
++static
++CK_RV
++_pkcs11h_mem_free (
++ IN const void * * const p
++);
++static
++CK_RV
++_pkcs11h_mem_strdup (
++ OUT const char * * const dest,
++ IN const char * const src
++);
++static
++CK_RV
++_pkcs11h_mem_duplicate (
++ OUT const void * * const dest,
++ OUT size_t * const dest_size,
++ IN const void * const src,
++ IN const size_t mem_size
++);
++
++#if defined(ENABLE_PKCS11H_THREADING)
++/*======================================================================*
++ * THREADING INTERFACE
++ *======================================================================*/
++
++static
++void
++_pkcs11h_threading_sleep (
++ IN const unsigned milli
++);
++static
++CK_RV
++_pkcs11h_threading_mutexInit (
++ OUT pkcs11h_mutex_t * const mutex
++);
++static
++CK_RV
++_pkcs11h_threading_mutexLock (
++ IN OUT pkcs11h_mutex_t *const mutex
++);
++static
++CK_RV
++_pkcs11h_threading_mutexRelease (
++ IN OUT pkcs11h_mutex_t *const mutex
++);
++static
++CK_RV
++_pkcs11h_threading_mutexFree (
++ IN OUT pkcs11h_mutex_t *const mutex
++);
++#if !defined(WIN32)
++static
++void
++__pkcs1h_threading_mutexLockAll ();
++static
++void
++__pkcs1h_threading_mutexReleaseAll ();
++#endif
++static
++CK_RV
++_pkcs11h_threading_condSignal (
++ IN OUT pkcs11h_cond_t *const cond
++);
++static
++CK_RV
++_pkcs11h_threading_condInit (
++ OUT pkcs11h_cond_t * const cond
++);
++static
++CK_RV
++_pkcs11h_threading_condWait (
++ IN OUT pkcs11h_cond_t *const cond,
++ IN const unsigned milli
++);
++static
++CK_RV
++_pkcs11h_threading_condFree (
++ IN OUT pkcs11h_cond_t *const cond
++);
++static
++CK_RV
++_pkcs11h_threading_threadStart (
++ OUT pkcs11h_thread_t * const thread,
++ IN pkcs11h_thread_start_t const start,
++ IN void * data
++);
++static
++CK_RV
++_pkcs11h_threading_threadJoin (
++ IN pkcs11h_thread_t * const thread
++);
++#endif /* ENABLE_PKCS11H_THREADING */
++
++/*======================================================================*
++ * COMMON INTERNAL INTERFACE
++ *======================================================================*/
++
++static
++void
++_pkcs11h_util_fixupFixedString (
++ OUT char * const target, /* MUST BE >= length+1 */
++ IN const char * const source,
++ IN const size_t length /* FIXED STRING LENGTH */
++);
++static
++CK_RV
++_pkcs11h_util_hexToBinary (
++ OUT unsigned char * const target,
++ IN const char * const source,
++ IN OUT size_t * const p_target_size
++);
++static
++CK_RV
++_pkcs11h_util_binaryToHex (
++ OUT char * const target,
++ IN const size_t target_size,
++ IN const unsigned char * const source,
++ IN const size_t source_size
++);
++CK_RV
++_pkcs11h_util_escapeString (
++ IN OUT char * const target,
++ IN const char * const source,
++ IN size_t * const max,
++ IN const char * const invalid_chars
++);
++static
++CK_RV
++_pkcs11h_util_unescapeString (
++ IN OUT char * const target,
++ IN const char * const source,
++ IN size_t * const max
++);
++static
++void
++_pkcs11h_log (
++ IN const unsigned flags,
++ IN const char * const format,
++ IN ...
++)
++#ifdef __GNUC__
++ __attribute__ ((format (printf, 2, 3)))
++#endif
++ ;
++
++static
++CK_RV
++_pkcs11h_session_getSlotList (
++ IN const pkcs11h_provider_t provider,
++ IN const CK_BBOOL token_present,
++ OUT CK_SLOT_ID_PTR * const pSlotList,
++ OUT CK_ULONG_PTR pulCount
++);
++static
++CK_RV
++_pkcs11h_session_getObjectAttributes (
++ IN const pkcs11h_session_t session,
++ IN const CK_OBJECT_HANDLE object,
++ IN OUT const CK_ATTRIBUTE_PTR attrs,
++ IN const unsigned count
++);
++static
++CK_RV
++_pkcs11h_session_freeObjectAttributes (
++ IN OUT const CK_ATTRIBUTE_PTR attrs,
++ IN const unsigned count
++);
++static
++CK_RV
++_pkcs11h_session_findObjects (
++ IN const pkcs11h_session_t session,
++ IN const CK_ATTRIBUTE * const filter,
++ IN const CK_ULONG filter_attrs,
++ OUT CK_OBJECT_HANDLE **const p_objects,
++ OUT CK_ULONG *p_objects_found
++);
++static
++CK_RV
++_pkcs11h_token_getTokenId (
++ IN const CK_TOKEN_INFO_PTR info,
++ OUT pkcs11h_token_id_t * const p_token_id
++);
++static
++CK_RV
++_pkcs11h_token_newTokenId (
++ OUT pkcs11h_token_id_t * const token_id
++);
++static
++CK_RV
++_pkcs11h_session_getSessionByTokenId (
++ IN const pkcs11h_token_id_t token_id,
++ OUT pkcs11h_session_t * const p_session
++);
++static
++CK_RV
++_pkcs11h_session_release (
++ IN const pkcs11h_session_t session
++);
++static
++CK_RV
++_pkcs11h_session_reset (
++ IN const pkcs11h_session_t session,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT CK_SLOT_ID * const p_slot
++);
++static
++CK_RV
++_pkcs11h_session_getObjectById (
++ IN const pkcs11h_session_t session,
++ IN const CK_OBJECT_CLASS class,
++ IN const CK_BYTE_PTR id,
++ IN const size_t id_size,
++ OUT CK_OBJECT_HANDLE * const p_handle
++);
++static
++CK_RV
++_pkcs11h_session_validate (
++ IN const pkcs11h_session_t session
++);
++static
++CK_RV
++_pkcs11h_session_touch (
++ IN const pkcs11h_session_t session
++);
++static
++CK_RV
++_pkcs11h_session_login (
++ IN const pkcs11h_session_t session,
++ IN const PKCS11H_BOOL public_only,
++ IN const PKCS11H_BOOL readonly,
++ IN void * const user_data,
++ IN const unsigned mask_prompt
++);
++static
++CK_RV
++_pkcs11h_session_logout (
++ IN const pkcs11h_session_t session
++);
++
++static
++void
++_pkcs11h_hooks_default_log (
++ IN void * const global_data,
++ IN const unsigned flags,
++ IN const char * const format,
++ IN va_list args
++);
++
++static
++PKCS11H_BOOL
++_pkcs11h_hooks_default_token_prompt (
++ IN void * const global_data,
++ IN void * const user_data,
++ IN const pkcs11h_token_id_t token,
++ IN const unsigned retry
++);
++
++static
++PKCS11H_BOOL
++_pkcs11h_hooks_default_pin_prompt (
++ IN void * const global_data,
++ IN void * const user_data,
++ IN const pkcs11h_token_id_t token,
++ IN const unsigned retry,
++ OUT char * const pin,
++ IN const size_t pin_max
++);
++
++#if !defined(WIN32)
++#if defined(ENABLE_PKCS11H_THREADING)
++static
++void
++__pkcs11h_threading_atfork_prepare ();
++static
++void
++__pkcs11h_threading_atfork_parent ();
++static
++void
++__pkcs11h_threading_atfork_child ();
++#endif
++static
++CK_RV
++_pkcs11h_forkFixup ();
++#endif
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++/*======================================================================*
++ * CERTIFICATE INTERFACE
++ *======================================================================*/
++
++static
++time_t
++_pkcs11h_certificate_getExpiration (
++ IN const unsigned char * const certificate,
++ IN const size_t certificate_size
++);
++static
++PKCS11H_BOOL
++_pkcs11h_certificate_isBetterCertificate (
++ IN const unsigned char * const current,
++ IN const size_t current_size,
++ IN const unsigned char * const newone,
++ IN const size_t newone_size
++);
++static
++CK_RV
++_pkcs11h_certificate_newCertificateId (
++ OUT pkcs11h_certificate_id_t * const certificate_id
++);
++static
++CK_RV
++_pkcs11h_certificate_getDN (
++ IN const unsigned char * const blob,
++ IN const size_t blob_size,
++ OUT char * const dn,
++ IN const size_t dn_size
++);
++static
++CK_RV
++_pkcs11h_certificate_loadCertificate (
++ IN const pkcs11h_certificate_t certificate
++);
++static
++CK_RV
++_pkcs11h_certificate_updateCertificateIdDescription (
++ IN OUT pkcs11h_certificate_id_t certificate_id
++);
++static
++CK_RV
++_pkcs11h_certificate_getKeyAttributes (
++ IN const pkcs11h_certificate_t certificate
++);
++static
++CK_RV
++_pkcs11h_certificate_validateSession (
++ IN const pkcs11h_certificate_t certificate
++);
++static
++CK_RV
++_pkcs11h_certificate_resetSession (
++ IN const pkcs11h_certificate_t certificate,
++ IN const PKCS11H_BOOL public_only,
++ IN const PKCS11H_BOOL session_mutex_locked
++);
++static
++CK_RV
++_pkcs11h_certificate_doPrivateOperation (
++ IN const pkcs11h_certificate_t certificate,
++ IN const enum _pkcs11h_private_op_e op,
++ 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 p_target_size
++);
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#if defined(ENABLE_PKCS11H_LOCATE)
++/*======================================================================*
++ * LOCATE INTERFACE
++ *======================================================================*/
++
++static
++CK_RV
++_pkcs11h_locate_getTokenIdBySlotId (
++ IN const char * const slot,
++ OUT pkcs11h_token_id_t * const p_token_id
++);
++static
++CK_RV
++_pkcs11h_locate_getTokenIdBySlotName (
++ IN const char * const name,
++ OUT pkcs11h_token_id_t * const p_token_id
++);
++static
++CK_RV
++_pkcs11h_locate_getTokenIdByLabel (
++ IN const char * const label,
++ OUT pkcs11h_token_id_t * const p_token_id
++);
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++
++static
++CK_RV
++_pkcs11h_locate_getCertificateIdByLabel (
++ IN const pkcs11h_session_t session,
++ IN OUT const pkcs11h_certificate_id_t certificate_id,
++ IN const char * const label
++);
++static
++CK_RV
++_pkcs11h_locate_getCertificateIdBySubject (
++ IN const pkcs11h_session_t session,
++ IN OUT const pkcs11h_certificate_id_t certificate_id,
++ IN const char * const subject
++);
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++#endif /* ENABLE_PKCS11H_LOCATE */
++
++#if defined(ENABLE_PKCS11H_ENUM)
++/*======================================================================*
++ * ENUM INTERFACE
++ *======================================================================*/
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++
++static
++CK_RV
++_pkcs11h_certificate_enumSessionCertificates (
++ IN const pkcs11h_session_t session,
++ IN void * const user_data,
++ IN const unsigned mask_prompt
++);
++static
++CK_RV
++_pkcs11h_certificate_splitCertificateIdList (
++ IN const pkcs11h_certificate_id_list_t cert_id_all,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
++);
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#endif /* ENABLE_PKCS11H_ENUM */
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++/*======================================================================*
++ * SLOTEVENT INTERFACE
++ *======================================================================*/
++
++static
++unsigned long
++_pkcs11h_slotevent_checksum (
++ IN const unsigned char * const p,
++ IN const size_t s
++);
++static
++void *
++_pkcs11h_slotevent_provider (
++ IN void *p
++);
++static
++void *
++_pkcs11h_slotevent_manager (
++ IN void *p
++);
++static
++CK_RV
++_pkcs11h_slotevent_init ();
++static
++CK_RV
++_pkcs11h_slotevent_notify ();
++static
++CK_RV
++_pkcs11h_slotevent_terminate ();
++
++#endif /* ENABLE_PKCS11H_SLOTEVENT */
++
++#if defined(ENABLE_PKCS11H_OPENSSL)
++/*======================================================================*
++ * OPENSSL INTERFACE
++ *======================================================================*/
++
++static
++int
++_pkcs11h_openssl_finish (
++ IN OUT RSA *rsa
++);
++#if OPENSSL_VERSION_NUMBER < 0x00907000L
++static
++int
++_pkcs11h_openssl_dec (
++ IN int flen,
++ IN unsigned char *from,
++ OUT unsigned char *to,
++ IN OUT RSA *rsa,
++ IN int padding
++);
++static
++int
++_pkcs11h_openssl_sign (
++ IN int type,
++ IN unsigned char *m,
++ IN unsigned int m_len,
++ OUT unsigned char *sigret,
++ OUT unsigned int *siglen,
++ IN OUT RSA *rsa
++);
++#else
++static
++int
++_pkcs11h_openssl_dec (
++ IN int flen,
++ IN const unsigned char *from,
++ OUT unsigned char *to,
++ IN OUT RSA *rsa,
++ IN int padding
++);
++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
++);
++#endif
++static
++pkcs11h_openssl_session_t
++_pkcs11h_openssl_get_openssl_session (
++ IN OUT const RSA *rsa
++);
++static
++pkcs11h_certificate_t
++_pkcs11h_openssl_get_pkcs11h_certificate (
++ IN OUT const RSA *rsa
++);
++#endif /* ENABLE_PKCS11H_OPENSSL */
++
++/*==========================================
++ * Static data
++ */
++
++#if defined(ENABLE_PKCS11H_THREADING)
++#if !defined(WIN32)
++static struct {
++ pkcs11h_mutex_t mutex;
++ __pkcs11h_threading_mutex_entry_t head;
++} __s_pkcs11h_threading_mutex_list = {
++ PTHREAD_MUTEX_INITIALIZER,
++ NULL
++};
++#endif
++#endif
++
++pkcs11h_data_t s_pkcs11h_data = NULL;
++unsigned int s_pkcs11h_loglevel = PKCS11H_LOG_INFO;
++
++/*======================================================================*
++ * PUBLIC INTERFACE
++ *======================================================================*/
++
++const char *
++pkcs11h_getMessage (
++ IN const CK_RV 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";
++ }
++}
++
++CK_RV
++pkcs11h_initialize () {
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_initialize entry"
++ );
++
++ pkcs11h_terminate ();
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_malloc ((void*)&s_pkcs11h_data, sizeof (struct pkcs11h_data_s));
++ }
++
++#if defined(USE_PKCS11H_OPENSSL) || defined(ENABLE_PKCS11H_OPENSSL)
++ OpenSSL_add_all_digests ();
++#endif
++#if defined(USE_PKCS11H_GNUTLS)
++ if (
++ rv == CKR_OK &&
++ gnutls_global_init () != GNUTLS_E_SUCCESS
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#endif
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_threading_mutexInit (&s_pkcs11h_data->mutexes.global);
++ }
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_threading_mutexInit (&s_pkcs11h_data->mutexes.session);
++ }
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_threading_mutexInit (&s_pkcs11h_data->mutexes.cache);
++ }
++#if !defined(WIN32)
++ if (
++ rv == CKR_OK &&
++ pthread_atfork (
++ __pkcs11h_threading_atfork_prepare,
++ __pkcs11h_threading_atfork_parent,
++ __pkcs11h_threading_atfork_child
++ )
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#endif
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.global)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ s_pkcs11h_data->max_retries = PKCS11H_DEFAULT_MAX_LOGIN_RETRY;
++ s_pkcs11h_data->allow_protected_auth = TRUE;
++ s_pkcs11h_data->pin_cache_period = PKCS11H_DEFAULT_PIN_CACHE_PERIOD;
++ s_pkcs11h_data->initialized = TRUE;
++ }
++
++ if (rv == CKR_OK) {
++ pkcs11h_setLogHook (_pkcs11h_hooks_default_log, NULL);
++ pkcs11h_setTokenPromptHook (_pkcs11h_hooks_default_token_prompt, NULL);
++ pkcs11h_setPINPromptHook (_pkcs11h_hooks_default_pin_prompt, NULL);
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.global);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_initialize return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_terminate () {
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_terminate entry"
++ );
++
++ if (s_pkcs11h_data != NULL) {
++ pkcs11h_provider_t current_provider = NULL;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Removing providers"
++ );
++
++ for (
++ current_provider = s_pkcs11h_data->providers;
++ current_provider != NULL;
++ current_provider = current_provider->next
++ ) {
++ pkcs11h_removeProvider (current_provider->reference);
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.cache);
++ _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.session);
++ _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.global);
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Releasing sessions"
++ );
++
++ while (s_pkcs11h_data->sessions != NULL) {
++ pkcs11h_session_t current = s_pkcs11h_data->sessions;
++ s_pkcs11h_data->sessions = s_pkcs11h_data->sessions->next;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ _pkcs11h_threading_mutexLock (¤t->mutex);
++#endif
++
++ current->valid = FALSE;
++
++ if (current->reference_count != 0) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Warning: Found session with references"
++ );
++ }
++
++ if (current->token_id != NULL) {
++ pkcs11h_token_freeTokenId (current->token_id);
++ current->token_id = NULL;
++ }
++
++#if defined(ENABLE_PKCS11H_ENUM)
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++ pkcs11h_certificate_freeCertificateIdList (current->cached_certs);
++#endif
++#endif
++
++ current->provider = NULL;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ _pkcs11h_threading_mutexFree (¤t->mutex);
++#endif
++
++ _pkcs11h_mem_free ((void *)¤t);
++ }
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Terminating slotevent"
++ );
++
++ _pkcs11h_slotevent_terminate ();
++#endif
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Marking as uninitialized"
++ );
++
++ s_pkcs11h_data->initialized = FALSE;
++
++ while (s_pkcs11h_data->providers != NULL) {
++ pkcs11h_provider_t current = s_pkcs11h_data->providers;
++ s_pkcs11h_data->providers = s_pkcs11h_data->providers->next;
++
++ _pkcs11h_mem_free ((void *)¤t);
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ _pkcs11h_threading_mutexFree (&s_pkcs11h_data->mutexes.cache);
++ _pkcs11h_threading_mutexFree (&s_pkcs11h_data->mutexes.global);
++ _pkcs11h_threading_mutexFree (&s_pkcs11h_data->mutexes.session);
++#endif
++
++#if defined(USE_PKCS11H_GNUTLS)
++ gnutls_global_deinit ();
++#endif
++
++ _pkcs11h_mem_free ((void *)&s_pkcs11h_data);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_terminate return"
++ );
++
++ return CKR_OK;
++}
++
++void
++pkcs11h_setLogLevel (
++ IN const unsigned flags
++) {
++ s_pkcs11h_loglevel = flags;
++}
++
++unsigned
++pkcs11h_getLogLevel () {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++
++ return s_pkcs11h_loglevel;
++}
++
++CK_RV
++pkcs11h_setLogHook (
++ IN const pkcs11h_hook_log_t hook,
++ IN void * const global_data
++) {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (hook!=NULL);
++
++ s_pkcs11h_data->hooks.log = hook;
++ s_pkcs11h_data->hooks.log_data = global_data;
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_setSlotEventHook (
++ IN const pkcs11h_hook_slotevent_t hook,
++ IN void * const global_data
++) {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (hook!=NULL);
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++ s_pkcs11h_data->hooks.slotevent = hook;
++ s_pkcs11h_data->hooks.slotevent_data = global_data;
++
++ return _pkcs11h_slotevent_init ();
++#else
++ (void)global_data;
++
++ return CKR_FUNCTION_NOT_SUPPORTED;
++#endif
++}
++
++CK_RV
++pkcs11h_setPINPromptHook (
++ IN const pkcs11h_hook_pin_prompt_t hook,
++ IN void * const global_data
++) {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (hook!=NULL);
++
++ s_pkcs11h_data->hooks.pin_prompt = hook;
++ s_pkcs11h_data->hooks.pin_prompt_data = global_data;
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_setTokenPromptHook (
++ IN const pkcs11h_hook_token_prompt_t hook,
++ IN void * const global_data
++) {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (hook!=NULL);
++
++ s_pkcs11h_data->hooks.token_prompt = hook;
++ s_pkcs11h_data->hooks.token_prompt_data = global_data;
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_setPINCachePeriod (
++ IN const int pin_cache_period
++) {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++
++ s_pkcs11h_data->pin_cache_period = pin_cache_period;
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_setMaxLoginRetries (
++ IN const unsigned max_retries
++) {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++
++ s_pkcs11h_data->max_retries = max_retries;
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_setProtectedAuthentication (
++ IN const PKCS11H_BOOL allow_protected_auth
++) {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++
++ s_pkcs11h_data->allow_protected_auth = allow_protected_auth;
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_addProvider (
++ IN const char * const reference,
++ IN const char * const provider_location,
++ IN const PKCS11H_BOOL allow_protected_auth,
++ IN const unsigned mask_sign_mode,
++ IN const int slot_event_method,
++ IN const int slot_poll_interval,
++ IN const PKCS11H_BOOL cert_is_private
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++#if defined(WIN32)
++ int mypid = 0;
++#else
++ pid_t mypid = getpid ();
++#endif
++ pkcs11h_provider_t provider = NULL;
++ CK_C_GetFunctionList gfl = NULL;
++ CK_INFO info;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (provider_location!=NULL);
++ /*PKCS11H_ASSERT (szSignMode!=NULL); NOT NEEDED*/
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_addProvider entry pid=%d, reference='%s', provider_location='%s', allow_protected_auth=%d, mask_sign_mode=%08x, cert_is_private=%d",
++ mypid,
++ reference,
++ provider_location,
++ allow_protected_auth ? 1 : 0,
++ mask_sign_mode,
++ cert_is_private ? 1 : 0
++ );
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Adding provider '%s'-'%s'",
++ reference,
++ provider_location
++ );
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.global)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc ((void *)&provider, sizeof (struct pkcs11h_provider_s))) == CKR_OK
++ ) {
++ strncpy (
++ provider->reference,
++ reference,
++ sizeof (provider->reference)-1
++ );
++ provider->reference[sizeof (provider->reference)-1] = '\x0';
++ strncpy (
++ provider->manufacturerID,
++ (
++ strlen (provider_location) < sizeof (provider->manufacturerID) ?
++ provider_location :
++ provider_location+strlen (provider_location)-sizeof (provider->manufacturerID)+1
++ ),
++ sizeof (provider->manufacturerID)-1
++ );
++ provider->manufacturerID[sizeof (provider->manufacturerID)-1] = '\x0';
++ provider->allow_protected_auth = allow_protected_auth;
++ provider->mask_sign_mode = mask_sign_mode;
++ provider->slot_event_method = slot_event_method;
++ provider->slot_poll_interval = slot_poll_interval;
++ provider->cert_is_private = cert_is_private;
++ }
++
++ if (rv == CKR_OK) {
++#if defined(WIN32)
++ provider->handle = LoadLibraryA (provider_location);
++#else
++ provider->handle = dlopen (provider_location, RTLD_NOW);
++#endif
++ if (provider->handle == NULL) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++ }
++
++ if (rv == CKR_OK) {
++#if defined(WIN32)
++ gfl = (CK_C_GetFunctionList)GetProcAddress (
++ provider->handle,
++ "C_GetFunctionList"
++ );
++#else
++ /*
++ * Make compiler happy!
++ */
++ void *p = dlsym (
++ provider->handle,
++ "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->should_finalize = TRUE;
++ }
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = provider->f->C_GetInfo (&info)) == CKR_OK
++ ) {
++ _pkcs11h_util_fixupFixedString (
++ provider->manufacturerID,
++ (char *)info.manufacturerID,
++ sizeof (info.manufacturerID)
++ );
++ }
++
++ if (rv == CKR_OK) {
++ provider->enabled = TRUE;
++ }
++
++ if (provider != NULL) {
++ if (s_pkcs11h_data->providers == NULL) {
++ s_pkcs11h_data->providers = provider;
++ }
++ else {
++ pkcs11h_provider_t last = NULL;
++
++ for (
++ last = s_pkcs11h_data->providers;
++ last->next != NULL;
++ last = last->next
++ );
++ last->next = provider;
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.global);
++ mutex_locked = FALSE;
++ }
++#endif
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++ _pkcs11h_slotevent_notify ();
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Provider '%s' added rv=%ld-'%s'",
++ reference,
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_addProvider return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_removeProvider (
++ IN const char * const reference
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ pkcs11h_session_t current_session = NULL;
++#endif
++ pkcs11h_provider_t provider = NULL;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (reference!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_removeProvider entry reference='%s'",
++ reference
++ );
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Removing provider '%s'",
++ reference
++ );
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.cache);
++ _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.session);
++ _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.global);
++
++ for (
++ current_session = s_pkcs11h_data->sessions;
++ current_session != NULL;
++ current_session = current_session->next
++ ) {
++ _pkcs11h_threading_mutexLock (¤t_session->mutex);
++ }
++#endif
++
++ provider = s_pkcs11h_data->providers;
++ while (
++ rv == CKR_OK &&
++ provider != NULL &&
++ strcmp (reference, provider->reference)
++ ) {
++ provider = provider->next;
++ }
++
++ if (rv == CKR_OK && provider == NULL) {
++ rv = CKR_OBJECT_HANDLE_INVALID;
++ }
++
++ if (rv == CKR_OK) {
++ provider->enabled = FALSE;
++ provider->reference[0] = '\0';
++
++ if (provider->should_finalize) {
++ provider->f->C_Finalize (NULL);
++ provider->should_finalize = FALSE;
++ }
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++ _pkcs11h_slotevent_notify ();
++
++ /*
++ * Wait until manager join this thread
++ * this happens saldom so I can poll
++ */
++ while (provider->slotevent_thread != PKCS11H_THREAD_NULL) {
++ _pkcs11h_threading_sleep (500);
++ }
++#endif
++
++ if (provider->f != NULL) {
++ provider->f = NULL;
++ }
++
++ if (provider->handle != NULL) {
++#if defined(WIN32)
++ FreeLibrary (provider->handle);
++#else
++ dlclose (provider->handle);
++#endif
++ provider->handle = NULL;
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ for (
++ current_session = s_pkcs11h_data->sessions;
++ current_session != NULL;
++ current_session = current_session->next
++ ) {
++ _pkcs11h_threading_mutexRelease (¤t_session->mutex);
++ }
++
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.cache);
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.session);
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.global);
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_removeProvider return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_forkFixup () {
++#if defined(WIN32)
++ return CKR_OK;
++#else
++#if defined(ENABLE_PKCS11H_THREADING)
++ return CKR_OK;
++#else
++ return _pkcs11h_forkFixup ();
++#endif
++#endif
++}
++
++CK_RV
++pkcs11h_plugAndPlay () {
++#if defined(WIN32)
++ int mypid = 0;
++#else
++ pid_t mypid = getpid ();
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_forkFixup entry pid=%d",
++ mypid
++ );
++
++ if (s_pkcs11h_data != NULL && s_pkcs11h_data->initialized) {
++ pkcs11h_provider_t current;
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++ PKCS11H_BOOL slot_event_active = FALSE;
++#endif
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.global);
++#endif
++ for (
++ current = s_pkcs11h_data->providers;
++ current != NULL;
++ current = current->next
++ ) {
++ if (current->enabled) {
++ current->f->C_Finalize (NULL);
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++ if (s_pkcs11h_data->slotevent.initialized) {
++ slot_event_active = TRUE;
++ _pkcs11h_slotevent_terminate ();
++ }
++#endif
++
++ for (
++ current = s_pkcs11h_data->providers;
++ current != NULL;
++ current = current->next
++ ) {
++ if (current->enabled) {
++ current->f->C_Initialize (NULL);
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++ if (slot_event_active) {
++ _pkcs11h_slotevent_init ();
++ }
++#endif
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.global);
++#endif
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_forkFixup return"
++ );
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_token_freeTokenId (
++ IN pkcs11h_token_id_t token_id
++) {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (token_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_freeTokenId entry certificate_id=%p",
++ (void *)token_id
++ );
++
++ _pkcs11h_mem_free ((void *)&token_id);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_freeTokenId return"
++ );
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_token_duplicateTokenId (
++ OUT pkcs11h_token_id_t * const to,
++ IN const pkcs11h_token_id_t from
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (to!=NULL);
++ PKCS11H_ASSERT (from!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_duplicateTokenId entry to=%p form=%p",
++ (void *)to,
++ (void *)from
++ );
++
++ *to = NULL;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_duplicate (
++ (void*)to,
++ NULL,
++ from,
++ sizeof (struct pkcs11h_token_id_s)
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_duplicateTokenId return rv=%ld-'%s', *to=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*to
++ );
++
++ return rv;
++}
++
++PKCS11H_BOOL
++pkcs11h_token_sameTokenId (
++ IN const pkcs11h_token_id_t a,
++ IN const pkcs11h_token_id_t b
++) {
++ PKCS11H_ASSERT (a!=NULL);
++ PKCS11H_ASSERT (b!=NULL);
++
++ return (
++ !strcmp (a->manufacturerID, b->manufacturerID) &&
++ !strcmp (a->model, b->model) &&
++ !strcmp (a->serialNumber, b->serialNumber) &&
++ !strcmp (a->label, b->label)
++ );
++}
++
++#if defined(ENABLE_PKCS11H_SERIALIZATION)
++
++CK_RV
++pkcs11h_token_serializeTokenId (
++ OUT char * const sz,
++ IN OUT size_t *max,
++ IN const pkcs11h_token_id_t token_id
++) {
++ const char *sources[5];
++ CK_RV rv = CKR_OK;
++ size_t n;
++ int e;
++
++ /*PKCS11H_ASSERT (sz!=NULL); Not required*/
++ PKCS11H_ASSERT (max!=NULL);
++ PKCS11H_ASSERT (token_id!=NULL);
++
++ { /* Must be after assert */
++ sources[0] = token_id->manufacturerID;
++ sources[1] = token_id->model;
++ sources[2] = token_id->serialNumber;
++ sources[3] = token_id->label;
++ sources[4] = NULL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_serializeTokenId entry sz=%p, *max=%u, token_id=%p",
++ sz,
++ sz != NULL ? *max : 0,
++ (void *)token_id
++ );
++
++ n = 0;
++ for (e=0;rv == CKR_OK && sources[e] != NULL;e++) {
++ size_t t;
++ rv = _pkcs11h_util_escapeString (NULL, sources[e], &t, PKCS11H_SERIALIZE_INVALID_CHARS);
++ n+=t;
++ }
++
++ if (sz != NULL) {
++ if (*max < n) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ else {
++ n = 0;
++ for (e=0;sources[e] != NULL;e++) {
++ size_t t = *max-n;
++ _pkcs11h_util_escapeString (sz+n, sources[e], &t, PKCS11H_SERIALIZE_INVALID_CHARS);
++ n+=t;
++ sz[n-1] = '/';
++ }
++ sz[n-1] = '\x0';
++ }
++ }
++
++ *max = n;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_serializeTokenId return rv=%ld-'%s', *max=%u, sz='%s'",
++ rv,
++ pkcs11h_getMessage (rv),
++ *max,
++ sz
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_token_deserializeTokenId (
++ OUT pkcs11h_token_id_t *p_token_id,
++ IN const char * const sz
++) {
++#define __PKCS11H_TARGETS_NUMBER 4
++ struct {
++ char *p;
++ size_t s;
++ } targets[__PKCS11H_TARGETS_NUMBER];
++
++ pkcs11h_token_id_t token_id = NULL;
++ char *p1 = NULL;
++ char *_sz = NULL;
++ int e;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (p_token_id!=NULL);
++ PKCS11H_ASSERT (sz!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_deserializeTokenId entry p_token_id=%p, sz='%s'",
++ (void *)p_token_id,
++ sz
++ );
++
++ *p_token_id = NULL;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_strdup (
++ (void *)&_sz,
++ sz
++ );
++ }
++
++ if (rv == CKR_OK) {
++ p1 = _sz;
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_token_newTokenId (&token_id)) == CKR_OK
++ ) {
++ targets[0].p = token_id->manufacturerID;
++ targets[0].s = sizeof (token_id->manufacturerID);
++ targets[1].p = token_id->model;
++ targets[1].s = sizeof (token_id->model);
++ targets[2].p = token_id->serialNumber;
++ targets[2].s = sizeof (token_id->serialNumber);
++ targets[3].p = token_id->label;
++ targets[3].s = sizeof (token_id->label);
++ }
++
++ for (e=0;rv == CKR_OK && e < __PKCS11H_TARGETS_NUMBER;e++) {
++ size_t l;
++ char *p2 = NULL;
++
++ /*
++ * Don't search for last
++ * separator
++ */
++ if (rv == CKR_OK) {
++ if (e != __PKCS11H_TARGETS_NUMBER-1) {
++ p2 = strchr (p1, '/');
++ if (p2 == NULL) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ else {
++ *p2 = '\x0';
++ }
++ }
++ }
++
++ if (rv == CKR_OK) {
++ _pkcs11h_util_unescapeString (
++ NULL,
++ p1,
++ &l
++ );
++ }
++
++ if (rv == CKR_OK) {
++ if (l > targets[e].s) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ }
++
++ if (rv == CKR_OK) {
++ l = targets[e].s;
++ _pkcs11h_util_unescapeString (
++ targets[e].p,
++ p1,
++ &l
++ );
++ }
++
++ if (rv == CKR_OK) {
++ p1 = p2+1;
++ }
++ }
++
++ if (rv == CKR_OK) {
++ strncpy (
++ token_id->display,
++ token_id->label,
++ sizeof (token_id->display)
++ );
++ }
++
++ if (rv == CKR_OK) {
++ *p_token_id = token_id;
++ token_id = NULL;
++ }
++
++ if (_sz != NULL) {
++ _pkcs11h_mem_free ((void *)&_sz);
++ }
++
++ if (token_id != NULL) {
++ pkcs11h_token_freeTokenId (token_id);
++ }
++
++ return rv;
++#undef __PKCS11H_TARGETS_NUMBER
++}
++
++#endif /* ENABLE_PKCS11H_SERIALIZATION */
++
++/*======================================================================*
++ * MEMORY INTERFACE
++ *======================================================================*/
++
++static
++CK_RV
++_pkcs11h_mem_malloc (
++ OUT const void * * const p,
++ IN const size_t s
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (p!=NULL);
++ PKCS11H_ASSERT (s!=0);
++
++ *p = NULL;
++
++ if (s > 0) {
++ if (
++ (*p = (void *)PKCS11H_MALLOC (s)) == NULL
++ ) {
++ rv = CKR_HOST_MEMORY;
++ }
++ else {
++ memset ((void *)*p, 0, s);
++ }
++ }
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_mem_free (
++ IN const void * * const p
++) {
++ PKCS11H_ASSERT (p!=NULL);
++
++ PKCS11H_FREE ((void *)*p);
++ *p = NULL;
++
++ return CKR_OK;
++}
++
++static
++CK_RV
++_pkcs11h_mem_strdup (
++ OUT const char * * const dest,
++ IN const char * const src
++) {
++ return _pkcs11h_mem_duplicate (
++ (void *)dest,
++ NULL,
++ src,
++ strlen (src)+1
++ );
++}
++
++static
++CK_RV
++_pkcs11h_mem_duplicate (
++ OUT const void * * const dest,
++ OUT size_t * const p_dest_size,
++ IN const void * const src,
++ IN const size_t mem_size
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (dest!=NULL);
++ /*PKCS11H_ASSERT (dest_size!=NULL); NOT NEEDED*/
++ PKCS11H_ASSERT (!(mem_size!=0&&src==NULL));
++
++ *dest = NULL;
++ if (p_dest_size != NULL) {
++ *p_dest_size = 0;
++ }
++
++ if (src != NULL) {
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc (dest, mem_size)) == CKR_OK
++ ) {
++ if (p_dest_size != NULL) {
++ *p_dest_size = mem_size;
++ }
++ memmove ((void*)*dest, src, mem_size);
++ }
++ }
++
++ return rv;
++}
++
++#if defined(ENABLE_PKCS11H_THREADING)
++/*======================================================================*
++ * THREADING INTERFACE
++ *======================================================================*/
++
++static
++void
++_pkcs11h_threading_sleep (
++ IN const unsigned milli
++) {
++#if defined(WIN32)
++ Sleep (milli);
++#else
++ usleep (milli*1000);
++#endif
++}
++
++static
++CK_RV
++_pkcs11h_threading_mutexInit (
++ OUT pkcs11h_mutex_t * const mutex
++) {
++ CK_RV rv = CKR_OK;
++#if defined(WIN32)
++ if (
++ rv == CKR_OK &&
++ (*mutex = CreateMutex (NULL, FALSE, NULL)) == NULL
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#else
++ {
++ __pkcs11h_threading_mutex_entry_t entry = NULL;
++ PKCS11H_BOOL mutex_locked = FALSE;
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&__s_pkcs11h_threading_mutex_list.mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_malloc (
++ (void *)&entry,
++ sizeof (struct __pkcs11h_threading_mutex_entry_s)
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ pthread_mutex_init (mutex, NULL)
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++
++ if (rv == CKR_OK) {
++ entry->p_mutex = mutex;
++ entry->next = __s_pkcs11h_threading_mutex_list.head;
++ __s_pkcs11h_threading_mutex_list.head = entry;
++ entry = NULL;
++ }
++
++ if (entry != NULL) {
++ _pkcs11h_mem_free ((void *)&entry);
++ }
++
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&__s_pkcs11h_threading_mutex_list.mutex);
++ mutex_locked = FALSE;
++ }
++ }
++#endif
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_threading_mutexLock (
++ IN OUT pkcs11h_mutex_t *const mutex
++) {
++ CK_RV rv = CKR_OK;
++#if defined(WIN32)
++ if (
++ rv == CKR_OK &&
++ WaitForSingleObject (*mutex, INFINITE) == WAIT_FAILED
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#else
++ if (
++ rv == CKR_OK &&
++ pthread_mutex_lock (mutex)
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#endif
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_threading_mutexRelease (
++ IN OUT pkcs11h_mutex_t *const mutex
++) {
++ CK_RV rv = CKR_OK;
++#if defined(WIN32)
++ if (
++ rv == CKR_OK &&
++ !ReleaseMutex (*mutex)
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#else
++ if (
++ rv == CKR_OK &&
++ pthread_mutex_unlock (mutex)
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#endif
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_threading_mutexFree (
++ IN OUT pkcs11h_mutex_t *const mutex
++) {
++#if defined(WIN32)
++ if (*mutex != NULL) {
++ CloseHandle (*mutex);
++ *mutex = NULL;
++ }
++#else
++ {
++ __pkcs11h_threading_mutex_entry_t last = NULL;
++ __pkcs11h_threading_mutex_entry_t entry = NULL;
++ PKCS11H_BOOL mutex_locked = FALSE;
++
++ if (_pkcs11h_threading_mutexLock (&__s_pkcs11h_threading_mutex_list.mutex) == CKR_OK) {
++ mutex_locked = TRUE;
++ }
++
++ entry = __s_pkcs11h_threading_mutex_list.head;
++ while (
++ entry != NULL &&
++ entry->p_mutex != mutex
++ ) {
++ last = entry;
++ entry = entry->next;
++ }
++
++ if (entry != NULL) {
++ if (last == NULL) {
++ __s_pkcs11h_threading_mutex_list.head = entry->next;
++ }
++ else {
++ last->next = entry->next;
++ }
++ _pkcs11h_mem_free ((void *)&entry);
++ }
++
++ pthread_mutex_destroy (mutex);
++
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&__s_pkcs11h_threading_mutex_list.mutex);
++ mutex_locked = FALSE;
++ }
++ }
++#endif
++ return CKR_OK;
++}
++
++#if !defined(WIN32)
++/*
++ * This function is required in order
++ * to lock all mutexes before fork is called,
++ * and to avoid dedlocks.
++ * The loop is required because there is no
++ * way to lock all mutex in one system call...
++ */
++static
++void
++__pkcs1h_threading_mutexLockAll () {
++ __pkcs11h_threading_mutex_entry_t entry = NULL;
++ PKCS11H_BOOL mutex_locked = FALSE;
++ PKCS11H_BOOL all_mutexes_locked = FALSE;
++
++ if (_pkcs11h_threading_mutexLock (&__s_pkcs11h_threading_mutex_list.mutex) == CKR_OK) {
++ mutex_locked = TRUE;
++ }
++
++ for (
++ entry = __s_pkcs11h_threading_mutex_list.head;
++ entry != NULL;
++ entry = entry->next
++ ) {
++ entry->locked = FALSE;
++ }
++
++ while (!all_mutexes_locked) {
++ PKCS11H_BOOL ok = TRUE;
++
++ for (
++ entry = __s_pkcs11h_threading_mutex_list.head;
++ entry != NULL && ok;
++ entry = entry->next
++ ) {
++ if (!pthread_mutex_trylock (entry->p_mutex)) {
++ entry->locked = TRUE;
++ }
++ else {
++ ok = FALSE;
++ }
++ }
++
++ if (!ok) {
++ for (
++ entry = __s_pkcs11h_threading_mutex_list.head;
++ entry != NULL;
++ entry = entry->next
++ ) {
++ if (entry->locked == TRUE) {
++ pthread_mutex_unlock (entry->p_mutex);
++ entry->locked = FALSE;
++ }
++ }
++
++ _pkcs11h_threading_mutexRelease (&__s_pkcs11h_threading_mutex_list.mutex);
++ _pkcs11h_threading_sleep (1000);
++ _pkcs11h_threading_mutexLock (&__s_pkcs11h_threading_mutex_list.mutex);
++ }
++ else {
++ all_mutexes_locked = TRUE;
++ }
++ }
++
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&__s_pkcs11h_threading_mutex_list.mutex);
++ mutex_locked = FALSE;
++ }
++}
++
++static
++void
++__pkcs1h_threading_mutexReleaseAll () {
++ __pkcs11h_threading_mutex_entry_t entry = NULL;
++ PKCS11H_BOOL mutex_locked = FALSE;
++
++ if (_pkcs11h_threading_mutexLock (&__s_pkcs11h_threading_mutex_list.mutex) == CKR_OK) {
++ mutex_locked = TRUE;
++ }
++
++ for (
++ entry = __s_pkcs11h_threading_mutex_list.head;
++ entry != NULL;
++ entry = entry->next
++ ) {
++ pthread_mutex_unlock (entry->p_mutex);
++ entry->locked = FALSE;
++ }
++
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&__s_pkcs11h_threading_mutex_list.mutex);
++ mutex_locked = FALSE;
++ }
++}
++#endif
++
++CK_RV
++_pkcs11h_threading_condSignal (
++ IN OUT pkcs11h_cond_t *const cond
++) {
++ CK_RV rv = CKR_OK;
++#if defined(WIN32)
++ if (
++ rv == CKR_OK &&
++ !SetEvent (*cond)
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#else
++ if (
++ rv == CKR_OK &&
++ (
++ pthread_mutex_lock (&cond->mut) ||
++ pthread_cond_signal (&cond->cond) ||
++ pthread_mutex_unlock (&cond->mut)
++ )
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#endif
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_threading_condInit (
++ OUT pkcs11h_cond_t * const cond
++) {
++ CK_RV rv = CKR_OK;
++#if defined(WIN32)
++ if (
++ rv == CKR_OK &&
++ (*cond = CreateEvent (NULL, FALSE, FALSE, NULL)) == NULL
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#else
++ if (
++ rv == CKR_OK &&
++ (
++ pthread_mutex_init (&cond->mut, NULL) ||
++ pthread_cond_init (&cond->cond, NULL) ||
++ pthread_mutex_lock (&cond->mut)
++ )
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#endif
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_threading_condWait (
++ IN OUT pkcs11h_cond_t *const cond,
++ IN const unsigned milli
++) {
++ CK_RV rv = CKR_OK;
++
++#if defined(WIN32)
++ DWORD dwMilli;
++
++ if (milli == PKCS11H_COND_INFINITE) {
++ dwMilli = INFINITE;
++ }
++ else {
++ dwMilli = milli;
++ }
++
++ if (
++ rv == CKR_OK &&
++ WaitForSingleObject (*cond, dwMilli) == WAIT_FAILED
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#else
++ if (milli == PKCS11H_COND_INFINITE) {
++ if (
++ rv == CKR_OK &&
++ pthread_cond_wait (&cond->cond, &cond->mut)
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++ }
++ else {
++ struct timeval now;
++ struct timespec timeout;
++
++ if (
++ rv == CKR_OK &&
++ gettimeofday (&now, NULL)
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++
++ if (rv == CKR_OK) {
++ timeout.tv_sec = now.tv_sec + milli/1000;
++ timeout.tv_nsec = now.tv_usec*1000 + milli%1000;
++ }
++
++ if (
++ rv == CKR_OK &&
++ pthread_cond_timedwait (&cond->cond, &cond->mut, &timeout)
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++ }
++#endif
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_threading_condFree (
++ IN OUT pkcs11h_cond_t *const cond
++) {
++#if defined(WIN32)
++ CloseHandle (*cond);
++ *cond = NULL;
++#else
++ pthread_mutex_unlock (&cond->mut);
++#endif
++ return CKR_OK;
++}
++
++#if defined(WIN32)
++static
++unsigned
++__stdcall
++__pkcs11h_thread_start (void *p) {
++ __pkcs11h_thread_data_t *_data = (__pkcs11h_thread_data_t *)p;
++ unsigned ret;
++
++ ret = (unsigned)_data->start (_data->data);
++
++ _pkcs11h_mem_free ((void *)&_data);
++
++ return ret;
++}
++#else
++static
++void *
++__pkcs11h_thread_start (void *p) {
++ __pkcs11h_thread_data_t *_data = (__pkcs11h_thread_data_t *)p;
++ void *ret;
++ int i;
++
++ /*
++ * Ignore any signal in
++ * this thread
++ */
++ for (i=1;i<16;i++) {
++ signal (i, SIG_IGN);
++ }
++
++ ret = _data->start (_data->data);
++
++ _pkcs11h_mem_free ((void *)&_data);
++
++ return ret;
++}
++#endif
++
++static
++CK_RV
++_pkcs11h_threading_threadStart (
++ OUT pkcs11h_thread_t * const thread,
++ IN pkcs11h_thread_start_t const start,
++ IN void * data
++) {
++ __pkcs11h_thread_data_t *_data = NULL;
++ CK_RV rv = CKR_OK;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_malloc (
++ (void *)&_data,
++ sizeof (__pkcs11h_thread_data_t)
++ );
++ }
++
++ if (rv == CKR_OK) {
++ _data->start = start;
++ _data->data = data;
++ }
++
++#if defined(WIN32)
++ {
++ unsigned tmp;
++
++ if (
++ rv == CKR_OK &&
++ (*thread = (HANDLE)_beginthreadex (
++ NULL,
++ 0,
++ __pkcs11h_thread_start,
++ _data,
++ 0,
++ &tmp
++ )) == NULL
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++ }
++#else
++ if (
++ rv == CKR_OK &&
++ pthread_create (thread, NULL, __pkcs11h_thread_start, _data)
++ ) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++#endif
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_threading_threadJoin (
++ IN pkcs11h_thread_t * const thread
++) {
++#if defined(WIN32)
++ WaitForSingleObject (*thread, INFINITE);
++ CloseHandle (*thread);
++ *thread = NULL;
++#else
++ pthread_join (*thread, NULL);
++ *thread = 0l;
++#endif
++ return CKR_OK;
++}
++
++#endif /* ENABLE_PKCS11H_THREADING */
++
++/*======================================================================*
++ * COMMON INTERNAL INTERFACE
++ *======================================================================*/
++
++static
++void
++_pkcs11h_util_fixupFixedString (
++ OUT char * const target, /* MUST BE >= length+1 */
++ IN const char * const source,
++ IN const size_t length /* FIXED STRING LENGTH */
++) {
++ char *p;
++
++ PKCS11H_ASSERT (source!=NULL);
++ PKCS11H_ASSERT (target!=NULL);
++
++ p = target+length;
++ memmove (target, source, length);
++ *p = '\0';
++ p--;
++ while (p >= target && *p == ' ') {
++ *p = '\0';
++ p--;
++ }
++}
++
++static
++CK_RV
++_pkcs11h_util_hexToBinary (
++ OUT unsigned char * const target,
++ IN const char * const source,
++ IN OUT size_t * const p_target_size
++) {
++ size_t target_max_size;
++ const char *p;
++ char buf[3] = {'\0', '\0', '\0'};
++ int i = 0;
++
++ PKCS11H_ASSERT (source!=NULL);
++ PKCS11H_ASSERT (target!=NULL);
++ PKCS11H_ASSERT (p_target_size!=NULL);
++
++ target_max_size = *p_target_size;
++ p = source;
++ *p_target_size = 0;
++
++ while (*p != '\x0' && *p_target_size < target_max_size) {
++ if (isxdigit ((unsigned char)*p)) {
++ buf[i%2] = *p;
++
++ if ((i%2) == 1) {
++ unsigned v;
++ if (sscanf (buf, "%x", &v) != 1) {
++ v = 0;
++ }
++ target[*p_target_size] = v & 0xff;
++ (*p_target_size)++;
++ }
++
++ i++;
++ }
++ p++;
++ }
++
++ if (*p != '\x0') {
++ return CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ else {
++ return CKR_OK;
++ }
++}
++
++static
++CK_RV
++_pkcs11h_util_binaryToHex (
++ OUT char * const target,
++ IN const size_t target_size,
++ IN const unsigned char * const source,
++ IN const size_t source_size
++) {
++ static const char *x = "0123456789ABCDEF";
++ size_t i;
++
++ PKCS11H_ASSERT (target!=NULL);
++ PKCS11H_ASSERT (source!=NULL);
++
++ if (target_size < source_size * 2 + 1) {
++ return CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++
++ for (i=0;i<source_size;i++) {
++ target[i*2] = x[(source[i]&0xf0)>>4];
++ target[i*2+1] = x[(source[i]&0x0f)>>0];
++ }
++ target[source_size*2] = '\x0';
++
++ return CKR_OK;
++}
++
++CK_RV
++_pkcs11h_util_escapeString (
++ IN OUT char * const target,
++ IN const char * const source,
++ IN size_t * const max,
++ IN const char * const invalid_chars
++) {
++ static const char *x = "0123456789ABCDEF";
++ CK_RV rv = CKR_OK;
++ const char *s = source;
++ char *t = target;
++ size_t n = 0;
++
++ /*PKCS11H_ASSERT (target!=NULL); Not required*/
++ PKCS11H_ASSERT (source!=NULL);
++ PKCS11H_ASSERT (max!=NULL);
++
++ while (rv == CKR_OK && *s != '\x0') {
++
++ if (*s == '\\' || strchr (invalid_chars, *s) || !isgraph (*s)) {
++ if (t != NULL) {
++ if (n+4 > *max) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ else {
++ t[0] = '\\';
++ t[1] = 'x';
++ t[2] = x[(*s&0xf0)>>4];
++ t[3] = x[(*s&0x0f)>>0];
++ t+=4;
++ }
++ }
++ n+=4;
++ }
++ else {
++ if (t != NULL) {
++ if (n+1 > *max) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ else {
++ *t = *s;
++ t++;
++ }
++ }
++ n+=1;
++ }
++
++ s++;
++ }
++
++ if (t != NULL) {
++ if (n+1 > *max) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ else {
++ *t = '\x0';
++ t++;
++ }
++ }
++ n++;
++
++ *max = n;
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_util_unescapeString (
++ IN OUT char * const target,
++ IN const char * const source,
++ IN size_t * const max
++) {
++ CK_RV rv = CKR_OK;
++ const char *s = source;
++ char *t = target;
++ size_t n = 0;
++
++ /*PKCS11H_ASSERT (target!=NULL); Not required*/
++ PKCS11H_ASSERT (source!=NULL);
++ PKCS11H_ASSERT (max!=NULL);
++
++ while (rv == CKR_OK && *s != '\x0') {
++ if (*s == '\\') {
++ if (t != NULL) {
++ if (n+1 > *max) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ else {
++ char b[3];
++ unsigned u;
++ b[0] = s[2];
++ b[1] = s[3];
++ b[2] = '\x0';
++ sscanf (b, "%08x", &u);
++ *t = u&0xff;
++ t++;
++ }
++ }
++ s+=4;
++ }
++ else {
++ if (t != NULL) {
++ if (n+1 > *max) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ else {
++ *t = *s;
++ t++;
++ }
++ }
++ s++;
++ }
++
++ n+=1;
++ }
++
++ if (t != NULL) {
++ if (n+1 > *max) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ else {
++ *t = '\x0';
++ t++;
++ }
++ }
++ n++;
++
++ *max = n;
++
++ return rv;
++}
++
++static
++void
++_pkcs11h_log (
++ IN const unsigned flags,
++ IN const char * const format,
++ IN ...
++) {
++ va_list args;
++
++ PKCS11H_ASSERT (format!=NULL);
++
++ va_start (args, format);
++
++ if (
++ s_pkcs11h_data != NULL &&
++ s_pkcs11h_data->initialized
++ ) {
++ if (PKCS11H_MSG_LEVEL_TEST (flags)) {
++ if (s_pkcs11h_data->hooks.log == NULL) {
++ _pkcs11h_hooks_default_log (
++ NULL,
++ flags,
++ format,
++ args
++ );
++ }
++ else {
++ s_pkcs11h_data->hooks.log (
++ s_pkcs11h_data->hooks.log_data,
++ flags,
++ format,
++ args
++ );
++ }
++ }
++ }
++
++ va_end (args);
++}
++
++static
++CK_RV
++_pkcs11h_session_getSlotList (
++ IN const pkcs11h_provider_t provider,
++ IN const CK_BBOOL token_present,
++ OUT CK_SLOT_ID_PTR * const pSlotList,
++ OUT CK_ULONG_PTR pulCount
++) {
++ CK_SLOT_ID_PTR _slots = NULL;
++ CK_ULONG _slotnum = 0;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (provider!=NULL);
++ PKCS11H_ASSERT (pSlotList!=NULL);
++ PKCS11H_ASSERT (pulCount!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_getSlotList entry provider=%p, token_present=%d, pSlotList=%p, pulCount=%p",
++ (void *)provider,
++ token_present,
++ (void *)pSlotList,
++ (void *)pulCount
++ );
++
++ *pSlotList = NULL;
++ *pulCount = 0;
++
++ if (
++ rv == CKR_OK &&
++ !provider->enabled
++ ) {
++ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
++ }
++
++ if (rv == CKR_OK) {
++ rv = provider->f->C_GetSlotList (
++ token_present,
++ NULL_PTR,
++ &_slotnum
++ );
++ }
++
++ if (rv == CKR_OK && _slotnum > 0) {
++ rv = _pkcs11h_mem_malloc ((void *)&_slots, _slotnum * sizeof (CK_SLOT_ID));
++ }
++
++ if (rv == CKR_OK && _slotnum > 0) {
++ rv = provider->f->C_GetSlotList (
++ token_present,
++ _slots,
++ &_slotnum
++ );
++ }
++
++ if (rv == CKR_OK) {
++ *pSlotList = _slots;
++ _slots = NULL;
++ *pulCount = _slotnum;
++ }
++
++ if (_slots != NULL) {
++ _pkcs11h_mem_free ((void *)&_slots);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_getSlotList return rv=%ld-'%s' *pulCount=%ld",
++ rv,
++ pkcs11h_getMessage (rv),
++ *pulCount
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_getObjectAttributes (
++ IN const pkcs11h_session_t session,
++ IN const CK_OBJECT_HANDLE object,
++ IN OUT const CK_ATTRIBUTE_PTR attrs,
++ IN const unsigned count
++) {
++ /*
++ * THREADING:
++ * session->mutex must be locked
++ */
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (session!=NULL);
++ PKCS11H_ASSERT (attrs!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_getObjectAttributes entry session=%p, object=%ld, attrs=%p, count=%u",
++ (void *)session,
++ object,
++ (void *)attrs,
++ count
++ );
++
++ if (
++ rv == CKR_OK &&
++ (rv = session->provider->f->C_GetAttributeValue (
++ session->session_handle,
++ object,
++ attrs,
++ count
++ )) == CKR_OK
++ ) {
++ unsigned i;
++ for (i=0;rv == CKR_OK && i<count;i++) {
++ if (attrs[i].ulValueLen == (CK_ULONG)-1) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++ else if (attrs[i].ulValueLen == 0) {
++ attrs[i].pValue = NULL;
++ }
++ else {
++ rv = _pkcs11h_mem_malloc (
++ (void *)&attrs[i].pValue,
++ attrs[i].ulValueLen
++ );
++ }
++ }
++ }
++
++ if (rv == CKR_OK) {
++ rv = session->provider->f->C_GetAttributeValue (
++ session->session_handle,
++ object,
++ attrs,
++ count
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_getObjectAttributes return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_freeObjectAttributes (
++ IN OUT const CK_ATTRIBUTE_PTR attrs,
++ IN const unsigned count
++) {
++ unsigned i;
++
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (attrs!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_freeObjectAttributes entry attrs=%p, count=%u",
++ (void *)attrs,
++ count
++ );
++
++ for (i=0;i<count;i++) {
++ if (attrs[i].pValue != NULL) {
++ _pkcs11h_mem_free ((void *)&attrs[i].pValue);
++ attrs[i].pValue = NULL;
++ }
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_freeObjectAttributes return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_findObjects (
++ IN const pkcs11h_session_t session,
++ IN const CK_ATTRIBUTE * const filter,
++ IN const CK_ULONG filter_attrs,
++ OUT CK_OBJECT_HANDLE **const p_objects,
++ OUT CK_ULONG *p_objects_found
++) {
++ /*
++ * THREADING:
++ * session->mutex must be locked
++ */
++ PKCS11H_BOOL should_FindObjectsFinal = FALSE;
++
++ CK_OBJECT_HANDLE *objects = NULL;
++ CK_ULONG objects_size = 0;
++ CK_OBJECT_HANDLE objects_buffer[100];
++ CK_ULONG objects_found;
++ CK_OBJECT_HANDLE oLast = PKCS11H_INVALID_OBJECT_HANDLE;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (session!=NULL);
++ PKCS11H_ASSERT (!(filter==NULL && filter_attrs!=0) || filter!=NULL);
++ PKCS11H_ASSERT (p_objects!=NULL);
++ PKCS11H_ASSERT (p_objects_found!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_findObjects entry session=%p, filter=%p, filter_attrs=%ld, p_objects=%p, p_objects_found=%p",
++ (void *)session,
++ (void *)filter,
++ filter_attrs,
++ (void *)p_objects,
++ (void *)p_objects_found
++ );
++
++ *p_objects = NULL;
++ *p_objects_found = 0;
++
++ if (
++ rv == CKR_OK &&
++ (rv = session->provider->f->C_FindObjectsInit (
++ session->session_handle,
++ (CK_ATTRIBUTE *)filter,
++ filter_attrs
++ )) == CKR_OK
++ ) {
++ should_FindObjectsFinal = TRUE;
++ }
++
++ while (
++ rv == CKR_OK &&
++ (rv = session->provider->f->C_FindObjects (
++ session->session_handle,
++ objects_buffer,
++ sizeof (objects_buffer) / sizeof (CK_OBJECT_HANDLE),
++ &objects_found
++ )) == CKR_OK &&
++ objects_found > 0
++ ) {
++ CK_OBJECT_HANDLE *temp = NULL;
++
++ /*
++ * Begin workaround
++ *
++ * Workaround iKey bug
++ * It returns the same objects over and over
++ */
++ if (oLast == objects_buffer[0]) {
++ PKCS11H_LOG (
++ PKCS11H_LOG_WARN,
++ "PKCS#11: Bad PKCS#11 C_FindObjects implementation detected, workaround applied"
++ );
++ break;
++ }
++ oLast = objects_buffer[0];
++ /* End workaround */
++
++ if (
++ (rv = _pkcs11h_mem_malloc (
++ (void *)&temp,
++ (objects_size+objects_found) * sizeof (CK_OBJECT_HANDLE)
++ )) == CKR_OK
++ ) {
++ if (objects != NULL) {
++ memmove (
++ temp,
++ objects,
++ objects_size * sizeof (CK_OBJECT_HANDLE)
++ );
++ }
++ memmove (
++ temp + objects_size,
++ objects_buffer,
++ objects_found * sizeof (CK_OBJECT_HANDLE)
++ );
++ }
++
++ if (objects != NULL) {
++ _pkcs11h_mem_free ((void *)&objects);
++ objects = NULL;
++ }
++
++ if (rv == CKR_OK) {
++ objects = temp;
++ objects_size += objects_found;
++ temp = NULL;
++ }
++
++ if (temp != NULL) {
++ _pkcs11h_mem_free ((void *)&temp);
++ temp = NULL;
++ }
++ }
++
++ if (should_FindObjectsFinal) {
++ session->provider->f->C_FindObjectsFinal (
++ session->session_handle
++ );
++ should_FindObjectsFinal = FALSE;
++ }
++
++ if (rv == CKR_OK) {
++ *p_objects = objects;
++ *p_objects_found = objects_size;
++ objects = NULL;
++ objects_size = 0;
++ }
++
++ if (objects != NULL) {
++ _pkcs11h_mem_free ((void *)&objects);
++ objects = NULL;
++ objects_size = 0;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_findObjects return rv=%ld-'%s', *p_objects_found=%ld",
++ rv,
++ pkcs11h_getMessage (rv),
++ *p_objects_found
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_token_getTokenId (
++ IN const CK_TOKEN_INFO_PTR info,
++ OUT pkcs11h_token_id_t * const p_token_id
++) {
++ pkcs11h_token_id_t token_id;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (info!=NULL);
++ PKCS11H_ASSERT (p_token_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_token_getTokenId entry p_token_id=%p",
++ (void *)p_token_id
++ );
++
++ *p_token_id = NULL;
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_token_newTokenId (&token_id)) == CKR_OK
++ ) {
++ _pkcs11h_util_fixupFixedString (
++ token_id->label,
++ (char *)info->label,
++ sizeof (info->label)
++ );
++ _pkcs11h_util_fixupFixedString (
++ token_id->manufacturerID,
++ (char *)info->manufacturerID,
++ sizeof (info->manufacturerID)
++ );
++ _pkcs11h_util_fixupFixedString (
++ token_id->model,
++ (char *)info->model,
++ sizeof (info->model)
++ );
++ _pkcs11h_util_fixupFixedString (
++ token_id->serialNumber,
++ (char *)info->serialNumber,
++ sizeof (info->serialNumber)
++ );
++ strncpy (
++ token_id->display,
++ token_id->label,
++ sizeof (token_id->display)
++ );
++ }
++
++ if (rv == CKR_OK) {
++ *p_token_id = token_id;
++ token_id = NULL;
++ }
++
++ if (token_id != NULL) {
++ _pkcs11h_mem_free ((void *)&token_id);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_token_getTokenId return rv=%ld-'%s', *p_token_id=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_token_id
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_token_newTokenId (
++ OUT pkcs11h_token_id_t * const p_token_id
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (p_token_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_token_newTokenId entry p_token_id=%p",
++ (void *)p_token_id
++ );
++
++ *p_token_id = NULL;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_malloc ((void *)p_token_id, sizeof (struct pkcs11h_token_id_s));
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_token_newTokenId return rv=%ld-'%s', *p_token_id=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_token_id
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_getSessionByTokenId (
++ IN const pkcs11h_token_id_t token_id,
++ OUT pkcs11h_session_t * const p_session
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ pkcs11h_session_t session = NULL;
++ PKCS11H_BOOL is_new_session = FALSE;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (token_id!=NULL);
++ PKCS11H_ASSERT (p_session!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_getSessionByTokenId entry token_id=%p, p_session=%p",
++ (void *)token_id,
++ (void *)p_session
++ );
++
++ *p_session = NULL;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.session)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ pkcs11h_session_t current_session;
++
++ for (
++ current_session = s_pkcs11h_data->sessions;
++ current_session != NULL && session == NULL;
++ current_session = current_session->next
++ ) {
++ if (
++ pkcs11h_token_sameTokenId (
++ current_session->token_id,
++ token_id
++ )
++ ) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Using cached session"
++ );
++ session = current_session;
++ session->reference_count++;
++ }
++ }
++ }
++
++ if (
++ rv == CKR_OK &&
++ session == NULL
++ ) {
++ is_new_session = TRUE;
++ }
++
++ if (is_new_session) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Creating a new session"
++ );
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc ((void *)&session, sizeof (struct pkcs11h_session_s))) == CKR_OK
++ ) {
++ session->reference_count = 1;
++ session->session_handle = PKCS11H_INVALID_SESSION_HANDLE;
++
++ session->pin_cache_period = s_pkcs11h_data->pin_cache_period;
++
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_token_duplicateTokenId (
++ &session->token_id,
++ token_id
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_threading_mutexInit (&session->mutex);
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ session->valid = TRUE;
++ session->next = s_pkcs11h_data->sessions;
++ s_pkcs11h_data->sessions = session;
++ }
++ else {
++#if defined(ENABLE_PKCS11H_THREADING)
++ _pkcs11h_threading_mutexFree (&session->mutex);
++#endif
++ _pkcs11h_mem_free ((void *)&session);
++ }
++ }
++
++ if (rv == CKR_OK) {
++ *p_session = session;
++ session = NULL;
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.session);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_getSessionByTokenId return rv=%ld-'%s', *p_session=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_session
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_release (
++ IN const pkcs11h_session_t session
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (session!=NULL);
++ PKCS11H_ASSERT (session->reference_count>=0);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_release entry session=%p",
++ (void *)session
++ );
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ /*
++ * Never logout for now
++ */
++ if (rv == CKR_OK) {
++ if (session->reference_count > 0) {
++ session->reference_count--;
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_release return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_reset (
++ IN const pkcs11h_session_t session,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT CK_SLOT_ID * const p_slot
++) {
++ PKCS11H_BOOL found = FALSE;
++
++ CK_RV rv = CKR_OK;
++
++ unsigned nRetry = 0;
++
++ PKCS11H_ASSERT (session!=NULL);
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++ PKCS11H_ASSERT (p_slot!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_reset entry session=%p, user_data=%p, mask_prompt=%08x, p_slot=%p",
++ (void *)session,
++ user_data,
++ mask_prompt,
++ (void *)p_slot
++ );
++
++ *p_slot = PKCS11H_INVALID_SLOT_ID;
++
++ while (
++ rv == CKR_OK &&
++ !found
++ ) {
++ pkcs11h_provider_t current_provider = NULL;
++
++ for (
++ current_provider = s_pkcs11h_data->providers;
++ (
++ rv == CKR_OK &&
++ current_provider != NULL &&
++ !found
++ );
++ current_provider = current_provider->next
++ ) {
++ CK_SLOT_ID_PTR slots = NULL;
++ CK_ULONG slotnum;
++ CK_SLOT_ID slot_index;
++
++ /*
++ * Skip all other providers,
++ * if one was set in the past
++ */
++ if (
++ session->provider != NULL &&
++ session->provider != current_provider
++ ) {
++ rv = CKR_CANCEL;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSlotList (
++ current_provider,
++ CK_TRUE,
++ &slots,
++ &slotnum
++ );
++ }
++
++ for (
++ slot_index=0;
++ (
++ slot_index < slotnum &&
++ rv == CKR_OK &&
++ !found
++ );
++ slot_index++
++ ) {
++ pkcs11h_token_id_t token_id = NULL;
++ CK_TOKEN_INFO info;
++
++ if (rv == CKR_OK) {
++ rv = current_provider->f->C_GetTokenInfo (
++ slots[slot_index],
++ &info
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_token_getTokenId (
++ &info,
++ &token_id
++ )) == CKR_OK &&
++ pkcs11h_token_sameTokenId (
++ session->token_id,
++ token_id
++ )
++ ) {
++ found = TRUE;
++ *p_slot = slots[slot_index];
++ if (session->provider == NULL) {
++ session->provider = current_provider;
++ session->allow_protected_auth_supported = (info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) != 0;
++ }
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get token information for provider '%s' slot %ld rv=%ld-'%s'",
++ current_provider->manufacturerID,
++ slots[slot_index],
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++
++ if (token_id != NULL) {
++ pkcs11h_token_freeTokenId (token_id);
++ }
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
++ current_provider->manufacturerID,
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++
++ if (slots != NULL) {
++ _pkcs11h_mem_free ((void *)&slots);
++ slots = NULL;
++ }
++ }
++
++ if (rv == CKR_OK && !found && (mask_prompt & PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT) == 0) {
++ rv = CKR_TOKEN_NOT_PRESENT;
++ }
++
++ if (
++ rv == CKR_OK &&
++ !found
++ ) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Calling token_prompt hook for '%s'",
++ session->token_id->display
++ );
++
++ if (
++ !s_pkcs11h_data->hooks.token_prompt (
++ s_pkcs11h_data->hooks.token_prompt_data,
++ user_data,
++ session->token_id,
++ nRetry++
++ )
++ ) {
++ rv = CKR_CANCEL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: token_prompt returned %ld",
++ rv
++ );
++ }
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_reset return rv=%ld-'%s', *p_slot=%ld",
++ rv,
++ pkcs11h_getMessage (rv),
++ *p_slot
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_getObjectById (
++ IN const pkcs11h_session_t session,
++ IN const CK_OBJECT_CLASS class,
++ IN const CK_BYTE_PTR id,
++ IN const size_t id_size,
++ OUT CK_OBJECT_HANDLE * const p_handle
++) {
++ /*
++ * THREADING:
++ * session->mutex must be locked
++ */
++ CK_ATTRIBUTE filter[] = {
++ {CKA_CLASS, (void *)&class, sizeof (class)},
++ {CKA_ID, (void *)id, id_size}
++ };
++ CK_OBJECT_HANDLE *objects = NULL;
++ CK_ULONG objects_found = 0;
++ CK_RV rv = CKR_OK;
++
++ /*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/
++ PKCS11H_ASSERT (id!=NULL);
++ PKCS11H_ASSERT (p_handle!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_getObjectById entry session=%p, class=%ld, id=%p, id_size=%u, p_handle=%p",
++ (void *)session,
++ class,
++ id,
++ id_size,
++ (void *)p_handle
++ );
++
++ *p_handle = PKCS11H_INVALID_OBJECT_HANDLE;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_findObjects (
++ session,
++ filter,
++ sizeof (filter) / sizeof (CK_ATTRIBUTE),
++ &objects,
++ &objects_found
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ objects_found == 0
++ ) {
++ rv = CKR_FUNCTION_REJECTED;
++ }
++
++ if (rv == CKR_OK) {
++ *p_handle = objects[0];
++ }
++
++ if (objects != NULL) {
++ _pkcs11h_mem_free ((void *)&objects);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_getObjectById return rv=%ld-'%s', *p_handle=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_handle
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_validate (
++ IN const pkcs11h_session_t session
++) {
++ CK_RV rv = CKR_OK;
++
++ /*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_validate entry session=%p",
++ (void *)session
++ );
++
++ if (
++ rv == CKR_OK &&
++ session == NULL
++ ) {
++ rv = CKR_SESSION_HANDLE_INVALID;
++ }
++
++ if (
++ rv == CKR_OK &&
++ (
++ session->provider == NULL ||
++ !session->provider->enabled ||
++ session->session_handle == PKCS11H_INVALID_SESSION_HANDLE
++ )
++ ) {
++ rv = CKR_SESSION_HANDLE_INVALID;
++ }
++
++ if (
++ rv == CKR_OK &&
++ session->pin_expire_time != (time_t)0 &&
++ session->pin_expire_time < PKCS11H_TIME (NULL)
++ ) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Forcing logout due to pin timeout"
++ );
++ _pkcs11h_session_logout (session);
++ rv = CKR_SESSION_HANDLE_INVALID;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_validate return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_touch (
++ IN const pkcs11h_session_t session
++) {
++ /*
++ * THREADING:
++ * session->mutex must be locked
++ */
++ PKCS11H_ASSERT (session!=NULL);
++
++ if (session->pin_cache_period == PKCS11H_PIN_CACHE_INFINITE) {
++ session->pin_expire_time = 0;
++ }
++ else {
++ session->pin_expire_time = (
++ PKCS11H_TIME (NULL) +
++ (time_t)session->pin_cache_period
++ );
++ }
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_token_login (
++ IN const pkcs11h_token_id_t token_id,
++ IN const PKCS11H_BOOL readonly,
++ IN const char * const pin
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ CK_SLOT_ID slot = PKCS11H_INVALID_SLOT_ID;
++ CK_ULONG pin_size = 0;
++ CK_RV rv = CKR_OK;
++
++ pkcs11h_session_t session = NULL;
++
++ PKCS11H_ASSERT (token_id!=NULL);
++ /*PKCS11H_ASSERT (pin!=NULL); NOT NEEDED*/
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_login entry token_id=%p, readonly=%d\n",
++ (void *)token_id,
++ readonly ? 1 : 0
++ );
++
++ if (pin != NULL) {
++ pin_size = strlen (pin);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSessionByTokenId (
++ token_id,
++ &session
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_logout (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_reset (session, NULL, 0, &slot);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_touch (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = session->provider->f->C_OpenSession (
++ slot,
++ (
++ CKF_SERIAL_SESSION |
++ (readonly ? 0 : CKF_RW_SESSION)
++ ),
++ NULL_PTR,
++ NULL_PTR,
++ &session->session_handle
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = session->provider->f->C_Login (
++ session->session_handle,
++ CKU_USER,
++ (CK_UTF8CHAR_PTR)pin,
++ pin_size
++ )) != CKR_OK
++ ) {
++ if (rv == CKR_USER_ALREADY_LOGGED_IN) {
++ rv = CKR_OK;
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ if (session != NULL) {
++ _pkcs11h_session_release (session);
++ session = NULL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_login return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_login (
++ IN const pkcs11h_session_t session,
++ IN const PKCS11H_BOOL is_publicOnly,
++ IN const PKCS11H_BOOL readonly,
++ IN void * const user_data,
++ IN const unsigned mask_prompt
++) {
++ /*
++ * THREADING:
++ * session->mutex must be locked
++ */
++ CK_SLOT_ID slot = PKCS11H_INVALID_SLOT_ID;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (session!=NULL);
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_login entry session=%p, is_publicOnly=%d, readonly=%d, user_data=%p, mask_prompt=%08x",
++ (void *)session,
++ is_publicOnly ? 1 : 0,
++ readonly ? 1 : 0,
++ user_data,
++ mask_prompt
++ );
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_logout (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_reset (session, user_data, mask_prompt, &slot);
++ }
++
++ if (rv == CKR_OK) {
++ rv = session->provider->f->C_OpenSession (
++ slot,
++ (
++ CKF_SERIAL_SESSION |
++ (readonly ? 0 : CKF_RW_SESSION)
++ ),
++ NULL_PTR,
++ NULL_PTR,
++ &session->session_handle
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ (
++ !is_publicOnly ||
++ session->provider->cert_is_private
++ )
++ ) {
++ PKCS11H_BOOL login_succeeded = FALSE;
++ unsigned nRetryCount = 0;
++
++ if ((mask_prompt & PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT) == 0) {
++ rv = CKR_USER_NOT_LOGGED_IN;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Calling pin_prompt hook denied because of prompt mask"
++ );
++ }
++
++ while (
++ rv == CKR_OK &&
++ !login_succeeded &&
++ nRetryCount < s_pkcs11h_data->max_retries
++ ) {
++ CK_UTF8CHAR_PTR utfPIN = NULL;
++ CK_ULONG lPINLength = 0;
++ char pin[1024];
++
++ if (
++ rv == CKR_OK &&
++ !(
++ s_pkcs11h_data->allow_protected_auth &&
++ session->provider->allow_protected_auth &&
++ session->allow_protected_auth_supported
++ )
++ ) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Calling pin_prompt hook for '%s'",
++ session->token_id->display
++ );
++
++ if (
++ !s_pkcs11h_data->hooks.pin_prompt (
++ s_pkcs11h_data->hooks.pin_prompt_data,
++ user_data,
++ session->token_id,
++ nRetryCount,
++ pin,
++ sizeof (pin)
++ )
++ ) {
++ rv = CKR_CANCEL;
++ }
++ else {
++ utfPIN = (CK_UTF8CHAR_PTR)pin;
++ lPINLength = strlen (pin);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: pin_prompt hook return rv=%ld",
++ rv
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_touch (session);
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = session->provider->f->C_Login (
++ session->session_handle,
++ CKU_USER,
++ utfPIN,
++ lPINLength
++ )) != CKR_OK
++ ) {
++ if (rv == CKR_USER_ALREADY_LOGGED_IN) {
++ rv = CKR_OK;
++ }
++ }
++
++ /*
++ * Clean PIN buffer
++ */
++ memset (pin, 0, sizeof (pin));
++
++ if (rv == CKR_OK) {
++ login_succeeded = TRUE;
++ }
++ else if (
++ rv == CKR_PIN_INCORRECT ||
++ rv == CKR_PIN_INVALID
++ ) {
++ /*
++ * Ignore these errors
++ * so retry can be performed
++ */
++ rv = CKR_OK;
++ }
++
++ nRetryCount++;
++ }
++
++ /*
++ * Retry limit
++ */
++ if (!login_succeeded && rv == CKR_OK) {
++ rv = CKR_PIN_INCORRECT;
++ }
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_login return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_session_logout (
++ IN const pkcs11h_session_t session
++) {
++ /*
++ * THREADING:
++ * session->mutex must be locked
++ */
++ /*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_logout entry session=%p",
++ (void *)session
++ );
++
++ if (
++ session != NULL &&
++ session->session_handle != PKCS11H_INVALID_SESSION_HANDLE
++ ) {
++ CK_RV rv = CKR_OK;
++
++ if (rv == CKR_OK) {
++ if (session->provider != NULL) {
++ session->provider->f->C_Logout (session->session_handle);
++ session->provider->f->C_CloseSession (session->session_handle);
++ }
++ session->session_handle = PKCS11H_INVALID_SESSION_HANDLE;
++ }
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_session_logout return"
++ );
++
++ return CKR_OK;
++}
++
++static
++void
++_pkcs11h_hooks_default_log (
++ IN void * const global_data,
++ IN const unsigned flags,
++ IN const char * const format,
++ IN va_list args
++) {
++ (void)global_data;
++ (void)flags;
++ (void)format;
++ (void)args;
++}
++
++static
++PKCS11H_BOOL
++_pkcs11h_hooks_default_token_prompt (
++ IN void * const global_data,
++ IN void * const user_data,
++ IN const pkcs11h_token_id_t token,
++ IN const unsigned retry
++) {
++ /*PKCS11H_ASSERT (global_data) NOT NEEDED */
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++ PKCS11H_ASSERT (token!=NULL);
++
++ (void)global_data;
++ (void)user_data;
++ (void)retry;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_hooks_default_token_prompt global_data=%p, user_data=%p, display='%s'",
++ global_data,
++ user_data,
++ token->display
++ );
++
++ return FALSE;
++}
++
++static
++PKCS11H_BOOL
++_pkcs11h_hooks_default_pin_prompt (
++ IN void * const global_data,
++ IN void * const user_data,
++ IN const pkcs11h_token_id_t token,
++ IN const unsigned retry,
++ OUT char * const pin,
++ IN const size_t pin_max
++) {
++ /*PKCS11H_ASSERT (global_data) NOT NEEDED */
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++ PKCS11H_ASSERT (token!=NULL);
++
++ (void)global_data;
++ (void)user_data;
++ (void)retry;
++ (void)pin;
++ (void)pin_max;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_hooks_default_pin_prompt global_data=%p, user_data=%p, display='%s'",
++ global_data,
++ user_data,
++ token->display
++ );
++
++ return FALSE;
++}
++
++#if !defined(WIN32)
++#if defined(ENABLE_PKCS11H_THREADING)
++
++static
++void
++__pkcs11h_threading_atfork_prepare () {
++ __pkcs1h_threading_mutexLockAll ();
++}
++static
++void
++__pkcs11h_threading_atfork_parent () {
++ __pkcs1h_threading_mutexReleaseAll ();
++}
++static
++void
++__pkcs11h_threading_atfork_child () {
++ __pkcs1h_threading_mutexReleaseAll ();
++ _pkcs11h_forkFixup ();
++}
++
++#endif /* ENABLE_PKCS11H_THREADING */
++
++static
++CK_RV
++_pkcs11h_forkFixup () {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ pid_t mypid = getpid ();
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_forkFixup entry pid=%d",
++ mypid
++ );
++
++ if (s_pkcs11h_data != NULL && s_pkcs11h_data->initialized) {
++ pkcs11h_provider_t current;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (_pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.global) == CKR_OK) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ for (
++ current = s_pkcs11h_data->providers;
++ current != NULL;
++ current = current->next
++ ) {
++ if (current->enabled) {
++ current->f->C_Initialize (NULL);
++ }
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++ /*
++ * After fork we have no threads...
++ * So just initialized.
++ */
++ if (s_pkcs11h_data->slotevent.initialized) {
++ s_pkcs11h_data->slotevent.initialized = FALSE;
++ _pkcs11h_slotevent_init ();
++ }
++#endif
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.global);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_forkFixup return"
++ );
++
++ return CKR_OK;
++}
++
++#endif /* !WIN32 */
++
++#if defined(ENABLE_PKCS11H_TOKEN)
++/*======================================================================*
++ * TOKEN INTERFACE
++ *======================================================================*/
++
++CK_RV
++pkcs11h_token_ensureAccess (
++ IN const pkcs11h_token_id_t token_id,
++ IN void * const user_data,
++ IN const unsigned mask_prompt
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ pkcs11h_session_t session = NULL;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (token_id!=NULL);
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_ensureAccess entry token_id=%p, user_data=%p, mask_prompt=%08x",
++ (void *)token_id,
++ user_data,
++ mask_prompt
++ );
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSessionByTokenId (
++ token_id,
++ &session
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ CK_SLOT_ID slot;
++
++ rv = _pkcs11h_session_reset (
++ session,
++ user_data,
++ mask_prompt,
++ &slot
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ if (session != NULL) {
++ _pkcs11h_session_release (session);
++ session = NULL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_ensureAccess return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++#endif /* ENABLE_PKCS11H_TOKEN */
++
++#if defined(ENABLE_PKCS11H_DATA)
++/*======================================================================*
++ * DATA INTERFACE
++ *======================================================================*/
++
++static
++CK_RV
++_pkcs11h_data_getObject (
++ IN const pkcs11h_session_t session,
++ IN const char * const application,
++ IN const char * const label,
++ OUT CK_OBJECT_HANDLE * const p_handle
++) {
++ CK_OBJECT_CLASS class = CKO_DATA;
++ CK_ATTRIBUTE filter[] = {
++ {CKA_CLASS, (void *)&class, sizeof (class)},
++ {CKA_APPLICATION, (void *)application, application == NULL ? 0 : strlen (application)},
++ {CKA_LABEL, (void *)label, label == NULL ? 0 : strlen (label)}
++ };
++ CK_OBJECT_HANDLE *objects = NULL;
++ CK_ULONG objects_found = 0;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (session!=NULL);
++ PKCS11H_ASSERT (application!=NULL);
++ PKCS11H_ASSERT (label!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_data_getObject entry session=%p, application='%s', label='%s', p_handle=%p",
++ (void *)session,
++ application,
++ label,
++ (void *)p_handle
++ );
++
++ *p_handle = PKCS11H_INVALID_OBJECT_HANDLE;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_findObjects (
++ session,
++ filter,
++ sizeof (filter) / sizeof (CK_ATTRIBUTE),
++ &objects,
++ &objects_found
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ objects_found == 0
++ ) {
++ rv = CKR_FUNCTION_REJECTED;
++ }
++
++ if (rv == CKR_OK) {
++ *p_handle = objects[0];
++ }
++
++ if (objects != NULL) {
++ _pkcs11h_mem_free ((void *)&objects);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_data_getObject return rv=%ld-'%s', *p_handle=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_handle
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_data_get (
++ IN const pkcs11h_token_id_t token_id,
++ IN const PKCS11H_BOOL is_public,
++ IN const char * const application,
++ IN const char * const label,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT unsigned char * const blob,
++ IN OUT size_t * const p_blob_size
++) {
++ CK_ATTRIBUTE attrs[] = {
++ {CKA_VALUE, NULL, 0}
++ };
++ CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE;
++ CK_RV rv = CKR_OK;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ pkcs11h_session_t session = NULL;
++ PKCS11H_BOOL op_succeed = FALSE;
++ PKCS11H_BOOL login_retry = FALSE;
++ size_t blob_size_max = 0;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (token_id!=NULL);
++ PKCS11H_ASSERT (application!=NULL);
++ PKCS11H_ASSERT (label!=NULL);
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++ /*PKCS11H_ASSERT (blob!=NULL); NOT NEEDED*/
++ PKCS11H_ASSERT (p_blob_size!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_data_get entry token_id=%p, application='%s', label='%s', user_data=%p, mask_prompt=%08x, blob=%p, *p_blob_size=%u",
++ (void *)token_id,
++ application,
++ label,
++ user_data,
++ mask_prompt,
++ blob,
++ blob != NULL ? *p_blob_size : 0
++ );
++
++ if (blob != NULL) {
++ blob_size_max = *p_blob_size;
++ }
++ *p_blob_size = 0;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSessionByTokenId (
++ token_id,
++ &session
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ while (rv == CKR_OK && !op_succeed) {
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_data_getObject (
++ session,
++ application,
++ label,
++ &handle
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getObjectAttributes (
++ session,
++ handle,
++ attrs,
++ sizeof (attrs)/sizeof (CK_ATTRIBUTE)
++ );
++ }
++
++ if (rv == CKR_OK) {
++ op_succeed = TRUE;
++ }
++ else {
++ if (!login_retry) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Read data object failed rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++ login_retry = TRUE;
++ rv = _pkcs11h_session_login (
++ session,
++ is_public,
++ TRUE,
++ user_data,
++ mask_prompt
++ );
++ }
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ *p_blob_size = attrs[0].ulValueLen;
++ }
++
++ if (rv == CKR_OK) {
++ if (blob != NULL) {
++ if (*p_blob_size > blob_size_max) {
++ rv = CKR_BUFFER_TOO_SMALL;
++ }
++ else {
++ memmove (blob, attrs[0].pValue, *p_blob_size);
++ }
++ }
++ }
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs,
++ sizeof (attrs)/sizeof (CK_ATTRIBUTE)
++ );
++
++ if (session != NULL) {
++ _pkcs11h_session_release (session);
++ session = NULL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_data_get return rv=%ld-'%s', *p_blob_size=%u",
++ rv,
++ pkcs11h_getMessage (rv),
++ *p_blob_size
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_data_put (
++ IN const pkcs11h_token_id_t token_id,
++ IN const PKCS11H_BOOL is_public,
++ IN const char * const application,
++ IN const char * const label,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT unsigned char * const blob,
++ IN const size_t blob_size
++) {
++ CK_OBJECT_CLASS class = CKO_DATA;
++ CK_BBOOL ck_true = CK_TRUE;
++ CK_BBOOL ck_false = CK_FALSE;
++
++ CK_ATTRIBUTE attrs[] = {
++ {CKA_CLASS, &class, sizeof (class)},
++ {CKA_TOKEN, &ck_true, sizeof (ck_true)},
++ {CKA_PRIVATE, is_public ? &ck_false : &ck_true, sizeof (CK_BBOOL)},
++ {CKA_APPLICATION, (void *)application, strlen (application)},
++ {CKA_LABEL, (void *)label, strlen (label)},
++ {CKA_VALUE, blob, blob_size}
++ };
++
++ CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE;
++ CK_RV rv = CKR_OK;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ pkcs11h_session_t session = NULL;
++ PKCS11H_BOOL op_succeed = FALSE;
++ PKCS11H_BOOL login_retry = FALSE;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (token_id!=NULL);
++ PKCS11H_ASSERT (application!=NULL);
++ PKCS11H_ASSERT (label!=NULL);
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++ PKCS11H_ASSERT (blob!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_data_put entry token_id=%p, application='%s', label='%s', user_data=%p, mask_prompt=%08x, blob=%p, blob_size=%u",
++ (void *)token_id,
++ application,
++ label,
++ user_data,
++ mask_prompt,
++ blob,
++ blob != NULL ? blob_size : 0
++ );
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSessionByTokenId (
++ token_id,
++ &session
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ while (rv == CKR_OK && !op_succeed) {
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = session->provider->f->C_CreateObject (
++ session->session_handle,
++ attrs,
++ sizeof (attrs)/sizeof (CK_ATTRIBUTE),
++ &handle
++ );
++ }
++
++ if (rv == CKR_OK) {
++ op_succeed = TRUE;
++ }
++ else {
++ if (!login_retry) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Write data object failed rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++ login_retry = TRUE;
++ rv = _pkcs11h_session_login (
++ session,
++ is_public,
++ FALSE,
++ user_data,
++ mask_prompt
++ );
++ }
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ if (session != NULL) {
++ _pkcs11h_session_release (session);
++ session = NULL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_data_put return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_data_del (
++ IN const pkcs11h_token_id_t token_id,
++ IN const PKCS11H_BOOL is_public,
++ IN const char * const application,
++ IN const char * const label,
++ IN void * const user_data,
++ IN const unsigned mask_prompt
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ pkcs11h_session_t session = NULL;
++ PKCS11H_BOOL op_succeed = FALSE;
++ PKCS11H_BOOL login_retry = FALSE;
++ CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (token_id!=NULL);
++ PKCS11H_ASSERT (application!=NULL);
++ PKCS11H_ASSERT (label!=NULL);
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_data_del entry token_id=%p, application='%s', label='%s', user_data=%p, mask_prompt=%08x",
++ (void *)token_id,
++ application,
++ label,
++ user_data,
++ mask_prompt
++ );
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSessionByTokenId (
++ token_id,
++ &session
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ while (rv == CKR_OK && !op_succeed) {
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_data_getObject (
++ session,
++ application,
++ label,
++ &handle
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = session->provider->f->C_DestroyObject (
++ session->session_handle,
++ handle
++ );
++ }
++
++ if (rv == CKR_OK) {
++ op_succeed = TRUE;
++ }
++ else {
++ if (!login_retry) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Remove data object failed rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++ login_retry = TRUE;
++ rv = _pkcs11h_session_login (
++ session,
++ is_public,
++ FALSE,
++ user_data,
++ mask_prompt
++ );
++ }
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ if (session != NULL) {
++ _pkcs11h_session_release (session);
++ session = NULL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_data_del return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++#endif /* ENABLE_PKCS11H_DATA */
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++/*======================================================================*
++ * CERTIFICATE INTERFACE
++ *======================================================================*/
++
++static
++time_t
++_pkcs11h_certificate_getExpiration (
++ IN const unsigned char * const certificate,
++ IN const size_t certificate_size
++) {
++ /*
++ * This function compare the notAfter
++ * and select the most recent certificate
++ */
++
++#if defined(USE_PKCS11H_OPENSSL)
++ X509 *x509 = NULL;
++#elif defined(USE_PKCS11H_GNUTLS)
++ gnutls_x509_crt_t cert = NULL;
++#endif
++ time_t expire = (time_t)0;
++
++ PKCS11H_ASSERT (certificate!=NULL);
++
++#if defined(USE_PKCS11H_OPENSSL)
++ x509 = X509_new ();
++
++ if (x509 != NULL) {
++ pkcs11_openssl_d2i_t d2i = (pkcs11_openssl_d2i_t)certificate;
++
++ if (
++ d2i_X509 (&x509, &d2i, certificate_size)
++ ) {
++ ASN1_TIME *notBefore = X509_get_notBefore (x509);
++ ASN1_TIME *notAfter = X509_get_notAfter (x509);
++
++ if (
++ notBefore != NULL &&
++ notAfter != NULL &&
++ X509_cmp_current_time (notBefore) <= 0 &&
++ X509_cmp_current_time (notAfter) >= 0 &&
++ notAfter->length >= 12
++ ) {
++ struct tm tm1;
++ time_t now = time (NULL);
++
++ memset (&tm1, 0, sizeof (tm1));
++ tm1.tm_year = (notAfter->data[ 0] - '0') * 10 + (notAfter->data[ 1] - '0') + 100;
++ tm1.tm_mon = (notAfter->data[ 2] - '0') * 10 + (notAfter->data[ 3] - '0') - 1;
++ tm1.tm_mday = (notAfter->data[ 4] - '0') * 10 + (notAfter->data[ 5] - '0');
++ tm1.tm_hour = (notAfter->data[ 6] - '0') * 10 + (notAfter->data[ 7] - '0');
++ tm1.tm_min = (notAfter->data[ 8] - '0') * 10 + (notAfter->data[ 9] - '0');
++ tm1.tm_sec = (notAfter->data[10] - '0') * 10 + (notAfter->data[11] - '0');
++
++ tm1.tm_sec += (int)(mktime (localtime (&now)) - mktime (gmtime (&now)));
++
++ expire = mktime (&tm1);
++ }
++ }
++ }
++
++ if (x509 != NULL) {
++ X509_free (x509);
++ x509 = NULL;
++ }
++#elif defined(USE_PKCS11H_GNUTLS)
++ if (gnutls_x509_crt_init (&cert) == GNUTLS_E_SUCCESS) {
++ gnutls_datum_t datum = {(unsigned char *)certificate, certificate_size};
++
++ if (gnutls_x509_crt_import (cert, &datum, GNUTLS_X509_FMT_DER) == GNUTLS_E_SUCCESS) {
++
++ time_t activation_time = gnutls_x509_crt_get_activation_time (cert);
++ time_t expiration_time = gnutls_x509_crt_get_expiration_time (cert);
++ time_t now = time (NULL);
++
++ if (
++ now >= activation_time &&
++ now <= expiration_time
++ ) {
++ expire = expiration_time;
++ }
++ }
++ gnutls_x509_crt_deinit (cert);
++ }
++#else
++#error Invalid configuration
++#endif
++
++ return expire;
++}
++
++static
++PKCS11H_BOOL
++_pkcs11h_certificate_isBetterCertificate (
++ IN const unsigned char * const current,
++ IN const size_t current_size,
++ IN const unsigned char * const newone,
++ IN const size_t newone_size
++) {
++ PKCS11H_BOOL is_better = FALSE;
++
++ /*PKCS11H_ASSERT (current!=NULL); NOT NEEDED */
++ PKCS11H_ASSERT (newone!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_isBetterCertificate entry current=%p, current_size=%u, newone=%p, newone_size=%u",
++ current,
++ current_size,
++ newone,
++ newone_size
++ );
++
++ /*
++ * First certificae
++ * always select
++ */
++ if (current_size == 0 || current == NULL) {
++ is_better = TRUE;
++ }
++ else {
++ time_t notAfterCurrent, notAfterNew;
++
++ notAfterCurrent = _pkcs11h_certificate_getExpiration (
++ current,
++ current_size
++ );
++ notAfterNew = _pkcs11h_certificate_getExpiration (
++ newone,
++ newone_size
++ );
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_isBetterCertificate notAfterCurrent='%s', notAfterNew='%s'",
++ asctime (localtime (¬AfterCurrent)),
++ asctime (localtime (¬AfterNew))
++ );
++
++ is_better = notAfterNew > notAfterCurrent;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_isBetterCertificate return is_better=%d",
++ is_better ? 1 : 0
++ );
++
++ return is_better;
++}
++
++static
++CK_RV
++_pkcs11h_certificate_newCertificateId (
++ OUT pkcs11h_certificate_id_t * const p_certificate_id
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (p_certificate_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_newCertificateId entry p_certificate_id=%p",
++ (void *)p_certificate_id
++ );
++
++ *p_certificate_id = NULL;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_malloc ((void *)p_certificate_id, sizeof (struct pkcs11h_certificate_id_s));
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_newCertificateId return rv=%ld-'%s', *p_certificate_id=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_certificate_id
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_certificate_getDN (
++ IN const unsigned char * const blob,
++ IN const size_t blob_size,
++ OUT char * const dn,
++ IN const size_t dn_size
++) {
++#if defined(USE_PKCS11H_OPENSSL)
++ X509 *x509 = NULL;
++ pkcs11_openssl_d2i_t d2i1;
++#elif defined(USE_PKCS11H_GNUTLS)
++ gnutls_x509_crt_t cert = NULL;
++#endif
++
++ PKCS11H_ASSERT (blob_size==0||blob!=NULL);
++ PKCS11H_ASSERT (dn!=NULL);
++
++ dn[0] = '\x0';
++
++#if defined(USE_PKCS11H_OPENSSL)
++
++ if (blob_size > 0) {
++ x509 = X509_new ();
++
++ d2i1 = (pkcs11_openssl_d2i_t)blob;
++ if (d2i_X509 (&x509, &d2i1, blob_size)) {
++ X509_NAME_oneline (
++ X509_get_subject_name (x509),
++ dn,
++ dn_size
++ );
++ }
++
++ if (x509 != NULL) {
++ X509_free (x509);
++ x509 = NULL;
++ }
++ }
++
++#elif defined(USE_PKCS11H_GNUTLS)
++
++ if (blob_size > 0) {
++ if (gnutls_x509_crt_init (&cert) == GNUTLS_E_SUCCESS) {
++ gnutls_datum_t datum = {(unsigned char *)blob, blob_size};
++
++ if (gnutls_x509_crt_import (cert, &datum, GNUTLS_X509_FMT_DER) == GNUTLS_E_SUCCESS) {
++ size_t s = dn_size;
++ if (
++ gnutls_x509_crt_get_dn (
++ cert,
++ dn,
++ &s
++ ) != GNUTLS_E_SUCCESS
++ ) {
++ /* gnutls sets output parameters */
++ dn[0] = '\x0';
++ }
++ }
++ gnutls_x509_crt_deinit (cert);
++ }
++ }
++
++#else
++#error Invalid configuration
++#endif
++
++ return CKR_OK;
++}
++
++static
++CK_RV
++_pkcs11h_certificate_loadCertificate (
++ IN const pkcs11h_certificate_t certificate
++) {
++ /*
++ * THREADING:
++ * certificate->mutex must be locked
++ */
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
++ CK_ATTRIBUTE cert_filter[] = {
++ {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)},
++ {CKA_ID, NULL, 0}
++ };
++
++ CK_OBJECT_HANDLE *objects = NULL;
++ CK_ULONG objects_found = 0;
++ CK_RV rv = CKR_OK;
++
++ CK_ULONG i;
++
++ PKCS11H_ASSERT (certificate!=NULL);
++ PKCS11H_ASSERT (certificate->id!=NULL);
++
++ /* Must be after assert */
++ cert_filter[1].pValue = certificate->id->attrCKA_ID;
++ cert_filter[1].ulValueLen = certificate->id->attrCKA_ID_size;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_loadCertificate entry certificate=%p",
++ (void *)certificate
++ );
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&certificate->session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (certificate->session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_findObjects (
++ certificate->session,
++ cert_filter,
++ sizeof (cert_filter) / sizeof (CK_ATTRIBUTE),
++ &objects,
++ &objects_found
++ );
++ }
++
++ for (i=0;rv == CKR_OK && i < objects_found;i++) {
++ CK_ATTRIBUTE attrs[] = {
++ {CKA_VALUE, NULL, 0}
++ };
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_session_getObjectAttributes (
++ certificate->session,
++ objects[i],
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ )) == CKR_OK
++ ) {
++ if (
++ _pkcs11h_certificate_isBetterCertificate (
++ certificate->id->certificate_blob,
++ certificate->id->certificate_blob_size,
++ attrs[0].pValue,
++ attrs[0].ulValueLen
++ )
++ ) {
++ if (certificate->id->certificate_blob != NULL) {
++ _pkcs11h_mem_free ((void *)&certificate->id->certificate_blob);
++ }
++
++ rv = _pkcs11h_mem_duplicate (
++ (void*)&certificate->id->certificate_blob,
++ &certificate->id->certificate_blob_size,
++ attrs[0].pValue,
++ attrs[0].ulValueLen
++ );
++ }
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'",
++ certificate->session->provider->manufacturerID,
++ objects[i],
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&certificate->session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ if (
++ rv == CKR_OK &&
++ certificate->id->certificate_blob == NULL
++ ) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++
++ if (objects != NULL) {
++ _pkcs11h_mem_free ((void *)&objects);
++ }
++
++ /*
++ * No need to free allocated objects
++ * on error, since the certificate_id
++ * should be free by caller.
++ */
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_loadCertificate return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_certificate_updateCertificateIdDescription (
++ IN OUT pkcs11h_certificate_id_t certificate_id
++) {
++ static const char * separator = " on ";
++ static const char * unknown = "UNKNOWN";
++
++ PKCS11H_ASSERT (certificate_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_updateCertificateIdDescription entry certificate_id=%p",
++ (void *)certificate_id
++ );
++
++ certificate_id->displayName[0] = '\x0';
++
++ _pkcs11h_certificate_getDN (
++ certificate_id->certificate_blob,
++ certificate_id->certificate_blob_size,
++ certificate_id->displayName,
++ sizeof (certificate_id->displayName)
++ );
++
++ if (strlen (certificate_id->displayName) == 0) {
++ strncpy (
++ certificate_id->displayName,
++ unknown,
++ sizeof (certificate_id->displayName)-1
++ );
++ }
++
++ /*
++ * Try to avoid using snprintf,
++ * may be unavailable
++ */
++ strncat (
++ certificate_id->displayName,
++ separator,
++ sizeof (certificate_id->displayName)-1-strlen (certificate_id->displayName)
++ );
++ strncat (
++ certificate_id->displayName,
++ certificate_id->token_id->display,
++ sizeof (certificate_id->displayName)-1-strlen (certificate_id->displayName)
++ );
++ certificate_id->displayName[sizeof (certificate_id->displayName) - 1] = '\0';
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_updateCertificateIdDescription return displayName='%s'",
++ certificate_id->displayName
++ );
++
++ return CKR_OK;
++}
++
++static
++CK_RV
++_pkcs11h_certificate_getKeyAttributes (
++ IN const pkcs11h_certificate_t certificate
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_BOOL op_succeed = FALSE;
++ PKCS11H_BOOL login_retry = FALSE;
++
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_getKeyAttributes entry certificate=%p",
++ (void *)certificate
++ );
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&certificate->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ certificate->mask_sign_mode = 0;
++
++ while (rv == CKR_OK && !op_succeed) {
++ CK_ATTRIBUTE key_attrs[] = {
++ {CKA_SIGN, NULL, 0},
++ {CKA_SIGN_RECOVER, NULL, 0}
++ };
++
++ /*
++ * Don't try invalid object
++ */
++ if (
++ rv == CKR_OK &&
++ certificate->key_handle == PKCS11H_INVALID_OBJECT_HANDLE
++ ) {
++ rv = CKR_OBJECT_HANDLE_INVALID;
++ }
++
++ if (rv == CKR_OK) {
++ if (certificate->session->provider->mask_sign_mode != 0) {
++ certificate->mask_sign_mode = certificate->session->provider->mask_sign_mode;
++ op_succeed = TRUE;
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Key attributes enforced by provider (%08x)",
++ certificate->mask_sign_mode
++ );
++ }
++ }
++
++ if (rv == CKR_OK && !op_succeed) {
++ rv = _pkcs11h_session_getObjectAttributes (
++ certificate->session,
++ certificate->key_handle,
++ key_attrs,
++ sizeof (key_attrs) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++
++ if (rv == CKR_OK && !op_succeed) {
++ CK_BBOOL *key_attrs_sign = (CK_BBOOL *)key_attrs[0].pValue;
++ CK_BBOOL *key_attrs_sign_recover = (CK_BBOOL *)key_attrs[1].pValue;
++
++ if (key_attrs_sign != NULL && *key_attrs_sign != CK_FALSE) {
++ certificate->mask_sign_mode |= PKCS11H_SIGNMODE_MASK_SIGN;
++ }
++ if (key_attrs_sign_recover != NULL && *key_attrs_sign_recover != CK_FALSE) {
++ certificate->mask_sign_mode |= PKCS11H_SIGNMODE_MASK_RECOVER;
++ }
++ if (certificate->mask_sign_mode == 0) {
++ rv = CKR_KEY_TYPE_INCONSISTENT;
++ }
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Key attributes loaded (%08x)",
++ certificate->mask_sign_mode
++ );
++ }
++
++ _pkcs11h_session_freeObjectAttributes (
++ key_attrs,
++ sizeof (key_attrs) / sizeof (CK_ATTRIBUTE)
++ );
++
++ if (rv == CKR_OK) {
++ op_succeed = TRUE;
++ }
++ else {
++ if (!login_retry) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Get private key attributes failed: %ld:'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ rv = _pkcs11h_certificate_resetSession (
++ certificate,
++ FALSE,
++ TRUE
++ );
++
++ login_retry = TRUE;
++ }
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&certificate->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_getKeyAttributes return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_certificate_validateSession (
++ IN const pkcs11h_certificate_t certificate
++) {
++ /*
++ * THREADING:
++ * certificate->mutex must be locked
++ * certificate->session->mutex must be locked
++ */
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_validateSession entry certificate=%p",
++ (void *)certificate
++ );
++
++ if (certificate->session == NULL) {
++ rv = CKR_SESSION_HANDLE_INVALID;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (certificate->session);
++ }
++
++ if (rv == CKR_OK) {
++ if (certificate->key_handle == PKCS11H_INVALID_OBJECT_HANDLE) {
++ rv = CKR_OBJECT_HANDLE_INVALID;
++ }
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_validateSession return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++_pkcs11h_certificate_resetSession (
++ IN const pkcs11h_certificate_t certificate,
++ IN const PKCS11H_BOOL public_only,
++ IN const PKCS11H_BOOL session_mutex_locked
++) {
++ /*
++ * THREADING:
++ * certificate->mutex must be locked
++ */
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ PKCS11H_BOOL is_key_valid = FALSE;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_resetSession entry certificate=%p, public_only=%d, session_mutex_locked=%d",
++ (void *)certificate,
++ public_only ? 1 : 0,
++ session_mutex_locked ? 1 : 0
++ );
++
++ if (rv == CKR_OK && certificate->session == NULL) {
++ rv = _pkcs11h_session_getSessionByTokenId (certificate->id->token_id, &certificate->session);
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ !session_mutex_locked &&
++ (rv = _pkcs11h_threading_mutexLock (&certificate->session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (
++ rv == CKR_OK &&
++ !certificate->pin_cache_populated_to_session
++ ) {
++ certificate->pin_cache_populated_to_session = TRUE;
++
++ if (certificate->pin_cache_period != PKCS11H_PIN_CACHE_INFINITE) {
++ if (certificate->session->pin_cache_period != PKCS11H_PIN_CACHE_INFINITE) {
++ if (certificate->session->pin_cache_period > certificate->pin_cache_period) {
++ certificate->session->pin_expire_time = (
++ certificate->session->pin_expire_time -
++ (time_t)certificate->session->pin_cache_period +
++ (time_t)certificate->pin_cache_period
++ );
++ certificate->session->pin_cache_period = certificate->pin_cache_period;
++ }
++ }
++ else {
++ certificate->session->pin_expire_time = (
++ PKCS11H_TIME (NULL) +
++ (time_t)certificate->pin_cache_period
++ );
++ certificate->session->pin_cache_period = certificate->pin_cache_period;
++ }
++ }
++ }
++
++ /*
++ * First, if session seems to be valid
++ * and key handle is invalid (hard-set),
++ * try to fetch key handle,
++ * maybe the token is already logged in
++ */
++ if (rv == CKR_OK) {
++ if (
++ certificate->session->session_handle != PKCS11H_INVALID_SESSION_HANDLE &&
++ certificate->key_handle == PKCS11H_INVALID_OBJECT_HANDLE
++ ) {
++ if (!public_only || certificate->session->provider->cert_is_private) {
++ if (
++ (rv = _pkcs11h_session_getObjectById (
++ certificate->session,
++ CKO_PRIVATE_KEY,
++ certificate->id->attrCKA_ID,
++ certificate->id->attrCKA_ID_size,
++ &certificate->key_handle
++ )) == CKR_OK
++ ) {
++ is_key_valid = TRUE;
++ }
++ else {
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ certificate->key_handle = PKCS11H_INVALID_OBJECT_HANDLE;
++ }
++ }
++ }
++ }
++
++ if (
++ !is_key_valid &&
++ rv == CKR_OK &&
++ (rv = _pkcs11h_session_login (
++ certificate->session,
++ public_only,
++ TRUE,
++ certificate->user_data,
++ certificate->mask_prompt
++ )) == CKR_OK
++ ) {
++ rv = _pkcs11h_certificate_updateCertificateIdDescription (certificate->id);
++ }
++
++ if (
++ !is_key_valid &&
++ rv == CKR_OK &&
++ !public_only &&
++ (rv = _pkcs11h_session_getObjectById (
++ certificate->session,
++ CKO_PRIVATE_KEY,
++ certificate->id->attrCKA_ID,
++ certificate->id->attrCKA_ID_size,
++ &certificate->key_handle
++ )) == CKR_OK
++ ) {
++ is_key_valid = TRUE;
++ }
++
++ if (
++ rv == CKR_OK &&
++ !public_only &&
++ !is_key_valid
++ ) {
++ rv = CKR_FUNCTION_REJECTED;
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&certificate->session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_resetSession return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_certificate_doPrivateOperation (
++ IN const pkcs11h_certificate_t certificate,
++ IN const enum _pkcs11h_private_op_e op,
++ 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 p_target_size
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ CK_MECHANISM mech = {
++ mech_type, NULL, 0
++ };
++
++ CK_RV rv = CKR_OK;
++ PKCS11H_BOOL login_retry = FALSE;
++ PKCS11H_BOOL op_succeed = FALSE;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++ PKCS11H_ASSERT (source!=NULL);
++ /*PKCS11H_ASSERT (target); NOT NEEDED*/
++ PKCS11H_ASSERT (p_target_size!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_doPrivateOperation entry certificate=%p, op=%d, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
++ (void *)certificate,
++ op,
++ mech_type,
++ source,
++ source_size,
++ target,
++ target != NULL ? *p_target_size : 0
++ );
++
++ if (target == NULL) {
++ *p_target_size = 0;
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&certificate->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ while (rv == CKR_OK && !op_succeed) {
++ if (rv == CKR_OK && !certificate->operation_active) {
++ rv = _pkcs11h_certificate_validateSession (certificate);
++ }
++
++ if (rv == CKR_OK && !certificate->operation_active) {
++ switch (op) {
++ case _pkcs11h_private_op_sign:
++ rv = certificate->session->provider->f->C_SignInit (
++ certificate->session->session_handle,
++ &mech,
++ certificate->key_handle
++ );
++ break;
++ case _pkcs11h_private_op_sign_recover:
++ rv = certificate->session->provider->f->C_SignRecoverInit (
++ certificate->session->session_handle,
++ &mech,
++ certificate->key_handle
++ );
++ break;
++ case _pkcs11h_private_op_decrypt:
++ rv = certificate->session->provider->f->C_DecryptInit (
++ certificate->session->session_handle,
++ &mech,
++ certificate->key_handle
++ );
++ break;
++ default:
++ rv = CKR_ARGUMENTS_BAD;
++ break;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_doPrivateOperation init rv=%ld",
++ rv
++ );
++ }
++
++ if (rv == CKR_OK) {
++ CK_ULONG size = *p_target_size;
++
++ switch (op) {
++ case _pkcs11h_private_op_sign:
++ rv = certificate->session->provider->f->C_Sign (
++ certificate->session->session_handle,
++ (CK_BYTE_PTR)source,
++ source_size,
++ (CK_BYTE_PTR)target,
++ &size
++ );
++ break;
++ case _pkcs11h_private_op_sign_recover:
++ rv = certificate->session->provider->f->C_SignRecover (
++ certificate->session->session_handle,
++ (CK_BYTE_PTR)source,
++ source_size,
++ (CK_BYTE_PTR)target,
++ &size
++ );
++ break;
++ case _pkcs11h_private_op_decrypt:
++ rv = certificate->session->provider->f->C_Decrypt (
++ certificate->session->session_handle,
++ (CK_BYTE_PTR)source,
++ source_size,
++ (CK_BYTE_PTR)target,
++ &size
++ );
++ break;
++ default:
++ rv = CKR_ARGUMENTS_BAD;
++ break;
++ }
++
++ *p_target_size = size;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_doPrivateOperation op rv=%ld",
++ rv
++ );
++ }
++
++ if (
++ target == NULL &&
++ (
++ rv == CKR_BUFFER_TOO_SMALL ||
++ rv == CKR_OK
++ )
++ ) {
++ certificate->operation_active = TRUE;
++ rv = CKR_OK;
++ }
++ else {
++ certificate->operation_active = FALSE;
++ }
++
++ if (rv == CKR_OK) {
++ op_succeed = TRUE;
++ }
++ else {
++ /*
++ * OpenSC workaround
++ * It still allows C_FindObjectsInit when
++ * token is removed/inserted but fails
++ * private key operation.
++ * So we force logout.
++ * bug#108 at OpenSC trac
++ */
++ if (login_retry && rv == CKR_DEVICE_REMOVED) {
++ login_retry = FALSE;
++ _pkcs11h_session_logout (certificate->session);
++ }
++
++ if (!login_retry) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Private key operation failed rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++ login_retry = TRUE;
++ rv = _pkcs11h_certificate_resetSession (
++ certificate,
++ FALSE,
++ TRUE
++ );
++ }
++ }
++
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&certificate->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_doPrivateOperation return rv=%ld-'%s', *p_target_size=%u",
++ rv,
++ pkcs11h_getMessage (rv),
++ *p_target_size
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_freeCertificateId (
++ IN pkcs11h_certificate_id_t certificate_id
++) {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_freeCertificateId entry certificate_id=%p",
++ (void *)certificate_id
++ );
++
++ if (certificate_id->attrCKA_ID != NULL) {
++ _pkcs11h_mem_free ((void *)&certificate_id->attrCKA_ID);
++ }
++ if (certificate_id->certificate_blob != NULL) {
++ _pkcs11h_mem_free ((void *)&certificate_id->certificate_blob);
++ }
++ if (certificate_id->token_id != NULL) {
++ pkcs11h_token_freeTokenId (certificate_id->token_id);
++ certificate_id->token_id = NULL;
++ }
++ _pkcs11h_mem_free ((void *)&certificate_id);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_freeCertificateId return"
++ );
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_certificate_duplicateCertificateId (
++ OUT pkcs11h_certificate_id_t * const to,
++ IN const pkcs11h_certificate_id_t from
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (to!=NULL);
++ PKCS11H_ASSERT (from!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_duplicateCertificateId entry to=%p form=%p",
++ (void *)to,
++ (void *)from
++ );
++
++ *to = NULL;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_duplicate (
++ (void*)to,
++ NULL,
++ from,
++ sizeof (struct pkcs11h_certificate_id_s)
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_duplicate (
++ (void*)&(*to)->token_id,
++ NULL,
++ from->token_id,
++ sizeof (struct pkcs11h_token_id_s)
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_duplicate (
++ (void*)&(*to)->attrCKA_ID,
++ &(*to)->attrCKA_ID_size,
++ from->attrCKA_ID,
++ from->attrCKA_ID_size
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_duplicate (
++ (void*)&(*to)->certificate_blob,
++ &(*to)->certificate_blob_size,
++ from->certificate_blob,
++ from->certificate_blob_size
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_duplicateCertificateId return rv=%ld-'%s', *to=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*to
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_setCertificateIdCertificateBlob (
++ IN const pkcs11h_certificate_id_t certificate_id,
++ IN const unsigned char * const blob,
++ IN const size_t blob_size
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate_id!=NULL);
++ PKCS11H_ASSERT (blob!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_setCertificateIdCertificateBlob entry certificate_id=%p",
++ (void *)certificate_id
++ );
++
++ if (rv == CKR_OK && certificate_id->certificate_blob != NULL) {
++ rv = _pkcs11h_mem_free ((void *)&certificate_id->certificate_blob);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_duplicate (
++ (void *)&certificate_id->certificate_blob,
++ &certificate_id->certificate_blob_size,
++ blob,
++ blob_size
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_setCertificateIdCertificateBlob return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_freeCertificate (
++ IN pkcs11h_certificate_t certificate
++) {
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_freeCertificate entry certificate=%p",
++ (void *)certificate
++ );
++
++ if (certificate != NULL) {
++ if (certificate->session != NULL) {
++ _pkcs11h_session_release (certificate->session);
++ }
++ pkcs11h_certificate_freeCertificateId (certificate->id);
++ certificate->id = NULL;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ _pkcs11h_threading_mutexFree (&certificate->mutex);
++#endif
++
++ _pkcs11h_mem_free ((void *)&certificate);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_freeCertificate return"
++ );
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_certificate_lockSession (
++ IN const pkcs11h_certificate_t certificate
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ if (rv == CKR_OK && certificate->session == NULL) {
++ rv = _pkcs11h_session_getSessionByTokenId (certificate->id->token_id, &certificate->session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_threading_mutexLock (&certificate->session->mutex);
++ }
++
++ return rv;
++#else
++ return CKR_OK;
++#endif
++}
++
++CK_RV
++pkcs11h_certificate_releaseSession (
++ IN const pkcs11h_certificate_t certificate
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ if (certificate->session != NULL) {
++ rv = _pkcs11h_threading_mutexRelease (&certificate->session->mutex);
++ }
++
++ return rv;
++#else
++ return CKR_OK;
++#endif
++}
++
++CK_RV
++pkcs11h_certificate_sign (
++ IN const pkcs11h_certificate_t certificate,
++ 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 p_target_size
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++ PKCS11H_ASSERT (source!=NULL);
++ /*PKCS11H_ASSERT (target); NOT NEEDED*/
++ PKCS11H_ASSERT (p_target_size!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_sign entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
++ (void *)certificate,
++ mech_type,
++ source,
++ source_size,
++ target,
++ target != NULL ? *p_target_size : 0
++ );
++
++ if (target == NULL) {
++ *p_target_size = 0;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_certificate_doPrivateOperation (
++ certificate,
++ _pkcs11h_private_op_sign,
++ mech_type,
++ source,
++ source_size,
++ target,
++ p_target_size
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_sign return rv=%ld-'%s', *p_target_size=%u",
++ rv,
++ pkcs11h_getMessage (rv),
++ *p_target_size
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_signRecover (
++ IN const pkcs11h_certificate_t certificate,
++ 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 p_target_size
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++ PKCS11H_ASSERT (source!=NULL);
++ /*PKCS11H_ASSERT (target); NOT NEEDED*/
++ PKCS11H_ASSERT (p_target_size!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_signRecover entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
++ (void *)certificate,
++ mech_type,
++ source,
++ source_size,
++ target,
++ target != NULL ? *p_target_size : 0
++ );
++
++ if (target == NULL) {
++ *p_target_size = 0;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_certificate_doPrivateOperation (
++ certificate,
++ _pkcs11h_private_op_sign_recover,
++ mech_type,
++ source,
++ source_size,
++ target,
++ p_target_size
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_signRecover return rv=%ld-'%s', *p_target_size=%u",
++ rv,
++ pkcs11h_getMessage (rv),
++ *p_target_size
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_signAny (
++ IN const pkcs11h_certificate_t certificate,
++ 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 p_target_size
++) {
++ CK_RV rv = CKR_OK;
++ PKCS11H_BOOL fSigned = FALSE;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++ PKCS11H_ASSERT (source!=NULL);
++ /*PKCS11H_ASSERT (target); NOT NEEDED*/
++ PKCS11H_ASSERT (p_target_size!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_signAny entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
++ (void *)certificate,
++ mech_type,
++ source,
++ source_size,
++ target,
++ target != NULL ? *p_target_size : 0
++ );
++
++ if (
++ rv == CKR_OK &&
++ certificate->mask_sign_mode == 0
++ ) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Getting key attributes"
++ );
++ rv = _pkcs11h_certificate_getKeyAttributes (certificate);
++ }
++
++ if (
++ rv == CKR_OK &&
++ !fSigned &&
++ (certificate->mask_sign_mode & PKCS11H_SIGNMODE_MASK_SIGN) != 0
++ ) {
++ rv = pkcs11h_certificate_sign (
++ certificate,
++ mech_type,
++ source,
++ source_size,
++ target,
++ p_target_size
++ );
++
++ if (rv == CKR_OK) {
++ fSigned = TRUE;
++ }
++ else if (
++ rv == CKR_FUNCTION_NOT_SUPPORTED ||
++ rv == CKR_KEY_FUNCTION_NOT_PERMITTED
++ ) {
++ certificate->mask_sign_mode &= ~PKCS11H_SIGNMODE_MASK_SIGN;
++ rv = CKR_OK;
++ }
++ }
++
++ if (
++ rv == CKR_OK &&
++ !fSigned &&
++ (certificate->mask_sign_mode & PKCS11H_SIGNMODE_MASK_RECOVER) != 0
++ ) {
++ rv = pkcs11h_certificate_signRecover (
++ certificate,
++ mech_type,
++ source,
++ source_size,
++ target,
++ p_target_size
++ );
++
++ if (rv == CKR_OK) {
++ fSigned = TRUE;
++ }
++ else if (
++ rv == CKR_FUNCTION_NOT_SUPPORTED ||
++ rv == CKR_KEY_FUNCTION_NOT_PERMITTED
++ ) {
++ certificate->mask_sign_mode &= ~PKCS11H_SIGNMODE_MASK_RECOVER;
++ rv = CKR_OK;
++ }
++ }
++
++ if (rv == CKR_OK && !fSigned) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_signAny return rv=%ld-'%s', *p_target_size=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_target_size
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_decrypt (
++ IN const pkcs11h_certificate_t certificate,
++ 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 p_target_size
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++ PKCS11H_ASSERT (source!=NULL);
++ /*PKCS11H_ASSERT (target); NOT NEEDED*/
++ PKCS11H_ASSERT (p_target_size!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_decrypt entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
++ (void *)certificate,
++ mech_type,
++ source,
++ source_size,
++ target,
++ target != NULL ? *p_target_size : 0
++ );
++
++ if (target == NULL) {
++ *p_target_size = 0;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_certificate_doPrivateOperation (
++ certificate,
++ _pkcs11h_private_op_decrypt,
++ mech_type,
++ source,
++ source_size,
++ target,
++ p_target_size
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_decrypt return rv=%ld-'%s', *p_target_size=%u",
++ rv,
++ pkcs11h_getMessage (rv),
++ *p_target_size
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_create (
++ IN const pkcs11h_certificate_id_t certificate_id,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ IN const int pin_cache_period,
++ OUT pkcs11h_certificate_t * const p_certificate
++) {
++ pkcs11h_certificate_t certificate = NULL;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ /*PKCS11H_ASSERT (user_data!=NULL); NOT NEEDED */
++ PKCS11H_ASSERT (p_certificate!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_create entry certificate_id=%p, user_data=%p, mask_prompt=%08x, pin_cache_period=%d, p_certificate=%p",
++ (void *)certificate_id,
++ user_data,
++ mask_prompt,
++ pin_cache_period,
++ (void *)p_certificate
++ );
++
++ *p_certificate = NULL;
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc ((void*)&certificate, sizeof (struct pkcs11h_certificate_s))) == CKR_OK
++ ) {
++ certificate->user_data = user_data;
++ certificate->mask_prompt = mask_prompt;
++ certificate->key_handle = PKCS11H_INVALID_OBJECT_HANDLE;
++ certificate->pin_cache_period = pin_cache_period;
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_threading_mutexInit (&certificate->mutex);
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_certificate_duplicateCertificateId (&certificate->id, certificate_id);
++ }
++
++ if (rv == CKR_OK) {
++ *p_certificate = certificate;
++ certificate = NULL;
++ }
++
++ if (certificate != NULL) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ _pkcs11h_threading_mutexFree (&certificate->mutex);
++#endif
++ _pkcs11h_mem_free ((void *)&certificate);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_create return rv=%ld-'%s' *p_certificate=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_certificate
++ );
++
++ return rv;
++}
++
++unsigned
++pkcs11h_certificate_getPromptMask (
++ IN const pkcs11h_certificate_t certificate
++) {
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ return certificate->mask_prompt;
++}
++
++void
++pkcs11h_certificate_setPromptMask (
++ IN const pkcs11h_certificate_t certificate,
++ IN const unsigned mask_prompt
++) {
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ certificate->mask_prompt = mask_prompt;
++}
++
++void *
++pkcs11h_certificate_getUserData (
++ IN const pkcs11h_certificate_t certificate
++) {
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ return certificate->user_data;
++}
++
++void
++pkcs11h_certificate_setUserData (
++ IN const pkcs11h_certificate_t certificate,
++ IN void * const user_data
++) {
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ certificate->user_data = user_data;
++}
++
++CK_RV
++pkcs11h_certificate_getCertificateId (
++ IN const pkcs11h_certificate_t certificate,
++ OUT pkcs11h_certificate_id_t * const p_certificate_id
++) {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++ PKCS11H_ASSERT (p_certificate_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_getCertificateId entry certificate=%p, certificate_id=%p",
++ (void *)certificate,
++ (void *)p_certificate_id
++ );
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_certificate_duplicateCertificateId (
++ p_certificate_id,
++ certificate->id
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_getCertificateId return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_getCertificateBlob (
++ IN const pkcs11h_certificate_t certificate,
++ OUT unsigned char * const certificate_blob,
++ IN OUT size_t * const p_certificate_blob_size
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ CK_RV rv = CKR_OK;
++ size_t certifiate_blob_size_max = 0;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++ /*PKCS11H_ASSERT (certificate_blob!=NULL); NOT NEEDED */
++ PKCS11H_ASSERT (p_certificate_blob_size!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_getCertificateBlob entry certificate=%p, certificate_blob=%p, *p_certificate_blob_size=%u",
++ (void *)certificate,
++ certificate_blob,
++ certificate_blob != NULL ? *p_certificate_blob_size : 0
++ );
++
++ if (certificate_blob != NULL) {
++ certifiate_blob_size_max = *p_certificate_blob_size;
++ }
++ *p_certificate_blob_size = 0;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&certificate->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (rv == CKR_OK && certificate->id->certificate_blob == NULL) {
++ PKCS11H_BOOL op_succeed = FALSE;
++ PKCS11H_BOOL login_retry = FALSE;
++ while (rv == CKR_OK && !op_succeed) {
++ if (certificate->session == NULL) {
++ rv = CKR_SESSION_HANDLE_INVALID;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_certificate_loadCertificate (certificate);
++ }
++
++ if (rv == CKR_OK) {
++ op_succeed = TRUE;
++ }
++ else {
++ if (!login_retry) {
++ login_retry = TRUE;
++ rv = _pkcs11h_certificate_resetSession (
++ certificate,
++ TRUE,
++ FALSE
++ );
++ }
++ }
++ }
++ }
++
++ if (
++ rv == CKR_OK &&
++ certificate->id->certificate_blob == NULL
++ ) {
++ rv = CKR_FUNCTION_REJECTED;
++ }
++
++ if (rv == CKR_OK) {
++ _pkcs11h_certificate_updateCertificateIdDescription (certificate->id);
++ }
++
++ if (rv == CKR_OK) {
++ *p_certificate_blob_size = certificate->id->certificate_blob_size;
++ }
++
++ if (certificate_blob != NULL) {
++ if (
++ rv == CKR_OK &&
++ certificate->id->certificate_blob_size > certifiate_blob_size_max
++ ) {
++ rv = CKR_BUFFER_TOO_SMALL;
++ }
++
++ if (rv == CKR_OK) {
++ memmove (
++ certificate_blob,
++ certificate->id->certificate_blob,
++ *p_certificate_blob_size
++ );
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&certificate->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_getCertificateBlob return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++#if defined(ENABLE_PKCS11H_SERIALIZATION)
++
++CK_RV
++pkcs11h_certificate_serializeCertificateId (
++ OUT char * const sz,
++ IN OUT size_t *max,
++ IN const pkcs11h_certificate_id_t certificate_id
++) {
++ CK_RV rv = CKR_OK;
++ size_t saved_max = 0;
++ size_t n = 0;
++ size_t _max = 0;
++
++ /*PKCS11H_ASSERT (sz!=NULL); Not required */
++ PKCS11H_ASSERT (max!=NULL);
++ PKCS11H_ASSERT (certificate_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_serializeCertificateId entry sz=%p, *max=%u, certificate_id=%p",
++ sz,
++ sz != NULL ? *max : 0,
++ (void *)certificate_id
++ );
++
++ if (sz != NULL) {
++ saved_max = n = *max;
++ }
++ *max = 0;
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_token_serializeTokenId (
++ sz,
++ &n,
++ certificate_id->token_id
++ );
++ }
++
++ if (rv == CKR_OK) {
++ _max = n + certificate_id->attrCKA_ID_size*2 + 1;
++ }
++
++ if (sz != NULL) {
++ if (saved_max < _max) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++
++ if (rv == CKR_OK) {
++ sz[n-1] = '/';
++ rv = _pkcs11h_util_binaryToHex (
++ sz+n,
++ saved_max-n,
++ certificate_id->attrCKA_ID,
++ certificate_id->attrCKA_ID_size
++ );
++
++ }
++ }
++
++ *max = _max;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_serializeCertificateId return rv=%ld-'%s', *max=%u, sz='%s'",
++ rv,
++ pkcs11h_getMessage (rv),
++ *max,
++ sz
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_deserializeCertificateId (
++ OUT pkcs11h_certificate_id_t * const p_certificate_id,
++ IN const char * const sz
++) {
++ pkcs11h_certificate_id_t certificate_id = NULL;
++ CK_RV rv = CKR_OK;
++ char *p = NULL;
++ char *_sz = NULL;
++
++ PKCS11H_ASSERT (p_certificate_id!=NULL);
++ PKCS11H_ASSERT (sz!=NULL);
++
++ *p_certificate_id = NULL;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_deserializeCertificateId entry p_certificate_id=%p, sz='%s'",
++ (void *)p_certificate_id,
++ sz
++ );
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_strdup (
++ (void *)&_sz,
++ sz
++ );
++ }
++
++ if (rv == CKR_OK) {
++ p = _sz;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_certificate_newCertificateId (&certificate_id);
++ }
++
++ if (
++ rv == CKR_OK &&
++ (p = strrchr (_sz, '/')) == NULL
++ ) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++
++ if (rv == CKR_OK) {
++ *p = '\x0';
++ p++;
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_token_deserializeTokenId (
++ &certificate_id->token_id,
++ _sz
++ );
++ }
++
++ if (rv == CKR_OK) {
++ certificate_id->attrCKA_ID_size = strlen (p)/2;
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc (
++ (void *)&certificate_id->attrCKA_ID,
++ certificate_id->attrCKA_ID_size)
++ ) == CKR_OK
++ ) {
++ rv = _pkcs11h_util_hexToBinary (
++ certificate_id->attrCKA_ID,
++ p,
++ &certificate_id->attrCKA_ID_size
++ );
++ }
++
++ if (rv == CKR_OK) {
++ *p_certificate_id = certificate_id;
++ certificate_id = NULL;
++ }
++
++ if (certificate_id != NULL) {
++ pkcs11h_certificate_freeCertificateId (certificate_id);
++ certificate_id = NULL;
++ }
++
++ if (_sz != NULL) {
++ _pkcs11h_mem_free ((void *)&_sz);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_deserializeCertificateId return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++
++}
++
++#endif /* ENABLE_PKCS11H_SERIALIZATION */
++
++CK_RV
++pkcs11h_certificate_ensureCertificateAccess (
++ IN const pkcs11h_certificate_t certificate
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked_cert = FALSE;
++ PKCS11H_BOOL mutex_locked_sess = FALSE;
++#endif
++ PKCS11H_BOOL validCert = FALSE;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_ensureCertificateAccess entry certificate=%p",
++ (void *)certificate
++ );
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&certificate->mutex)) == CKR_OK
++ ) {
++ mutex_locked_cert = TRUE;
++ }
++#endif
++
++ if (!validCert && rv == CKR_OK) {
++ CK_OBJECT_HANDLE h = PKCS11H_INVALID_OBJECT_HANDLE;
++
++ if (certificate->session == NULL) {
++ rv = CKR_SESSION_HANDLE_INVALID;
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&certificate->session->mutex)) == CKR_OK
++ ) {
++ mutex_locked_sess = TRUE;
++ }
++#endif
++
++ if (
++ (rv = _pkcs11h_session_getObjectById (
++ certificate->session,
++ CKO_CERTIFICATE,
++ certificate->id->attrCKA_ID,
++ certificate->id->attrCKA_ID_size,
++ &h
++ )) == CKR_OK
++ ) {
++ validCert = TRUE;
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked_sess) {
++ _pkcs11h_threading_mutexRelease (&certificate->session->mutex);
++ mutex_locked_sess = FALSE;
++ }
++#endif
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot access existing object rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++ }
++
++ if (!validCert && rv == CKR_OK) {
++ if (
++ (rv = _pkcs11h_certificate_resetSession (
++ certificate,
++ TRUE,
++ FALSE
++ )) == CKR_OK
++ ) {
++ validCert = TRUE;
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked_cert) {
++ _pkcs11h_threading_mutexRelease (&certificate->mutex);
++ mutex_locked_cert = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_ensureCertificateAccess return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_ensureKeyAccess (
++ IN const pkcs11h_certificate_t certificate
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked_cert = FALSE;
++ PKCS11H_BOOL mutex_locked_sess = FALSE;
++#endif
++ CK_RV rv = CKR_OK;
++ PKCS11H_BOOL valid_key = FALSE;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_ensureKeyAccess entry certificate=%p",
++ (void *)certificate
++ );
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&certificate->mutex)) == CKR_OK
++ ) {
++ mutex_locked_cert = TRUE;
++ }
++#endif
++
++ if (!valid_key && rv == CKR_OK) {
++
++ if (certificate->session == NULL) {
++ rv = CKR_SESSION_HANDLE_INVALID;
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&certificate->session->mutex)) == CKR_OK
++ ) {
++ mutex_locked_sess = TRUE;
++ }
++#endif
++
++ if (
++ (rv = _pkcs11h_session_getObjectById (
++ certificate->session,
++ CKO_PRIVATE_KEY,
++ certificate->id->attrCKA_ID,
++ certificate->id->attrCKA_ID_size,
++ &certificate->key_handle
++ )) == CKR_OK
++ ) {
++ valid_key = TRUE;
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked_sess) {
++ _pkcs11h_threading_mutexRelease (&certificate->session->mutex);
++ mutex_locked_sess = FALSE;
++ }
++#endif
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot access existing object rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ certificate->key_handle = PKCS11H_INVALID_OBJECT_HANDLE;
++ }
++ }
++
++ if (!valid_key && rv == CKR_OK) {
++ if (
++ (rv = _pkcs11h_certificate_resetSession (
++ certificate,
++ FALSE,
++ FALSE
++ )) == CKR_OK
++ ) {
++ valid_key = TRUE;
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked_sess) {
++ _pkcs11h_threading_mutexRelease (&certificate->session->mutex);
++ mutex_locked_sess = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_ensureKeyAccess return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#if defined(ENABLE_PKCS11H_LOCATE)
++/*======================================================================*
++ * LOCATE INTERFACE
++ *======================================================================*/
++
++#if defined(ENABLE_PKCS11H_TOKEN) || defined(ENABLE_PKCS11H_CERTIFICATE)
++
++static
++CK_RV
++_pkcs11h_locate_getTokenIdBySlotId (
++ IN const char * const slot,
++ OUT pkcs11h_token_id_t * const p_token_id
++) {
++ pkcs11h_provider_t current_provider = NULL;
++ char reference[sizeof (((pkcs11h_provider_t)NULL)->reference)];
++
++ CK_SLOT_ID selected_slot = PKCS11H_INVALID_SLOT_ID;
++ CK_TOKEN_INFO info;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (slot!=NULL);
++ PKCS11H_ASSERT (p_token_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_locate_getTokenIdBySlotId entry slot='%s', p_token_id=%p",
++ slot,
++ (void *)p_token_id
++ );
++
++ *p_token_id = NULL;
++
++ if (rv == CKR_OK) {
++ if (strchr (slot, ':') == NULL) {
++ reference[0] = '\0';
++ selected_slot = atol (slot);
++ }
++ else {
++ char *p;
++
++ strncpy (reference, slot, sizeof (reference));
++ reference[sizeof (reference)-1] = '\0';
++
++ p = strchr (reference, ':');
++
++ *p = '\0';
++ p++;
++ selected_slot = atol (p);
++ }
++ }
++
++ if (rv == CKR_OK) {
++ current_provider=s_pkcs11h_data->providers;
++ while (
++ current_provider != NULL &&
++ reference[0] != '\0' && /* So first provider will be selected */
++ strcmp (current_provider->reference, reference)
++ ) {
++ current_provider = current_provider->next;
++ }
++
++ if (
++ current_provider == NULL ||
++ (
++ current_provider != NULL &&
++ !current_provider->enabled
++ )
++ ) {
++ rv = CKR_SLOT_ID_INVALID;
++ }
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = current_provider->f->C_GetTokenInfo (selected_slot, &info)) == CKR_OK
++ ) {
++ rv = _pkcs11h_token_getTokenId (
++ &info,
++ p_token_id
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_locate_getTokenIdBySlotId return rv=%ld-'%s', *p_token_id=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_token_id
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_locate_getTokenIdBySlotName (
++ IN const char * const name,
++ OUT pkcs11h_token_id_t * const p_token_id
++) {
++ pkcs11h_provider_t current_provider = NULL;
++
++ CK_SLOT_ID selected_slot = PKCS11H_INVALID_SLOT_ID;
++ CK_TOKEN_INFO info;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_BOOL found = FALSE;
++
++ PKCS11H_ASSERT (name!=NULL);
++ PKCS11H_ASSERT (p_token_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_locate_getTokenIdBySlotName entry name='%s', p_token_id=%p",
++ name,
++ (void *)p_token_id
++ );
++
++ *p_token_id = NULL;
++
++ current_provider = s_pkcs11h_data->providers;
++ while (
++ current_provider != NULL &&
++ rv == CKR_OK &&
++ !found
++ ) {
++ CK_SLOT_ID_PTR slots = NULL;
++ CK_ULONG slotnum;
++ CK_SLOT_ID slot_index;
++
++ if (!current_provider->enabled) {
++ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSlotList (
++ current_provider,
++ CK_TRUE,
++ &slots,
++ &slotnum
++ );
++ }
++
++ for (
++ slot_index=0;
++ (
++ slot_index < slotnum &&
++ rv == CKR_OK &&
++ !found
++ );
++ slot_index++
++ ) {
++ CK_SLOT_INFO info;
++
++ if (
++ (rv = current_provider->f->C_GetSlotInfo (
++ slots[slot_index],
++ &info
++ )) == CKR_OK
++ ) {
++ char current_name[sizeof (info.slotDescription)+1];
++
++ _pkcs11h_util_fixupFixedString (
++ current_name,
++ (char *)info.slotDescription,
++ sizeof (info.slotDescription)
++ );
++
++ if (!strcmp (current_name, name)) {
++ found = TRUE;
++ selected_slot = slots[slot_index];
++ }
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get slot information for provider '%s' slot %ld rv=%ld-'%s'",
++ current_provider->manufacturerID,
++ slots[slot_index],
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
++ current_provider->manufacturerID,
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++
++ if (slots != NULL) {
++ _pkcs11h_mem_free ((void *)&slots);
++ slots = NULL;
++ }
++
++ if (!found) {
++ current_provider = current_provider->next;
++ }
++ }
++
++ if (rv == CKR_OK && !found) {
++ rv = CKR_SLOT_ID_INVALID;
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = current_provider->f->C_GetTokenInfo (selected_slot, &info)) == CKR_OK
++ ) {
++ rv = _pkcs11h_token_getTokenId (
++ &info,
++ p_token_id
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_locate_getTokenIdBySlotName return rv=%ld-'%s' *p_token_id=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_token_id
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_locate_getTokenIdByLabel (
++ IN const char * const label,
++ OUT pkcs11h_token_id_t * const p_token_id
++) {
++ pkcs11h_provider_t current_provider = NULL;
++
++ CK_SLOT_ID selected_slot = PKCS11H_INVALID_SLOT_ID;
++ CK_TOKEN_INFO info;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_BOOL found = FALSE;
++
++ PKCS11H_ASSERT (label!=NULL);
++ PKCS11H_ASSERT (p_token_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_locate_getTokenIdByLabel entry label='%s', p_token_id=%p",
++ label,
++ (void *)p_token_id
++ );
++
++ *p_token_id = NULL;
++
++ current_provider = s_pkcs11h_data->providers;
++ while (
++ current_provider != NULL &&
++ rv == CKR_OK &&
++ !found
++ ) {
++ CK_SLOT_ID_PTR slots = NULL;
++ CK_ULONG slotnum;
++ CK_SLOT_ID slot_index;
++
++ if (!current_provider->enabled) {
++ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSlotList (
++ current_provider,
++ CK_TRUE,
++ &slots,
++ &slotnum
++ );
++ }
++
++ for (
++ slot_index=0;
++ (
++ slot_index < slotnum &&
++ rv == CKR_OK &&
++ !found
++ );
++ slot_index++
++ ) {
++ CK_TOKEN_INFO info;
++
++ if (rv == CKR_OK) {
++ rv = current_provider->f->C_GetTokenInfo (
++ slots[slot_index],
++ &info
++ );
++ }
++
++ if (rv == CKR_OK) {
++ char current_label[sizeof (info.label)+1];
++
++ _pkcs11h_util_fixupFixedString (
++ current_label,
++ (char *)info.label,
++ sizeof (info.label)
++ );
++
++ if (!strcmp (current_label, label)) {
++ found = TRUE;
++ selected_slot = slots[slot_index];
++ }
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get token information for provider '%s' slot %ld rv=%ld-'%s'",
++ current_provider->manufacturerID,
++ slots[slot_index],
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
++ current_provider->manufacturerID,
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++
++ if (slots != NULL) {
++ _pkcs11h_mem_free ((void *)&slots);
++ slots = NULL;
++ }
++
++ if (!found) {
++ current_provider = current_provider->next;
++ }
++ }
++
++ if (rv == CKR_OK && !found) {
++ rv = CKR_SLOT_ID_INVALID;
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = current_provider->f->C_GetTokenInfo (selected_slot, &info)) == CKR_OK
++ ) {
++ rv = _pkcs11h_token_getTokenId (
++ &info,
++ p_token_id
++ );
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_locate_getTokenIdByLabel return rv=%ld-'%s', *p_token_id=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_token_id
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_locate_token (
++ IN const char * const slot_type,
++ IN const char * const slot,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT pkcs11h_token_id_t * const p_token_id
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++
++ pkcs11h_token_id_t dummy_token_id = NULL;
++ pkcs11h_token_id_t token_id = NULL;
++ PKCS11H_BOOL found = FALSE;
++
++ CK_RV rv = CKR_OK;
++
++ unsigned nRetry = 0;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (slot_type!=NULL);
++ PKCS11H_ASSERT (slot!=NULL);
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++ PKCS11H_ASSERT (p_token_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_locate_token entry slot_type='%s', slot='%s', user_data=%p, p_token_id=%p",
++ slot_type,
++ slot,
++ user_data,
++ (void *)p_token_id
++ );
++
++ *p_token_id = NULL;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.global)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_token_newTokenId (&dummy_token_id)) == CKR_OK
++ ) {
++ /*
++ * Temperary slot id
++ */
++ strcpy (dummy_token_id->display, "SLOT(");
++ strncat (dummy_token_id->display, slot_type, sizeof (dummy_token_id->display)-1-strlen (dummy_token_id->display));
++ strncat (dummy_token_id->display, "=", sizeof (dummy_token_id->display)-1-strlen (dummy_token_id->display));
++ strncat (dummy_token_id->display, slot, sizeof (dummy_token_id->display)-1-strlen (dummy_token_id->display));
++ strncat (dummy_token_id->display, ")", sizeof (dummy_token_id->display)-1-strlen (dummy_token_id->display));
++ dummy_token_id->display[sizeof (dummy_token_id->display)-1] = 0;
++ }
++
++ while (rv == CKR_OK && !found) {
++ if (!strcmp (slot_type, "id")) {
++ rv = _pkcs11h_locate_getTokenIdBySlotId (
++ slot,
++ &token_id
++ );
++ }
++ else if (!strcmp (slot_type, "name")) {
++ rv = _pkcs11h_locate_getTokenIdBySlotName (
++ slot,
++ &token_id
++ );
++ }
++ else if (!strcmp (slot_type, "label")) {
++ rv = _pkcs11h_locate_getTokenIdByLabel (
++ slot,
++ &token_id
++ );
++ }
++ else {
++ rv = CKR_ARGUMENTS_BAD;
++ }
++
++ if (rv == CKR_OK) {
++ found = TRUE;
++ }
++
++ /*
++ * Ignore error, since we have what we
++ * want in found.
++ */
++ if (rv != CKR_OK && rv != CKR_ARGUMENTS_BAD) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: pkcs11h_locate_token failed rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ rv = CKR_OK;
++ }
++
++ if (rv == CKR_OK && !found && (mask_prompt & PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT) == 0) {
++ rv = CKR_TOKEN_NOT_PRESENT;
++ }
++
++ if (rv == CKR_OK && !found) {
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Calling token_prompt hook for '%s'",
++ dummy_token_id->display
++ );
++
++ if (
++ !s_pkcs11h_data->hooks.token_prompt (
++ s_pkcs11h_data->hooks.token_prompt_data,
++ user_data,
++ dummy_token_id,
++ nRetry++
++ )
++ ) {
++ rv = CKR_CANCEL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: token_prompt returned %ld",
++ rv
++ );
++ }
++ }
++
++ if (rv == CKR_OK && !found) {
++ rv = CKR_SLOT_ID_INVALID;
++ }
++
++ if (rv == CKR_OK) {
++ *p_token_id = token_id;
++ token_id = NULL;
++ }
++
++ if (dummy_token_id != NULL) {
++ pkcs11h_token_freeTokenId (dummy_token_id);
++ dummy_token_id = NULL;
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.global);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_locate_token return rv=%ld-'%s', *p_token_id=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_token_id
++ );
++
++ return rv;
++}
++
++#endif /* ENABLE_PKCS11H_TOKEN || ENABLE_PKCS11H_CERTIFICATE */
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++
++static
++CK_RV
++_pkcs11h_locate_getCertificateIdByLabel (
++ IN const pkcs11h_session_t session,
++ IN OUT const pkcs11h_certificate_id_t certificate_id,
++ IN const char * const label
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
++ CK_ATTRIBUTE cert_filter[] = {
++ {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)},
++ {CKA_LABEL, (CK_BYTE_PTR)label, strlen (label)}
++ };
++
++ CK_OBJECT_HANDLE *objects = NULL;
++ CK_ULONG objects_found = 0;
++ CK_RV rv = CKR_OK;
++
++ CK_ULONG i;
++
++ PKCS11H_ASSERT (session!=NULL);
++ PKCS11H_ASSERT (certificate_id!=NULL);
++ PKCS11H_ASSERT (label!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_locate_getCertificateIdByLabel entry session=%p, certificate_id=%p, label='%s'",
++ (void *)session,
++ (void *)certificate_id,
++ label
++ );
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_findObjects (
++ session,
++ cert_filter,
++ sizeof (cert_filter) / sizeof (CK_ATTRIBUTE),
++ &objects,
++ &objects_found
++ );
++ }
++
++ for (i=0;rv == CKR_OK && i < objects_found;i++) {
++ CK_ATTRIBUTE attrs[] = {
++ {CKA_ID, NULL, 0},
++ {CKA_VALUE, NULL, 0}
++ };
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getObjectAttributes (
++ session,
++ objects[i],
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ _pkcs11h_certificate_isBetterCertificate (
++ certificate_id->certificate_blob,
++ certificate_id->certificate_blob_size,
++ attrs[1].pValue,
++ attrs[1].ulValueLen
++ )
++ ) {
++ if (certificate_id->attrCKA_ID != NULL) {
++ _pkcs11h_mem_free ((void *)&certificate_id->attrCKA_ID);
++ }
++ if (certificate_id->certificate_blob != NULL) {
++ _pkcs11h_mem_free ((void *)&certificate_id->certificate_blob);
++ }
++ rv = _pkcs11h_mem_duplicate (
++ (void *)&certificate_id->attrCKA_ID,
++ &certificate_id->attrCKA_ID_size,
++ attrs[0].pValue,
++ attrs[0].ulValueLen
++ );
++ rv = _pkcs11h_mem_duplicate (
++ (void *)&certificate_id->certificate_blob,
++ &certificate_id->certificate_blob_size,
++ attrs[1].pValue,
++ attrs[1].ulValueLen
++ );
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'",
++ session->provider->manufacturerID,
++ objects[i],
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ certificate_id->certificate_blob == NULL
++ ) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++
++ if (objects != NULL) {
++ _pkcs11h_mem_free ((void *)&objects);
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ /*
++ * No need to free allocated objects
++ * on error, since the certificate_id
++ * should be free by caller.
++ */
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_locate_getCertificateIdByLabel return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_locate_getCertificateIdBySubject (
++ IN const pkcs11h_session_t session,
++ IN OUT const pkcs11h_certificate_id_t certificate_id,
++ IN const char * const subject
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
++ CK_ATTRIBUTE cert_filter[] = {
++ {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)}
++ };
++
++ CK_OBJECT_HANDLE *objects = NULL;
++ CK_ULONG objects_found = 0;
++ CK_RV rv = CKR_OK;
++
++ CK_ULONG i;
++
++ PKCS11H_ASSERT (session!=NULL);
++ PKCS11H_ASSERT (certificate_id!=NULL);
++ PKCS11H_ASSERT (subject!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_locate_getCertificateIdBySubject entry session=%p, certificate_id=%p, subject='%s'",
++ (void *)session,
++ (void *)certificate_id,
++ subject
++ );
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_findObjects (
++ session,
++ cert_filter,
++ sizeof (cert_filter) / sizeof (CK_ATTRIBUTE),
++ &objects,
++ &objects_found
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ for (i=0;rv == CKR_OK && i < objects_found;i++) {
++ CK_ATTRIBUTE attrs[] = {
++ {CKA_ID, NULL, 0},
++ {CKA_VALUE, NULL, 0}
++ };
++ char current_subject[1024];
++ current_subject[0] = '\0';
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getObjectAttributes (
++ session,
++ objects[i],
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_certificate_getDN (
++ attrs[1].pValue,
++ attrs[1].ulValueLen,
++ current_subject,
++ sizeof (current_subject)
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ !strcmp (subject, current_subject) &&
++ _pkcs11h_certificate_isBetterCertificate (
++ certificate_id->certificate_blob,
++ certificate_id->certificate_blob_size,
++ attrs[1].pValue,
++ attrs[1].ulValueLen
++ )
++ ) {
++ if (certificate_id->attrCKA_ID != NULL) {
++ _pkcs11h_mem_free ((void *)&certificate_id->attrCKA_ID);
++ }
++ if (certificate_id->certificate_blob != NULL) {
++ _pkcs11h_mem_free ((void *)&certificate_id->certificate_blob);
++ }
++ rv = _pkcs11h_mem_duplicate (
++ (void *)&certificate_id->attrCKA_ID,
++ &certificate_id->attrCKA_ID_size,
++ attrs[0].pValue,
++ attrs[0].ulValueLen
++ );
++ rv = _pkcs11h_mem_duplicate (
++ (void *)&certificate_id->certificate_blob,
++ &certificate_id->certificate_blob_size,
++ attrs[1].pValue,
++ attrs[1].ulValueLen
++ );
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'",
++ session->provider->manufacturerID,
++ objects[i],
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ certificate_id->certificate_blob == NULL
++ ) {
++ rv = CKR_ATTRIBUTE_VALUE_INVALID;
++ }
++
++ if (objects != NULL) {
++ _pkcs11h_mem_free ((void *)&objects);
++ }
++
++ /*
++ * No need to free allocated objects
++ * on error, since the certificate_id
++ * should be free by caller.
++ */
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_locate_getCertificateIdBySubject return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_locate_certificate (
++ IN const char * const slot_type,
++ IN const char * const slot,
++ IN const char * const id_type,
++ IN const char * const id,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT pkcs11h_certificate_id_t * const p_certificate_id
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ pkcs11h_certificate_id_t certificate_id = NULL;
++ pkcs11h_session_t session = NULL;
++ PKCS11H_BOOL op_succeed = FALSE;
++ PKCS11H_BOOL login_retry = FALSE;
++
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (slot_type!=NULL);
++ PKCS11H_ASSERT (slot!=NULL);
++ PKCS11H_ASSERT (id_type!=NULL);
++ PKCS11H_ASSERT (id!=NULL);
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++ PKCS11H_ASSERT (p_certificate_id!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_locateCertificate entry slot_type='%s', slot='%s', id_type='%s', id='%s', user_data=%p, mask_prompt=%08x, p_certificate_id=%p",
++ slot_type,
++ slot,
++ id_type,
++ id,
++ user_data,
++ mask_prompt,
++ (void *)p_certificate_id
++ );
++
++ *p_certificate_id = NULL;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_certificate_newCertificateId (&certificate_id);
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_locate_token (
++ slot_type,
++ slot,
++ user_data,
++ mask_prompt,
++ &certificate_id->token_id
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSessionByTokenId (
++ certificate_id->token_id,
++ &session
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.global)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ while (rv == CKR_OK && !op_succeed) {
++ if (!strcmp (id_type, "id")) {
++ certificate_id->attrCKA_ID_size = strlen (id)/2;
++
++ if (certificate_id->attrCKA_ID_size == 0) {
++ rv = CKR_FUNCTION_FAILED;
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc (
++ (void*)&certificate_id->attrCKA_ID,
++ certificate_id->attrCKA_ID_size
++ )) == CKR_OK
++ ) {
++ _pkcs11h_util_hexToBinary (
++ certificate_id->attrCKA_ID,
++ id,
++ &certificate_id->attrCKA_ID_size
++ );
++ }
++ }
++ else if (!strcmp (id_type, "label")) {
++ rv = _pkcs11h_locate_getCertificateIdByLabel (
++ session,
++ certificate_id,
++ id
++ );
++ }
++ else if (!strcmp (id_type, "subject")) {
++ rv = _pkcs11h_locate_getCertificateIdBySubject (
++ session,
++ certificate_id,
++ id
++ );
++ }
++ else {
++ rv = CKR_ARGUMENTS_BAD;
++ }
++
++ if (rv == CKR_OK) {
++ op_succeed = TRUE;
++ }
++ else {
++ if (!login_retry) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Get certificate failed: %ld:'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ rv = _pkcs11h_session_login (
++ session,
++ TRUE,
++ TRUE,
++ user_data,
++ mask_prompt
++ );
++
++ login_retry = TRUE;
++ }
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.global);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ *p_certificate_id = certificate_id;
++ certificate_id = NULL;
++ }
++
++ if (certificate_id != NULL) {
++ pkcs11h_certificate_freeCertificateId (certificate_id);
++ certificate_id = NULL;
++ }
++
++ if (session != NULL) {
++ _pkcs11h_session_release (session);
++ session = NULL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_locateCertificate return rv=%ld-'%s' *p_certificate_id=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_certificate_id
++ );
++
++ return rv;
++}
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#endif /* ENABLE_PKCS11H_LOCATE */
++
++#if defined(ENABLE_PKCS11H_ENUM)
++/*======================================================================*
++ * ENUM INTERFACE
++ *======================================================================*/
++
++#if defined(ENABLE_PKCS11H_TOKEN)
++
++CK_RV
++pkcs11h_token_freeTokenIdList (
++ IN const pkcs11h_token_id_list_t token_id_list
++) {
++ pkcs11h_token_id_list_t _id = token_id_list;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ /*PKCS11H_ASSERT (token_id_list!=NULL); NOT NEEDED*/
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_freeTokenIdList entry token_id_list=%p",
++ (void *)token_id_list
++ );
++
++ while (_id != NULL) {
++ pkcs11h_token_id_list_t x = _id;
++ _id = _id->next;
++ if (x->token_id != NULL) {
++ pkcs11h_token_freeTokenId (x->token_id);
++ }
++ x->next = NULL;
++ _pkcs11h_mem_free ((void *)&x);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_freeTokenIdList return"
++ );
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_token_enumTokenIds (
++ IN const int method,
++ OUT pkcs11h_token_id_list_t * const p_token_id_list
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++
++ pkcs11h_token_id_list_t token_id_list = NULL;
++ pkcs11h_provider_t current_provider;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (p_token_id_list!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_enumTokenIds entry p_token_id_list=%p",
++ (void *)p_token_id_list
++ );
++
++ *p_token_id_list = NULL;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.global)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ for (
++ current_provider = s_pkcs11h_data->providers;
++ (
++ current_provider != NULL &&
++ rv == CKR_OK
++ );
++ current_provider = current_provider->next
++ ) {
++ CK_SLOT_ID_PTR slots = NULL;
++ CK_ULONG slotnum;
++ CK_SLOT_ID slot_index;
++
++ if (!current_provider->enabled) {
++ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSlotList (
++ current_provider,
++ CK_TRUE,
++ &slots,
++ &slotnum
++ );
++ }
++
++ for (
++ slot_index=0;
++ (
++ slot_index < slotnum &&
++ rv == CKR_OK
++ );
++ slot_index++
++ ) {
++ pkcs11h_token_id_list_t entry = NULL;
++ CK_TOKEN_INFO info;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_malloc ((void *)&entry, sizeof (struct pkcs11h_token_id_list_s));
++ }
++
++ if (rv == CKR_OK) {
++ rv = current_provider->f->C_GetTokenInfo (
++ slots[slot_index],
++ &info
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_token_getTokenId (
++ &info,
++ &entry->token_id
++ );
++ }
++
++ if (rv == CKR_OK) {
++ entry->next = token_id_list;
++ token_id_list = entry;
++ entry = NULL;
++ }
++
++ if (entry != NULL) {
++ pkcs11h_token_freeTokenIdList (entry);
++ entry = NULL;
++ }
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
++ current_provider->manufacturerID,
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++
++ if (slots != NULL) {
++ _pkcs11h_mem_free ((void *)&slots);
++ slots = NULL;
++ }
++ }
++
++ if (rv == CKR_OK && method == PKCS11H_ENUM_METHOD_CACHE) {
++ pkcs11h_session_t session = NULL;
++
++ for (
++ session = s_pkcs11h_data->sessions;
++ session != NULL && rv == CKR_OK;
++ session = session->next
++ ) {
++ pkcs11h_token_id_list_t entry = NULL;
++ PKCS11H_BOOL found = FALSE;
++
++ for (
++ entry = token_id_list;
++ entry != NULL && !found;
++ entry = entry->next
++ ) {
++ if (
++ pkcs11h_token_sameTokenId (
++ session->token_id,
++ entry->token_id
++ )
++ ) {
++ found = TRUE;
++ }
++ }
++
++ if (!found) {
++ entry = NULL;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_malloc (
++ (void *)&entry,
++ sizeof (struct pkcs11h_token_id_list_s)
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = pkcs11h_token_duplicateTokenId (
++ &entry->token_id,
++ session->token_id
++ );
++ }
++
++ if (rv == CKR_OK) {
++ entry->next = token_id_list;
++ token_id_list = entry;
++ entry = NULL;
++ }
++
++ if (entry != NULL) {
++ if (entry->token_id != NULL) {
++ pkcs11h_token_freeTokenId (entry->token_id);
++ }
++ _pkcs11h_mem_free ((void *)&entry);
++ }
++ }
++ }
++ }
++
++ if (rv == CKR_OK) {
++ *p_token_id_list = token_id_list;
++ token_id_list = NULL;
++ }
++
++ if (token_id_list != NULL) {
++ pkcs11h_token_freeTokenIdList (token_id_list);
++ token_id_list = NULL;
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ rv = _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.global);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_enumTokenIds return rv=%ld-'%s', *p_token_id_list=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)p_token_id_list
++ );
++
++ return rv;
++}
++
++#endif
++
++#if defined(ENABLE_PKCS11H_DATA)
++
++CK_RV
++pkcs11h_data_freeDataIdList (
++ IN const pkcs11h_data_id_list_t data_id_list
++) {
++ pkcs11h_data_id_list_t _id = data_id_list;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ /*PKCS11H_ASSERT (data_id_list!=NULL); NOT NEEDED*/
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_freeDataIdList entry token_id_list=%p",
++ (void *)data_id_list
++ );
++
++ while (_id != NULL) {
++ pkcs11h_data_id_list_t x = _id;
++ _id = _id->next;
++
++ if (x->application != NULL) {
++ _pkcs11h_mem_free ((void *)&x->application);
++ }
++ if (x->label != NULL) {
++ _pkcs11h_mem_free ((void *)&x->label);
++ }
++ _pkcs11h_mem_free ((void *)&x);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_token_freeDataIdList return"
++ );
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_data_enumDataObjects (
++ IN const pkcs11h_token_id_t token_id,
++ IN const PKCS11H_BOOL is_public,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT pkcs11h_data_id_list_t * const p_data_id_list
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ pkcs11h_session_t session = NULL;
++ pkcs11h_data_id_list_t data_id_list = NULL;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_BOOL op_succeed = FALSE;
++ PKCS11H_BOOL login_retry = FALSE;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (p_data_id_list!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_data_enumDataObjects entry token_id=%p, is_public=%d, user_data=%p, mask_prompt=%08x, p_data_id_list=%p",
++ (void *)token_id,
++ is_public ? 1 : 0,
++ user_data,
++ mask_prompt,
++ (void *)p_data_id_list
++ );
++
++ *p_data_id_list = NULL;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSessionByTokenId (
++ token_id,
++ &session
++ );
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ while (rv == CKR_OK && !op_succeed) {
++
++ CK_OBJECT_CLASS class = CKO_DATA;
++ CK_ATTRIBUTE filter[] = {
++ {CKA_CLASS, (void *)&class, sizeof (class)}
++ };
++ CK_OBJECT_HANDLE *objects = NULL;
++ CK_ULONG objects_found = 0;
++
++ CK_ULONG i;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_findObjects (
++ session,
++ filter,
++ sizeof (filter) / sizeof (CK_ATTRIBUTE),
++ &objects,
++ &objects_found
++ );
++ }
++
++ for (i = 0;rv == CKR_OK && i < objects_found;i++) {
++ pkcs11h_data_id_list_t entry = NULL;
++
++ CK_ATTRIBUTE attrs[] = {
++ {CKA_APPLICATION, NULL, 0},
++ {CKA_LABEL, NULL, 0}
++ };
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getObjectAttributes (
++ session,
++ objects[i],
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_malloc (
++ (void *)&entry,
++ sizeof (struct pkcs11h_data_id_list_s)
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc (
++ (void *)&entry->application,
++ attrs[0].ulValueLen+1
++ )) == CKR_OK
++ ) {
++ memmove (entry->application, attrs[0].pValue, attrs[0].ulValueLen);
++ entry->application[attrs[0].ulValueLen] = '\0';
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc (
++ (void *)&entry->label,
++ attrs[1].ulValueLen+1
++ )) == CKR_OK
++ ) {
++ memmove (entry->label, attrs[1].pValue, attrs[1].ulValueLen);
++ entry->label[attrs[1].ulValueLen] = '\0';
++ }
++
++ if (rv == CKR_OK) {
++ entry->next = data_id_list;
++ data_id_list = entry;
++ entry = NULL;
++ }
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ );
++
++ if (entry != NULL) {
++ if (entry->application != NULL) {
++ _pkcs11h_mem_free ((void *)&entry->application);
++ }
++ if (entry->label != NULL) {
++ _pkcs11h_mem_free ((void *)&entry->label);
++ }
++ _pkcs11h_mem_free ((void *)&entry);
++ }
++ }
++
++ if (objects != NULL) {
++ _pkcs11h_mem_free ((void *)&objects);
++ }
++
++ if (rv == CKR_OK) {
++ op_succeed = TRUE;
++ }
++ else {
++ if (!login_retry) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Enumerate data objects failed rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++ login_retry = TRUE;
++ rv = _pkcs11h_session_login (
++ session,
++ is_public,
++ TRUE,
++ user_data,
++ mask_prompt
++ );
++ }
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ if (rv == CKR_OK) {
++ *p_data_id_list = data_id_list;
++ data_id_list = NULL;
++ }
++
++ if (session != NULL) {
++ _pkcs11h_session_release (session);
++ session = NULL;
++ }
++
++ if (data_id_list != NULL) {
++ pkcs11h_data_freeDataIdList (data_id_list);
++ data_id_list = NULL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_data_enumDataObjects return rv=%ld-'%s', *p_data_id_list=%p",
++ rv,
++ pkcs11h_getMessage (rv),
++ (void *)*p_data_id_list
++ );
++
++ return rv;
++}
++
++#endif /* ENABLE_PKCS11H_DATA */
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++
++static
++CK_RV
++_pkcs11h_certificate_enumSessionCertificates (
++ IN const pkcs11h_session_t session,
++ IN void * const user_data,
++ IN const unsigned mask_prompt
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ PKCS11H_BOOL op_succeed = FALSE;
++ PKCS11H_BOOL login_retry = FALSE;
++
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (session!=NULL);
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_enumSessionCertificates entry session=%p, user_data=%p, mask_prompt=%08x",
++ (void *)session,
++ user_data,
++ mask_prompt
++ );
++
++ /* THREADS: NO NEED TO LOCK, GLOBAL CACHE IS LOCKED */
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ while (rv == CKR_OK && !op_succeed) {
++ CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
++ CK_ATTRIBUTE cert_filter[] = {
++ {CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)}
++ };
++
++ CK_OBJECT_HANDLE *objects = NULL;
++ CK_ULONG objects_found = 0;
++
++ CK_ULONG i;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_validate (session);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_findObjects (
++ session,
++ cert_filter,
++ sizeof (cert_filter) / sizeof (CK_ATTRIBUTE),
++ &objects,
++ &objects_found
++ );
++ }
++
++ for (i=0;rv == CKR_OK && i < objects_found;i++) {
++ pkcs11h_certificate_id_t certificate_id = NULL;
++ pkcs11h_certificate_id_list_t new_element = NULL;
++
++ CK_ATTRIBUTE attrs[] = {
++ {CKA_ID, NULL, 0},
++ {CKA_VALUE, NULL, 0}
++ };
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getObjectAttributes (
++ session,
++ objects[i],
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_certificate_newCertificateId (&certificate_id)) == CKR_OK
++ ) {
++ rv = pkcs11h_token_duplicateTokenId (
++ &certificate_id->token_id,
++ session->token_id
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_duplicate (
++ (void*)&certificate_id->attrCKA_ID,
++ &certificate_id->attrCKA_ID_size,
++ attrs[0].pValue,
++ attrs[0].ulValueLen
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_duplicate (
++ (void*)&certificate_id->certificate_blob,
++ &certificate_id->certificate_blob_size,
++ attrs[1].pValue,
++ attrs[1].ulValueLen
++ );
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_certificate_updateCertificateIdDescription (certificate_id);
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc (
++ (void *)&new_element,
++ sizeof (struct pkcs11h_certificate_id_list_s)
++ )) == CKR_OK
++ ) {
++ new_element->next = session->cached_certs;
++ new_element->certificate_id = certificate_id;
++ certificate_id = NULL;
++
++ session->cached_certs = new_element;
++ new_element = NULL;
++ }
++
++ if (certificate_id != NULL) {
++ pkcs11h_certificate_freeCertificateId (certificate_id);
++ certificate_id = NULL;
++ }
++
++ if (new_element != NULL) {
++ _pkcs11h_mem_free ((void *)&new_element);
++ new_element = NULL;
++ }
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ );
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'",
++ session->provider->manufacturerID,
++ objects[i],
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++ }
++
++ if (objects != NULL) {
++ _pkcs11h_mem_free ((void *)&objects);
++ }
++
++ if (rv == CKR_OK) {
++ op_succeed = TRUE;
++ }
++ else {
++ if (!login_retry) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Get certificate attributes failed: %ld:'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ rv = _pkcs11h_session_login (
++ session,
++ TRUE,
++ TRUE,
++ user_data,
++ (mask_prompt & PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT)
++ );
++
++ login_retry = TRUE;
++ }
++ }
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&session->mutex);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_enumSessionCertificates return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_certificate_splitCertificateIdList (
++ IN const pkcs11h_certificate_id_list_t cert_id_all,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
++) {
++ typedef struct info_s {
++ struct info_s *next;
++ pkcs11h_certificate_id_t e;
++#if defined(USE_PKCS11H_OPENSSL)
++ X509 *x509;
++#elif defined(USE_PKCS11H_GNUTLS)
++ gnutls_x509_crt_t cert;
++#endif
++ PKCS11H_BOOL is_issuer;
++ } *info_t;
++
++ pkcs11h_certificate_id_list_t cert_id_issuers_list = NULL;
++ pkcs11h_certificate_id_list_t cert_id_end_list = NULL;
++
++ info_t head = NULL;
++ info_t info = NULL;
++
++ CK_RV rv = CKR_OK;
++
++ /*PKCS11H_ASSERT (cert_id_all!=NULL); NOT NEEDED */
++ /*PKCS11H_ASSERT (p_cert_id_issuers_list!=NULL); NOT NEEDED*/
++ PKCS11H_ASSERT (p_cert_id_end_list!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_splitCertificateIdList entry cert_id_all=%p, p_cert_id_issuers_list=%p, p_cert_id_end_list=%p",
++ (void *)cert_id_all,
++ (void *)p_cert_id_issuers_list,
++ (void *)p_cert_id_end_list
++ );
++
++ if (p_cert_id_issuers_list != NULL) {
++ *p_cert_id_issuers_list = NULL;
++ }
++ *p_cert_id_end_list = NULL;
++
++ if (rv == CKR_OK) {
++ pkcs11h_certificate_id_list_t entry = NULL;
++
++ for (
++ entry = cert_id_all;
++ entry != NULL && rv == CKR_OK;
++ entry = entry->next
++ ) {
++ info_t new_info = NULL;
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc ((void *)&new_info, sizeof (struct info_s))) == CKR_OK &&
++ entry->certificate_id->certificate_blob != NULL
++ ) {
++#if defined(USE_PKCS11H_OPENSSL)
++ pkcs11_openssl_d2i_t d2i = (pkcs11_openssl_d2i_t)entry->certificate_id->certificate_blob;
++#endif
++
++ new_info->next = head;
++ new_info->e = entry->certificate_id;
++#if defined(USE_PKCS11H_OPENSSL)
++ new_info->x509 = X509_new ();
++ if (
++ new_info->x509 != NULL &&
++ !d2i_X509 (
++ &new_info->x509,
++ &d2i,
++ entry->certificate_id->certificate_blob_size
++ )
++ ) {
++ X509_free (new_info->x509);
++ new_info->x509 = NULL;
++ }
++#elif defined(USE_PKCS11H_GNUTLS)
++ if (gnutls_x509_crt_init (&new_info->cert) != GNUTLS_E_SUCCESS) {
++ /* gnutls sets output */
++ new_info->cert = NULL;
++ }
++ else {
++ gnutls_datum_t datum = {
++ entry->certificate_id->certificate_blob,
++ entry->certificate_id->certificate_blob_size
++ };
++
++ if (
++ gnutls_x509_crt_import (
++ new_info->cert,
++ &datum,
++ GNUTLS_X509_FMT_DER
++ ) != GNUTLS_E_SUCCESS
++ ) {
++ gnutls_x509_crt_deinit (new_info->cert);
++ new_info->cert = NULL;
++ }
++ }
++#else
++#error Invalid configuration.
++#endif
++ head = new_info;
++ new_info = NULL;
++ }
++ }
++
++ }
++
++ if (rv == CKR_OK) {
++ for (
++ info = head;
++ info != NULL;
++ info = info->next
++ ) {
++ info_t info2 = NULL;
++#if defined(USE_PKCS11H_OPENSSL)
++ EVP_PKEY *pub = X509_get_pubkey (info->x509);
++#endif
++
++ for (
++ info2 = head;
++ info2 != NULL && !info->is_issuer;
++ info2 = info2->next
++ ) {
++ if (info != info2) {
++#if defined(USE_PKCS11H_OPENSSL)
++ if (
++ info->x509 != NULL &&
++ info2->x509 != NULL &&
++ !X509_NAME_cmp (
++ X509_get_subject_name (info->x509),
++ X509_get_issuer_name (info2->x509)
++ ) &&
++ X509_verify (info2->x509, pub) == 1
++ ) {
++ info->is_issuer = TRUE;
++ }
++#elif defined(USE_PKCS11H_GNUTLS)
++ unsigned result;
++
++ if (
++ info->cert != NULL &&
++ info2->cert != NULL &&
++ gnutls_x509_crt_verify (
++ info2->cert,
++ &info->cert,
++ 1,
++ 0,
++ &result
++ ) &&
++ (result & GNUTLS_CERT_INVALID) == 0
++ ) {
++ info->is_issuer = TRUE;
++ }
++#else
++#error Invalid configuration.
++#endif
++ }
++
++ }
++
++#if defined(USE_PKCS11H_OPENSSL)
++ if (pub != NULL) {
++ EVP_PKEY_free (pub);
++ pub = NULL;
++ }
++#endif
++ }
++ }
++
++ if (rv == CKR_OK) {
++ for (
++ info = head;
++ info != NULL && rv == CKR_OK;
++ info = info->next
++ ) {
++ pkcs11h_certificate_id_list_t new_entry = NULL;
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_mem_malloc (
++ (void *)&new_entry,
++ sizeof (struct pkcs11h_certificate_id_list_s)
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_certificate_duplicateCertificateId (
++ &new_entry->certificate_id,
++ info->e
++ )) == CKR_OK
++ ) {
++ /*
++ * Should not free base list
++ */
++ info->e = NULL;
++ }
++
++ if (rv == CKR_OK) {
++ if (info->is_issuer) {
++ new_entry->next = cert_id_issuers_list;
++ cert_id_issuers_list = new_entry;
++ new_entry = NULL;
++ }
++ else {
++ new_entry->next = cert_id_end_list;
++ cert_id_end_list = new_entry;
++ new_entry = NULL;
++ }
++ }
++
++ if (new_entry != NULL) {
++ if (new_entry->certificate_id != NULL) {
++ pkcs11h_certificate_freeCertificateId (new_entry->certificate_id);
++ }
++ _pkcs11h_mem_free ((void *)&new_entry);
++ }
++ }
++ }
++
++ if (rv == CKR_OK) {
++ while (head != NULL) {
++ info_t entry = head;
++ head = head->next;
++
++#if defined(USE_PKCS11H_OPENSSL)
++ if (entry->x509 != NULL) {
++ X509_free (entry->x509);
++ entry->x509 = NULL;
++ }
++#elif defined(USE_PKCS11H_GNUTLS)
++ if (entry->cert != NULL) {
++ gnutls_x509_crt_deinit (entry->cert);
++ entry->cert = NULL;
++ }
++#else
++#error Invalid configuration.
++#endif
++
++ _pkcs11h_mem_free ((void *)&entry);
++ }
++ }
++
++ if (rv == CKR_OK && p_cert_id_issuers_list != NULL ) {
++ *p_cert_id_issuers_list = cert_id_issuers_list;
++ cert_id_issuers_list = NULL;
++ }
++
++ if (rv == CKR_OK) {
++ *p_cert_id_end_list = cert_id_end_list;
++ cert_id_end_list = NULL;
++ }
++
++ if (cert_id_issuers_list != NULL) {
++ pkcs11h_certificate_freeCertificateIdList (cert_id_issuers_list);
++ }
++
++ if (cert_id_end_list != NULL) {
++ pkcs11h_certificate_freeCertificateIdList (cert_id_end_list);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_certificate_splitCertificateIdList return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_freeCertificateIdList (
++ IN const pkcs11h_certificate_id_list_t cert_id_list
++) {
++ pkcs11h_certificate_id_list_t _id = cert_id_list;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ /*PKCS11H_ASSERT (cert_id_list!=NULL); NOT NEEDED*/
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_freeCertificateIdList entry cert_id_list=%p",
++ (void *)cert_id_list
++ );
++
++ while (_id != NULL) {
++ pkcs11h_certificate_id_list_t x = _id;
++ _id = _id->next;
++ if (x->certificate_id != NULL) {
++ pkcs11h_certificate_freeCertificateId (x->certificate_id);
++ }
++ x->next = NULL;
++ _pkcs11h_mem_free ((void *)&x);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_freeCertificateIdList return"
++ );
++
++ return CKR_OK;
++}
++
++CK_RV
++pkcs11h_certificate_enumTokenCertificateIds (
++ IN const pkcs11h_token_id_t token_id,
++ IN const int method,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ pkcs11h_session_t session = NULL;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ PKCS11H_ASSERT (token_id!=NULL);
++ /*PKCS11H_ASSERT (user_data) NOT NEEDED */
++ /*PKCS11H_ASSERT (p_cert_id_issuers_list!=NULL); NOT NEEDED*/
++ PKCS11H_ASSERT (p_cert_id_end_list!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_enumTokenCertificateIds entry token_id=%p, method=%d, user_data=%p, mask_prompt=%08x, p_cert_id_issuers_list=%p, p_cert_id_end_list=%p",
++ (void *)token_id,
++ method,
++ user_data,
++ mask_prompt,
++ (void *)p_cert_id_issuers_list,
++ (void *)p_cert_id_end_list
++ );
++
++ if (p_cert_id_issuers_list != NULL) {
++ *p_cert_id_issuers_list = NULL;
++ }
++ *p_cert_id_end_list = NULL;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.cache)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_session_getSessionByTokenId (
++ token_id,
++ &session
++ )) == CKR_OK
++ ) {
++ if (method == PKCS11H_ENUM_METHOD_RELOAD) {
++ pkcs11h_certificate_freeCertificateIdList (session->cached_certs);
++ session->cached_certs = NULL;
++ }
++
++ if (session->cached_certs == NULL) {
++ rv = _pkcs11h_certificate_enumSessionCertificates (session, user_data, mask_prompt);
++ }
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_certificate_splitCertificateIdList (
++ session->cached_certs,
++ p_cert_id_issuers_list,
++ p_cert_id_end_list
++ );
++ }
++
++ if (session != NULL) {
++ _pkcs11h_session_release (session);
++ }
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.cache);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_enumTokenCertificateIds return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++CK_RV
++pkcs11h_certificate_enumCertificateIds (
++ IN const int method,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
++) {
++#if defined(ENABLE_PKCS11H_THREADING)
++ PKCS11H_BOOL mutex_locked = FALSE;
++#endif
++ pkcs11h_certificate_id_list_t cert_id_list = NULL;
++ pkcs11h_provider_t current_provider;
++ pkcs11h_session_t current_session;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_ASSERT (s_pkcs11h_data!=NULL);
++ PKCS11H_ASSERT (s_pkcs11h_data->initialized);
++ /*PKCS11H_ASSERT (user_data!=NULL); NOT NEEDED*/
++ /*PKCS11H_ASSERT (p_cert_id_issuers_list!=NULL); NOT NEEDED*/
++ PKCS11H_ASSERT (p_cert_id_end_list!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_enumCertificateIds entry method=%d, mask_prompt=%08x, p_cert_id_issuers_list=%p, p_cert_id_end_list=%p",
++ method,
++ mask_prompt,
++ (void *)p_cert_id_issuers_list,
++ (void *)p_cert_id_end_list
++ );
++
++ if (p_cert_id_issuers_list != NULL) {
++ *p_cert_id_issuers_list = NULL;
++ }
++ *p_cert_id_end_list = NULL;
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_threading_mutexLock (&s_pkcs11h_data->mutexes.cache)) == CKR_OK
++ ) {
++ mutex_locked = TRUE;
++ }
++#endif
++
++ for (
++ current_session = s_pkcs11h_data->sessions;
++ current_session != NULL;
++ current_session = current_session->next
++ ) {
++ current_session->touch = FALSE;
++ if (method == PKCS11H_ENUM_METHOD_RELOAD) {
++ pkcs11h_certificate_freeCertificateIdList (current_session->cached_certs);
++ current_session->cached_certs = NULL;
++ }
++ }
++
++ for (
++ current_provider = s_pkcs11h_data->providers;
++ (
++ current_provider != NULL &&
++ rv == CKR_OK
++ );
++ current_provider = current_provider->next
++ ) {
++ CK_SLOT_ID_PTR slots = NULL;
++ CK_ULONG slotnum;
++ CK_SLOT_ID slot_index;
++
++ if (!current_provider->enabled) {
++ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_session_getSlotList (
++ current_provider,
++ CK_TRUE,
++ &slots,
++ &slotnum
++ );
++ }
++
++ for (
++ slot_index=0;
++ (
++ slot_index < slotnum &&
++ rv == CKR_OK
++ );
++ slot_index++
++ ) {
++ pkcs11h_session_t session = NULL;
++ pkcs11h_token_id_t token_id = NULL;
++ CK_TOKEN_INFO info;
++
++ if (rv == CKR_OK) {
++ rv = current_provider->f->C_GetTokenInfo (
++ slots[slot_index],
++ &info
++ );
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_token_getTokenId (
++ &info,
++ &token_id
++ )) == CKR_OK &&
++ (rv = _pkcs11h_session_getSessionByTokenId (
++ token_id,
++ &session
++ )) == CKR_OK
++ ) {
++ session->touch = TRUE;
++
++ if (session->cached_certs == NULL) {
++ rv = _pkcs11h_certificate_enumSessionCertificates (session, user_data, mask_prompt);
++ }
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get token information for provider '%s' slot %ld rv=%ld-'%s'",
++ current_provider->manufacturerID,
++ slots[slot_index],
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++
++ if (session != NULL) {
++ _pkcs11h_session_release (session);
++ session = NULL;
++ }
++
++ if (token_id != NULL) {
++ pkcs11h_token_freeTokenId (token_id);
++ token_id = NULL;
++ }
++ }
++
++ if (rv != CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
++ current_provider->manufacturerID,
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ /*
++ * Ignore error
++ */
++ rv = CKR_OK;
++ }
++
++ if (slots != NULL) {
++ _pkcs11h_mem_free ((void *)&slots);
++ slots = NULL;
++ }
++ }
++
++ for (
++ current_session = s_pkcs11h_data->sessions;
++ (
++ current_session != NULL &&
++ rv == CKR_OK
++ );
++ current_session = current_session->next
++ ) {
++ if (
++ method == PKCS11H_ENUM_METHOD_CACHE ||
++ (
++ (
++ method == PKCS11H_ENUM_METHOD_RELOAD ||
++ method == PKCS11H_ENUM_METHOD_CACHE_EXIST
++ ) &&
++ current_session->touch
++ )
++ ) {
++ pkcs11h_certificate_id_list_t entry = NULL;
++
++ for (
++ entry = current_session->cached_certs;
++ (
++ entry != NULL &&
++ rv == CKR_OK
++ );
++ entry = entry->next
++ ) {
++ pkcs11h_certificate_id_list_t new_entry = NULL;
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc (
++ (void *)&new_entry,
++ sizeof (struct pkcs11h_certificate_id_list_s)
++ )) == CKR_OK &&
++ (rv = pkcs11h_certificate_duplicateCertificateId (
++ &new_entry->certificate_id,
++ entry->certificate_id
++ )) == CKR_OK
++ ) {
++ new_entry->next = cert_id_list;
++ cert_id_list = new_entry;
++ new_entry = NULL;
++ }
++
++ if (new_entry != NULL) {
++ new_entry->next = NULL;
++ pkcs11h_certificate_freeCertificateIdList (new_entry);
++ new_entry = NULL;
++ }
++ }
++ }
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_certificate_splitCertificateIdList (
++ cert_id_list,
++ p_cert_id_issuers_list,
++ p_cert_id_end_list
++ );
++ }
++
++ if (cert_id_list != NULL) {
++ pkcs11h_certificate_freeCertificateIdList (cert_id_list);
++ cert_id_list = NULL;
++ }
++
++
++#if defined(ENABLE_PKCS11H_THREADING)
++ if (mutex_locked) {
++ _pkcs11h_threading_mutexRelease (&s_pkcs11h_data->mutexes.cache);
++ mutex_locked = FALSE;
++ }
++#endif
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_certificate_enumCertificateIds return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#endif /* ENABLE_PKCS11H_ENUM */
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT)
++/*======================================================================*
++ * SLOTEVENT INTERFACE
++ *======================================================================*/
++
++static
++unsigned long
++_pkcs11h_slotevent_checksum (
++ IN const unsigned char * const p,
++ IN const size_t s
++) {
++ unsigned long r = 0;
++ size_t i;
++ for (i=0;i<s;i++) {
++ r += p[i];
++ }
++ return r;
++}
++
++static
++void *
++_pkcs11h_slotevent_provider (
++ IN void *p
++) {
++ pkcs11h_provider_t provider = (pkcs11h_provider_t)p;
++ CK_SLOT_ID slot;
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_provider provider='%s' entry",
++ provider->manufacturerID
++ );
++
++ if (rv == CKR_OK && !provider->enabled) {
++ rv = CKR_OPERATION_NOT_INITIALIZED;
++ }
++
++ if (rv == CKR_OK) {
++
++ if (provider->slot_poll_interval == 0) {
++ provider->slot_poll_interval = PKCS11H_DEFAULT_SLOTEVENT_POLL;
++ }
++
++ /*
++ * If we cannot finalize, we cannot cause
++ * WaitForSlotEvent to terminate
++ */
++ if (!provider->should_finalize) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Setup slotevent provider='%s' mode hardset to poll",
++ provider->manufacturerID
++ );
++ provider->slot_event_method = PKCS11H_SLOTEVENT_METHOD_POLL;
++ }
++
++ if (
++ provider->slot_event_method == PKCS11H_SLOTEVENT_METHOD_AUTO ||
++ provider->slot_event_method == PKCS11H_SLOTEVENT_METHOD_TRIGGER
++ ) {
++ if (
++ provider->f->C_WaitForSlotEvent (
++ CKF_DONT_BLOCK,
++ &slot,
++ NULL_PTR
++ ) == CKR_FUNCTION_NOT_SUPPORTED
++ ) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Setup slotevent provider='%s' mode is poll",
++ provider->manufacturerID
++ );
++
++ provider->slot_event_method = PKCS11H_SLOTEVENT_METHOD_POLL;
++ }
++ else {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Setup slotevent provider='%s' mode is trigger",
++ provider->manufacturerID
++ );
++
++ provider->slot_event_method = PKCS11H_SLOTEVENT_METHOD_TRIGGER;
++ }
++ }
++ }
++
++ if (provider->slot_event_method == PKCS11H_SLOTEVENT_METHOD_TRIGGER) {
++ while (
++ !s_pkcs11h_data->slotevent.should_terminate &&
++ provider->enabled &&
++ rv == CKR_OK &&
++ (rv = provider->f->C_WaitForSlotEvent (
++ 0,
++ &slot,
++ NULL_PTR
++ )) == CKR_OK
++ ) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Slotevent provider='%s' event",
++ provider->manufacturerID
++ );
++
++ _pkcs11h_threading_condSignal (&s_pkcs11h_data->slotevent.cond_event);
++ }
++ }
++ else {
++ unsigned long ulLastChecksum = 0;
++ PKCS11H_BOOL is_first_time = TRUE;
++
++ while (
++ !s_pkcs11h_data->slotevent.should_terminate &&
++ provider->enabled &&
++ rv == CKR_OK
++ ) {
++ unsigned long ulCurrentChecksum = 0;
++
++ CK_SLOT_ID_PTR slots = NULL;
++ CK_ULONG slotnum;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Slotevent provider='%s' poll",
++ provider->manufacturerID
++ );
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_session_getSlotList (
++ provider,
++ TRUE,
++ &slots,
++ &slotnum
++ )) == CKR_OK
++ ) {
++ CK_ULONG i;
++
++ for (i=0;i<slotnum;i++) {
++ CK_TOKEN_INFO info;
++
++ if (provider->f->C_GetTokenInfo (slots[i], &info) == CKR_OK) {
++ ulCurrentChecksum += (
++ _pkcs11h_slotevent_checksum (
++ info.label,
++ sizeof (info.label)
++ ) +
++ _pkcs11h_slotevent_checksum (
++ info.manufacturerID,
++ sizeof (info.manufacturerID)
++ ) +
++ _pkcs11h_slotevent_checksum (
++ info.model,
++ sizeof (info.model)
++ ) +
++ _pkcs11h_slotevent_checksum (
++ info.serialNumber,
++ sizeof (info.serialNumber)
++ )
++ );
++ }
++ }
++ }
++
++ if (rv == CKR_OK) {
++ if (is_first_time) {
++ is_first_time = FALSE;
++ }
++ else {
++ if (ulLastChecksum != ulCurrentChecksum) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Slotevent provider='%s' event",
++ provider->manufacturerID
++ );
++
++ _pkcs11h_threading_condSignal (&s_pkcs11h_data->slotevent.cond_event);
++ }
++ }
++ ulLastChecksum = ulCurrentChecksum;
++ }
++
++ if (slots != NULL) {
++ _pkcs11h_mem_free ((void *)&slots);
++ }
++
++ if (!s_pkcs11h_data->slotevent.should_terminate) {
++ _pkcs11h_threading_sleep (provider->slot_poll_interval);
++ }
++ }
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_provider provider='%s' return",
++ provider->manufacturerID
++ );
++
++ return NULL;
++}
++
++static
++void *
++_pkcs11h_slotevent_manager (
++ IN void *p
++) {
++ PKCS11H_BOOL first_time = TRUE;
++
++ (void)p;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_manager entry"
++ );
++
++ /*
++ * Trigger hook, so application may
++ * depend on initial slot change
++ */
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Calling slotevent hook"
++ );
++ s_pkcs11h_data->hooks.slotevent (s_pkcs11h_data->hooks.slotevent_data);
++
++ while (
++ first_time || /* Must enter wait or mutex will never be free */
++ !s_pkcs11h_data->slotevent.should_terminate
++ ) {
++ pkcs11h_provider_t current_provider;
++
++ first_time = FALSE;
++
++ /*
++ * Start each provider thread
++ * if not already started.
++ * This is required in order to allow
++ * adding new providers.
++ */
++ for (
++ current_provider = s_pkcs11h_data->providers;
++ current_provider != NULL;
++ current_provider = current_provider->next
++ ) {
++ if (!current_provider->enabled) {
++ if (current_provider->slotevent_thread == PKCS11H_THREAD_NULL) {
++ _pkcs11h_threading_threadStart (
++ ¤t_provider->slotevent_thread,
++ _pkcs11h_slotevent_provider,
++ current_provider
++ );
++ }
++ }
++ else {
++ if (current_provider->slotevent_thread != PKCS11H_THREAD_NULL) {
++ _pkcs11h_threading_threadJoin (¤t_provider->slotevent_thread);
++ }
++ }
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_manager waiting for slotevent"
++ );
++ _pkcs11h_threading_condWait (&s_pkcs11h_data->slotevent.cond_event, PKCS11H_COND_INFINITE);
++
++ if (s_pkcs11h_data->slotevent.skip_event) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Slotevent skipping event"
++ );
++ s_pkcs11h_data->slotevent.skip_event = FALSE;
++ }
++ else {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Calling slotevent hook"
++ );
++ s_pkcs11h_data->hooks.slotevent (s_pkcs11h_data->hooks.slotevent_data);
++ }
++ }
++
++ {
++ pkcs11h_provider_t current_provider;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_manager joining threads"
++ );
++
++
++ for (
++ current_provider = s_pkcs11h_data->providers;
++ current_provider != NULL;
++ current_provider = current_provider->next
++ ) {
++ if (current_provider->slotevent_thread != PKCS11H_THREAD_NULL) {
++ _pkcs11h_threading_threadJoin (¤t_provider->slotevent_thread);
++ }
++ }
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_manager return"
++ );
++
++ return NULL;
++}
++
++static
++CK_RV
++_pkcs11h_slotevent_init () {
++ CK_RV rv = CKR_OK;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_init entry"
++ );
++
++ if (!s_pkcs11h_data->slotevent.initialized) {
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_threading_condInit (&s_pkcs11h_data->slotevent.cond_event);
++ }
++
++ if (rv == CKR_OK) {
++ rv = _pkcs11h_threading_threadStart (
++ &s_pkcs11h_data->slotevent.thread,
++ _pkcs11h_slotevent_manager,
++ NULL
++ );
++ }
++
++ if (rv == CKR_OK) {
++ s_pkcs11h_data->slotevent.initialized = TRUE;
++ }
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_init return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv;
++}
++
++static
++CK_RV
++_pkcs11h_slotevent_notify () {
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_notify entry"
++ );
++
++ if (s_pkcs11h_data->slotevent.initialized) {
++ s_pkcs11h_data->slotevent.skip_event = TRUE;
++ _pkcs11h_threading_condSignal (&s_pkcs11h_data->slotevent.cond_event);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_notify return"
++ );
++
++ return CKR_OK;
++}
++
++static
++CK_RV
++_pkcs11h_slotevent_terminate () {
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_terminate entry"
++ );
++
++ if (s_pkcs11h_data->slotevent.initialized) {
++ s_pkcs11h_data->slotevent.should_terminate = TRUE;
++
++ _pkcs11h_slotevent_notify ();
++
++ if (s_pkcs11h_data->slotevent.thread != PKCS11H_THREAD_NULL) {
++ _pkcs11h_threading_threadJoin (&s_pkcs11h_data->slotevent.thread);
++ }
++
++ _pkcs11h_threading_condFree (&s_pkcs11h_data->slotevent.cond_event);
++ s_pkcs11h_data->slotevent.initialized = FALSE;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_slotevent_terminate return"
++ );
++
++ return CKR_OK;
++}
++
++#endif
++
++#if defined(ENABLE_PKCS11H_OPENSSL)
++/*======================================================================*
++ * OPENSSL INTERFACE
++ *======================================================================*/
++
++static
++pkcs11h_openssl_session_t
++_pkcs11h_openssl_get_openssl_session (
++ IN OUT const RSA *rsa
++) {
++ pkcs11h_openssl_session_t session;
++
++ PKCS11H_ASSERT (rsa!=NULL);
++#if OPENSSL_VERSION_NUMBER < 0x00907000L
++ session = (pkcs11h_openssl_session_t)RSA_get_app_data ((RSA *)rsa);
++#else
++ session = (pkcs11h_openssl_session_t)RSA_get_app_data (rsa);
++#endif
++ PKCS11H_ASSERT (session!=NULL);
++
++ return session;
++}
++
++static
++pkcs11h_certificate_t
++_pkcs11h_openssl_get_pkcs11h_certificate (
++ IN OUT const RSA *rsa
++) {
++ pkcs11h_openssl_session_t session = _pkcs11h_openssl_get_openssl_session (rsa);
++
++ PKCS11H_ASSERT (session!=NULL);
++ PKCS11H_ASSERT (session->certificate!=NULL);
++
++ return session->certificate;
++}
++
++#if OPENSSL_VERSION_NUMBER < 0x00907000L
++static
++int
++_pkcs11h_openssl_dec (
++ IN int flen,
++ IN unsigned char *from,
++ OUT unsigned char *to,
++ IN OUT RSA *rsa,
++ IN int padding
++) {
++#else
++static
++int
++_pkcs11h_openssl_dec (
++ IN int flen,
++ IN const unsigned char *from,
++ OUT unsigned char *to,
++ IN OUT RSA *rsa,
++ IN int padding
++) {
++#endif
++ PKCS11H_ASSERT (from!=NULL);
++ PKCS11H_ASSERT (to!=NULL);
++ PKCS11H_ASSERT (rsa!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_openssl_dec entered - flen=%d, from=%p, to=%p, rsa=%p, padding=%d",
++ flen,
++ from,
++ to,
++ (void *)rsa,
++ padding
++ );
++
++ PKCS11H_LOG (
++ PKCS11H_LOG_ERROR,
++ "PKCS#11: Private key decryption is not supported"
++ );
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_openssl_dec return"
++ );
++
++ return -1;
++}
++
++#if OPENSSL_VERSION_NUMBER < 0x00907000L
++static
++int
++_pkcs11h_openssl_sign (
++ IN int type,
++ IN unsigned char *m,
++ IN unsigned int m_len,
++ OUT unsigned char *sigret,
++ OUT unsigned int *siglen,
++ IN OUT RSA *rsa
++) {
++#else
++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
++) {
++#endif
++ pkcs11h_certificate_t certificate = _pkcs11h_openssl_get_pkcs11h_certificate (rsa);
++ PKCS11H_BOOL session_locked = FALSE;
++ CK_RV rv = CKR_OK;
++
++ int myrsa_size = 0;
++
++ unsigned char *enc_alloc = NULL;
++ unsigned char *enc = NULL;
++ int enc_len = 0;
++
++ PKCS11H_ASSERT (m!=NULL);
++ PKCS11H_ASSERT (sigret!=NULL);
++ PKCS11H_ASSERT (siglen!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_openssl_sign entered - type=%d, m=%p, m_len=%u, signret=%p, *signlen=%u, rsa=%p",
++ type,
++ m,
++ m_len,
++ sigret,
++ sigret != NULL ? *siglen : 0,
++ (void *)rsa
++ );
++
++ if (rv == CKR_OK) {
++ myrsa_size=RSA_size(rsa);
++ }
++
++ if (type == NID_md5_sha1) {
++ if (rv == CKR_OK) {
++ enc = (unsigned char *)m;
++ enc_len = m_len;
++ }
++ }
++ else {
++ X509_SIG sig;
++ ASN1_TYPE parameter;
++ X509_ALGOR algor;
++ ASN1_OCTET_STRING digest;
++ unsigned char *p = NULL;
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_mem_malloc ((void*)&enc, myrsa_size+1)) == CKR_OK
++ ) {
++ enc_alloc = enc;
++ }
++
++ 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 = ¶meter;
++
++ 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;
++ }
++
++ /*
++ * d_X509_SIG increments pointer!
++ */
++ p = enc;
++
++ if (
++ rv == CKR_OK &&
++ (enc_len=i2d_X509_SIG (&sig, &p)) < 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 &&
++ (rv = pkcs11h_certificate_lockSession (certificate)) == CKR_OK
++ ) {
++ session_locked = TRUE;
++ }
++
++ if (rv == CKR_OK) {
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG1,
++ "PKCS#11: Performing signature"
++ );
++
++ *siglen = myrsa_size;
++
++ if (
++ (rv = pkcs11h_certificate_signAny (
++ certificate,
++ CKM_RSA_PKCS,
++ enc,
++ enc_len,
++ sigret,
++ siglen
++ )) != CKR_OK
++ ) {
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot perform signature %ld:'%s'", rv, pkcs11h_getMessage (rv));
++ }
++ }
++
++ if (session_locked) {
++ pkcs11h_certificate_releaseSession (certificate);
++ session_locked = FALSE;
++ }
++
++ if (enc_alloc != NULL) {
++ _pkcs11h_mem_free ((void *)&enc_alloc);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_openssl_sign - return rv=%ld-'%s'",
++ rv,
++ pkcs11h_getMessage (rv)
++ );
++
++ return rv == CKR_OK ? 1 : -1;
++}
++
++static
++int
++_pkcs11h_openssl_finish (
++ IN OUT RSA *rsa
++) {
++ pkcs11h_openssl_session_t openssl_session = _pkcs11h_openssl_get_openssl_session (rsa);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_openssl_finish - entered rsa=%p",
++ (void *)rsa
++ );
++
++ RSA_set_app_data (rsa, NULL);
++
++ 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
++ }
++
++ pkcs11h_openssl_freeSession (openssl_session);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: _pkcs11h_openssl_finish - return"
++ );
++
++ return 1;
++}
++
++X509 *
++pkcs11h_openssl_getX509 (
++ IN const pkcs11h_certificate_t certificate
++) {
++ unsigned char *certificate_blob = NULL;
++ size_t certificate_blob_size = 0;
++ X509 *x509 = NULL;
++ CK_RV rv = CKR_OK;
++
++ pkcs11_openssl_d2i_t d2i1 = NULL;
++ PKCS11H_BOOL ok = TRUE;
++
++ PKCS11H_ASSERT (certificate!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_openssl_getX509 - entry certificate=%p",
++ (void *)certificate
++ );
++
++ if (
++ ok &&
++ (x509 = X509_new ()) == NULL
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Unable to allocate certificate object");
++ }
++
++ if (
++ ok &&
++ pkcs11h_certificate_getCertificateBlob (
++ certificate,
++ NULL,
++ &certificate_blob_size
++ ) != CKR_OK
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (
++ ok &&
++ (rv = _pkcs11h_mem_malloc ((void *)&certificate_blob, certificate_blob_size)) != CKR_OK
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot allocate X.509 memory %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (
++ ok &&
++ pkcs11h_certificate_getCertificateBlob (
++ certificate,
++ certificate_blob,
++ &certificate_blob_size
++ ) != CKR_OK
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11h_getMessage (rv));
++ }
++
++ d2i1 = (pkcs11_openssl_d2i_t)certificate_blob;
++ if (
++ ok &&
++ !d2i_X509 (&x509, &d2i1, certificate_blob_size)
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Unable to parse X.509 certificate");
++ }
++
++ if (!ok) {
++ X509_free (x509);
++ x509 = NULL;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_openssl_getX509 - return x509=%p",
++ (void *)x509
++ );
++
++ return x509;
++}
++
++pkcs11h_openssl_session_t
++pkcs11h_openssl_createSession (
++ IN const pkcs11h_certificate_t certificate
++) {
++ pkcs11h_openssl_session_t openssl_session = NULL;
++ PKCS11H_BOOL ok = TRUE;
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_openssl_createSession - entry"
++ );
++
++ if (
++ ok &&
++ _pkcs11h_mem_malloc (
++ (void*)&openssl_session,
++ sizeof (struct pkcs11h_openssl_session_s)) != CKR_OK
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot allocate memory");
++ }
++
++ if (ok) {
++ const RSA_METHOD *def = RSA_get_default_method();
++
++ 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_dec = _pkcs11h_openssl_dec;
++ openssl_session->smart_rsa.rsa_sign = _pkcs11h_openssl_sign;
++ openssl_session->smart_rsa.finish = _pkcs11h_openssl_finish;
++ openssl_session->smart_rsa.flags = RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY;
++ openssl_session->certificate = certificate;
++ openssl_session->reference_count = 1;
++ }
++
++ if (!ok) {
++ _pkcs11h_mem_free ((void *)&openssl_session);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_openssl_createSession - return openssl_session=%p",
++ (void *)openssl_session
++ );
++
++ return openssl_session;
++}
++
++pkcs11h_hook_openssl_cleanup_t
++pkcs11h_openssl_getCleanupHook (
++ IN const pkcs11h_openssl_session_t openssl_session
++) {
++ PKCS11H_ASSERT (openssl_session!=NULL);
++
++ return openssl_session->cleanup_hook;
++}
++
++void
++pkcs11h_openssl_setCleanupHook (
++ IN const pkcs11h_openssl_session_t openssl_session,
++ IN const pkcs11h_hook_openssl_cleanup_t cleanup
++) {
++ PKCS11H_ASSERT (openssl_session!=NULL);
++
++ openssl_session->cleanup_hook = cleanup;
++}
++
++void
++pkcs11h_openssl_freeSession (
++ IN const pkcs11h_openssl_session_t openssl_session
++) {
++ PKCS11H_ASSERT (openssl_session!=NULL);
++ PKCS11H_ASSERT (openssl_session->reference_count>0);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_openssl_freeSession - entry openssl_session=%p, count=%d",
++ (void *)openssl_session,
++ openssl_session->reference_count
++ );
++
++ openssl_session->reference_count--;
++
++ if (openssl_session->reference_count == 0) {
++ if (openssl_session->cleanup_hook != NULL) {
++ openssl_session->cleanup_hook (openssl_session->certificate);
++ }
++
++ if (openssl_session->x509 != NULL) {
++ X509_free (openssl_session->x509);
++ openssl_session->x509 = NULL;
++ }
++ if (openssl_session->certificate != NULL) {
++ pkcs11h_certificate_freeCertificate (openssl_session->certificate);
++ openssl_session->certificate = NULL;
++ }
++
++ _pkcs11h_mem_free ((void *)&openssl_session);
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_openssl_freeSession - return"
++ );
++}
++
++RSA *
++pkcs11h_openssl_session_getRSA (
++ IN const pkcs11h_openssl_session_t openssl_session
++) {
++ X509 *x509 = NULL;
++ RSA *rsa = NULL;
++ EVP_PKEY *pubkey = NULL;
++ PKCS11H_BOOL ok = TRUE;
++
++ PKCS11H_ASSERT (openssl_session!=NULL);
++ PKCS11H_ASSERT (!openssl_session->initialized);
++ PKCS11H_ASSERT (openssl_session!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_openssl_session_getRSA - entry openssl_session=%p",
++ (void *)openssl_session
++ );
++
++ /*
++ * Dup x509 so RSA will not hold session x509
++ */
++ if (
++ ok &&
++ (x509 = pkcs11h_openssl_session_getX509 (openssl_session)) == NULL
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get certificate object");
++ }
++
++ if (
++ ok &&
++ (pubkey = X509_get_pubkey (x509)) == NULL
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get public key");
++ }
++
++ if (
++ ok &&
++ pubkey->type != EVP_PKEY_RSA
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Invalid public key algorithm");
++ }
++
++ if (
++ ok &&
++ (rsa = EVP_PKEY_get1_RSA (pubkey)) == NULL
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get RSA key");
++ }
++
++ if (ok) {
++ RSA_set_method (rsa, &openssl_session->smart_rsa);
++ RSA_set_app_data (rsa, openssl_session);
++ openssl_session->reference_count++;
++ }
++
++#ifdef BROKEN_OPENSSL_ENGINE
++ if (ok) {
++ if (!rsa->engine) {
++ rsa->engine = ENGINE_get_default_RSA();
++ }
++
++ ENGINE_set_RSA(ENGINE_get_default_RSA(), &openssl_session->smart_rsa);
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: OpenSSL engine support is broken! Workaround enabled");
++ }
++#endif
++
++ if (ok) {
++ rsa->flags |= RSA_FLAG_SIGN_VER;
++ openssl_session->initialized = 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;
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_openssl_session_getRSA - return rsa=%p",
++ (void *)rsa
++ );
++
++ return rsa;
++}
++
++X509 *
++pkcs11h_openssl_session_getX509 (
++ IN const pkcs11h_openssl_session_t openssl_session
++) {
++ X509 *x509 = NULL;
++ PKCS11H_BOOL ok = TRUE;
++
++ PKCS11H_ASSERT (openssl_session!=NULL);
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_openssl_session_getX509 - entry openssl_session=%p",
++ (void *)openssl_session
++ );
++
++ if (
++ ok &&
++ openssl_session->x509 == NULL &&
++ (openssl_session->x509 = pkcs11h_openssl_getX509 (openssl_session->certificate)) == NULL
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get certificate object");
++ }
++
++ if (
++ ok &&
++ (x509 = X509_dup (openssl_session->x509)) == NULL
++ ) {
++ ok = FALSE;
++ PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot duplicate certificate object");
++ }
++
++ PKCS11H_DEBUG (
++ PKCS11H_LOG_DEBUG2,
++ "PKCS#11: pkcs11h_openssl_session_getX509 - return x509=%p",
++ (void *)x509
++ );
++
++ return x509;
++}
++
++#endif /* ENABLE_PKCS11H_OPENSSL */
++
++#if defined(ENABLE_PKCS11H_STANDALONE)
++/*======================================================================*
++ * STANDALONE INTERFACE
++ *======================================================================*/
++
++void
++pkcs11h_standalone_dump_slots (
++ IN const pkcs11h_output_print_t my_output,
++ IN void * const global_data,
++ IN const char * const provider
++) {
++ CK_RV rv = CKR_OK;
++
++ pkcs11h_provider_t pkcs11h_provider;
++
++ PKCS11H_ASSERT (my_output!=NULL);
++ /*PKCS11H_ASSERT (global_data) NOT NEEDED */
++ PKCS11H_ASSERT (provider!=NULL);
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_initialize ()) != CKR_OK
++ ) {
++ my_output (global_data, "PKCS#11: Cannot initialize interface %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_addProvider (
++ provider,
++ provider,
++ FALSE,
++ (
++ PKCS11H_SIGNMODE_MASK_SIGN |
++ PKCS11H_SIGNMODE_MASK_RECOVER
++ ),
++ PKCS11H_SLOTEVENT_METHOD_AUTO,
++ 0,
++ FALSE
++ )) != CKR_OK
++ ) {
++ my_output (global_data, "PKCS#11: Cannot initialize provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
++ }
++
++ /*
++ * our provider is head
++ */
++ if (rv == CKR_OK) {
++ pkcs11h_provider = s_pkcs11h_data->providers;
++ if (pkcs11h_provider == NULL || !pkcs11h_provider->enabled) {
++ my_output (global_data, "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 (global_data, "PKCS#11: Cannot get PKCS#11 provider information %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
++ rv = CKR_OK;
++ }
++ else {
++ char manufacturerID[sizeof (info.manufacturerID)+1];
++
++ _pkcs11h_util_fixupFixedString (
++ manufacturerID,
++ (char *)info.manufacturerID,
++ sizeof (info.manufacturerID)
++ );
++
++ my_output (
++ global_data,
++ (
++ "Provider Information:\n"
++ "\tcryptokiVersion:\t%u.%u\n"
++ "\tmanufacturerID:\t\t%s\n"
++ "\tflags:\t\t\t%08x\n"
++ "\n"
++ ),
++ info.cryptokiVersion.major,
++ info.cryptokiVersion.minor,
++ manufacturerID,
++ (unsigned)info.flags
++ );
++ }
++ }
++
++ if (rv == CKR_OK) {
++ CK_SLOT_ID_PTR slots = NULL;
++ CK_ULONG slotnum;
++ CK_SLOT_ID slot_index;
++
++ if (
++ _pkcs11h_session_getSlotList (
++ pkcs11h_provider,
++ CK_FALSE,
++ &slots,
++ &slotnum
++ ) != CKR_OK
++ ) {
++ my_output (global_data, "PKCS#11: Cannot get slot list %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
++ }
++ else {
++ my_output (
++ global_data,
++ "The following slots are available for use with this provider.\n"
++ );
++
++#if defined(PKCS11H_PRM_SLOT_TYPE)
++ my_output (
++ global_data,
++ (
++ "Each slot shown below may be used as a parameter to a\n"
++ "%s and %s options.\n"
++ ),
++ PKCS11H_PRM_SLOT_TYPE,
++ PKCS11H_PRM_SLOT_ID
++ );
++#endif
++
++ my_output (
++ global_data,
++ (
++ "\n"
++ "Slots: (id - name)\n"
++ )
++ );
++
++ for (slot_index=0;slot_index < slotnum;slot_index++) {
++ CK_SLOT_INFO info;
++
++ if (
++ (rv = pkcs11h_provider->f->C_GetSlotInfo (
++ slots[slot_index],
++ &info
++ )) == CKR_OK
++ ) {
++ char current_name[sizeof (info.slotDescription)+1];
++
++ _pkcs11h_util_fixupFixedString (
++ current_name,
++ (char *)info.slotDescription,
++ sizeof (info.slotDescription)
++ );
++
++ my_output (global_data, "\t%lu - %s\n", slots[slot_index], current_name);
++ }
++ }
++ }
++
++ if (slots != NULL) {
++ _pkcs11h_mem_free ((void *)&slots);
++ }
++ }
++
++ pkcs11h_terminate ();
++}
++
++static
++PKCS11H_BOOL
++_pkcs11h_standalone_dump_objects_pin_prompt (
++ IN void * const global_data,
++ IN void * const user_data,
++ IN const pkcs11h_token_id_t token,
++ IN const unsigned retry,
++ OUT char * const pin,
++ IN const size_t pin_max
++) {
++ (void)user_data;
++ (void)token;
++
++ /*
++ * Don't lock card
++ */
++ if (retry == 0) {
++ strncpy (pin, (char *)global_data, pin_max);
++ return TRUE;
++ }
++ else {
++ return FALSE;
++ }
++}
++
++void
++_pkcs11h_standalone_dump_objects_hex (
++ IN const unsigned char * const p,
++ IN const size_t p_size,
++ OUT char * const sz,
++ IN const size_t max,
++ IN const char * const prefix
++) {
++ size_t j;
++
++ sz[0] = '\0';
++
++ for (j=0;j<p_size;j+=16) {
++ char line[3*16+1];
++ size_t k;
++
++ line[0] = '\0';
++ for (k=0;k<16 && j+k<p_size;k++) {
++ sprintf (line+strlen (line), "%02x ", p[j+k]);
++ }
++
++ strncat (
++ sz,
++ prefix,
++ max-1-strlen (sz)
++ );
++ strncat (
++ sz,
++ line,
++ max-1-strlen (sz)
++ );
++ strncat (
++ sz,
++ "\n",
++ max-1-strlen (sz)
++ );
++ }
++
++ sz[max-1] = '\0';
++}
++
++void
++pkcs11h_standalone_dump_objects (
++ IN const pkcs11h_output_print_t my_output,
++ IN void * const global_data,
++ 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 = NULL;
++ pkcs11h_token_id_t token_id = NULL;
++ pkcs11h_session_t session = NULL;
++
++ PKCS11H_ASSERT (my_output!=NULL);
++ /*PKCS11H_ASSERT (global_data) NOT NEEDED */
++ PKCS11H_ASSERT (provider!=NULL);
++ PKCS11H_ASSERT (slot!=NULL);
++ PKCS11H_ASSERT (pin!=NULL);
++
++ s = atoi (slot);
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_initialize ()) != CKR_OK
++ ) {
++ my_output (global_data, "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 (global_data, "PKCS#11: Cannot set hooks %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
++ }
++
++ if (
++ rv == CKR_OK &&
++ (rv = pkcs11h_addProvider (
++ provider,
++ provider,
++ FALSE,
++ (
++ PKCS11H_SIGNMODE_MASK_SIGN |
++ PKCS11H_SIGNMODE_MASK_RECOVER
++ ),
++ PKCS11H_SLOTEVENT_METHOD_AUTO,
++ 0,
++ FALSE
++ )) != CKR_OK
++ ) {
++ my_output (global_data, "PKCS#11: Cannot initialize provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
++ }
++
++ /*
++ * our provider is head
++ */
++ if (rv == CKR_OK) {
++ pkcs11h_provider = s_pkcs11h_data->providers;
++ if (pkcs11h_provider == NULL || !pkcs11h_provider->enabled) {
++ my_output (global_data, "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 (global_data, "PKCS#11: Cannot get token information for slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv));
++ /* Ignore this error */
++ rv = CKR_OK;
++ }
++ else {
++ char label[sizeof (info.label)+1];
++ char manufacturerID[sizeof (info.manufacturerID)+1];
++ char model[sizeof (info.model)+1];
++ char serialNumberNumber[sizeof (info.serialNumber)+1];
++
++ _pkcs11h_util_fixupFixedString (
++ label,
++ (char *)info.label,
++ sizeof (info.label)
++ );
++ _pkcs11h_util_fixupFixedString (
++ manufacturerID,
++ (char *)info.manufacturerID,
++ sizeof (info.manufacturerID)
++ );
++ _pkcs11h_util_fixupFixedString (
++ model,
++ (char *)info.model,
++ sizeof (info.model)
++ );
++ _pkcs11h_util_fixupFixedString (
++ serialNumberNumber,
++ (char *)info.serialNumber,
++ sizeof (info.serialNumber)
++ );
++
++ my_output (
++ global_data,
++ (
++ "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"
++ ),
++ label,
++ manufacturerID,
++ model,
++ serialNumberNumber,
++ (unsigned)info.flags
++ );
++
++#if defined(PKCS11H_PRM_SLOT_TYPE)
++ my_output (
++ global_data,
++ (
++ "You can access this token using\n"
++ "%s \"label\" %s \"%s\" options.\n"
++ "\n"
++ ),
++ PKCS11H_PRM_SLOT_TYPE,
++ PKCS11H_PRM_SLOT_ID,
++ label
++ );
++#endif
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_token_getTokenId (
++ &info,
++ &token_id
++ )) != CKR_OK
++ ) {
++ my_output (global_data, "PKCS#11: Cannot get token id for slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv));
++ rv = CKR_OK;
++ }
++ }
++ }
++
++ if (token_id != NULL) {
++ if (
++ (rv = _pkcs11h_session_getSessionByTokenId (
++ token_id,
++ &session
++ )) != CKR_OK
++ ) {
++ my_output (global_data, "PKCS#11: Cannot session for token '%s' %ld-'%s'\n", token_id->display, rv, pkcs11h_getMessage (rv));
++ rv = CKR_OK;
++ }
++ }
++
++ if (session != NULL) {
++ CK_OBJECT_HANDLE *objects = NULL;
++ CK_ULONG objects_found = 0;
++ CK_ULONG i;
++
++ if (
++ (rv = _pkcs11h_session_login (
++ session,
++ FALSE,
++ TRUE,
++ NULL,
++ PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT
++ )) != CKR_OK
++ ) {
++ my_output (global_data, "PKCS#11: Cannot open session to token '%s' %ld-'%s'\n", session->token_id->display, rv, pkcs11h_getMessage (rv));
++ }
++
++ my_output (
++ global_data,
++ "The following objects are available for use with this token.\n"
++ );
++
++#if defined(PKCS11H_PRM_OBJ_TYPE)
++ my_output (
++ global_data,
++ (
++ "Each object shown below may be used as a parameter to\n"
++ "%s and %s options.\n"
++ ),
++ PKCS11H_PRM_OBJ_TYPE,
++ PKCS11H_PRM_OBJ_ID
++ );
++#endif
++
++ my_output (
++ global_data,
++ "\n"
++ );
++
++ if (
++ rv == CKR_OK &&
++ (rv = _pkcs11h_session_findObjects (
++ session,
++ NULL,
++ 0,
++ &objects,
++ &objects_found
++ )) != CKR_OK
++ ) {
++ my_output (global_data, "PKCS#11: Cannot query objects for token '%s' %ld-'%s'\n", session->token_id->display, rv, pkcs11h_getMessage (rv));
++ }
++
++ for (i=0;rv == CKR_OK && i < objects_found;i++) {
++ CK_OBJECT_CLASS attrs_class = 0;
++ CK_ATTRIBUTE attrs[] = {
++ {CKA_CLASS, &attrs_class, sizeof (attrs_class)}
++ };
++
++ if (
++ _pkcs11h_session_getObjectAttributes (
++ session,
++ objects[i],
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ ) == CKR_OK
++ ) {
++ if (attrs_class == CKO_CERTIFICATE) {
++ CK_ATTRIBUTE attrs_cert[] = {
++ {CKA_ID, NULL, 0},
++ {CKA_LABEL, NULL, 0},
++ {CKA_VALUE, NULL, 0}
++ };
++ unsigned char *attrs_id = NULL;
++ int attrs_id_size = 0;
++ unsigned char *attrs_value = NULL;
++ int attrs_value_size = 0;
++ char *attrs_label = NULL;
++ char hex_id[1024];
++ char subject[1024];
++ char serialNumber[1024];
++ time_t notAfter = 0;
++
++ subject[0] = '\0';
++ serialNumber[0] = '\0';
++
++
++ if (
++ _pkcs11h_session_getObjectAttributes (
++ session,
++ objects[i],
++ attrs_cert,
++ sizeof (attrs_cert) / sizeof (CK_ATTRIBUTE)
++ ) == CKR_OK &&
++ _pkcs11h_mem_malloc (
++ (void *)&attrs_label,
++ attrs_cert[1].ulValueLen+1
++ ) == CKR_OK
++ ) {
++ attrs_id = (unsigned char *)attrs_cert[0].pValue;
++ attrs_id_size = attrs_cert[0].ulValueLen;
++ attrs_value = (unsigned char *)attrs_cert[2].pValue;
++ attrs_value_size = attrs_cert[2].ulValueLen;
++
++ memset (attrs_label, 0, attrs_cert[1].ulValueLen+1);
++ memmove (attrs_label, attrs_cert[1].pValue, attrs_cert[1].ulValueLen);
++ _pkcs11h_standalone_dump_objects_hex (
++ attrs_id,
++ attrs_id_size,
++ hex_id,
++ sizeof (hex_id),
++ "\t\t"
++ );
++ }
++
++ if (attrs_value != NULL) {
++#if defined(USE_PKCS11H_OPENSSL)
++ X509 *x509 = NULL;
++ BIO *bioSerial = NULL;
++#elif defined(USE_PKCS11H_GNUTLS)
++ gnutls_x509_crt_t cert = NULL;
++#endif
++
++ _pkcs11h_certificate_getDN (
++ attrs_value,
++ attrs_value_size,
++ subject,
++ sizeof (subject)
++ );
++ notAfter = _pkcs11h_certificate_getExpiration (
++ attrs_value,
++ attrs_value_size
++ );
++#if defined(USE_PKCS11H_OPENSSL)
++ if ((x509 = X509_new ()) == NULL) {
++ my_output (global_data, "Cannot create x509 context\n");
++ }
++ else {
++ pkcs11_openssl_d2i_t d2i1 = (pkcs11_openssl_d2i_t)attrs_value;
++ if (d2i_X509 (&x509, &d2i1, attrs_value_size)) {
++ if ((bioSerial = BIO_new (BIO_s_mem ())) == NULL) {
++ my_output (global_data, "Cannot create BIO context\n");
++ }
++ else {
++ int n;
++
++ i2a_ASN1_INTEGER(bioSerial, X509_get_serialNumber (x509));
++ n = BIO_read (bioSerial, serialNumber, sizeof (serialNumber)-1);
++ if (n<0) {
++ serialNumber[0] = '\0';
++ }
++ else {
++ serialNumber[n] = '\0';
++ }
++ }
++ }
++ }
++
++
++ if (bioSerial != NULL) {
++ BIO_free_all (bioSerial);
++ bioSerial = NULL;
++ }
++ if (x509 != NULL) {
++ X509_free (x509);
++ x509 = NULL;
++ }
++#elif defined(USE_PKCS11H_GNUTLS)
++ if (gnutls_x509_crt_init (&cert) == GNUTLS_E_SUCCESS) {
++ gnutls_datum_t datum = {attrs_value, attrs_value_size};
++
++ if (gnutls_x509_crt_import (cert, &datum, GNUTLS_X509_FMT_DER) == GNUTLS_E_SUCCESS) {
++ unsigned char ser[1024];
++ size_t ser_size = sizeof (ser);
++ if (gnutls_x509_crt_get_serial (cert, ser, &ser_size) == GNUTLS_E_SUCCESS) {
++ _pkcs11h_util_binaryToHex (
++ serialNumber,
++ sizeof (serialNumber),
++ ser,
++ ser_size
++ );
++ }
++ }
++ gnutls_x509_crt_deinit (cert);
++ }
++#else
++#error Invalid configuration.
++#endif
++ }
++
++ my_output (
++ global_data,
++ (
++ "Object\n"
++ "\tType:\t\t\tCertificate\n"
++ "\tCKA_ID:\n"
++ "%s"
++ "\tCKA_LABEL:\t\t%s\n"
++ "\tsubject:\t\t%s\n"
++ "\tserialNumber:\t\t%s\n"
++ "\tnotAfter:\t\t%s\n"
++ ),
++ hex_id,
++ attrs_label,
++ subject,
++ serialNumber,
++ asctime (localtime (¬After))
++ );
++
++ _pkcs11h_mem_free ((void *)&attrs_label);
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs_cert,
++ sizeof (attrs_cert) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++ else if (attrs_class == CKO_PRIVATE_KEY) {
++ CK_BBOOL sign_recover = CK_FALSE;
++ CK_BBOOL sign = CK_FALSE;
++ CK_ATTRIBUTE attrs_key[] = {
++ {CKA_SIGN, &sign, sizeof (sign)},
++ {CKA_SIGN_RECOVER, &sign_recover, sizeof (sign_recover)}
++ };
++ CK_ATTRIBUTE attrs_key_common[] = {
++ {CKA_ID, NULL, 0},
++ {CKA_LABEL, NULL, 0}
++ };
++ unsigned char *attrs_id = NULL;
++ int attrs_id_size = 0;
++ char *attrs_label = NULL;
++ char hex_id[1024];
++
++ pkcs11h_provider->f->C_GetAttributeValue (
++ session->session_handle,
++ objects[i],
++ attrs_key,
++ sizeof (attrs_key) / sizeof (CK_ATTRIBUTE)
++ );
++
++ if (
++ _pkcs11h_session_getObjectAttributes (
++ session,
++ objects[i],
++ attrs_key_common,
++ sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
++ ) == CKR_OK &&
++ _pkcs11h_mem_malloc (
++ (void *)&attrs_label,
++ attrs_key_common[1].ulValueLen+1
++ ) == CKR_OK
++ ) {
++ attrs_id = (unsigned char *)attrs_key_common[0].pValue;
++ attrs_id_size = attrs_key_common[0].ulValueLen;
++
++ memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1);
++ memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen);
++
++ _pkcs11h_standalone_dump_objects_hex (
++ attrs_id,
++ attrs_id_size,
++ hex_id,
++ sizeof (hex_id),
++ "\t\t"
++ );
++
++ }
++
++ my_output (
++ global_data,
++ (
++ "Object\n"
++ "\tType:\t\t\tPrivate Key\n"
++ "\tCKA_ID:\n"
++ "%s"
++ "\tCKA_LABEL:\t\t%s\n"
++ "\tCKA_SIGN:\t\t%s\n"
++ "\tCKA_SIGN_RECOVER:\t%s\n"
++ ),
++ hex_id,
++ attrs_label,
++ sign ? "TRUE" : "FALSE",
++ sign_recover ? "TRUE" : "FALSE"
++ );
++
++ _pkcs11h_mem_free ((void *)&attrs_label);
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs_key_common,
++ sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++ else if (attrs_class == CKO_PUBLIC_KEY) {
++ CK_ATTRIBUTE attrs_key_common[] = {
++ {CKA_ID, NULL, 0},
++ {CKA_LABEL, NULL, 0}
++ };
++ unsigned char *attrs_id = NULL;
++ int attrs_id_size = 0;
++ char *attrs_label = NULL;
++ char hex_id[1024];
++
++ if (
++ _pkcs11h_session_getObjectAttributes (
++ session,
++ objects[i],
++ attrs_key_common,
++ sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
++ ) == CKR_OK &&
++ _pkcs11h_mem_malloc (
++ (void *)&attrs_label,
++ attrs_key_common[1].ulValueLen+1
++ ) == CKR_OK
++ ) {
++ attrs_id = (unsigned char *)attrs_key_common[0].pValue;
++ attrs_id_size = attrs_key_common[0].ulValueLen;
++
++ memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1);
++ memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen);
++
++ _pkcs11h_standalone_dump_objects_hex (
++ attrs_id,
++ attrs_id_size,
++ hex_id,
++ sizeof (hex_id),
++ "\t\t"
++ );
++
++ }
++
++ my_output (
++ global_data,
++ (
++ "Object\n"
++ "\tType:\t\t\tPublic Key\n"
++ "\tCKA_ID:\n"
++ "%s"
++ "\tCKA_LABEL:\t\t%s\n"
++ ),
++ hex_id,
++ attrs_label
++ );
++
++ _pkcs11h_mem_free ((void *)&attrs_label);
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs_key_common,
++ sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++ else if (attrs_class == CKO_DATA) {
++ CK_ATTRIBUTE attrs_key_common[] = {
++ {CKA_APPLICATION, NULL, 0},
++ {CKA_LABEL, NULL, 0}
++ };
++ char *attrs_application = NULL;
++ char *attrs_label = NULL;
++
++ if (
++ _pkcs11h_session_getObjectAttributes (
++ session,
++ objects[i],
++ attrs_key_common,
++ sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
++ ) == CKR_OK &&
++ _pkcs11h_mem_malloc (
++ (void *)&attrs_application,
++ attrs_key_common[0].ulValueLen+1
++ ) == CKR_OK &&
++ _pkcs11h_mem_malloc (
++ (void *)&attrs_label,
++ attrs_key_common[1].ulValueLen+1
++ ) == CKR_OK
++ ) {
++ memset (attrs_application, 0, attrs_key_common[0].ulValueLen+1);
++ memmove (attrs_application, attrs_key_common[0].pValue, attrs_key_common[0].ulValueLen);
++ memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1);
++ memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen);
++ }
++
++ my_output (
++ global_data,
++ (
++ "Object\n"
++ "\tType:\t\t\tData\n"
++ "\tCKA_APPLICATION\t\t%s\n"
++ "\tCKA_LABEL:\t\t%s\n"
++ ),
++ attrs_application,
++ attrs_label
++ );
++
++ _pkcs11h_mem_free ((void *)&attrs_application);
++ _pkcs11h_mem_free ((void *)&attrs_label);
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs_key_common,
++ sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
++ );
++ }
++ else {
++ my_output (
++ global_data,
++ (
++ "Object\n"
++ "\tType:\t\t\tUnsupported\n"
++ )
++ );
++ }
++ }
++
++ _pkcs11h_session_freeObjectAttributes (
++ attrs,
++ sizeof (attrs) / sizeof (CK_ATTRIBUTE)
++ );
++
++ /*
++ * Ignore any error and
++ * perform next iteration
++ */
++ rv = CKR_OK;
++ }
++
++ if (objects != NULL) {
++ _pkcs11h_mem_free ((void *)&objects);
++ }
++
++ /*
++ * Ignore this error
++ */
++ rv = CKR_OK;
++ }
++
++ if (session != NULL) {
++ _pkcs11h_session_release (session);
++ session = NULL;
++ }
++
++ if (token_id != NULL) {
++ pkcs11h_token_freeTokenId (token_id);
++ token_id = NULL;
++ }
++
++ pkcs11h_terminate ();
++}
++
++#endif /* ENABLE_PKCS11H_STANDALONE */
++
++#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 /* PKCS11H_HELPER_ENABLE */
++
+diff -urNp openssh-4.4p1/pkcs11-helper-config.h openssh-4.4p1+pkcs11-0.17/pkcs11-helper-config.h
+--- openssh-4.4p1/pkcs11-helper-config.h 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/pkcs11-helper-config.h 2006-10-12 16:43:38.000000000 +0200
+@@ -0,0 +1,103 @@
++/*
++ * Copyright (c) 2005-2006 Alon Bar-Lev. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 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.
++ */
++
++#ifndef __PKCS11H_HELPER_CONFIG_H
++#define __PKCS11H_HELPER_CONFIG_H
++
++#if !defined(PKCS11H_NO_NEED_INCLUDE_CONFIG)
++
++#include "includes.h"
++
++#endif /* PKCS11H_NO_NEED_INCLUDE_CONFIG */
++
++#ifndef SSH_PKCS11H_DISABLED
++#define ENABLE_PKCS11H_HELPER
++#endif
++
++#include <assert.h>
++#include <string.h>
++#include <ctype.h>
++#if !defined(WIN32)
++#include <unistd.h>
++#include <dlfcn.h>
++#endif
++
++#include "log.h"
++#include "xmalloc.h"
++#include "openssl/x509.h"
++
++#if defined(HAVE_CYGWIN)
++#define PKCS11H_USE_CYGWIN
++#endif
++
++#if !defined(FALSE)
++#define FALSE 0
++#endif
++#if !defined(TRUE)
++#define TRUE (!FALSE)
++#endif
++
++typedef int PKCS11H_BOOL;
++
++#if !defined(IN)
++#define IN
++#endif
++#if !defined(OUT)
++#define OUT
++#endif
++
++#define USE_PKCS11H_OPENSSL
++#define ENABLE_PKCS11H_DEBUG
++#undef ENABLE_PKCS11H_THREADING
++#undef ENABLE_PKCS11H_TOKEN
++#undef ENABLE_PKCS11H_DATA
++#define ENABLE_PKCS11H_CERTIFICATE
++#undef ENABLE_PKCS11H_LOCATE
++#define ENABLE_PKCS11H_ENUM
++#define ENABLE_PKCS11H_SERIALIZATION
++#undef ENABLE_PKCS11H_SLOTEVENT
++#define ENABLE_PKCS11H_OPENSSL
++#define ENABLE_PKCS11H_STANDALONE
++
++/*
++#define PKCS11H_PRM_SLOT_TYPE "--pkcs11-slot-type"
++#define PKCS11H_PRM_SLOT_ID "--pkcs11-slot"
++#define PKCS11H_PRM_OBJ_TYPE "--pkcs11-id-type"
++#define PKCS11H_PRM_OBJ_ID "--pkcs11-id"
++*/
++
++#define PKCS11H_ASSERT assert
++#define PKCS11H_TIME time
++#define PKCS11H_MALLOC xmalloc
++#define PKCS11H_FREE xfree
++
++#ifdef ENABLE_PKCS11H_HELPER
++#if defined(WIN32) || defined(PKCS11H_USE_CYGWIN)
++#include "cryptoki-win32.h"
++#else
++#include "cryptoki.h"
++#endif
++
++#endif /* ENABLE_PKCS11H_HELPER */
++#endif /* __PKCS11H_HELPER_CONFIG_H */
+diff -urNp openssh-4.4p1/pkcs11-helper.h openssh-4.4p1+pkcs11-0.17/pkcs11-helper.h
+--- openssh-4.4p1/pkcs11-helper.h 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/pkcs11-helper.h 2006-10-22 17:11:14.000000000 +0200
+@@ -0,0 +1,1303 @@
++/*
++ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev@gmail.com>
++ * All rights reserved.
++ *
++ * This software is available to you under a choice of one of two
++ * licenses. You may choose to be licensed under the terms of the GNU
++ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
++ *
++ * GNU General Public License (GPL) Version 2
++ * ===========================================
++ * 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[.GPL2] included with this
++ * distribution); if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * OpenIB.org BSD license
++ * =======================
++ * 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 __PKCS11H_HELPER_H
++#define __PKCS11H_HELPER_H
++
++#if defined(__cplusplus)
++extern "C" {
++#endif
++
++#include "pkcs11-helper-config.h"
++
++#if !defined(USE_PKCS11H_OPENSSL) && !defined(USE_PKCS11H_GNUTLS)
++#error PKCS#11: USE_PKCS11H_OPENSSL or USE_PKCS11H_GNUTLS must be defined
++#endif
++
++#if defined(ENABLE_PKCS11H_SLOTEVENT) && !defined(ENABLE_PKCS11H_THREADING)
++#error PKCS#11: ENABLE_PKCS11H_SLOTEVENT requires ENABLE_PKCS11H_THREADING
++#endif
++#if defined(ENABLE_PKCS11H_OPENSSL) && !defined(ENABLE_PKCS11H_CERTIFICATE)
++#error PKCS#11: ENABLE_PKCS11H_OPENSSL requires ENABLE_PKCS11H_CERTIFICATE
++#endif
++
++#define PKCS11H_LOG_DEBUG2 5
++#define PKCS11H_LOG_DEBUG1 4
++#define PKCS11H_LOG_INFO 3
++#define PKCS11H_LOG_WARN 2
++#define PKCS11H_LOG_ERROR 1
++#define PKCS11H_LOG_QUITE 0
++
++#define PKCS11H_PIN_CACHE_INFINITE -1
++
++#define PKCS11H_SIGNMODE_MASK_SIGN (1<<0)
++#define PKCS11H_SIGNMODE_MASK_RECOVER (1<<1)
++
++#define PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT (1<<0)
++#define PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT (1<<1)
++#define PKCS11H_PROMPT_MASK_ALLOW_ALL ( \
++ PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT | \
++ PKCS11H_PROMPT_MAST_ALLOW_CARD_PROMPT \
++ )
++
++#define PKCS11H_SLOTEVENT_METHOD_AUTO 0
++#define PKCS11H_SLOTEVENT_METHOD_TRIGGER 1
++#define PKCS11H_SLOTEVENT_METHOD_POLL 2
++
++#define PKCS11H_ENUM_METHOD_CACHE 0
++#define PKCS11H_ENUM_METHOD_CACHE_EXIST 1
++#define PKCS11H_ENUM_METHOD_RELOAD 2
++
++typedef void (*pkcs11h_output_print_t)(
++ IN void * const global_data,
++ IN const char * const format,
++ IN ...
++)
++#if __GNUC__ > 2
++ __attribute__ ((format (printf, 2, 3)))
++#endif
++ ;
++
++struct pkcs11h_token_id_s;
++typedef struct pkcs11h_token_id_s *pkcs11h_token_id_t;
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++
++struct pkcs11h_certificate_id_s;
++struct pkcs11h_certificate_s;
++typedef struct pkcs11h_certificate_id_s *pkcs11h_certificate_id_t;
++typedef struct pkcs11h_certificate_s *pkcs11h_certificate_t;
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#if defined(ENABLE_PKCS11H_ENUM)
++
++struct pkcs11h_token_id_list_s;
++typedef struct pkcs11h_token_id_list_s *pkcs11h_token_id_list_t;
++
++#if defined(ENABLE_PKCS11H_DATA)
++
++struct pkcs11h_data_id_list_s;
++typedef struct pkcs11h_data_id_list_s *pkcs11h_data_id_list_t;
++
++#endif /* ENABLE_PKCS11H_DATA */
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++
++struct pkcs11h_certificate_id_list_s;
++typedef struct pkcs11h_certificate_id_list_s *pkcs11h_certificate_id_list_t;
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#endif /* ENABLE_PKCS11H_ENUM */
++
++typedef void (*pkcs11h_hook_log_t)(
++ IN void * const global_data,
++ IN const unsigned flags,
++ IN const char * const format,
++ IN va_list args
++);
++
++typedef void (*pkcs11h_hook_slotevent_t)(
++ IN void * const global_data
++);
++
++typedef PKCS11H_BOOL (*pkcs11h_hook_token_prompt_t)(
++ IN void * const global_data,
++ IN void * const user_data,
++ IN const pkcs11h_token_id_t token,
++ IN const unsigned retry
++);
++
++typedef PKCS11H_BOOL (*pkcs11h_hook_pin_prompt_t)(
++ IN void * const global_data,
++ IN void * const user_data,
++ IN const pkcs11h_token_id_t token,
++ IN const unsigned retry,
++ OUT char * const pin,
++ IN const size_t pin_max
++);
++
++struct pkcs11h_token_id_s {
++ char display[1024];
++ char manufacturerID[sizeof (((CK_TOKEN_INFO *)NULL)->manufacturerID)+1];
++ char model[sizeof (((CK_TOKEN_INFO *)NULL)->model)+1];
++ char serialNumber[sizeof (((CK_TOKEN_INFO *)NULL)->serialNumber)+1];
++ char label[sizeof (((CK_TOKEN_INFO *)NULL)->label)+1];
++};
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++
++struct pkcs11h_certificate_id_s {
++ pkcs11h_token_id_t token_id;
++
++ char displayName[1024];
++ CK_BYTE_PTR attrCKA_ID;
++ size_t attrCKA_ID_size;
++
++ unsigned char *certificate_blob;
++ size_t certificate_blob_size;
++};
++
++#endif
++
++#if defined(ENABLE_PKCS11H_ENUM)
++
++struct pkcs11h_token_id_list_s {
++ pkcs11h_token_id_list_t next;
++ pkcs11h_token_id_t token_id;
++};
++
++#if defined(ENABLE_PKCS11H_DATA)
++
++struct pkcs11h_data_id_list_s {
++ pkcs11h_data_id_list_t next;
++
++ char *application;
++ char *label;
++};
++
++#endif /* ENABLE_PKCS11H_DATA */
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++
++struct pkcs11h_certificate_id_list_s {
++ pkcs11h_certificate_id_list_t next;
++ pkcs11h_certificate_id_t certificate_id;
++};
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#if defined(ENABLE_PKCS11H_OPENSSL)
++
++typedef void (*pkcs11h_hook_openssl_cleanup_t) (
++ IN const pkcs11h_certificate_t certificate
++);
++
++struct pkcs11h_openssl_session_s;
++typedef struct pkcs11h_openssl_session_s *pkcs11h_openssl_session_t;
++
++#endif /* ENABLE_PKCS11H_OPENSSL */
++
++/*
++ * pkcs11h_getMessage - Get message by return value.
++ *
++ * Parameters:
++ * rv - Return value.
++ */
++const char *
++pkcs11h_getMessage (
++ IN const CK_RV rv
++);
++
++/*
++ * pkcs11h_initialize - Inititalize helper interface.
++ *
++ * Must be called once, from main thread.
++ * Defaults:
++ * Protected authentication enabled.
++ * PIN cached is infinite.
++ */
++CK_RV
++pkcs11h_initialize ();
++
++/*
++ * pkcs11h_terminate - Terminate helper interface.
++ *
++ * Must be called once, from main thread, after all
++ * related resources freed.
++ */
++CK_RV
++pkcs11h_terminate ();
++
++/*
++ * pkcs11h_setLogLevel - Set current log level of the helper.
++ *
++ * Parameters:
++ * flags - current log level.
++ *
++ * The log level can be set to maximum, but setting it to lower
++ * level will improve performance.
++ */
++void
++pkcs11h_setLogLevel (
++ IN const unsigned flags
++);
++
++/*
++ * pkcs11h_getLogLevel - Get current log level.
++ */
++unsigned
++pkcs11h_getLogLevel ();
++
++/*
++ * pkcs11h_setLogHook - Set a log callback.
++ *
++ * Parameters:
++ * hook - Callback.
++ * pData - Data to send to callback.
++ */
++CK_RV
++pkcs11h_setLogHook (
++ IN const pkcs11h_hook_log_t hook,
++ IN void * const global_data
++);
++
++/*
++ * pkcs11h_setSlotEventHook - Set a slot event callback.
++ *
++ * Parameters:
++ * hook - Callback.
++ * pData - Data to send to callback.
++ *
++ * Calling this function initialize slot event notifications, these
++ * notifications can be started, but never terminate due to PKCS#11 limitation.
++ *
++ * In order to use slot events you must have threading enabled.
++ */
++CK_RV
++pkcs11h_setSlotEventHook (
++ IN const pkcs11h_hook_slotevent_t hook,
++ IN void * const global_data
++);
++
++/*
++ * pkcs11h_setTokenPromptHook - Set a token prompt callback.
++ *
++ * Parameters:
++ * hook - Callback.
++ * pData - Data to send to callback.
++ */
++CK_RV
++pkcs11h_setTokenPromptHook (
++ IN const pkcs11h_hook_token_prompt_t hook,
++ IN void * const global_data
++);
++
++/*
++ * pkcs11h_setPINPromptHook - Set a pin prompt callback.
++ *
++ * Parameters:
++ * hook - Callback.
++ * pData - Data to send to callback.
++ */
++CK_RV
++pkcs11h_setPINPromptHook (
++ IN const pkcs11h_hook_pin_prompt_t hook,
++ IN void * const global_data
++);
++
++/*
++ * pkcs11h_setProtectedAuthentication - Set global protected authentication mode.
++ *
++ * Parameters:
++ * allow_protected_auth - Allow protected authentication if enabled by token.
++ */
++CK_RV
++pkcs11h_setProtectedAuthentication (
++ IN const PKCS11H_BOOL allow_protected_auth
++);
++
++/*
++ * pkcs11h_setPINCachePeriod - Set global PIN cache timeout.
++ *
++ * Parameters:
++ * pin_cache_period - Cache period in seconds, or PKCS11H_PIN_CACHE_INFINITE.
++ */
++CK_RV
++pkcs11h_setPINCachePeriod (
++ IN const int pin_cache_period
++);
++
++/*
++ * pkcs11h_setMaxLoginRetries - Set global login retries attempts.
++ *
++ * Parameters:
++ * max_retries - Login retries handled by the helper.
++ */
++CK_RV
++pkcs11h_setMaxLoginRetries (
++ IN const unsigned max_retries
++);
++
++/*
++ * pkcs11h_addProvider - Add a PKCS#11 provider.
++ *
++ * Parameters:
++ * reference - Reference name for this provider.
++ * provider - Provider library location.
++ * allow_protected_auth - Allow this provider to use protected authentication.
++ * mask_sign_mode - Provider signmode override.
++ * slot_event_method - Provider slot event method.
++ * slot_poll_interval - Slot event poll interval (If in polling mode).
++ * cert_is_private - Provider's certificate access should be done after login.
++ *
++ * This function must be called from the main thread.
++ *
++ * The global allow_protected_auth must be enabled in order to allow provider specific.
++ * The mask_sign_mode can be 0 in order to automatically detect key sign mode.
++ */
++CK_RV
++pkcs11h_addProvider (
++ IN const char * const reference,
++ IN const char * const provider_location,
++ IN const PKCS11H_BOOL allow_protected_auth,
++ IN const unsigned mask_sign_mode,
++ IN const int slot_event_method,
++ IN const int slot_poll_interval,
++ IN const PKCS11H_BOOL cert_is_private
++);
++
++/*
++ * pkcs11h_delProvider - Delete a PKCS#11 provider.
++ *
++ * Parameters:
++ * reference - Reference name for this provider.
++ *
++ * This function must be called from the main thread.
++ */
++CK_RV
++pkcs11h_removeProvider (
++ IN const char * const reference
++);
++
++/*
++ * pkcs11h_forkFixup - Handle special case of Unix fork()
++ *
++ * This function should be called after fork is called. This is required
++ * due to a limitation of the PKCS#11 standard.
++ *
++ * This function must be called from the main thread.
++ *
++ * The helper library handles fork automatically if ENABLE_PKCS11H_THREADING
++ * is set on configuration file, by use of pthread_atfork.
++ */
++CK_RV
++pkcs11h_forkFixup ();
++
++/*
++ * pkcs11h_plugAndPlay - Handle slot rescan.
++ *
++ * This function must be called from the main thread.
++ *
++ * PKCS#11 providers do not allow plug&play, plug&play can be established by
++ * finalizing all providers and initializing them again.
++ *
++ * The cost of this process is invalidating all sessions, and require user
++ * login at the next access.
++ */
++CK_RV
++pkcs11h_plugAndPlay ();
++
++/*
++ * pkcs11h_token_freeTokenId - Free token_id object.
++ *
++ * Parameters:
++ * token_id - token_id.
++ */
++CK_RV
++pkcs11h_token_freeTokenId (
++ IN pkcs11h_token_id_t token_id
++);
++
++/*
++ * pkcs11h_duplicateTokenId - Duplicate token_id object.
++ *
++ * Parameters:
++ * to - target.
++ * from - source.
++ */
++CK_RV
++pkcs11h_token_duplicateTokenId (
++ OUT pkcs11h_token_id_t * const to,
++ IN const pkcs11h_token_id_t from
++);
++
++/*
++ * pkcs11h_sameTokenId - Returns TRUE if same token id
++ *
++ * Parameters:
++ * a - a.
++ * b - b.
++ */
++PKCS11H_BOOL
++pkcs11h_token_sameTokenId (
++ IN const pkcs11h_token_id_t a,
++ IN const pkcs11h_token_id_t b
++);
++
++/*
++ * pkcs11h_token_login - Force login, avoid hooks.
++ *
++ * Parameters:
++ * token_id - Token to login into.
++ * readonly - Should session be readonly.
++ * pin - PIN to login, NULL for protected authentication
++ */
++CK_RV
++pkcs11h_token_login (
++ IN const pkcs11h_token_id_t token_id,
++ IN const PKCS11H_BOOL readonly,
++ IN const char * const pin
++);
++
++#if defined(ENABLE_PKCS11H_SERIALIZATION)
++
++/*
++ * pkcs11h_serializeTokenId - Serialize token_id into string.
++ *
++ * Parameters:
++ * sz - Output string.
++ * max - Maximum string size.
++ * token_id - id to serialize
++ *
++ * sz may be NULL to get size
++ */
++CK_RV
++pkcs11h_token_serializeTokenId (
++ OUT char * const sz,
++ IN OUT size_t *max,
++ IN const pkcs11h_token_id_t token_id
++);
++
++/*
++ * pkcs11h_deserializeTokenId - Deserialize token_id from string.
++ *
++ * Parameters:
++ * p_token_id - id.
++ * sz - Input string
++ */
++CK_RV
++pkcs11h_token_deserializeTokenId (
++ OUT pkcs11h_token_id_t *p_token_id,
++ IN const char * const sz
++);
++
++#endif /* ENABLE_PKCS11H_SERIALIZATION */
++
++#if defined(ENABLE_PKCS11H_TOKEN)
++
++/*
++ * pkcs11h_token_ensureAccess - Ensure token is accessible.
++ *
++ * Parameters:
++ * token_id - Token id object.
++ * user_data - Optional user data, to be passed to hooks.
++ * mask_prompt - Allow prompt.
++ */
++CK_RV
++pkcs11h_token_ensureAccess (
++ IN const pkcs11h_token_id_t token_id,
++ IN void * const user_data,
++ IN const unsigned mask_prompt
++);
++
++#endif /* ENABLE_PKCS11H_TOKEN */
++
++#if defined(ENABLE_PKCS11H_DATA)
++
++/*
++ * pkcs11h_data_get - get data object.
++ *
++ * Parameters:
++ * token_id - Token id object.
++ * is_public - Object is public.
++ * application - Object application attribute.
++ * label - Object label attribute.
++ * user_data - Optional user data, to be passed to hooks.
++ * mask_prompt - Allow prompt.
++ * blob - blob, set to NULL to get size.
++ * p_blob_size - blob size.
++ */
++CK_RV
++pkcs11h_data_get (
++ IN const pkcs11h_token_id_t token_id,
++ IN const PKCS11H_BOOL is_public,
++ IN const char * const application,
++ IN const char * const label,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT unsigned char * const blob,
++ IN OUT size_t * const p_blob_size
++);
++
++/*
++ * pkcs11h_data_put - put data object.
++ *
++ * Parameters:
++ * token_id - Token id object.
++ * is_public - Object is public.
++ * application - Object application attribute.
++ * label - Object label attribute.
++ * user_data - Optional user data, to be passed to hooks.
++ * mask_prompt - Allow prompt.
++ * blob - blob.
++ * blob_size - blob size.
++ */
++CK_RV
++pkcs11h_data_put (
++ IN const pkcs11h_token_id_t token_id,
++ IN const PKCS11H_BOOL is_public,
++ IN const char * const application,
++ IN const char * const label,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT unsigned char * const blob,
++ IN const size_t blob_size
++);
++
++/*
++ * pkcs11h_data_del - delete data object.
++ *
++ * Parameters:
++ * token_id - Token id object.
++ * is_public - Object is public.
++ * application - Object application attribute.
++ * label - Object label attribute.
++ * user_data - Optional user data, to be passed to hooks.
++ * mask_prompt - Allow prompt.
++ */
++CK_RV
++pkcs11h_data_del (
++ IN const pkcs11h_token_id_t token_id,
++ IN const PKCS11H_BOOL is_public,
++ IN const char * const application,
++ IN const char * const label,
++ IN void * const user_data,
++ IN const unsigned mask_prompt
++);
++
++#endif /* ENABLE_PKCS11H_DATA */
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++/*======================================================================*
++ * CERTIFICATE INTERFACE
++ *======================================================================*/
++
++/*
++ * pkcs11h_certificate_freeCertificateId - Free certificate_id object.
++ */
++CK_RV
++pkcs11h_certificate_freeCertificateId (
++ IN pkcs11h_certificate_id_t certificate_id
++);
++
++/*
++ * pkcs11h_duplicateCertificateId - Duplicate certificate_id object.
++ */
++CK_RV
++pkcs11h_certificate_duplicateCertificateId (
++ OUT pkcs11h_certificate_id_t * const to,
++ IN const pkcs11h_certificate_id_t from
++);
++
++/*
++ * pkcs11h_certificate_setCertificateIdCertificateBlob - Sets internal certificate_id blob.
++ *
++ * Parameters:
++ * certificate_id - Certificate id ojbect.
++ * blob - blob.
++ * blob_size - blob size.
++ *
++ * Useful to set after deserialization so certificate is available and not read from token.
++ */
++CK_RV
++pkcs11h_certificate_setCertificateIdCertificateBlob (
++ IN const pkcs11h_certificate_id_t certificate_id,
++ IN const unsigned char * const blob,
++ IN const size_t blob_size
++);
++
++/*
++ * pkcs11h_certificate_freeCertificate - Free certificate object.
++ *
++ * Parameters:
++ * certificate - Certificate ojbect.
++ */
++CK_RV
++pkcs11h_certificate_freeCertificate (
++ IN pkcs11h_certificate_t certificate
++);
++
++/*
++ * pkcs11h_certificate_create - Create a certificate object out of certificate_id.
++ *
++ * Parameters:
++ * certificate_id - Certificate id object to be based on.
++ * user_data - Optional user data, to be passed to hooks.
++ * mask_prompt - Allow prompt.
++ * pin_cache_period - Session specific cache period.
++ * p_certificate - Receives certificate object.
++ *
++ * The certificate id object may not specify the full certificate.
++ * The certificate object must be freed by caller.
++ */
++CK_RV
++pkcs11h_certificate_create (
++ IN const pkcs11h_certificate_id_t certificate_id,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ IN const int pin_cache_period,
++ OUT pkcs11h_certificate_t * const p_certificate
++);
++
++/*
++ * pkcs11h_certificate_getPromptMask - Extract user data out of certificate.
++ *
++ * Parameters:
++ * certificate - Certificate ojbect.
++ *
++ * Returns:
++ * mask_prompt - Allow prompt.
++ *
++ */
++unsigned
++pkcs11h_certificate_getPromptMask (
++ IN const pkcs11h_certificate_t certificate
++);
++
++/*
++ * pkcs11h_certificate_setPromptMask - Extract user data out of certificate.
++ *
++ * Parameters:
++ * certificate - Certificate ojbect.
++ * mask_prompt - Allow prompt.
++ */
++void
++pkcs11h_certificate_setPromptMask (
++ IN const pkcs11h_certificate_t certificate,
++ IN const unsigned ask_prompt
++);
++
++/*
++ * pkcs11h_certificate_getUserData - Extract user data out of certificate.
++ *
++ * Parameters:
++ * certificate - Certificate ojbect.
++ *
++ * Returns:
++ * user_data - Optional user data, to be passed to hooks.
++ */
++void *
++pkcs11h_certificate_getUserData (
++ IN const pkcs11h_certificate_t certificate
++);
++
++/*
++ * pkcs11h_certificate_setUserData - Extract user data out of certificate.
++ *
++ * Parameters:
++ * certificate - Certificate ojbect.
++ * user_data - Optional user data, to be passed to hooks.
++ */
++void
++pkcs11h_certificate_setUserData (
++ IN const pkcs11h_certificate_t certificate,
++ IN void * const user_data
++);
++
++/*
++ * pkcs11h_certificate_getCertificateId - Get certifiate id object out of a certifiate
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ * p_certificate_id - Certificate id object pointer.
++ *
++ * The certificate id must be freed by caller.
++ */
++CK_RV
++pkcs11h_certificate_getCertificateId (
++ IN const pkcs11h_certificate_t certificate,
++ OUT pkcs11h_certificate_id_t * const p_certificate_id
++);
++
++/*
++ * pkcs11h_certificate_getCertificateBlob - Get the certificate blob out of the certificate object.
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ * certificate_blob - Buffer.
++ * certificate_blob_size - Buffer size.
++ *
++ * Buffer may be NULL in order to get size.
++ */
++CK_RV
++pkcs11h_certificate_getCertificateBlob (
++ IN const pkcs11h_certificate_t certificate,
++ OUT unsigned char * const certificate_blob,
++ IN OUT size_t * const p_certificate_blob_size
++);
++
++#if defined(ENABLE_PKCS11H_SERIALIZATION)
++
++/*
++ * pkcs11h_certificate_serializeCertificateId - Serialize certificate_id into a string
++ *
++ * Parametrs:
++ * sz - Output string.
++ * max - Max buffer size.
++ * certificate_id - id to serialize
++ *
++ * sz may be NULL in order to get size.
++ */
++CK_RV
++pkcs11h_certificate_serializeCertificateId (
++ OUT char * const sz,
++ IN OUT size_t *max,
++ IN const pkcs11h_certificate_id_t certificate_id
++);
++
++/*
++ * pkcs11h_certificate_deserializeCertificateId - Deserialize certificate_id out of string.
++ *
++ * Parameters:
++ * p_certificate_id - id.
++ * sz - Inut string
++ */
++CK_RV
++pkcs11h_certificate_deserializeCertificateId (
++ OUT pkcs11h_certificate_id_t * const p_certificate_id,
++ IN const char * const sz
++);
++
++#endif /* ENABLE_PKCS11H_SERIALIZATION */
++
++/*
++ * pkcs11h_certificate_ensureCertificateAccess - Ensure certificate is accessible.
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ */
++CK_RV
++pkcs11h_certificate_ensureCertificateAccess (
++ IN const pkcs11h_certificate_t certificate
++);
++
++/*
++ * pkcs11h_certificate_ensureKeyAccess - Ensure key is accessible.
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ */
++CK_RV
++pkcs11h_certificate_ensureKeyAccess (
++ IN const pkcs11h_certificate_t certificate
++);
++
++/*
++ * pkcs11h_certificate_lockSession - Lock session for threded environment
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ *
++ * This must be called on threaded environment, so both calls to _sign and
++ * _signRecover and _decrypt will be from the same source.
++ * Failing to lock session, will result with CKR_OPERATION_ACTIVE if
++ * provider is good, or unexpected behaviour for others.
++ *
++ * It is save to call this also in none threaded environment, it will do nothing.
++ * Call this also if you are doing one stage operation, since locking is not
++ * done by method.
++ */
++CK_RV
++pkcs11h_certificate_lockSession (
++ IN const pkcs11h_certificate_t certificate
++);
++
++/*
++ * pkcs11h_certificate_releaseSession - Releases session lock.
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ *
++ * See pkcs11h_certificate_lockSession.
++ */
++CK_RV
++pkcs11h_certificate_releaseSession (
++ IN const pkcs11h_certificate_t certificate
++);
++
++/*
++ * pkcs11h_certificate_sign - Sign data.
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ * mech_type - PKCS#11 mechanism.
++ * source - Buffer to sign.
++ * source_size - Buffer size.
++ * target - Target buffer, can be NULL to get size.
++ * target_size - Target buffer size.
++ */
++CK_RV
++pkcs11h_certificate_sign (
++ IN const pkcs11h_certificate_t certificate,
++ 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 p_target_size
++);
++
++/*
++ * pkcs11h_certificate_signRecover - Sign data.
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ * mech_type - PKCS#11 mechanism.
++ * source - Buffer to sign.
++ * source_size - Buffer size.
++ * target - Target buffer, can be NULL to get size.
++ * target_size - Target buffer size.
++ */
++CK_RV
++pkcs11h_certificate_signRecover (
++ IN const pkcs11h_certificate_t certificate,
++ 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 p_target_size
++);
++
++/*
++ * pkcs11h_certificate_signAny - Sign data mechanism determined by key attributes.
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ * mech_type - PKCS#11 mechanism.
++ * source - Buffer to sign.
++ * source_size - Buffer size.
++ * target - Target buffer, can be NULL to get size.
++ * target_size - Target buffer size.
++ */
++CK_RV
++pkcs11h_certificate_signAny (
++ IN const pkcs11h_certificate_t certificate,
++ 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 p_target_size
++);
++
++/*
++ * pkcs11h_certificate_decrypt - Decrypt data.
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ * mech_type - PKCS#11 mechanism.
++ * source - Buffer to sign.
++ * source_size - Buffer size.
++ * target - Target buffer, can be NULL to get size.
++ * target_size - Target buffer size.
++ */
++CK_RV
++pkcs11h_certificate_decrypt (
++ IN const pkcs11h_certificate_t certificate,
++ 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 p_target_size
++);
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#if defined(ENABLE_PKCS11H_LOCATE)
++/*======================================================================*
++ * LOCATE INTERFACE
++ *======================================================================*/
++
++#if defined(ENABLE_PKCS11H_TOKEN) || defined(ENABLE_PKCS11H_CERTIFICATE)
++
++/*
++ * pkcs11h_locate_token - Locate token based on atributes.
++ *
++ * Parameters:
++ * slot_type - How to locate slot.
++ * slot - Slot name.
++ * user_data - Optional user data, to be passed to hooks.
++ * mask_prompt - Allow prompt.
++ * p_token_id - Token object.
++ *
++ * Slot:
++ * id - Slot number.
++ * name - Slot name.
++ * label - Available token label.
++ *
++ * Caller must free token id.
++ */
++CK_RV
++pkcs11h_locate_token (
++ IN const char * const slot_type,
++ IN const char * const slot,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT pkcs11h_token_id_t * const p_token_id
++);
++
++#endif /* ENABLE_PKCS11H_TOKEN || ENABLE_PKCS11H_CERTIFICATE */
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++
++/*
++ * pkcs11h_locate_certificate - Locate certificate based on atributes.
++ *
++ * Parameters:
++ * slot_type - How to locate slot.
++ * slot - Slot name.
++ * id_type - How to locate object.
++ * id - Object name.
++ * user_data - Optional user data, to be passed to hooks.
++ * mask_prompt - Allow prompt.
++ * p_certificate_id - Certificate object.
++ *
++ * Slot:
++ * Same as pkcs11h_locate_token.
++ *
++ * Object:
++ * id - Certificate CKA_ID (hex string) (Fastest).
++ * label - Certificate CKA_LABEL (string).
++ * subject - Certificate subject (OpenSSL or gnutls DN).
++ *
++ * Caller must free certificate id.
++ */
++CK_RV
++pkcs11h_locate_certificate (
++ IN const char * const slot_type,
++ IN const char * const slot,
++ IN const char * const id_type,
++ IN const char * const id,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT pkcs11h_certificate_id_t * const p_certificate_id
++);
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#endif /* ENABLE_PKCS11H_LOCATE */
++
++#if defined(ENABLE_PKCS11H_ENUM)
++/*======================================================================*
++ * ENUM INTERFACE
++ *======================================================================*/
++
++#if defined(ENABLE_PKCS11H_TOKEN)
++
++/*
++ * pkcs11h_freeTokenIdList - Free certificate_id list.
++ */
++CK_RV
++pkcs11h_token_freeTokenIdList (
++ IN const pkcs11h_token_id_list_t token_id_list
++);
++
++/*
++ * pkcs11h_token_enumTokenIds - Enumerate available tokens
++ *
++ * Parameters:
++ * p_token_id_list - A list of token ids.
++ *
++ * Caller must free the list.
++ */
++CK_RV
++pkcs11h_token_enumTokenIds (
++ IN const int method,
++ OUT pkcs11h_token_id_list_t * const p_token_id_list
++);
++
++#endif /* ENABLE_PKCS11H_TOKEN */
++
++#if defined(ENABLE_PKCS11H_DATA)
++
++/*
++ * pkcs11h_data_freeDataIdList - free data object list..
++ *
++ * Parameters:
++ * data_id_list - list to free.
++ */
++CK_RV
++pkcs11h_data_freeDataIdList (
++ IN const pkcs11h_data_id_list_t data_id_list
++);
++
++/*
++ * pkcs11h_data_enumDataObjects - get list of data objects.
++ *
++ * Parameters:
++ * token_id - token id.
++ * is_public - Get a list of public objects.
++ * user_data - Optional user data, to be passed to hooks.
++ * mask_prompt - Allow prompt.
++ * p_data_id_list - List location.
++ */
++CK_RV
++pkcs11h_data_enumDataObjects (
++ IN const pkcs11h_token_id_t token_id,
++ IN const PKCS11H_BOOL is_public,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT pkcs11h_data_id_list_t * const p_data_id_list
++);
++
++#endif /* ENABLE_PKCS11H_DATA */
++
++#if defined(ENABLE_PKCS11H_CERTIFICATE)
++
++/*
++ * pkcs11h_certificate_freeCertificateIdList - Free certificate_id list.
++ */
++CK_RV
++pkcs11h_certificate_freeCertificateIdList (
++ IN const pkcs11h_certificate_id_list_t cert_id_list
++);
++
++/*
++ * pkcs11h_certificate_enumTokenCertificateIds - Enumerate available certificates on specific token
++ *
++ * Parameters:
++ * token_id - Token id to enum.
++ * method - How to fetch certificates.
++ * user_data - Some user specific data.
++ * mask_prompt - Allow prompt.
++ * p_cert_id_issuers_list - Receives issues list, can be NULL.
++ * p_cert_id_end_list - Receives end certificates list.
++ *
++ * This function will likely take long time.
++ *
++ * Method can be one of the following:
++ * PKCS11H_ENUM_METHOD_CACHE
++ * Return available certificates, even if token was once detected and
++ * was removed.
++ * PKCS11H_ENUM_METHOD_CACHE_EXIST
++ * Return available certificates for available tokens only, don't
++ * read the contents of the token if already read, even if this token
++ * removed and inserted.
++ * PKCS11H_ENUM_METHOD_RELOAD
++ * Clear all caches and then enum.
++ *
++ * Caller must free the lists.
++ */
++CK_RV
++pkcs11h_certificate_enumTokenCertificateIds (
++ IN const pkcs11h_token_id_t token_id,
++ IN const int method,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
++);
++
++/*
++ * pkcs11h_enum_getCertificateIds - Enumerate available certificates.
++ *
++ * Parameters:
++ * method - How to fetch certificates.
++ * user_data - Some user specific data.
++ * mask_prompt - Allow prompt.
++ * p_cert_id_issuers_list - Receives issues list, can be NULL.
++ * p_cert_id_end_list - Receives end certificates list.
++ *
++ * This function will likely take long time.
++ *
++ * Method can be one of the following:
++ * PKCS11H_ENUM_METHOD_CACHE
++ * Return available certificates, even if token was once detected and
++ * was removed.
++ * PKCS11H_ENUM_METHOD_CACHE_EXIST
++ * Return available certificates for available tokens only, don't
++ * read the contents of the token if already read, even if this token
++ * removed and inserted.
++ * PKCS11H_ENUM_METHOD_RELOAD
++ * Clear all caches and then enum.
++ *
++ * Caller must free lists.
++ */
++CK_RV
++pkcs11h_certificate_enumCertificateIds (
++ IN const int method,
++ IN void * const user_data,
++ IN const unsigned mask_prompt,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
++ OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
++);
++
++#endif /* ENABLE_PKCS11H_CERTIFICATE */
++
++#endif /* ENABLE_PKCS11H_ENUM */
++
++#if defined(ENABLE_PKCS11H_OPENSSL)
++/*======================================================================*
++ * OPENSSL INTERFACE
++ *======================================================================*/
++
++/*
++ * pkcs11h_openssl_getX509 - Returns an X509 object out of the openssl_session object.
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ */
++X509 *
++pkcs11h_openssl_getX509 (
++ IN const pkcs11h_certificate_t certificate
++);
++
++/*
++ * pkcs11h_openssl_createSession - Create OpenSSL session based on a certificate object.
++ *
++ * Parameters:
++ * certificate - Certificate object.
++ *
++ * The certificate object will be freed by the OpenSSL interface on session end.
++ */
++pkcs11h_openssl_session_t
++pkcs11h_openssl_createSession (
++ IN const pkcs11h_certificate_t certificate
++);
++
++/*
++ * pkcs11h_openssl_getCleanupHook - Sets cleanup hook
++ *
++ * Parameters:
++ * openssl_session - session.
++ */
++pkcs11h_hook_openssl_cleanup_t
++pkcs11h_openssl_getCleanupHook (
++ IN const pkcs11h_openssl_session_t openssl_session
++);
++
++/*
++ * pkcs11h_openssl_setCleanupHook - Sets cleanup hook
++ *
++ * Parameters:
++ * openssl_session - session.
++ * cleanup - hook.
++ */
++void
++pkcs11h_openssl_setCleanupHook (
++ IN const pkcs11h_openssl_session_t openssl_session,
++ IN const pkcs11h_hook_openssl_cleanup_t cleanup
++);
++
++/*
++ * pkcs11h_openssl_freeSession - Free OpenSSL session.
++ *
++ * Parameters:
++ * openssl_session - Session to free.
++ *
++ * The openssl_session object has a reference count just like other OpenSSL objects.
++ */
++void
++pkcs11h_openssl_freeSession (
++ IN const pkcs11h_openssl_session_t openssl_session
++);
++
++/*
++ * pkcs11h_openssl_session_getRSA - Returns an RSA object out of the openssl_session object.
++ *
++ * Parameters:
++ * openssl_session - Session.
++ */
++RSA *
++pkcs11h_openssl_session_getRSA (
++ IN const pkcs11h_openssl_session_t openssl_session
++);
++
++/*
++ * pkcs11h_openssl_session_getX509 - Returns an X509 object out of the openssl_session object.
++ *
++ * Parameters:
++ * openssl_session - Session.
++ */
++X509 *
++pkcs11h_openssl_session_getX509 (
++ IN const pkcs11h_openssl_session_t openssl_session
++);
++
++#endif /* ENABLE_PKCS11H_OPENSSL */
++
++#if defined(ENABLE_PKCS11H_STANDALONE)
++/*======================================================================*
++ * STANDALONE INTERFACE
++ *======================================================================*/
++
++void
++pkcs11h_standalone_dump_slots (
++ IN const pkcs11h_output_print_t my_output,
++ IN void * const global_data,
++ IN const char * const provider
++);
++
++void
++pkcs11h_standalone_dump_objects (
++ IN const pkcs11h_output_print_t my_output,
++ IN void * const global_data,
++ IN const char * const provider,
++ IN const char * const slot,
++ IN const char * const pin
++);
++
++#endif /* ENABLE_PKCS11H_STANDALONE */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* __PKCS11H_HELPER_H */
+diff -urNp openssh-4.4p1/README.pkcs11 openssh-4.4p1+pkcs11-0.17/README.pkcs11
+--- openssh-4.4p1/README.pkcs11 1970-01-01 02:00:00.000000000 +0200
++++ openssh-4.4p1+pkcs11-0.17/README.pkcs11 2006-10-18 20:22:08.000000000 +0200
+@@ -0,0 +1,49 @@
++The PKCS#11 patch modify ssh-add and ssh-agent to support PKCS#11 private keys
++and certificates (http://alon.barlev.googlepages.com/openssh-pkcs11).
++
++It allows using multiple PKCS#11 providers at the same time, selecting keys by
++id, label or certificate subject, handling card removal and card insert events,
++handling card re-insert to a different slot, supporting session expiration.
++
++A valid X.509 certificate should exist on the token, without X.509 support it is
++exported as regular RSA key. Self-signed certificates are treated as RSA key and
++not as X.509 RSA key.
++
++If you like X.509 (http://roumenpetrov.info/openssh) support apply the X.509
++patch AFTER the PKCS#11 patch. You can use -o PubkeyAlgorithms=ssh-rsa in order to
++authenticate to none X.509 servers.
++
++One significant change is that the ssh-agent prompts for passwords now... So you
++need to configure it with a program that asks for card insert or PIN, a program
++such as x11-ssh-askpass. Current implementation (ssh-add asks for passwords) is
++not valid for dynamic smartcard environment.
++
++Current implementation uses the askpin program also for prompting card insert...
++Don't be confused, it only expects ok or cancel, some simple scripts available
++at http://alon.barlev.googlepages.com/openssh-pkcs11 that uses KDE, Gnome and .NET
++in order to display these dialogs.
++
++You can view full usage by:
++$ ssh-agent /bin/sh
++$ ssh-add -h
++
++A common scenario is the following:
++$ ssh-agent /bin/sh
++$ ssh-add --pkcs11-ask-pin `which openssh-kde-dialogs.sh`
++$ ssh-add --pkcs11-add-provider --pkcs11-provider /usr/lib/pkcs11/MyProvider.so
++$ ssh-add --pkcs11-add-id --pkcs11-id "serialized id"
++$ ssh myhost
++
++In order to see available objects, you can use:
++$ ssh-add --pkcs11-show-ids --pkcs11-provider /usr/lib/pkcs11/MyProvider.so
++
++In order to add id without accessing the token, you must put the certificate in
++a PEM file and use:
++$ ssh-add --pkcs11-add-id --pkcs11-id "serialized id" --pkcs11-cert-file my.pem
++
++In order to debug open two shells:
++1$ rm -fr /tmp/s; ssh-agent -d -d -d -a /tmp/s
++
++2$ SSH_AUTH_SOCK=/tmp/s; export SSH_AUTH_SOCK;
++2$ [ssh-add]...
++
+diff -urNp openssh-4.4p1/ssh-add.c openssh-4.4p1+pkcs11-0.17/ssh-add.c
+--- openssh-4.4p1/ssh-add.c 2006-09-01 08:38:37.000000000 +0300
++++ openssh-4.4p1+pkcs11-0.17/ssh-add.c 2006-10-12 15:10:42.000000000 +0200
+@@ -56,12 +56,15 @@
+ #include "rsa.h"
+ #include "log.h"
+ #include "key.h"
++#include "pkcs11.h"
+ #include "buffer.h"
+ #include "authfd.h"
+ #include "authfile.h"
+ #include "pathnames.h"
+ #include "misc.h"
+
++static void usage (void);
++
+ /* argv0 */
+ extern char *__progname;
+
+@@ -306,6 +309,261 @@ do_file(AuthenticationConnection *ac, in
+ return 0;
+ }
+
++#ifndef SSH_PKCS11_DISABLED
++
++static
++int
++do_pkcs11 (AuthenticationConnection *ac, int argc, char *argv[])
++{
++ /*
++ * TEMP TEMP TEMP TEMP
++ *
++ * This should be fixed if another mechanism
++ * will be propsed.
++ */
++ pkcs11_identity *id = NULL;
++ char *szPKCS11Provider = NULL;
++ char *szPKCS11Id = NULL;
++ char *szPKCS11SignMode = NULL;
++ char *szPKCS11AskPIN = NULL;
++ char *szPKCS11SlotId = NULL;
++ char *szPKCS11CertFile = NULL;
++ int fDebug = 0;
++ int fPKCS11AddProvider = 0;
++ int fPKCS11AddId = 0;
++ int fPKCS11RemoveId = 0;
++ int fPKCS11ShowIds = 0;
++ int fPKCS11DumpSlots = 0;
++ int fPKCS11DumpObjects = 0;
++ int fPKCS11ProtectedAuthentication = 0;
++ int fPKCS11CertPrivate = 0;
++ int nPKCS11PINCachePeriod = -1;
++ int fBadUsage = 0;
++ int ret = 0;
++ int nSkipPrmCount;
++ int i;
++
++ for (i=0,nSkipPrmCount=0;i<argc;i++) {
++ if (!strcmp (argv[i], "--pkcs11-provider")) {
++ szPKCS11Provider = argv[i+1];
++ i++;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-id")) {
++ szPKCS11Id = argv[i+1];
++ i++;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-pin-cache")) {
++ nPKCS11PINCachePeriod = atoi (argv[i+1]);
++ i++;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-sign-mode")) {
++ szPKCS11SignMode = argv[i+1];
++ i++;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-ask-pin")) {
++ szPKCS11AskPIN = argv[i+1];
++ i++;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-slot")) {
++ szPKCS11SlotId = argv[i+1];
++ i++;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-cert-file")) {
++ szPKCS11CertFile = argv[i+1];
++ i++;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-add-provider")) {
++ fPKCS11AddProvider = 1;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-remove-id")) {
++ fPKCS11RemoveId = 1;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-add-id")) {
++ fPKCS11AddId = 1;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-show-ids")) {
++ fPKCS11ShowIds = 1;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-dump-slots")) {
++ fPKCS11DumpSlots = 1;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-dump-objects")) {
++ fPKCS11DumpObjects = 1;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-protected-authentication")) {
++ fPKCS11ProtectedAuthentication = 1;
++ }
++ else if (!strcmp (argv[i], "--pkcs11-cert-private")) {
++ fPKCS11CertPrivate = 1;
++ }
++ else if (!strcmp (argv[i], "-d")) {
++ fDebug = 1;
++ }
++ else {
++ nSkipPrmCount++;
++ }
++ }
++
++ if (nSkipPrmCount == argc) {
++ /* no pkcs#11 arguments */
++ ret = -2;
++ }
++
++ if (ret == 0) {
++ if (
++ !fBadUsage &&
++ fPKCS11AddProvider &&
++ szPKCS11Provider == NULL
++ ) {
++ fBadUsage = 1;
++ }
++
++ if (
++ !fBadUsage &&
++ fPKCS11AddId &&
++ (
++ szPKCS11Id == NULL
++ )
++ ) {
++ fBadUsage = 1;
++ }
++
++ if (
++ !fBadUsage &&
++ fPKCS11RemoveId &&
++ (
++ szPKCS11Id == NULL
++ )
++ ) {
++ fBadUsage = 1;
++ }
++
++ if (
++ !fBadUsage &&
++ fPKCS11ShowIds &&
++ szPKCS11Provider == NULL
++ ) {
++ fBadUsage = 1;
++ }
++
++ if (
++ !fBadUsage &&
++ fPKCS11DumpSlots &&
++ szPKCS11Provider == NULL
++ ) {
++ fBadUsage = 1;
++ }
++
++ if (
++ !fBadUsage &&
++ fPKCS11DumpObjects &&
++ (
++ szPKCS11Provider == NULL ||
++ szPKCS11SlotId == NULL
++ )
++ ) {
++ fBadUsage = 1;
++ }
++
++ if (fBadUsage) {
++ usage ();
++ ret = 1;
++ }
++ }
++
++ if (ret == 0) {
++ if (fPKCS11AddId || fPKCS11RemoveId) {
++ id = pkcs11_identity_new ();
++ if (id == NULL) {
++ ret = 1;
++ }
++ else {
++ id->id = strdup (szPKCS11Id);
++ id->pin_cache_period = nPKCS11PINCachePeriod;
++ id->cert_file = szPKCS11CertFile;
++ }
++ }
++ }
++
++ if (ret == 0) {
++ if (fDebug) {
++ log_init(__progname, SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1);
++ }
++
++ if (fPKCS11ShowIds) {
++ pkcs11_show_ids (szPKCS11Provider, fPKCS11ProtectedAuthentication, fPKCS11CertPrivate);
++ ret = 0;
++ }
++ else if (fPKCS11DumpSlots) {
++ pkcs11_dump_slots (szPKCS11Provider);
++ ret = 0;
++ }
++ else if (fPKCS11DumpObjects) {
++ char *szPIN = read_passphrase("PIN: ", RP_ALLOW_STDIN);
++ if (szPIN[0] != '\0') {
++ pkcs11_dump_objects (szPKCS11Provider, szPKCS11SlotId, szPIN);
++ }
++ memset (szPIN, 0, strlen (szPIN));
++ xfree (szPIN);
++ ret = 0;
++ }
++ else if (szPKCS11AskPIN != NULL) {
++ ret = !ssh_pkcs11_set_ask_pin (ac, szPKCS11AskPIN);
++
++ if (ret) {
++ fprintf (stderr, "Failed\n");
++ }
++ else {
++ fprintf (stderr, "Success\n");
++ }
++ }
++ else if (fPKCS11AddProvider) {
++ ret = !ssh_pkcs11_add_provider (
++ ac,
++ szPKCS11Provider,
++ fPKCS11ProtectedAuthentication,
++ szPKCS11SignMode,
++ fPKCS11CertPrivate
++ );
++
++ if (ret) {
++ fprintf (stderr, "Cannot add provider %s\n", szPKCS11Provider);
++ }
++ else {
++ fprintf (stderr, "Provider %s added successfully\n", szPKCS11Provider);
++ }
++ }
++ else if (fPKCS11AddId) {
++ ret = !ssh_pkcs11_id (ac, id, 0);
++
++ if (ret) {
++ fprintf (stderr, "Cannot add identity\n");
++ }
++ else {
++ fprintf (stderr, "Identity added successfully\n");
++ }
++ }
++ else if (fPKCS11RemoveId) {
++ ret = !ssh_pkcs11_id (ac, id, 1);
++
++ if (ret) {
++ fprintf (stderr, "Cannot remove identity\n");
++ }
++ else {
++ fprintf (stderr, "Identity removed successfully\n");
++ }
++ }
++ }
++
++ if (id != NULL) {
++ pkcs11_identity_free (id);
++ }
++
++ return ret;
++}
++
++#endif /* SSH_PKCS11_DISABLED */
++
+ static void
+ usage(void)
+ {
+@@ -323,6 +581,50 @@ usage(void)
+ fprintf(stderr, " -s reader Add key in smartcard reader.\n");
+ fprintf(stderr, " -e reader Remove key in smartcard reader.\n");
+ #endif
++#ifndef SSH_PKCS11_DISABLED
++ fprintf(
++ stderr,
++ (
++ "\n"
++ " PKCS#11 Options:\n"
++ " --pkcs11-ask-pin prog Set ask-pin program\n"
++ "\n"
++ " --pkcs11-add-provider Add PKCS#11 provider\n"
++ " --pkcs11-provider provider PKCS#11 provider library\n"
++ " [--pkcs11-protected-authentication] Use PKCS#11 protected authentication\n"
++ " [--pkcs11-sign-mode mode] Provider signature mode\n"
++ " auto - determine automatically\n"
++ " sign - perform sign\n"
++ " recover - perform sign recover\n"
++ " any - perform sign and then sign recover\n"
++ " [--pkcs11-cert-private] Login required in order to access certificate\n"
++ "\n"
++ " --pkcs11-show-ids Show available identities\n"
++ " --pkcs11-provider provider PKCS#11 provider library\n"
++ " [--pkcs11-protected-authentication] Use PKCS#11 protected authentication\n"
++ " [--pkcs11-cert-private] Login required in order to access certificate\n"
++ " [-d] debug\n"
++ "\n"
++ " --pkcs11-add-id Add PKCS#11 identity\n"
++ " --pkcs11-id id Serialized string\n"
++ " [--pkcs11-cert-file file] Use this PEM file, don't access token\n"
++ " [--pkcs11-pin-cache period] PIN cache period (seconds)\n"
++ "\n"
++ " --pkcs11-remove-id Remove PKCS#11 identity\n"
++ " --pkcs11-id id Serialized string\n"
++ " [--pkcs11-cert-file file] Use this PEM file, don't access token\n"
++ "\n"
++ " PKCS#11 Debugging Options:\n"
++ " --pkcs11-dump-slots Dump available PKCS#11 slots\n"
++ " --pkcs11-provider provider PKCS#11 provider library\n"
++ "\n"
++ " --pkcs11-dump-objects Dump available PKCS#11 objects\n"
++ " --pkcs11-provider provider PKCS#11 provider library\n"
++ " --pkcs11-slot slot Slot numeric id\n"
++ "\n"
++ )
++ );
++#endif /* SSH_PKCS11_DISABLED */
+ }
+
+ int
+@@ -350,6 +652,17 @@ main(int argc, char **argv)
+ "Could not open a connection to your authentication agent.\n");
+ exit(2);
+ }
++
++#ifndef SSH_PKCS11_DISABLED
++ {
++ int r = do_pkcs11 (ac, argc, argv);
++ if (r != -2) {
++ ret = r;
++ goto done;
++ }
++ }
++#endif /* SSH_PKCS11_DISABLED */
++
+ while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:")) != -1) {
+ switch (ch) {
+ case 'l':
+diff -urNp openssh-4.4p1/ssh-agent.c openssh-4.4p1+pkcs11-0.17/ssh-agent.c
+--- openssh-4.4p1/ssh-agent.c 2006-09-01 08:38:37.000000000 +0300
++++ openssh-4.4p1+pkcs11-0.17/ssh-agent.c 2006-10-12 14:00:53.000000000 +0200
+@@ -71,6 +71,7 @@
+ #include "buffer.h"
+ #include "key.h"
+ #include "authfd.h"
++#include "pkcs11.h"
+ #include "compat.h"
+ #include "log.h"
+ #include "misc.h"
+@@ -690,6 +691,157 @@ send:
+ }
+ #endif /* SMARTCARD */
+
++#ifndef SSH_PKCS11_DISABLED
++
++static
++void
++process_pkcs11_set_ask_pin (SocketEntry *e)
++{
++ char *szAskPIN = NULL;
++ int success = 0;
++
++ szAskPIN = buffer_get_string(&e->request, NULL);
++
++ success = pkcs11_setAskPIN (szAskPIN);
++
++ buffer_put_int(&e->output, 1);
++ buffer_put_char(&e->output,
++ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
++}
++
++static void
++process_pkcs11_add_provider (SocketEntry *e)
++{
++ char *szProvider = NULL;
++ int fProtectedAuthentication = 0;
++ char *szSignMode = NULL;
++ int fCertIsPrivate = 0;
++ int success = 0;
++
++ szProvider = buffer_get_string(&e->request, NULL);
++ fProtectedAuthentication = buffer_get_int (&e->request);
++ szSignMode = buffer_get_string(&e->request, NULL);
++ fCertIsPrivate = buffer_get_int (&e->request);
++
++ success = pkcs11_addProvider (szProvider, fProtectedAuthentication, szSignMode, fCertIsPrivate);
++
++ buffer_put_int(&e->output, 1);
++ buffer_put_char(&e->output,
++ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
++}
++
++static
++void
++process_pkcs11_add_id (SocketEntry *e)
++{
++ int success = 0;
++ int version = 2;
++ char szComment[1024];
++ Key *k = NULL;
++ pkcs11_identity *pkcs11_id = NULL;
++
++ pkcs11_id = pkcs11_identity_new ();
++ if (pkcs11_id != NULL) {
++ pkcs11_id->id = strdup (buffer_get_string(&e->request, NULL));
++ pkcs11_id->pin_cache_period = buffer_get_int(&e->request);
++ pkcs11_id->cert_file = strdup (buffer_get_string(&e->request, NULL));
++
++ pkcs11_getKey (
++ pkcs11_id,
++ &k,
++ szComment,
++ sizeof (szComment)
++ );
++
++ if (k != NULL) {
++ if (lookup_identity(k, version) == NULL) {
++ Identity *id = xmalloc(sizeof(Identity));
++ Idtab *tab = NULL;
++
++ id->key = k;
++ k = NULL;
++ id->comment = xstrdup (szComment);
++ id->death = 0; /* handled by pkcs#11 helper */
++ id->confirm = 0;
++
++ tab = idtab_lookup(version);
++ TAILQ_INSERT_TAIL(&tab->idlist, id, next);
++ /* Increment the number of identities. */
++ tab->nentries++;
++ success = 1;
++ }
++ }
++ }
++
++ if (k != NULL) {
++ key_free (k);
++ }
++
++ if (pkcs11_id != NULL) {
++ pkcs11_identity_free (pkcs11_id);
++ }
++
++ buffer_put_int(&e->output, 1);
++ buffer_put_char(&e->output,
++ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
++}
++
++static
++void
++process_pkcs11_remove_id (SocketEntry *e)
++{
++ int success = 0;
++ Identity *id = NULL;
++ int version = 2;
++ char szComment[1024];
++ Key *k = NULL;
++
++ pkcs11_identity *pkcs11_id = NULL;
++
++ pkcs11_id = pkcs11_identity_new ();
++ if (pkcs11_id != NULL) {
++ pkcs11_id->id = strdup (buffer_get_string(&e->request, NULL));
++ pkcs11_id->pin_cache_period = buffer_get_int(&e->request);
++ pkcs11_id->cert_file = strdup (buffer_get_string(&e->request, NULL));
++
++ pkcs11_getKey (
++ pkcs11_id,
++ &k,
++ szComment,
++ sizeof (szComment)
++ );
++
++ if (k != NULL) {
++ id = lookup_identity (k, version);
++ }
++
++ if (id != NULL) {
++ Idtab *tab = NULL;
++
++ tab = idtab_lookup(version);
++ TAILQ_REMOVE(&tab->idlist, id, next);
++ tab->nentries--;
++ free_identity(id);
++ id = NULL;
++ success = 1;
++ }
++ }
++
++ if (k != NULL) {
++ key_free (k);
++ }
++
++ if (pkcs11_id != NULL) {
++ pkcs11_identity_free (pkcs11_id);
++ }
++
++ buffer_put_int(&e->output, 1);
++ buffer_put_char(&e->output,
++ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
++}
++
++#endif /* SSH_PKCS11_DISABLED */
++
+ /* dispatch incoming messages */
+
+ static void
+@@ -785,6 +937,21 @@ process_message(SocketEntry *e)
+ process_remove_smartcard_key(e);
+ break;
+ #endif /* SMARTCARD */
++
++#ifndef SSH_PKCS11_DISABLED
++ case SSH_AGENTC_PKCS11_SET_ASK_PIN:
++ process_pkcs11_set_ask_pin (e);
++ break;
++ case SSH_AGENTC_PKCS11_ADD_PROVIDER:
++ process_pkcs11_add_provider (e);
++ break;
++ case SSH_AGENTC_PKCS11_ADD_ID:
++ process_pkcs11_add_id (e);
++ break;
++ case SSH_AGENTC_PKCS11_REMOVE_ID:
++ process_pkcs11_remove_id (e);
++ break;
++#endif /* SSH_PKCS11_DISABLED */
+ default:
+ /* Unknown message. Respond with failure. */
+ error("Unknown message %d", type);
+@@ -1064,7 +1231,7 @@ main(int ac, char **av)
+ s_flag++;
+ break;
+ case 'd':
+- if (d_flag)
++ if (d_flag > 3)
+ usage();
+ d_flag++;
+ break;
+@@ -1167,7 +1334,7 @@ main(int ac, char **av)
+ * the socket data. The child continues as the authentication agent.
+ */
+ if (d_flag) {
+- log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1);
++ log_init(__progname, SYSLOG_LEVEL_DEBUG1+d_flag-1, SYSLOG_FACILITY_AUTH, 1);
+ format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
+ printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
+ SSH_AUTHSOCKET_ENV_NAME);
+@@ -1228,6 +1395,11 @@ main(int ac, char **av)
+ #endif
+
+ skip:
++
++#ifndef SSH_PKCS11_DISABLED
++ pkcs11_initialize (1, -1);
++#endif /* SSH_PKCS11_DISABLED */
++
+ new_socket(AUTH_SOCKET, sock);
+ if (ac > 0) {
+ mysignal(SIGALRM, check_parent_exists);
+@@ -1251,4 +1423,8 @@ skip:
+ after_select(readsetp, writesetp);
+ }
+ /* NOTREACHED */
++
++#ifndef SSH_PKCS11_DISABLED
++ pkcs11_terminate ();
++#endif /* SSH_PKCS11_DISABLED */
+ }