summaryrefslogtreecommitdiff
path: root/pkcs11.c
diff options
context:
space:
mode:
authorAlberto Gonzalez Iniesta <agi@inittab.org>2012-02-21 15:53:40 +0100
committerAlberto Gonzalez Iniesta <agi@inittab.org>2012-02-21 15:53:40 +0100
commit349cfa7acb95abe865209a28e417ec74b56f9bba (patch)
treead65334821b587c4ecdd461be84c94305ffdb888 /pkcs11.c
Imported Upstream version 2.2.1upstream/2.2.1
Diffstat (limited to 'pkcs11.c')
-rw-r--r--pkcs11.c990
1 files changed, 990 insertions, 0 deletions
diff --git a/pkcs11.c b/pkcs11.c
new file mode 100644
index 0000000..9cf18e5
--- /dev/null
+++ b/pkcs11.c
@@ -0,0 +1,990 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "syshead.h"
+
+#if defined(ENABLE_PKCS11)
+
+#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
+#include <pkcs11-helper-1.0/pkcs11h-openssl.h>
+#include "basic.h"
+#include "error.h"
+#include "manage.h"
+#include "base64.h"
+#include "pkcs11.h"
+#include "misc.h"
+#include "otime.h"
+
+static
+time_t
+__mytime (void) {
+ return openvpn_time (NULL);
+}
+
+#if !defined(_WIN32)
+static
+int
+__mygettimeofday (struct timeval *tv) {
+ return gettimeofday (tv, NULL);
+}
+#endif
+
+static
+void
+__mysleep (const unsigned long usec) {
+#if defined(_WIN32)
+ Sleep (usec/1000);
+#else
+ usleep (usec);
+#endif
+}
+
+
+static pkcs11h_engine_system_t s_pkcs11h_sys_engine = {
+ malloc,
+ free,
+ __mytime,
+ __mysleep,
+#if defined(_WIN32)
+ NULL
+#else
+ __mygettimeofday
+#endif
+};
+
+static
+unsigned
+_pkcs11_msg_pkcs112openvpn (
+ const unsigned flags
+) {
+ unsigned openvpn_flags;
+
+ switch (flags) {
+ case PKCS11H_LOG_DEBUG2:
+ openvpn_flags = D_PKCS11_DEBUG;
+ break;
+ case PKCS11H_LOG_DEBUG1:
+ openvpn_flags = D_SHOW_PKCS11;
+ break;
+ case PKCS11H_LOG_INFO:
+ openvpn_flags = M_INFO;
+ break;
+ case PKCS11H_LOG_WARN:
+ openvpn_flags = M_WARN;
+ break;
+ case PKCS11H_LOG_ERROR:
+ openvpn_flags = M_FATAL;
+ break;
+ default:
+ openvpn_flags = M_FATAL;
+ break;
+ }
+
+#if defined(ENABLE_PKCS11_FORCE_DEBUG)
+ openvpn_flags=M_INFO;
+#endif
+
+ return openvpn_flags;
+}
+
+static
+unsigned
+_pkcs11_msg_openvpn2pkcs11 (
+ const unsigned flags
+) {
+ unsigned pkcs11_flags;
+
+ if ((flags & D_PKCS11_DEBUG) != 0) {
+ pkcs11_flags = PKCS11H_LOG_DEBUG2;
+ }
+ else if ((flags & D_SHOW_PKCS11) != 0) {
+ pkcs11_flags = PKCS11H_LOG_DEBUG1;
+ }
+ else if ((flags & M_INFO) != 0) {
+ pkcs11_flags = PKCS11H_LOG_INFO;
+ }
+ else if ((flags & M_WARN) != 0) {
+ pkcs11_flags = PKCS11H_LOG_WARN;
+ }
+ else if ((flags & M_FATAL) != 0) {
+ pkcs11_flags = PKCS11H_LOG_ERROR;
+ }
+ else {
+ pkcs11_flags = PKCS11H_LOG_ERROR;
+ }
+
+#if defined(ENABLE_PKCS11_FORCE_DEBUG)
+ pkcs11_flags = PKCS11H_LOG_DEBUG2;
+#endif
+
+ return pkcs11_flags;
+}
+
+static
+void
+_pkcs11_openvpn_log (
+ void * const global_data,
+ unsigned flags,
+ const char * const szFormat,
+ va_list args
+) {
+ char Buffer[10*1024];
+
+ (void)global_data;
+
+ vsnprintf (Buffer, sizeof (Buffer), szFormat, args);
+ Buffer[sizeof (Buffer)-1] = 0;
+
+ msg (_pkcs11_msg_pkcs112openvpn (flags), "%s", Buffer);
+}
+
+static
+PKCS11H_BOOL
+_pkcs11_openvpn_token_prompt (
+ void * const global_data,
+ void * const user_data,
+ const pkcs11h_token_id_t token,
+ const unsigned retry
+) {
+ struct user_pass token_resp;
+
+ (void)global_data;
+ (void)user_data;
+ (void)retry;
+
+ ASSERT (token!=NULL);
+
+ CLEAR (token_resp);
+ token_resp.defined = false;
+ token_resp.nocache = true;
+ openvpn_snprintf (
+ token_resp.username,
+ sizeof (token_resp.username),
+ "Please insert %s token",
+ token->label
+ );
+
+ if (
+ !get_user_pass (
+ &token_resp,
+ NULL,
+ "token-insertion-request",
+ GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK|GET_USER_PASS_NOFATAL
+ )
+ ) {
+ return false;
+ }
+ else {
+ return strcmp (token_resp.password, "ok") == 0;
+ }
+}
+
+static
+PKCS11H_BOOL
+_pkcs11_openvpn_pin_prompt (
+ void * const global_data,
+ void * const user_data,
+ const pkcs11h_token_id_t token,
+ const unsigned retry,
+ char * const pin,
+ const size_t pin_max
+) {
+ struct user_pass token_pass;
+ char prompt[1024];
+
+ (void)global_data;
+ (void)user_data;
+ (void)retry;
+
+ ASSERT (token!=NULL);
+
+ openvpn_snprintf (prompt, sizeof (prompt), "%s token", token->label);
+
+ token_pass.defined = false;
+ token_pass.nocache = true;
+
+ if (
+ !get_user_pass (
+ &token_pass,
+ NULL,
+ prompt,
+ GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY|GET_USER_PASS_NOFATAL
+ )
+ ) {
+ return false;
+ }
+ else {
+ strncpynt (pin, token_pass.password, pin_max);
+ purge_user_pass (&token_pass, true);
+
+ if (strlen (pin) == 0) {
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+}
+
+bool
+pkcs11_initialize (
+ const bool protected_auth,
+ const int nPINCachePeriod
+) {
+ CK_RV rv = CKR_FUNCTION_FAILED;
+
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_initialize - entered"
+ );
+
+ if ((rv = pkcs11h_engine_setSystem (&s_pkcs11h_sys_engine)) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot initialize system engine %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((rv = pkcs11h_initialize ()) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((rv = pkcs11h_setLogHook (_pkcs11_openvpn_log, NULL)) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ pkcs11h_setLogLevel (_pkcs11_msg_openvpn2pkcs11 (get_debug_level ()));
+
+ if ((rv = pkcs11h_setForkMode (TRUE)) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot set fork mode %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((rv = pkcs11h_setTokenPromptHook (_pkcs11_openvpn_token_prompt, NULL)) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((rv = pkcs11h_setPINPromptHook (_pkcs11_openvpn_pin_prompt, NULL)) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((rv = pkcs11h_setProtectedAuthentication (protected_auth)) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot set protected authentication mode %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((rv = pkcs11h_setPINCachePeriod (nPINCachePeriod)) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot set Pcache period %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ rv = CKR_OK;
+
+cleanup:
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_initialize - return %ld-'%s'",
+ rv,
+ pkcs11h_getMessage (rv)
+ );
+
+ return rv == CKR_OK;
+}
+
+void
+pkcs11_terminate () {
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_terminate - entered"
+ );
+
+ pkcs11h_terminate ();
+
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_terminate - return"
+ );
+}
+
+void
+pkcs11_forkFixup () {
+ pkcs11h_forkFixup ();
+}
+
+bool
+pkcs11_addProvider (
+ const char * const provider,
+ const bool protected_auth,
+ const unsigned private_mode,
+ const bool cert_private
+) {
+ CK_RV rv = CKR_OK;
+
+ ASSERT (provider!=NULL);
+
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_addProvider - entered - provider='%s', private_mode=%08x",
+ provider,
+ private_mode
+ );
+
+ msg (
+ M_INFO,
+ "PKCS#11: Adding PKCS#11 provider '%s'",
+ provider
+ );
+
+ if (
+ (rv = pkcs11h_addProvider (
+ provider,
+ provider,
+ protected_auth,
+ private_mode,
+ PKCS11H_SLOTEVENT_METHOD_AUTO,
+ 0,
+ cert_private
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage (rv));
+ }
+
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_addProvider - return rv=%ld-'%s'",
+ rv,
+ pkcs11h_getMessage (rv)
+ );
+
+ return rv == CKR_OK;
+}
+
+int
+pkcs11_logout() {
+ return pkcs11h_logout () == CKR_OK;
+}
+
+int
+pkcs11_management_id_count () {
+ pkcs11h_certificate_id_list_t id_list = NULL;
+ pkcs11h_certificate_id_list_t t = NULL;
+ CK_RV rv = CKR_OK;
+ int count = 0;
+
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_management_id_count - entered"
+ );
+
+ if (
+ (rv = pkcs11h_certificate_enumCertificateIds (
+ PKCS11H_ENUM_METHOD_CACHE_EXIST,
+ NULL,
+ PKCS11H_PROMPT_MASK_ALLOW_ALL,
+ NULL,
+ &id_list
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot get certificate list %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ for (count = 0, t = id_list; t != NULL; t = t->next) {
+ count++;
+ }
+
+cleanup:
+
+ if (id_list != NULL) {
+ pkcs11h_certificate_freeCertificateIdList (id_list);
+ id_list = NULL;
+ }
+
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_management_id_count - return count=%d",
+ count
+ );
+
+ return count;
+}
+
+bool
+pkcs11_management_id_get (
+ const int index,
+ char ** id,
+ char **base64
+) {
+ pkcs11h_certificate_id_list_t id_list = NULL;
+ pkcs11h_certificate_id_list_t entry = NULL;
+#if 0 /* certificate_id seems to be unused -- JY */
+ pkcs11h_certificate_id_t certificate_id = NULL;
+#endif
+ pkcs11h_certificate_t certificate = NULL;
+ CK_RV rv = CKR_OK;
+ unsigned char *certificate_blob = NULL;
+ size_t certificate_blob_size = 0;
+ size_t max;
+ char *internal_id = NULL;
+ char *internal_base64 = NULL;
+ int count = 0;
+ bool success = false;
+
+ ASSERT (id!=NULL);
+ ASSERT (base64!=NULL);
+
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_management_id_get - entered index=%d",
+ index
+ );
+
+ *id = NULL;
+ *base64 = NULL;
+
+ if (
+ (rv = pkcs11h_certificate_enumCertificateIds (
+ PKCS11H_ENUM_METHOD_CACHE_EXIST,
+ NULL,
+ PKCS11H_PROMPT_MASK_ALLOW_ALL,
+ NULL,
+ &id_list
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot get certificate list %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ entry = id_list;
+ count = 0;
+ while (entry != NULL && count != index) {
+ count++;
+ entry = entry->next;
+ }
+
+ if (entry == NULL) {
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_management_id_get - no certificate at index=%d",
+ index
+ );
+ goto cleanup;
+ }
+
+ if (
+ (rv = pkcs11h_certificate_serializeCertificateId (
+ NULL,
+ &max,
+ entry->certificate_id
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot serialize certificate id %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((internal_id = (char *)malloc (max)) == NULL) {
+ msg (M_FATAL, "PKCS#11: Cannot allocate memory");
+ goto cleanup;
+ }
+
+ if (
+ (rv = pkcs11h_certificate_serializeCertificateId (
+ internal_id,
+ &max,
+ entry->certificate_id
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot serialize certificate id %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if (
+ (rv = pkcs11h_certificate_create (
+ entry->certificate_id,
+ NULL,
+ PKCS11H_PROMPT_MASK_ALLOW_ALL,
+ PKCS11H_PIN_CACHE_INFINITE,
+ &certificate
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if (
+ (rv = pkcs11h_certificate_getCertificateBlob (
+ certificate,
+ NULL,
+ &certificate_blob_size
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((certificate_blob = (unsigned char *)malloc (certificate_blob_size)) == NULL) {
+ msg (M_FATAL, "PKCS#11: Cannot allocate memory");
+ goto cleanup;
+ }
+
+ if (
+ (rv = pkcs11h_certificate_getCertificateBlob (
+ certificate,
+ certificate_blob,
+ &certificate_blob_size
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if (base64_encode (certificate_blob, certificate_blob_size, &internal_base64) == -1) {
+ msg (M_WARN, "PKCS#11: Cannot encode certificate");
+ goto cleanup;
+ }
+
+ *id = internal_id;
+ internal_id = NULL;
+ *base64 = internal_base64;
+ internal_base64 = NULL;
+ success = true;
+
+cleanup:
+
+ if (id_list != NULL) {
+ pkcs11h_certificate_freeCertificateIdList (id_list);
+ id_list = NULL;
+ }
+
+ if (internal_id != NULL) {
+ free (internal_id);
+ internal_id = NULL;
+ }
+
+ if (internal_base64 != NULL) {
+ free (internal_base64);
+ internal_base64 = NULL;
+ }
+
+ if (certificate_blob != NULL) {
+ free (certificate_blob);
+ certificate_blob = NULL;
+ }
+
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: pkcs11_management_id_get - return success=%d, id='%s'",
+ success ? 1 : 0,
+ *id
+ );
+
+ return success;
+}
+
+int
+SSL_CTX_use_pkcs11 (
+ SSL_CTX * const ssl_ctx,
+ bool pkcs11_id_management,
+ const char * const pkcs11_id
+) {
+ X509 *x509 = NULL;
+ RSA *rsa = NULL;
+ pkcs11h_certificate_id_t certificate_id = NULL;
+ pkcs11h_certificate_t certificate = NULL;
+ pkcs11h_openssl_session_t openssl_session = NULL;
+ CK_RV rv = CKR_OK;
+
+ bool ok = false;
+
+ ASSERT (ssl_ctx!=NULL);
+ ASSERT (pkcs11_id_management || pkcs11_id!=NULL);
+
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: SSL_CTX_use_pkcs11 - entered - ssl_ctx=%p, pkcs11_id_management=%d, pkcs11_id='%s'",
+ (void *)ssl_ctx,
+ pkcs11_id_management ? 1 : 0,
+ pkcs11_id
+ );
+
+ if (pkcs11_id_management) {
+ struct user_pass id_resp;
+
+ CLEAR (id_resp);
+
+ id_resp.defined = false;
+ id_resp.nocache = true;
+ openvpn_snprintf (
+ id_resp.username,
+ sizeof (id_resp.username),
+ "Please specify PKCS#11 id to use"
+ );
+
+ if (
+ !get_user_pass (
+ &id_resp,
+ NULL,
+ "pkcs11-id-request",
+ GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_STR|GET_USER_PASS_NOFATAL
+ )
+ ) {
+ goto cleanup;
+ }
+
+ if (
+ (rv = pkcs11h_certificate_deserializeCertificateId (
+ &certificate_id,
+ id_resp.password
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+ }
+ else {
+ if (
+ (rv = pkcs11h_certificate_deserializeCertificateId (
+ &certificate_id,
+ pkcs11_id
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+ }
+
+ if (
+ (rv = pkcs11h_certificate_create (
+ certificate_id,
+ NULL,
+ PKCS11H_PROMPT_MASK_ALLOW_ALL,
+ PKCS11H_PIN_CACHE_INFINITE,
+ &certificate
+ )) != CKR_OK
+ ) {
+ msg (M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((openssl_session = pkcs11h_openssl_createSession (certificate)) == NULL ) {
+ msg (M_WARN, "PKCS#11: Cannot initialize openssl session");
+ goto cleanup;
+ }
+
+ /*
+ * Will be released by openssl_session
+ */
+ certificate = NULL;
+
+ if ((rsa = pkcs11h_openssl_session_getRSA (openssl_session)) == NULL) {
+ msg (M_WARN, "PKCS#11: Unable get rsa object");
+ goto cleanup;
+ }
+
+ if ((x509 = pkcs11h_openssl_session_getX509 (openssl_session)) == NULL) {
+ msg (M_WARN, "PKCS#11: Unable get certificate object");
+ goto cleanup;
+ }
+
+ if (!SSL_CTX_use_RSAPrivateKey (ssl_ctx, rsa)) {
+ msg (M_WARN, "PKCS#11: Cannot set private key for openssl");
+ goto cleanup;
+ }
+
+ if (!SSL_CTX_use_certificate (ssl_ctx, x509)) {
+ msg (M_WARN, "PKCS#11: Cannot set certificate for openssl");
+ goto cleanup;
+ }
+
+ ok = true;
+
+cleanup:
+ /*
+ * openssl objects have reference
+ * count, so release them
+ */
+
+ if (x509 != NULL) {
+ X509_free (x509);
+ x509 = NULL;
+ }
+
+ if (rsa != NULL) {
+ RSA_free (rsa);
+ rsa = NULL;
+ }
+
+ if (certificate != NULL) {
+ pkcs11h_certificate_freeCertificate (certificate);
+ certificate = NULL;
+ }
+
+ if (certificate_id != NULL) {
+ pkcs11h_certificate_freeCertificateId (certificate_id);
+ certificate_id = NULL;
+ }
+
+ if (openssl_session != NULL) {
+ pkcs11h_openssl_freeSession (openssl_session);
+ openssl_session = NULL;
+ }
+
+ dmsg (
+ D_PKCS11_DEBUG,
+ "PKCS#11: SSL_CTX_use_pkcs11 - return ok=%d, rv=%ld",
+ ok ? 1 : 0,
+ rv
+ );
+
+ return ok ? 1 : 0;
+}
+
+static
+bool
+_pkcs11_openvpn_show_pkcs11_ids_pin_prompt (
+ void * const global_data,
+ void * const user_data,
+ const pkcs11h_token_id_t token,
+ const unsigned retry,
+ char * const pin,
+ const size_t pin_max
+) {
+ struct gc_arena gc = gc_new ();
+ struct buffer pass_prompt = alloc_buf_gc (128, &gc);
+
+ (void)global_data;
+ (void)user_data;
+ (void)retry;
+
+ ASSERT (token!=NULL);
+
+ buf_printf (&pass_prompt, "Please enter '%s' token PIN or 'cancel': ", token->display);
+
+ if (!get_console_input (BSTR (&pass_prompt), false, pin, pin_max)) {
+ msg (M_FATAL, "Cannot read password from stdin");
+ }
+
+ gc_free (&gc);
+
+ if (!strcmp (pin, "cancel")) {
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+void
+show_pkcs11_ids (
+ const char * const provider,
+ bool cert_private
+) {
+ pkcs11h_certificate_id_list_t user_certificates = NULL;
+ pkcs11h_certificate_id_list_t current = NULL;
+ CK_RV rv = CKR_FUNCTION_FAILED;
+
+ if ((rv = pkcs11h_initialize ()) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((rv = pkcs11h_setLogHook (_pkcs11_openvpn_log, NULL)) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ pkcs11h_setLogLevel (_pkcs11_msg_openvpn2pkcs11 (get_debug_level ()));
+
+ if ((rv = pkcs11h_setProtectedAuthentication (TRUE)) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot set protected authentication %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if ((rv = pkcs11h_setPINPromptHook (_pkcs11_openvpn_show_pkcs11_ids_pin_prompt, NULL)) != CKR_OK) {
+ msg (M_FATAL, "PKCS#11: Cannot set PIN hook %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if (
+ (rv = pkcs11h_addProvider (
+ provider,
+ provider,
+ TRUE,
+ 0,
+ FALSE,
+ 0,
+ cert_private ? TRUE : FALSE
+ )) != CKR_OK
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot add provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ if (
+ (rv = pkcs11h_certificate_enumCertificateIds (
+ PKCS11H_ENUM_METHOD_CACHE_EXIST,
+ NULL,
+ PKCS11H_PROMPT_MASK_ALLOW_ALL,
+ NULL,
+ &user_certificates
+ )) != CKR_OK
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot enumerate certificates %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup;
+ }
+
+ msg (
+ M_INFO|M_NOPREFIX|M_NOLF,
+ (
+ "\n"
+ "The following objects are available for use.\n"
+ "Each object shown below may be used as parameter to\n"
+ "--pkcs11-id option please remember to use single quote mark.\n"
+ )
+ );
+ for (current = user_certificates;current != NULL; current = current->next) {
+ pkcs11h_certificate_t certificate = NULL;
+ X509 *x509 = NULL;
+ BIO *bio = NULL;
+ char dn[1024] = {0};
+ char serial[1024] = {0};
+ char *ser = NULL;
+ size_t ser_len = 0;
+ int n;
+
+ if (
+ (rv = pkcs11h_certificate_serializeCertificateId (
+ NULL,
+ &ser_len,
+ current->certificate_id
+ )) != CKR_OK
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup1;
+ }
+
+ if (
+ rv == CKR_OK &&
+ (ser = (char *)malloc (ser_len)) == NULL
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot allocate memory");
+ goto cleanup1;
+ }
+
+ if (
+ (rv = pkcs11h_certificate_serializeCertificateId (
+ ser,
+ &ser_len,
+ current->certificate_id
+ )) != CKR_OK
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup1;
+ }
+
+ if (
+ (rv = pkcs11h_certificate_create (
+ current->certificate_id,
+ NULL,
+ PKCS11H_PROMPT_MASK_ALLOW_ALL,
+ PKCS11H_PIN_CACHE_INFINITE,
+ &certificate
+ ))
+ ) {
+ msg (M_FATAL, "PKCS#11: Cannot create certificate %ld-'%s'", rv, pkcs11h_getMessage (rv));
+ goto cleanup1;
+ }
+
+ if ((x509 = pkcs11h_openssl_getX509 (certificate)) == NULL) {
+ msg (M_FATAL, "PKCS#11: Cannot get X509");
+ goto cleanup1;
+ }
+
+ X509_NAME_oneline (
+ X509_get_subject_name (x509),
+ dn,
+ sizeof (dn)
+ );
+
+ if ((bio = BIO_new (BIO_s_mem ())) == NULL) {
+ msg (M_FATAL, "PKCS#11: Cannot create BIO");
+ goto cleanup1;
+ }
+
+ i2a_ASN1_INTEGER(bio, X509_get_serialNumber (x509));
+ n = BIO_read (bio, serial, sizeof (serial)-1);
+ if (n<0) {
+ serial[0] = '\x0';
+ }
+ else {
+ serial[n] = 0;
+ }
+
+ msg (
+ M_INFO|M_NOPREFIX|M_NOLF,
+ (
+ "\n"
+ "Certificate\n"
+ " DN: %s\n"
+ " Serial: %s\n"
+ " Serialized id: %s\n"
+ ),
+ dn,
+ serial,
+ ser
+ );
+
+ cleanup1:
+ if (x509 != NULL) {
+ X509_free (x509);
+ x509 = NULL;
+ }
+
+ if (certificate != NULL) {
+ pkcs11h_certificate_freeCertificate (certificate);
+ certificate = NULL;
+ }
+
+ if (ser != NULL) {
+ free (ser);
+ ser = NULL;
+ }
+ }
+
+cleanup:
+ if (user_certificates != NULL) {
+ pkcs11h_certificate_freeCertificateIdList (user_certificates);
+ user_certificates = NULL;
+ }
+
+ pkcs11h_terminate ();
+}
+
+#else
+#ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */
+static void dummy (void) {}
+#endif
+#endif /* ENABLE_PKCS11 */