summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2010-05-09 17:20:40 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2010-05-11 22:21:30 +0200
commit3cf07e35cd7b73868887d3d1c2f8f0455cf583d3 (patch)
tree4380735b478fd7cdde0fe84faeb2750f15dfd3f9
parenta2c2560e555a71dbbf0d0973b2946031816b103a (diff)
downloadgnutls-3cf07e35cd7b73868887d3d1c2f8f0455cf583d3.tar.gz
Added initial PKCS #11 support. Certtool can now print lists of certificates
available in system.
-rw-r--r--lib/Makefile.am8
-rw-r--r--lib/auth_srp.c4
-rw-r--r--lib/configure.ac17
-rw-r--r--lib/gnutls.pc.in2
-rw-r--r--lib/gnutls_constate.c6
-rw-r--r--lib/gnutls_errors.c2
-rw-r--r--lib/gnutls_handshake.c6
-rw-r--r--lib/gnutls_kx.c12
-rw-r--r--lib/gnutls_psk.c2
-rw-r--r--lib/gnutls_str.c121
-rw-r--r--lib/gnutls_str.h5
-rw-r--r--lib/includes/Makefile.am2
-rw-r--r--lib/includes/gnutls/pkcs11.h229
-rw-r--r--lib/libgnutls.map18
-rw-r--r--lib/openpgp/gnutls_openpgp.c4
-rw-r--r--lib/pkcs11.c1252
-rw-r--r--lib/x509/common.c2
-rw-r--r--lib/x509/dn.c2
-rw-r--r--src/Makefile.am2
-rw-r--r--src/certtool-common.h5
-rw-r--r--src/certtool-gaa.c252
-rw-r--r--src/certtool-gaa.h30
-rw-r--r--src/certtool.c26
-rw-r--r--src/certtool.gaa11
-rw-r--r--src/pkcs11.c50
25 files changed, 1938 insertions, 132 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 5e4ce56c62..7b6b90d14d 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -84,6 +84,10 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c gnutls_cipher.c \
rnd-libgcrypt.c cipher-libgcrypt.c mac-libgcrypt.c ext_signature.c \
crypto-api.c ext_safe_renegotiation.c
+if ENABLE_PKCS11
+COBJECTS += pkcs11.c
+endif
+
if ENABLE_OPRFI
COBJECTS += $(OPRFI_COBJECTS)
endif
@@ -134,6 +138,10 @@ else
libgnutls_la_LDFLAGS += $(LTLIBTASN1)
endif
+if ENABLE_PKCS11
+libgnutls_la_LDFLAGS += $(LTLIBPAKCHOIS)
+endif
+
if HAVE_LD_OUTPUT_DEF
libgnutls_la_LDFLAGS += -Wl,--output-def,libgnutls-$(DLL_VERSION).def
defexecdir = $(bindir)
diff --git a/lib/auth_srp.c b/lib/auth_srp.c
index 3f5eb55f7f..9a45fa4eca 100644
--- a/lib/auth_srp.c
+++ b/lib/auth_srp.c
@@ -247,7 +247,7 @@ _gnutls_gen_srp_server_kx (gnutls_session_t session, opaque ** data)
_gnutls_write_uint16 (n_b, data_b);
_gnutls_hard_log ("INT: SRP B[%d]: %s\n", (int) n_b,
- _gnutls_bin2hex (&data_b[2], n_b, buf, sizeof (buf)));
+ _gnutls_bin2hex (&data_b[2], n_b, buf, sizeof (buf), NULL));
_gnutls_srp_entry_free (pwd_entry);
@@ -366,7 +366,7 @@ _gnutls_gen_srp_client_kx (gnutls_session_t session, opaque ** data)
}
_gnutls_hard_log ("INT: SRP A[%d]: %s\n", (int) n_a,
- _gnutls_bin2hex (&data_a[2], n_a, buf, sizeof (buf)));
+ _gnutls_bin2hex (&data_a[2], n_a, buf, sizeof (buf), NULL));
_gnutls_mpi_release (&A);
diff --git a/lib/configure.ac b/lib/configure.ac
index 1ef9d970d8..fdb3857f90 100644
--- a/lib/configure.ac
+++ b/lib/configure.ac
@@ -79,6 +79,23 @@ else
AC_MSG_RESULT(no)
fi
+AC_ARG_WITH(pakchois, AS_HELP_STRING([--without-pakchois],
+ [disable pakchois PKCS11 support]),
+ ac_pakchois=$withval, ac_pakchois=yes)
+AC_MSG_CHECKING([whether to include pakchois PKCS11 support])
+if test x$ac_pakchois != xno; then
+ AC_MSG_RESULT(yes)
+ AC_LIB_HAVE_LINKFLAGS(pakchois,, [#include <pakchois/pakchois.h>], [pakchois_module_load(0,0);])
+ if test "$ac_cv_libpakchois" != yes; then
+ AC_MSG_WARN(
+***
+*** Pakchois was not found. You will not be able to use PKCS11 support.)
+ fi
+else
+ AC_MSG_RESULT(no)
+fi
+AM_CONDITIONAL(ENABLE_PKCS11, test "$ac_cv_libpakchois" = "yes")
+
lgl_INIT
LIBGNUTLS_LIBS="-L${libdir} -lgnutls $LIBS"
diff --git a/lib/gnutls.pc.in b/lib/gnutls.pc.in
index a4a34954ff..5898ca1a72 100644
--- a/lib/gnutls.pc.in
+++ b/lib/gnutls.pc.in
@@ -20,5 +20,5 @@ Description: Transport Security Layer implementation for the GNU system
URL: http://www.gnu.org/software/gnutls/
Version: @VERSION@
Libs: -L${libdir} -lgnutls
-Libs.private: @LIBGNUTLS_LIBS@ @LTLIBTASN1@
+Libs.private: @LIBGNUTLS_LIBS@ @LTLIBTASN1@ @LTLIBPAKCHOIS@
Cflags: -I${includedir}
diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c
index 5b2678f4e4..af83448811 100644
--- a/lib/gnutls_constate.c
+++ b/lib/gnutls_constate.c
@@ -116,7 +116,7 @@ _gnutls_set_keys (gnutls_session_t session, int hash_size, int IV_size,
_gnutls_hard_log ("INT: KEY BLOCK[%d]: %s\n", block_size,
_gnutls_bin2hex (key_block, block_size, buf,
- sizeof (buf)));
+ sizeof (buf), NULL));
_gnutls_free_datum (&session->cipher_specs.server_write_mac_secret);
_gnutls_free_datum (&session->cipher_specs.client_write_mac_secret);
@@ -242,7 +242,7 @@ _gnutls_set_keys (gnutls_session_t session, int hash_size, int IV_size,
client_write_key_size,
_gnutls_bin2hex (client_write_key,
client_write_key_size, buf,
- sizeof (buf)));
+ sizeof (buf), NULL));
if (_gnutls_sset_datum
(&session->cipher_specs.server_write_key,
@@ -256,7 +256,7 @@ _gnutls_set_keys (gnutls_session_t session, int hash_size, int IV_size,
server_write_key_size,
_gnutls_bin2hex (server_write_key,
server_write_key_size, buf,
- sizeof (buf)));
+ sizeof (buf), NULL));
}
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
index 21f40b1cc1..d83c3547d7 100644
--- a/lib/gnutls_errors.c
+++ b/lib/gnutls_errors.c
@@ -487,7 +487,7 @@ _gnutls_mpi_log (const char *prefix, bigint_t a)
return;
}
- _gnutls_bin2hex (binbuf, binlen, hexbuf, hexlen);
+ _gnutls_bin2hex (binbuf, binlen, hexbuf, hexlen, NULL);
_gnutls_hard_log ("MPI: length: %d\n\t%s%s\n", (int) binlen, prefix,
hexbuf);
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index fe7cd9809f..f24fa631fc 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -1668,7 +1668,7 @@ _gnutls_client_check_if_resuming (gnutls_session_t session,
session_id_len);
_gnutls_handshake_log ("HSK[%p]: SessionID: %s\n", session,
_gnutls_bin2hex (session_id, session_id_len, buf,
- sizeof (buf)));
+ sizeof (buf), NULL));
if (session_id_len > 0 &&
session->internals.resumed_security_parameters.session_id_size ==
@@ -2258,7 +2258,7 @@ _gnutls_send_server_hello (gnutls_session_t session, int again)
_gnutls_handshake_log ("HSK[%p]: SessionID: %s\n", session,
_gnutls_bin2hex (session->security_parameters.
session_id, session_id_len, buf,
- sizeof (buf)));
+ sizeof (buf), NULL));
memcpy (&data[pos],
session->security_parameters.current_cipher_suite.suite, 2);
@@ -2763,7 +2763,7 @@ _gnutls_handshake_client (gnutls_session_t session)
internals.resumed_security_parameters.session_id,
session->
internals.resumed_security_parameters.session_id_size,
- buf, sizeof (buf)));
+ buf, sizeof (buf), NULL));
#endif
switch (STATE)
diff --git a/lib/gnutls_kx.c b/lib/gnutls_kx.c
index 82e9702994..5b5a8e77b0 100644
--- a/lib/gnutls_kx.c
+++ b/lib/gnutls_kx.c
@@ -64,15 +64,15 @@ generate_normal_master (gnutls_session_t session, int keep_premaster)
_gnutls_hard_log ("INT: PREMASTER SECRET[%d]: %s\n", PREMASTER.size,
_gnutls_bin2hex (PREMASTER.data, PREMASTER.size, buf,
- sizeof (buf)));
+ sizeof (buf), NULL));
_gnutls_hard_log ("INT: CLIENT RANDOM[%d]: %s\n", 32,
_gnutls_bin2hex (session->
security_parameters.client_random, 32,
- buf, sizeof (buf)));
+ buf, sizeof (buf), NULL));
_gnutls_hard_log ("INT: SERVER RANDOM[%d]: %s\n", 32,
_gnutls_bin2hex (session->
security_parameters.server_random, 32,
- buf, sizeof (buf)));
+ buf, sizeof (buf), NULL));
if (gnutls_protocol_get_version (session) == GNUTLS_SSL3)
{
@@ -116,7 +116,7 @@ generate_normal_master (gnutls_session_t session, int keep_premaster)
session->
security_parameters.extensions.
oprfi_client_len, buf,
- sizeof (buf)));
+ sizeof (buf), NULL));
_gnutls_hard_log ("INT: SERVER OPRFI[%d]: %s\n",
session->security_parameters.extensions.
oprfi_server_len,
@@ -126,7 +126,7 @@ generate_normal_master (gnutls_session_t session, int keep_premaster)
session->
security_parameters.extensions.
oprfi_server_len, buf,
- sizeof (buf)));
+ sizeof (buf), NULL));
memcpy (rnd, session->security_parameters.client_random,
GNUTLS_RANDOM_SIZE);
@@ -178,7 +178,7 @@ generate_normal_master (gnutls_session_t session, int keep_premaster)
_gnutls_hard_log ("INT: MASTER SECRET: %s\n",
_gnutls_bin2hex (session->
security_parameters.master_secret,
- GNUTLS_MASTER_SIZE, buf, sizeof (buf)));
+ GNUTLS_MASTER_SIZE, buf, sizeof (buf), NULL));
return ret;
}
diff --git a/lib/gnutls_psk.c b/lib/gnutls_psk.c
index 67cef93890..1f43743abc 100644
--- a/lib/gnutls_psk.c
+++ b/lib/gnutls_psk.c
@@ -416,7 +416,7 @@ gnutls_hex_encode (const gnutls_datum_t * data, char *result,
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
- _gnutls_bin2hex (data->data, data->size, result, *result_size);
+ _gnutls_bin2hex (data->data, data->size, result, *result_size, NULL);
*result_size = res;
return 0;
diff --git a/lib/gnutls_str.c b/lib/gnutls_str.c
index 0bb4b2b34c..008c141b4f 100644
--- a/lib/gnutls_str.c
+++ b/lib/gnutls_str.c
@@ -283,6 +283,101 @@ _gnutls_string_append_printf (gnutls_string * dest, const char *fmt, ...)
return len;
}
+static int _gnutls_string_insert_data(gnutls_string * dest, int pos, const void* str, size_t str_size)
+{
+ size_t orig_length = dest->length;
+ int ret;
+
+ ret = _gnutls_string_resize(dest, dest->length+str_size); /* resize to make space */
+ if (ret < 0)
+ return ret;
+
+ memmove(&dest->data[pos+str_size], &dest->data[pos], orig_length-pos);
+
+ memcpy(&dest->data[pos], str, str_size);
+ dest->length += str_size;
+
+ return 0;
+}
+
+static void _gnutls_string_delete_data(gnutls_string * dest, int pos, size_t str_size)
+{
+ memmove(&dest->data[pos], &dest->data[pos+str_size], dest->length-pos-str_size);
+
+ dest->length -= str_size;
+
+ return;
+}
+
+
+int _gnutls_string_escape(gnutls_string * dest, const char *const invalid_chars)
+{
+ static const char *x = "0123456789ABCDEF";
+ int rv = -1;
+ char t[5];
+ int pos = 0;
+
+ /*_PKCS11H_ASSERT (target!=NULL); Not required*/
+
+ while (pos < dest->length) {
+
+ if (dest->data[pos] == '\\' || strchr(invalid_chars, dest->data[pos])
+ || !isgraph(dest->data[pos])) {
+
+ t[0] = '%';
+ t[1] = x[(dest->data[pos] & 0xf0) >> 4];
+ t[2] = x[(dest->data[pos] & 0x0f) >> 0];
+
+ _gnutls_string_delete_data(dest, pos, 1);
+
+ if (_gnutls_string_insert_data(dest, pos, t, 3) < 0) {
+ rv = -1;
+ goto cleanup;
+ }
+
+ }
+ pos++;
+ }
+
+ rv = 0;
+
+ cleanup:
+
+ return rv;
+}
+
+int _gnutls_string_unescape(gnutls_string * dest)
+{
+ int rv = -1;
+ int pos = 0;
+
+ /*_PKCS11H_ASSERT (target!=NULL); Not required*/
+
+ while (pos < dest->length) {
+ if (dest->data[pos] == '%') {
+ char b[3];
+ unsigned u;
+ char x;
+ b[0] = dest->data[pos+1];
+ b[1] = dest->data[pos+2];
+ b[2] = '\x0';
+
+ sscanf(b, "%08x", &u);
+ x = u & 0xff;
+ _gnutls_string_delete_data(dest, pos, 3);
+ _gnutls_string_insert_data(dest, pos, &x, 1);
+ }
+ pos++;
+ }
+
+ rv = 0;
+
+ cleanup:
+
+ return rv;
+}
+
+
/* Converts the given string (old) to hex. A buffer must be provided
* to hold the new hex string. The new string will be null terminated.
* If the buffer does not have enough space to hold the string, a
@@ -290,14 +385,27 @@ _gnutls_string_append_printf (gnutls_string * dest, const char *fmt, ...)
*/
char *
_gnutls_bin2hex (const void *_old, size_t oldlen,
- char *buffer, size_t buffer_size)
+ char *buffer, size_t buffer_size, const char *separator)
{
unsigned int i, j;
const opaque *old = _old;
+ int init = 0;
+ int step = 2;
+ const char empty[] = "";
+
+ if (separator != NULL && separator[0] != 0)
+ step = 3;
+ else
+ separator = empty;
- for (i = j = 0; i < oldlen && j + 2 < buffer_size; j += 2)
+ i = j = 0;
+ sprintf (&buffer[j], "%.2x", old[i]);
+ j+=2;
+ i++;
+
+ for (; i < oldlen && j + step < buffer_size; j += step)
{
- sprintf (&buffer[j], "%.2x", old[i]);
+ sprintf (&buffer[j], "%s%.2x", separator, old[i]);
i++;
}
buffer[j] = '\0';
@@ -344,11 +452,16 @@ _gnutls_hex2bin (const opaque * hex_data, int hex_size, opaque * bin_data,
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
- for (i = j = 0; j < hex_size; i += 2, j++)
+ for (i = j = 0; j < hex_size; j++)
{
+
+ if (!isxdigit(hex_data[i])) /* skip non-hex such as the ':' in 00:FF */
+ continue;
+
hex2_data[0] = hex_data[i];
hex2_data[1] = hex_data[i + 1];
hex2_data[2] = 0;
+ i+=2;
val = strtoul ((char *) hex2_data, NULL, 16);
if (val == ULONG_MAX)
{
diff --git a/lib/gnutls_str.h b/lib/gnutls_str.h
index 9888ea3b3c..804a0b87f2 100644
--- a/lib/gnutls_str.h
+++ b/lib/gnutls_str.h
@@ -57,6 +57,9 @@ void _gnutls_string_get_data (gnutls_string *, void *, size_t * size);
void _gnutls_string_get_datum (gnutls_string *, gnutls_datum_t *,
size_t max_size);
+int _gnutls_string_escape(gnutls_string * dest, const char *const invalid_chars);
+int _gnutls_string_unescape(gnutls_string * dest);
+
#ifndef __attribute__
/* This feature is available in gcc versions 2.5 and later. */
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
@@ -77,7 +80,7 @@ typedef gnutls_string gnutls_buffer;
#define _gnutls_buffer_resize _gnutls_string_resize
char *_gnutls_bin2hex (const void *old, size_t oldlen, char *buffer,
- size_t buffer_size);
+ size_t buffer_size, const char* separator);
int _gnutls_hex2bin (const opaque * hex_data, int hex_size, opaque * bin_data,
size_t * bin_size);
diff --git a/lib/includes/Makefile.am b/lib/includes/Makefile.am
index e419786887..00dd37558a 100644
--- a/lib/includes/Makefile.am
+++ b/lib/includes/Makefile.am
@@ -22,7 +22,7 @@
# MA 02110-1301, USA
nobase_include_HEADERS = gnutls/x509.h gnutls/pkcs12.h gnutls/compat.h \
- gnutls/openpgp.h gnutls/crypto.h
+ gnutls/openpgp.h gnutls/crypto.h gnutls/pkcs11.h
if ENABLE_CXX
nobase_include_HEADERS += gnutls/gnutlsxx.h
diff --git a/lib/includes/gnutls/pkcs11.h b/lib/includes/gnutls/pkcs11.h
new file mode 100644
index 0000000000..092333a14c
--- /dev/null
+++ b/lib/includes/gnutls/pkcs11.h
@@ -0,0 +1,229 @@
+#ifndef __GNUTLS_PKCS11_H
+#define __GNUTLS_PKCS11_H
+
+/**
+ * @addtogroup gnutls_pkcs11 GnuTLS PKCS#11 interface.
+ *
+ * @{
+ */
+
+/**
+ * @file gnutls-pkcs11.h
+ * @brief gnutls-pkcs11 interface.
+ * @author Alon Bar-Lev <alon.barlev@gmail.com>
+ * @see @ref gnutls_pkcs11
+ */
+
+#include <stdarg.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+/**
+ * @brief PKCS#11 error
+ */
+#define GNUTLS_E_PKCS11_ERROR (GNUTLS_E_APPLICATION_ERROR_MIN+529)
+#define GNUTLS_E_PKCS11_LOAD_ERROR 1821
+#define GNUTLS_E_PARSING_ERROR 1822
+#define GNUTLS_E_PKCS11_PIN_ERROR 1823
+
+#define GNUTLS_PKCS11_MAX_PIN_LEN 32
+
+/**
+ * @brief Token prompt callback.
+ * @param global_data Callback data.
+ * @param label Token label.
+ * @param retry Retry counter.
+ * @return none zero on success.
+ */
+typedef int (*gnutls_pkcs11_token_callback_t)(
+ void * const global_data,
+ const char * const label,
+ const unsigned retry
+);
+
+/* flags */
+#define GNUTLS_PKCS11_PIN_FINAL_TRY 1
+#define GNUTLS_PKCS11_PIN_COUNT_LOW 2
+
+/* Callback for PKCS#11 PIN entry. The callback provides the PIN code
+ * to unlock the token with label 'token_label' in the slot described
+ * by 'slot_descr'.
+ *
+ * The PIN code, as a NUL-terminated ASCII string, should be copied
+ * into the 'pin' buffer (of fixed length NE_SSL_P11PINLEN), and
+ * return 0 to indicate success. Alternatively, the callback may
+ * return -1 to indicate failure and cancel PIN entry (in which case,
+ * the contents of the 'pin' parameter are ignored).
+ *
+ * When a PIN is required, the callback will be invoked repeatedly
+ * (and indefinitely) until either the returned PIN code is correct,
+ * the callback returns failure, or the token refuses login (e.g. when
+ * the token is locked due to too many incorrect PINs!). For the
+ * first such invocation, the 'attempt' counter will have value zero;
+ * it will increase by one for each subsequent attempt.
+ *
+ * The NE_SSL_P11PIN_COUNT_LOW and/or NE_SSL_P11PIN_FINAL_TRY hints
+ * may be set in the 'flags' argument, if these hints are made
+ * available by the token; not all tokens expose these hints. */
+typedef int (*gnutls_pkcs11_pin_callback_t)(void *userdata, int attempt,
+ const char *slot_descr,
+ const char *token_label,
+ unsigned int flags,
+ char *pin, size_t pin_max);
+
+/**
+ * @brief PKCS#11 certificate reference.
+ */
+struct gnutls_pkcs11_crt_st;
+
+
+typedef struct gnutls_pkcs11_crt_st* gnutls_pkcs11_crt_t;
+
+
+#define GNUTLS_PKCS11_FLAG_MANUAL 0 /* Manual loading of libraries */
+#define GNUTLS_PKCS11_FLAG_AUTO 1 /* Automatically load libraries by reading /etc/gnutls/pkcs11.conf */
+
+/* pkcs11.conf format:
+ * load = /lib/xxx-pkcs11.so
+ * load = /lib/yyy-pkcs11.so
+ */
+
+/**
+ * @brief Initialize gnutls-pkcs11.
+ * @param params Misc values to use.
+ * @return gnutls status.
+ * @note gnutls-pkcs11 must be uninitialize.
+ * @see gnutls_pkcs11_deinit()
+ * @todo params is not implemented yet.
+ *
+ * params is in the format of:
+ * name=value;name=value;
+ */
+int gnutls_pkcs11_init (unsigned int flags, const char* configfile);
+
+/**
+ * @brief Deinitialize gnutls-pkcs11.
+ * @return gnutls status.
+ */
+void gnutls_pkcs11_deinit (void);
+
+/**
+ * @brief Set token prompt callback.
+ * @param callback Callback to use.
+ * @param data Data to use when calling callback.
+ * @return gnutls status.
+ */
+//int gnutls_pkcs11_set_token_function (const gnutls_pkcs11_token_callback_t callback, void * const data);
+
+/**
+ * @brief Set PIN prompt callback.
+ * @param callback Callback to use.
+ * @param data Data to use when calling callback.
+ * @return gnutls status.
+ */
+void gnutls_pkcs11_set_pin_function (const gnutls_pkcs11_pin_callback_t callback, void * const data);
+
+/**
+ * @brief Add PKCS#11 provider.
+ * @param name Library to load.
+ * @param params Misc provider parameters.
+ * @return gnutls status.
+ * @todo params is not implemented yet.
+ *
+ * params is in the format of:
+ * name=value;name=value;
+ */
+int gnutls_pkcs11_add_provider (const char * name, const char * params);
+
+/**
+ * @brief Free certificate reference.
+ * @param certificate Certificate reference to free.
+ * @return gnutls stauts.
+ */
+int gnutls_pkcs11_crt_init ( gnutls_pkcs11_crt_t *certificate);
+
+/**
+ * @brief Deserialize a certificate reference.
+ * @param serialized Serialized certificate.
+ * @param p_certificate Certificate reference.
+ * @return gnutls status.
+ */
+int gnutls_pkcs11_crt_import_url (gnutls_pkcs11_crt_t p_certificate, const char * url);
+
+/**
+ * @brief Serialize a certificate reference.
+ * @param certificate Certificate reference to serialize.
+ * @param serialized Serialize result (string). Use gnutls_free() to free it.
+ * @return gnutls status.
+ */
+int gnutls_pkcs11_crt_export_url (gnutls_pkcs11_crt_t certificate, char** url);
+
+/**
+ * @brief Free certificate reference.
+ * @param certificate Certificate reference to free.
+ * @return gnutls stauts.
+ */
+void gnutls_pkcs11_crt_deinit ( gnutls_pkcs11_crt_t certificate);
+
+/**
+ * @brief Release array of certificate references.
+ * @param certificates Array to free.
+ * @param ncertificates Array size.
+ * @return gnutls status.
+ */
+int gnutls_pkcs11_crt_list_deinit (gnutls_pkcs11_crt_t * certificates, const unsigned int ncertificates);
+
+typedef enum {
+ GNUTLS_PKCS11_CRT_ATTR_ALL,
+ GNUTLS_PKCS11_CRT_ATTR_TRUSTED, /* marked as trusted */
+ GNUTLS_PKCS11_CRT_ATTR_WITH_PK, /* with corresponding private key */
+} pkcs11_crt_attributes;
+
+/**
+ * @brief Enumerate available certificates.
+ * @param p_list Location to store the list.
+ * @param n_list Location to store end list length.
+ * @param url Enumerate only certificates found in token(s) pointed by url
+ * @param attributes Only export certificates that match this attribute
+ * @return gnutls status.
+ * @note the p_list is should not be initialized.
+ */
+int gnutls_pkcs11_crt_list_import (gnutls_pkcs11_crt_t * p_list, unsigned int *const n_list, const char* url, pkcs11_crt_attributes flags);
+
+int gnutls_x509_crt_import_pkcs11( gnutls_x509_crt_t crt, gnutls_pkcs11_crt_t pkcs11_crt);
+
+/**
+ * @brief Return the type of the certificate
+ * @param certificate Certificate reference.
+ * @return gnutls status.
+ */
+gnutls_certificate_type_t gnutls_pkcs11_crt_get_type (gnutls_pkcs11_crt_t certificate);
+
+int gnutls_x509_crt_list_import_pkcs11 (gnutls_x509_crt_t * certs,
+ unsigned int cert_max,
+ gnutls_pkcs11_crt_t * const pkcs11_certs,
+ unsigned int flags);
+
+
+/* XXX: private key functions...*/
+
+/**
+ * @brief Setup session to be used with gnutls-pkcs11.
+ * @param session Session to setup.
+ * @param certificate Certificate to use in this session.
+ * @return gnutls status.
+ * @see gnutls_pkcs11_cleanup_session()
+ * @note Resources must be released using @ref gnutls_pkcs11_cleanup_session().
+ */
+//int gnutls_pkcs11_setup_session (gnutls_session session, gnutls_pkcs11_crt_t certificate);
+
+/**
+ * @brief Cleanup session.
+ * @param session Session to cleanup.
+ * @return gnutls status.
+ */
+//int gnutls_pkcs11_cleanup_session (gnutls_session session);
+
+/** @} */
+
+#endif
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 5dfc75d884..b2143a4286 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -604,6 +604,24 @@ GNUTLS_2_10
gnutls_safe_renegotiation_status;
} GNUTLS_2_8;
+GNUTLS_2_11
+{
+ global:
+ gnutls_pkcs11_init;
+ gnutls_pkcs11_deinit;
+ gnutls_pkcs11_set_pin_function;
+ gnutls_pkcs11_add_provider;
+ gnutls_pkcs11_crt_init;
+ gnutls_pkcs11_crt_import_url;
+ gnutls_pkcs11_crt_export_url;
+ gnutls_pkcs11_crt_deinit;
+ gnutls_pkcs11_crt_list_deinit;
+ gnutls_pkcs11_crt_list_import;
+ gnutls_x509_crt_import_pkcs11;
+ gnutls_pkcs11_crt_get_type;
+ gnutls_x509_crt_list_import_pkcs11;
+} GNUTLS_2_10;
+
GNUTLS_PRIVATE {
global:
# Internal symbols needed by libgnutls-extra:
diff --git a/lib/openpgp/gnutls_openpgp.c b/lib/openpgp/gnutls_openpgp.c
index d9c498a447..dd6a374e48 100644
--- a/lib/openpgp/gnutls_openpgp.c
+++ b/lib/openpgp/gnutls_openpgp.c
@@ -746,7 +746,7 @@ _gnutls_openpgp_privkey_to_gkey (gnutls_privkey * dest,
_gnutls_debug_log
("Importing Openpgp key and using openpgp sub key: %s\n",
- _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf)));
+ _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf), NULL));
KEYID_IMPORT (kid32, keyid);
@@ -812,7 +812,7 @@ _gnutls_openpgp_crt_to_gcert (gnutls_cert * gcert, gnutls_openpgp_crt_t cert)
_gnutls_debug_log
("Importing Openpgp cert and using openpgp sub key: %s\n",
- _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf)));
+ _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf), NULL));
KEYID_IMPORT (kid32, keyid);
diff --git a/lib/pkcs11.c b/lib/pkcs11.c
new file mode 100644
index 0000000000..c49e628fd9
--- /dev/null
+++ b/lib/pkcs11.c
@@ -0,0 +1,1252 @@
+/*
+ neon PKCS#11 support
+ Copyright (C) 2008, Joe Orton <joe@manyfish.co.uk>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA
+*/
+
+#include <gnutls_int.h>
+#include <pakchois/pakchois.h>
+#include <gnutls/pkcs11.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+
+#define MAX_PROVIDERS 16
+#define ID_SIZE 128
+
+typedef int (*find_func_t)(pakchois_session_t *pks, struct ck_token_info* tinfo, void* input);
+
+struct gnutls_pkcs11_provider_s {
+ pakchois_module_t *module;
+ unsigned long nslots;
+ ck_slot_id_t *slots;
+};
+
+struct pkcs11_url_info
+{
+ /* everything here is null terminated strings */
+ opaque id[ID_SIZE];
+ opaque type[16]; /* cert/key etc. */
+ opaque manufacturer[sizeof (((struct ck_token_info *)NULL)->manufacturer_id)+1];
+ opaque token[sizeof (((struct ck_token_info *)NULL)->label)+1];
+ opaque serial[sizeof (((struct ck_token_info *)NULL)->serial_number)+1];
+ opaque model[sizeof (((struct ck_token_info *)NULL)->model)+1];
+};
+
+struct gnutls_pkcs11_crt_st {
+ gnutls_datum_t raw;
+ gnutls_certificate_type_t type;
+ struct pkcs11_url_info info;
+};
+
+struct url_find_data_st {
+ gnutls_pkcs11_crt_t crt;
+ char certid_raw[ID_SIZE/2];
+ size_t certid_raw_size;
+};
+
+struct crt_find_data_st {
+ gnutls_pkcs11_crt_t *p_list;
+ unsigned int* n_list;
+ unsigned int current;
+ pkcs11_crt_attributes flags;
+ struct pkcs11_url_info info;
+};
+
+static struct gnutls_pkcs11_provider_s providers[MAX_PROVIDERS];
+static int active_providers = 0;
+
+static gnutls_pkcs11_pin_callback_t pin_func;
+static void* pin_data;
+
+int gnutls_pkcs11_add_provider (const char * name, const char * params)
+{
+
+ if (active_providers >= MAX_PROVIDERS) {
+ gnutls_assert();
+ return GNUTLS_E_CONSTRAINT_ERROR;
+ }
+
+ active_providers++;
+ if (pakchois_module_load(&providers[active_providers-1].module, name) != CKR_OK) {
+ gnutls_assert();
+ _gnutls_debug_log("p11: Cannot load provider %s\n", name);
+ active_providers--;
+ return GNUTLS_E_PKCS11_LOAD_ERROR;
+ }
+
+ /* cache the number of slots in this module */
+ if (pakchois_get_slot_list(providers[active_providers-1].module, 0, NULL, &providers[active_providers-1].nslots) != CKR_OK) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ providers[active_providers-1].slots = gnutls_malloc(sizeof(*providers[active_providers-1].slots)*providers[active_providers-1].nslots);
+ if (providers[active_providers-1].slots==NULL) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ if (pakchois_get_slot_list(providers[active_providers-1].module, 0, providers[active_providers-1].slots, &providers[active_providers-1].nslots) != CKR_OK) {
+ gnutls_assert();
+ gnutls_free(providers[active_providers-1].slots);
+ goto fail;
+ }
+
+ _gnutls_debug_log("p11: loaded provider '%s' with %d slots\n", name, providers[active_providers-1].nslots);
+
+ return 0;
+
+fail:
+ pakchois_module_destroy(providers[active_providers-1].module);
+ active_providers--;
+ return GNUTLS_E_PKCS11_LOAD_ERROR;
+
+}
+
+int gnutls_pkcs11_init(unsigned int flags, const char* configfile)
+{
+ int ret;
+
+ if (flags == GNUTLS_PKCS11_FLAG_MANUAL)
+ return 0;
+ else {
+ FILE *fp;
+ char line[512];
+ const char* library;
+
+ if (configfile == NULL)
+ configfile = "/etc/gnutls/pkcs11.conf";
+
+ fp = fopen(configfile, "r");
+ if (fp == NULL) {
+ gnutls_assert();
+ _gnutls_debug_log("Cannot load %s\n", configfile);
+ return GNUTLS_E_FILE_ERROR;
+ }
+
+ while (fgets (line, sizeof (line), fp) != NULL) {
+ if (strncmp(line, "load", sizeof("load")-1) == 0) {
+ char* p;
+ p = strchr(line, '=');
+ if (p==NULL) continue;
+
+ library = ++p;
+
+ p = strchr(line, '\n');
+ if (p!=NULL) {
+ *p=0;
+ }
+
+ ret = gnutls_pkcs11_add_provider(library, NULL);
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_debug_log("Cannot load provider: %s\n", library);
+ continue;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+void gnutls_pkcs11_deinit (void)
+{
+ int i;
+
+ for (i=0;i<active_providers;i++) {
+ pakchois_module_destroy(providers[i].module);
+ }
+ active_providers = 0;
+}
+
+void gnutls_pkcs11_set_pin_function(gnutls_pkcs11_pin_callback_t fn,
+ void *userdata)
+{
+ pin_func = fn;
+ pin_data = userdata;
+}
+
+static int unescape_string (char* output, const char* input, size_t* size, char terminator)
+{
+ gnutls_string str;
+ int ret = 0;
+ char* p;
+ int len;
+
+ _gnutls_string_init(&str, gnutls_malloc, gnutls_realloc, gnutls_free);
+
+ /* find terminator */
+ p = strchr(input, terminator);
+ if (p!=NULL)
+ len = p-input;
+ else
+ len = strlen(input);
+
+ ret = _gnutls_string_append_data(&str, input, len);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = _gnutls_string_unescape(&str);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = _gnutls_string_append_data(&str, "", 1);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ _gnutls_string_get_data(&str, output, size);
+
+ _gnutls_string_clear(&str);
+
+ return ret;
+}
+
+static int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info)
+{
+int ret;
+char* p1;
+char* hexid = NULL;
+size_t l;
+
+ memset( info, 0, sizeof(*info));
+
+ if (strstr(url, "pkcs11:")==NULL) {
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto cleanup;
+ }
+
+ if ((p1=strstr(url, "manufacturer="))!= NULL) {
+ p1+=sizeof("manufacturer=")-1;
+ l=sizeof (info->manufacturer);
+
+ ret = unescape_string(info->manufacturer, p1, &l, ';');
+ if (ret < 0) {
+ goto cleanup;
+ }
+ }
+
+ if ((p1=strstr(url, "token="))!= NULL) {
+ p1+=sizeof("token=")-1;
+ l=sizeof (info->token);
+
+ ret = unescape_string(info->token, p1, &l, ';');
+ if (ret < 0) {
+ goto cleanup;
+ }
+ }
+
+ if ((p1=strstr(url, "serial="))!= NULL) {
+ p1+=sizeof("serial=")-1;
+ l=sizeof (info->serial);
+
+ ret = unescape_string (info->serial, p1, &l, ';');
+ if (ret < 0) {
+ goto cleanup;
+ }
+ }
+
+ if ((p1=strstr(url, "model="))!= NULL) {
+ p1+=sizeof("model=")-1;
+ l=sizeof (info->model);
+
+ ret = unescape_string (info->model,
+ p1, &l, ';');
+ if (ret < 0) {
+ goto cleanup;
+ }
+ }
+
+
+ if (((p1=strstr(url, ";id="))!= NULL) || ((p1=strstr(url, ":id="))!= NULL)) {
+ p1+=sizeof(";id=")-1;
+ hexid = gnutls_strdup(p1);
+ if (hexid == NULL) {
+ goto cleanup;
+ }
+
+ if ((p1=strchr(hexid, ';'))!= NULL) {
+ *p1 = 0;
+ } else {
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto cleanup;
+ }
+
+ l = sizeof(info->id);
+ ret = _gnutls_hex2bin(hexid, strlen(hexid), info->id, &l);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ gnutls_free(hexid);
+
+ return ret;
+
+}
+
+#define INVALID_CHARS "\\/\"'%&#@!?$* <>{}[]()`|:;,.+-"
+
+static int append(gnutls_string* dest, const char* tname, const char* p11name, int init)
+{
+ gnutls_string tmpstr;
+ int ret;
+
+ _gnutls_string_init(&tmpstr, gnutls_malloc, gnutls_realloc, gnutls_free);
+ if ((ret=_gnutls_string_append_str(&tmpstr, tname))<0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_string_escape(&tmpstr, INVALID_CHARS);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if ((ret=_gnutls_string_append_data(&tmpstr, "", 1)) < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if ((ret=_gnutls_string_append_printf(dest, "%s%s=%s", (init!=0)?";":"", p11name, tmpstr.data)) < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ _gnutls_string_clear(&tmpstr);
+
+ return ret;
+
+}
+
+
+static int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url)
+{
+ gnutls_string str;
+ int init = 0;
+ int ret;
+ char *s;
+
+ _gnutls_string_init (&str, gnutls_malloc, gnutls_realloc, gnutls_free);
+
+ _gnutls_string_append_str(&str, "pkcs11:");
+
+ if (info->token[0]) {
+ ret = append(&str, info->token, "token", init);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ init = 1;
+ }
+
+ if (info->model[0]) {
+ ret = append(&str, info->model, "model", init);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ init = 1;
+ }
+
+ if (info->manufacturer[0]) {
+ ret = append(&str, info->manufacturer, "manufacturer", init);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ init = 1;
+ }
+
+ if (info->serial[0]) {
+ ret = append(&str, info->serial, "serial", init);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ init = 1;
+ }
+
+ ret = _gnutls_string_append_printf(&str, ";id=%s", info->id);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ *url = str.data;
+
+ return 0;
+
+cleanup:
+ _gnutls_string_clear(&str);
+ return ret;
+}
+
+int gnutls_pkcs11_crt_init(gnutls_pkcs11_crt_t * crt)
+{
+ *crt = gnutls_malloc(sizeof(struct gnutls_pkcs11_crt_st));
+ if (*crt == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+}
+
+void gnutls_pkcs11_crt_deinit(gnutls_pkcs11_crt_t crt)
+{
+ free(crt);
+}
+
+static void terminate_string(unsigned char *str, size_t len)
+{
+ unsigned char *ptr = str + len - 1;
+
+ while ((*ptr == ' ' || *ptr == '\t' || *ptr == '\0') && ptr >= str)
+ ptr--;
+
+ if (ptr == str - 1)
+ str[0] = '\0';
+ else if (ptr == str + len - 1)
+ str[len-1] = '\0';
+ else
+ ptr[1] = '\0';
+}
+
+static int pk11_login(struct gnutls_pkcs11_provider_s *prov, ck_slot_id_t slot_id,
+ pakchois_session_t *pks, struct ck_slot_info *sinfo, struct ck_token_info* tinfo)
+{
+ int attempt = 0;
+ ck_rv_t rv;
+
+ if (pakchois_get_token_info(prov->module, slot_id, tinfo) != CKR_OK) {
+ gnutls_assert();
+ _gnutls_debug_log("pk11: GetTokenInfo failed\n");
+ return GNUTLS_E_PKCS11_ERROR;
+ }
+
+ if ((tinfo->flags & CKF_LOGIN_REQUIRED) == 0) {
+ _gnutls_debug_log("pk11: No login required.\n");
+ return 0;
+ }
+
+ /* For a token with a "protected" (out-of-band) authentication
+ * path, calling login with a NULL username is all that is
+ * required. */
+ if (tinfo->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
+ if (pakchois_login(pks, CKU_USER, NULL, 0) == CKR_OK) {
+ return 0;
+ }
+ else {
+ gnutls_assert();
+ _gnutls_debug_log("pk11: Protected login failed.\n");
+ return GNUTLS_E_PKCS11_ERROR;
+ }
+ }
+
+ /* Otherwise, PIN entry is necessary for login, so fail if there's
+ * no callback. */
+ if (!pin_func) {
+ gnutls_assert();
+ _gnutls_debug_log("pk11: No pin callback but login required.\n");
+ return GNUTLS_E_PKCS11_PIN_ERROR;
+ }
+
+ terminate_string(sinfo->slot_description, sizeof sinfo->slot_description);
+
+ do {
+ char pin[GNUTLS_PKCS11_MAX_PIN_LEN];
+ unsigned int flags = 0;
+
+ /* If login has been attempted once already, check the token
+ * status again, the flags might change. */
+ if (attempt) {
+ if (pakchois_get_token_info(prov->module, slot_id,
+ tinfo) != CKR_OK) {
+ _gnutls_debug_log("pk11: GetTokenInfo failed\n");
+ gnutls_assert();
+ return GNUTLS_E_PKCS11_ERROR;
+ }
+ }
+
+ if (tinfo->flags & CKF_USER_PIN_COUNT_LOW)
+ flags |= GNUTLS_PKCS11_PIN_COUNT_LOW;
+ if (tinfo->flags & CKF_USER_PIN_FINAL_TRY)
+ flags |= GNUTLS_PKCS11_PIN_FINAL_TRY;
+
+ terminate_string(tinfo->label, sizeof tinfo->label);
+
+ if (pin_func(pin_data, attempt++,
+ (char *)sinfo->slot_description,
+ (char *)tinfo->label, flags, pin, sizeof(pin))) {
+ return GNUTLS_E_PKCS11_PIN_ERROR;
+ }
+
+ rv = pakchois_login(pks, CKU_USER, (unsigned char *)pin, strlen(pin));
+
+ /* Try to scrub the pin off the stack. Clever compilers will
+ * probably optimize this away, oh well. */
+ memset(pin, 0, sizeof pin);
+ } while (rv == CKR_PIN_INCORRECT);
+
+ _gnutls_debug_log("pk11: Login result = %lu\n", rv);
+
+ return (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) ? 0 : GNUTLS_E_PKCS11_ERROR;
+}
+
+static int traverse_tokens (find_func_t find_func, void* input)
+{
+ struct ck_attribute a[3];
+ ck_rv_t rv;
+ int found = 0, x, z, ret;
+ pakchois_session_t *pks = NULL;
+
+ for (x=0;x<active_providers;x++) {
+ for (z=0;z<providers[x].nslots;z++) {
+ struct ck_token_info tinfo;
+ rv = pakchois_open_session(providers[x].module, providers[x].slots[z],
+ CKF_SERIAL_SESSION, NULL, NULL, &pks);
+ if (rv != CKR_OK) {
+ continue;
+ }
+
+ if (pakchois_get_token_info(providers[x].module, providers[x].slots[z], &tinfo) != CKR_OK) {
+ continue;
+ }
+
+ /* XXX make wrapper for token_info? */
+ terminate_string(tinfo.manufacturer_id, sizeof tinfo.manufacturer_id);
+ terminate_string(tinfo.label, sizeof tinfo.label);
+ terminate_string(tinfo.model, sizeof tinfo.model);
+ terminate_string(tinfo.serial_number, sizeof tinfo.serial_number);
+
+ ret = find_func(pks, &tinfo, input);
+
+ pakchois_close_session(pks);
+ pks = NULL;
+
+ if (ret == 0) {
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ /* final call */
+
+ if (found == 0) {
+ ret = find_func(pks, NULL, input);
+ } else {
+ ret = 0;
+ }
+
+cleanup:
+ if (pks != NULL) pakchois_close_session(pks);
+
+ return ret;
+}
+
+/* imports a raw certificate from a token to a pkcs11_crt_t structure.
+ */
+static int pkcs11_crt_import(gnutls_pkcs11_crt_t crt, const gnutls_datum_t* data,
+ const gnutls_datum_t * id, struct ck_token_info* tinfo)
+{
+ char *s;
+ int ret;
+
+ crt->type = GNUTLS_CRT_X509;
+ ret = _gnutls_set_datum(&crt->raw, data->data, data->size);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ terminate_string(tinfo->manufacturer_id, sizeof tinfo->manufacturer_id);
+ terminate_string(tinfo->label, sizeof tinfo->label);
+ terminate_string(tinfo->model, sizeof tinfo->model);
+ terminate_string(tinfo->serial_number, sizeof tinfo->serial_number);
+
+ /* write data */
+ snprintf(crt->info.manufacturer, sizeof(crt->info.manufacturer), "%s", tinfo->manufacturer_id);
+ snprintf(crt->info.token, sizeof(crt->info.token), "%s", tinfo->label);
+ snprintf(crt->info.model, sizeof(crt->info.model), "%s", tinfo->model);
+ snprintf(crt->info.serial, sizeof(crt->info.serial), "%s", tinfo->serial_number);
+ strcpy(crt->info.type, "cert");
+
+ s = _gnutls_bin2hex(id->data, id->size, crt->info.id, sizeof(crt->info.id), ":");
+ if (s == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_PKCS11_ERROR;
+ }
+
+ return 0;
+}
+
+
+static int find_url(pakchois_session_t *pks, struct ck_token_info *tinfo, void* input)
+{
+ struct url_find_data_st* find_data = input;
+ struct ck_attribute a[3];
+ ck_object_class_t class;
+ ck_certificate_type_t type;
+ ck_rv_t rv;
+ ck_object_handle_t obj;
+ unsigned long count;
+ int found = 0, ret;
+ unsigned char value[8192], subject[8192];
+ char certid_tmp[ID_SIZE/2];
+
+ if (tinfo == NULL) { /* we don't support multiple calls */
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ /* do not bother reading the token if basic fields do not match
+ */
+ if (find_data->crt->info.manufacturer[0] != 0) {
+ if (strcmp(find_data->crt->info.manufacturer, tinfo->manufacturer_id) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->crt->info.token[0] != 0) {
+ if (strcmp(find_data->crt->info.token, tinfo->label) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->crt->info.model[0] != 0) {
+ if (strcmp(find_data->crt->info.model, tinfo->model) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->crt->info.serial[0] != 0) {
+ if (strcmp(find_data->crt->info.serial, tinfo->serial_number) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->crt->info.type[0] != 0) {
+ if (strcmp(find_data->crt->info.type, "cert") != 0) {
+ gnutls_assert();
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ }
+ }
+
+ /* search the token for the id */
+
+ /* Find objects with cert class and X.509 cert type. */
+ class = CKO_CERTIFICATE;
+ type = CKC_X_509;
+
+ a[0].type = CKA_CLASS;
+ a[0].value = &class;
+ a[0].value_len = sizeof class;
+ a[1].type = CKA_CERTIFICATE_TYPE;
+ a[1].value = &type;
+ a[1].value_len = sizeof type;
+
+
+ rv = pakchois_find_objects_init(pks, a, 2);
+ if (rv != CKR_OK) {
+ gnutls_assert();
+ _gnutls_debug_log("pk11: FindObjectsInit failed.\n");
+ ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ goto cleanup;
+ }
+
+ while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+ && count == 1) {
+
+ a[0].type = CKA_VALUE;
+ a[0].value = value;
+ a[0].value_len = sizeof value;
+ a[1].type = CKA_ID;
+ a[1].value = certid_tmp;
+ a[1].value_len = sizeof(certid_tmp);
+ a[2].type = CKA_SUBJECT;
+ a[2].value = subject;
+ a[2].value_len = sizeof subject;
+
+ if (pakchois_get_attribute_value(pks, obj, a, 3) == CKR_OK) {
+
+ if (a[1].value_len == find_data->certid_raw_size &&
+ memcmp(certid_tmp, find_data->certid_raw, find_data->certid_raw_size)==0) {
+ gnutls_datum_t id = { a[1].value, a[1].value_len };
+ gnutls_datum_t data = { a[0].value, a[0].value_len };
+
+ ret = pkcs11_crt_import(find_data->crt, &data, &id, tinfo);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ found = 1;
+ break;
+ }
+ }
+ else {
+ _gnutls_debug_log("pk11: Skipped cert, missing attrs.\n");
+ }
+ }
+
+ if (found == 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ } else {
+ ret = 0;
+ }
+
+cleanup:
+ pakchois_find_objects_final(pks);
+
+ return ret;
+}
+
+int gnutls_pkcs11_crt_import_url (gnutls_pkcs11_crt_t cert, const char * url)
+{
+ int ret;
+ struct url_find_data_st find_data;
+ size_t size;
+
+ /* fill in the find data structure */
+ find_data.crt = cert;
+
+ ret = pkcs11_url_to_info(url, &cert->info);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ find_data.certid_raw_size = sizeof(find_data.certid_raw);
+
+ size = find_data.certid_raw_size;
+ ret = _gnutls_hex2bin(cert->info.id, sizeof cert->info.id, find_data.certid_raw, &size);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = traverse_tokens(find_url, &find_data);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return 0;
+}
+
+int gnutls_pkcs11_crt_export_url (gnutls_pkcs11_crt_t cert, char ** url)
+{
+int ret;
+
+ ret = pkcs11_info_to_url(&cert->info, url);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return 0;
+}
+
+gnutls_certificate_type_t gnutls_pkcs11_crt_get_type (gnutls_pkcs11_crt_t certificate)
+{
+ return certificate->type;
+}
+
+/* Recover certificate list from tokens */
+
+static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void* input)
+{
+ struct crt_find_data_st* find_data = input;
+ struct ck_attribute a[3];
+ ck_object_class_t class;
+ ck_certificate_type_t type;
+ bool trusted;
+ ck_rv_t rv;
+ ck_object_handle_t obj;
+ unsigned long count;
+ unsigned char value[8192], subject[8192];
+ char certid_tmp[ID_SIZE/2];
+ int ret, i;
+
+ if (tinfo == NULL) { /* final call */
+ if (find_data->current <= *find_data->n_list)
+ ret = 0;
+ else
+ ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
+
+ *find_data->n_list = find_data->current;
+
+ return ret;
+ }
+
+ /* do not bother reading the token if basic fields do not match
+ */
+ if (find_data->info.manufacturer[0] != 0) {
+ if (strcmp(find_data->info.manufacturer, tinfo->manufacturer_id) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->info.token[0] != 0) {
+ if (strcmp(find_data->info.token, tinfo->label) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->info.model[0] != 0) {
+ if (strcmp(find_data->info.model, tinfo->model) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->info.serial[0] != 0) {
+ if (strcmp(find_data->info.serial, tinfo->serial_number) != 0)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (find_data->info.type[0] != 0) {
+ if (strcmp(find_data->info.type, "cert") != 0) {
+ gnutls_assert();
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ }
+ }
+
+ /* Find objects with cert class and X.509 cert type. */
+ class = CKO_CERTIFICATE;
+ type = CKC_X_509;
+ trusted = 1;
+
+ a[0].type = CKA_CLASS;
+ a[0].value = &class;
+ a[0].value_len = sizeof class;
+
+ if (find_data->flags == GNUTLS_PKCS11_CRT_ATTR_ALL || find_data->flags==GNUTLS_PKCS11_CRT_ATTR_WITH_PK) {
+ a[1].type = CKA_CERTIFICATE_TYPE;
+ a[1].value = &type;
+ a[1].value_len = sizeof type;
+ }
+
+ if (find_data->flags == GNUTLS_PKCS11_CRT_ATTR_TRUSTED) {
+ a[1].type = CKA_TRUSTED;
+ a[1].value = &trusted;
+ a[1].value_len = sizeof trusted;
+ }
+
+ rv = pakchois_find_objects_init(pks, a, 2);
+ if (rv != CKR_OK) {
+ gnutls_assert();
+ _gnutls_debug_log("pk11: FindObjectsInit failed.\n");
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+ && count == 1) {
+
+ a[0].type = CKA_VALUE;
+ a[0].value = value;
+ a[0].value_len = sizeof value;
+ a[1].type = CKA_ID;
+ a[1].value = certid_tmp;
+ a[1].value_len = sizeof(certid_tmp);
+ a[2].type = CKA_SUBJECT;
+ a[2].value = subject;
+ a[2].value_len = sizeof subject;
+
+ if (pakchois_get_attribute_value(pks, obj, a, 3) == CKR_OK) {
+ gnutls_datum_t data = { a[0].value, a[0].value_len };
+ gnutls_datum_t id = { a[1].value, a[1].value_len };
+
+ /* XXX check also ID with find_data->info.id */
+
+ if (find_data->flags == GNUTLS_PKCS11_CRT_ATTR_WITH_PK) {
+ gnutls_assert();
+ /* XXX verify that certificate has a corresponding private key */
+ //not yet
+ }
+
+ if (find_data->current < *find_data->n_list) {
+
+ ret = gnutls_pkcs11_crt_init(&find_data->p_list[find_data->current]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ ret = pkcs11_crt_import(find_data->p_list[find_data->current], &data, &id, tinfo);
+ if (ret < 0) {
+ gnutls_assert();
+ goto fail;
+ }
+ }
+
+ find_data->current++;
+
+ }
+ else {
+ _gnutls_debug_log("pk11: Skipped cert, missing attrs.\n");
+ }
+ }
+
+ pakchois_find_objects_final(pks);
+
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; /* continue until all tokens have been checked */
+
+fail:
+ pakchois_find_objects_final(pks);
+ for (i=0;i<find_data->current;i++) {
+ gnutls_pkcs11_crt_deinit(find_data->p_list[i]);
+ }
+ find_data->current = 0;
+
+ return ret;
+}
+
+int gnutls_pkcs11_crt_list_import (gnutls_pkcs11_crt_t * p_list, unsigned int *n_list, const char* url, pkcs11_crt_attributes flags)
+{
+ int ret;
+ struct crt_find_data_st find_data;
+
+ /* fill in the find data structure */
+ find_data.p_list = p_list;
+ find_data.n_list = n_list;
+ find_data.flags = flags;
+ find_data.current = 0;
+
+ if (url == NULL || url[0] == 0) {
+ url = "pkcs11:";
+ }
+
+ ret = pkcs11_url_to_info(url, &find_data.info);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = traverse_tokens(find_crts, &find_data);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return 0;
+}
+
+int gnutls_x509_crt_import_pkcs11( gnutls_x509_crt_t crt, gnutls_pkcs11_crt_t pkcs11_crt)
+{
+ return gnutls_x509_crt_import(crt, &pkcs11_crt->raw, GNUTLS_X509_FMT_DER);
+}
+
+int gnutls_x509_crt_list_import_pkcs11 (gnutls_x509_crt_t * certs,
+ unsigned int cert_max, gnutls_pkcs11_crt_t * const pkcs11_certs,
+ unsigned int flags)
+{
+ int i, j;
+ int ret;
+
+ for (i=0;i<cert_max;i++) {
+ ret = gnutls_x509_crt_init(&certs[i]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = gnutls_x509_crt_import_pkcs11( certs[i], pkcs11_certs[i]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ return 0;
+
+cleanup:
+ for (j=0;j<i;j++) {
+ gnutls_x509_crt_deinit(certs[j]);
+ }
+
+ return ret;
+}
+
+
+/* To do list for PKCS#11 support:
+
+ - propagate error strings back to ne_session; use new
+ pakchois_error() for pakchois API 0.2
+ - add API to specify a particular slot number to use for clicert
+ - add API to specify a particular cert ID for clicert
+ - find a certificate which has an issuer matching the
+ CA dnames given by GnuTLS
+ - make sure subject name matches between pubkey and privkey
+ - check error handling & fail gracefully if the token is
+ ejected mid-session
+ - add API to enumerate/search provided certs and allow
+ direct choice? (or just punt)
+ - the session<->provider interface requires that
+ one clicert is used for all sessions. remove this limitation
+ - add API to import all CA certs as trusted
+ (CKA_CERTIFICATE_CATEGORY seems to be unused unfortunately;
+ just add all X509 certs with CKA_TRUSTED set to true))
+ - make DSA work
+
+*/
+
+
+#if 0
+#define KEYTYPE_IS_DSA(kt) (kt == CKK_DSA)
+
+static int pk11_find_pkey(ne_ssl_pkcs11_provider *prov,
+ pakchois_session_t *pks,
+ unsigned char *certid, unsigned long cid_len)
+{
+ struct ck_attribute a[3];
+ ck_object_class_t class;
+ ck_rv_t rv;
+ ck_object_handle_t obj;
+ unsigned long count;
+ int found = 0;
+
+ class = CKO_PRIVATE_KEY;
+
+ /* Find an object with private key class and a certificate ID
+ * which matches the certificate. */
+ /* FIXME: also match the cert subject. */
+ a[0].type = CKA_CLASS;
+ a[0].value = &class;
+ a[0].value_len = sizeof class;
+ a[1].type = CKA_ID;
+ a[1].value = certid;
+ a[1].value_len = cid_len;
+
+ rv = pakchois_find_objects_init(pks, a, 2);
+ if (rv != CKR_OK) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: FindObjectsInit failed.\n");
+ /* TODO: error propagation */
+ return 0;
+ }
+
+ rv = pakchois_find_objects(pks, &obj, 1, &count);
+ if (rv == CKR_OK && count == 1) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: Found private key.\n");
+
+ a[0].type = CKA_KEY_TYPE;
+ a[0].value = &prov->keytype;
+ a[0].value_len = sizeof prov->keytype;
+
+ if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK
+ && (prov->keytype == CKK_RSA || KEYTYPE_IS_DSA(prov->keytype))) {
+ found = 1;
+ prov->privkey = obj;
+ }
+ else {
+ NE_DEBUG(NE_DBG_SSL, "pk11: Could not determine key type.\n");
+ }
+ }
+
+ pakchois_find_objects_final(pks);
+
+ return found;
+}
+
+static int find_client_cert(ne_ssl_pkcs11_provider *prov,
+ pakchois_session_t *pks)
+{
+ unsigned char certid[8192];
+ unsigned long cid_len = sizeof certid;
+
+ /* TODO: match cert subject too. */
+ return pk11_find_x509(prov, pks, certid, &cid_len)
+ && pk11_find_pkey(prov, pks, certid, cid_len);
+}
+
+/* Callback invoked by GnuTLS to provide the signature. The signature
+ * operation is handled here by the PKCS#11 provider. */
+static int pk11_sign_callback(gnutls_session_t session,
+ void *userdata,
+ gnutls_certificate_type_t cert_type,
+ const gnutls_datum_t *cert,
+ const gnutls_datum_t *hash,
+ gnutls_datum_t *signature)
+{
+ ne_ssl_pkcs11_provider *prov = userdata;
+ ck_rv_t rv;
+ struct ck_mechanism mech;
+ unsigned long siglen;
+
+ if (!prov->session || prov->privkey == CK_INVALID_HANDLE) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: Cannot sign, no session/key.\n");
+ return GNUTLS_E_NO_CERTIFICATE_FOUND;
+ }
+
+ mech.mechanism = prov->keytype == CKK_DSA ? CKM_DSA : CKM_RSA_PKCS;
+ mech.parameter = NULL;
+ mech.parameter_len = 0;
+
+ /* Initialize signing operation; using the private key discovered
+ * earlier. */
+ rv = pakchois_sign_init(prov->session, &mech, prov->privkey);
+ if (rv != CKR_OK) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: SignInit failed: %lx.\n", rv);
+ return GNUTLS_E_PK_SIGN_FAILED;
+ }
+
+ /* Work out how long the signature must be: */
+ rv = pakchois_sign(prov->session, hash->data, hash->size, NULL, &siglen);
+ if (rv != CKR_OK) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: Sign1 failed.\n");
+ return GNUTLS_E_PK_SIGN_FAILED;
+ }
+
+ signature->data = gnutls_malloc(siglen);
+ signature->size = siglen;
+
+ rv = pakchois_sign(prov->session, hash->data, hash->size,
+ signature->data, &siglen);
+ if (rv != CKR_OK) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: Sign2 failed.\n");
+ return GNUTLS_E_PK_SIGN_FAILED;
+ }
+
+ NE_DEBUG(NE_DBG_SSL, "pk11: Signed successfully.\n");
+
+ return 0;
+}
+
+static void terminate_string(unsigned char *str, size_t len)
+{
+ unsigned char *ptr = str + len - 1;
+
+ while ((*ptr == ' ' || *ptr == '\t' || *ptr == '\0') && ptr >= str)
+ ptr--;
+
+ if (ptr == str - 1)
+ str[0] = '\0';
+ else if (ptr == str + len - 1)
+ str[len-1] = '\0';
+ else
+ ptr[1] = '\0';
+}
+
+
+static void pk11_provide(void *userdata, ne_session *sess,
+ const ne_ssl_dname *const *dnames,
+ int dncount)
+{
+ ne_ssl_pkcs11_provider *prov = userdata;
+ ck_slot_id_t *slots;
+ unsigned long scount, n;
+
+ if (prov->clicert) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: Using existing clicert.\n");
+ ne_ssl_set_clicert(sess, prov->clicert);
+ return;
+ }
+
+ if (pakchois_get_slot_list(prov->module, 1, NULL, &scount) != CKR_OK
+ || scount == 0) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: No slots.\n");
+ /* TODO: propagate error. */
+ return;
+ }
+
+ slots = ne_malloc(scount * sizeof *slots);
+ if (pakchois_get_slot_list(prov->module, 1, slots, &scount) != CKR_OK) {
+ ne_free(slots);
+ NE_DEBUG(NE_DBG_SSL, "pk11: Really, no slots?\n");
+ /* TODO: propagate error. */
+ return;
+ }
+
+ NE_DEBUG(NE_DBG_SSL, "pk11: Found %ld slots.\n", scount);
+
+ for (n = 0; n < scount; n++) {
+ pakchois_session_t *pks;
+ ck_rv_t rv;
+ struct ck_slot_info sinfo;
+
+ if (pakchois_get_slot_info(prov->module, slots[n], &sinfo) != CKR_OK) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: GetSlotInfo failed\n");
+ continue;
+ }
+
+ if ((sinfo.flags & CKF_TOKEN_PRESENT) == 0) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: slot empty, ignoring\n");
+ continue;
+ }
+
+ rv = pakchois_open_session(prov->module, slots[n],
+ CKF_SERIAL_SESSION,
+ NULL, NULL, &pks);
+ if (rv != CKR_OK) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: could not open slot, %ld (%ld: %ld)\n",
+ rv, n, slots[n]);
+ continue;
+ }
+
+ if (pk11_login(prov, slots[n], pks, &sinfo) == 0) {
+ if (find_client_cert(prov, pks)) {
+ NE_DEBUG(NE_DBG_SSL, "pk11: Setup complete.\n");
+ prov->session = pks;
+ ne_ssl_set_clicert(sess, prov->clicert);
+ ne_free(slots);
+ return;
+ }
+ }
+
+ pakchois_close_session(pks);
+ }
+
+ ne_free(slots);
+}
+
+
+
+void ne_ssl_set_pkcs11_provider(ne_session *sess,
+ ne_ssl_pkcs11_provider *provider)
+{
+ sess->ssl_context->sign_func = pk11_sign_callback;
+ sess->ssl_context->sign_data = provider;
+
+ ne_ssl_provide_clicert(sess, pk11_provide, provider);
+}
+
+void ne_ssl_pkcs11_provider_destroy(ne_ssl_pkcs11_provider *prov)
+{
+ if (prov->session) {
+ pakchois_close_session(prov->session);
+ }
+ if (prov->clicert) {
+ ne_ssl_clicert_free(prov->clicert);
+ }
+ pakchois_module_destroy(prov->module);
+ ne_free(prov);
+}
+
+#endif
+
+
diff --git a/lib/x509/common.c b/lib/x509/common.c
index 788d926232..445a9328f3 100644
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -342,7 +342,7 @@ _gnutls_x509_data2hex (const opaque * data, size_t data_size,
return GNUTLS_E_INTERNAL_ERROR;
}
- res = _gnutls_bin2hex (data, data_size, escaped, sizeof (escaped));
+ res = _gnutls_bin2hex (data, data_size, escaped, sizeof (escaped), NULL);
if (!res)
{
gnutls_assert ();
diff --git a/lib/x509/dn.c b/lib/x509/dn.c
index a601264957..11e4c2de95 100644
--- a/lib/x509/dn.c
+++ b/lib/x509/dn.c
@@ -281,7 +281,7 @@ _gnutls_x509_parse_dn (ASN1_TYPE asn1_struct,
gnutls_assert ();
_gnutls_x509_log
("Found OID: '%s' with value '%s'\n",
- oid, _gnutls_bin2hex (value2, len, escaped, sizeof_escaped));
+ oid, _gnutls_bin2hex (value2, len, escaped, sizeof_escaped, NULL));
goto cleanup;
}
STR_APPEND (str_escape (string, escaped, sizeof_escaped));
diff --git a/src/Makefile.am b/src/Makefile.am
index 8b61d88ae4..f8648cee99 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -80,7 +80,7 @@ noinst_LTLIBRARIES += libcmd-cli-debug.la
libcmd_cli_debug_la_CFLAGS =
libcmd_cli_debug_la_SOURCES = tls_test.gaa tls_test-gaa.h tls_test-gaa.c
-certtool_SOURCES = certtool.c prime.c
+certtool_SOURCES = certtool.c prime.c pkcs11.c
certtool_LDADD = ../lib/libgnutls.la ../libextra/libgnutls-extra.la
certtool_LDADD += libcmd-certtool.la ../gl/libgnu.la
certtool_LDADD += $(LTLIBGCRYPT)
diff --git a/src/certtool-common.h b/src/certtool-common.h
index cb2e9ab1d7..07be84c5fc 100644
--- a/src/certtool-common.h
+++ b/src/certtool-common.h
@@ -22,10 +22,13 @@ enum
ACTION_PGP_INFO,
ACTION_PGP_PRIVKEY_INFO,
ACTION_RING_INFO,
- ACTION_REQUEST
+ ACTION_REQUEST,
+ ACTION_PKCS11_LIST,
};
#define TYPE_CRT 1
#define TYPE_CRQ 2
void certtool_version (void);
+void pkcs11_list( const char* url);
+
diff --git a/src/certtool-gaa.c b/src/certtool-gaa.c
index 8ff1d81fcd..b0bfd3f73c 100644
--- a/src/certtool-gaa.c
+++ b/src/certtool-gaa.c
@@ -161,6 +161,9 @@ void gaa_help(void)
__gaa_helpsingle(0, "v1", "", "Generate an X.509 version 1 certificate (no extensions).");
__gaa_helpsingle(0, "to-p12", "", "Generate a PKCS #12 structure.");
__gaa_helpsingle(0, "to-p8", "", "Generate a PKCS #8 key structure.");
+ __gaa_helpsingle(0, "pkcs11-provider", "Library ", "Specify the pkcs11 provider library");
+ __gaa_helpsingle(0, "pkcs11-url", "URL ", "Specify a pkcs11 URL");
+ __gaa_helpsingle(0, "pkcs11-list", "", "List objects specified by a PKCS#11 URL");
__gaa_helpsingle('8', "pkcs8", "", "Use PKCS #8 format for private keys.");
__gaa_helpsingle(0, "dsa", "", "Use DSA keys.");
__gaa_helpsingle(0, "hash", "STR ", "Hash algorithm to use for signing (MD5,SHA1,RMD160,SHA256,SHA384,SHA512).");
@@ -192,32 +195,36 @@ typedef struct _gaainfo gaainfo;
struct _gaainfo
{
-#line 131 "certtool.gaa"
+#line 139 "certtool.gaa"
int debug;
-#line 127 "certtool.gaa"
+#line 135 "certtool.gaa"
char *pkcs_cipher;
-#line 124 "certtool.gaa"
+#line 132 "certtool.gaa"
char *template;
-#line 121 "certtool.gaa"
+#line 129 "certtool.gaa"
char *infile;
-#line 118 "certtool.gaa"
+#line 126 "certtool.gaa"
char *outfile;
-#line 115 "certtool.gaa"
+#line 123 "certtool.gaa"
int quick_random;
-#line 112 "certtool.gaa"
+#line 120 "certtool.gaa"
int bits;
-#line 108 "certtool.gaa"
+#line 116 "certtool.gaa"
int outcert_format;
-#line 104 "certtool.gaa"
+#line 112 "certtool.gaa"
int incert_format;
-#line 101 "certtool.gaa"
+#line 109 "certtool.gaa"
int export;
-#line 98 "certtool.gaa"
+#line 106 "certtool.gaa"
char *hash;
-#line 95 "certtool.gaa"
+#line 103 "certtool.gaa"
int dsa;
-#line 92 "certtool.gaa"
+#line 100 "certtool.gaa"
int pkcs8;
+#line 95 "certtool.gaa"
+ char* pkcs11_url;
+#line 92 "certtool.gaa"
+ char* pkcs11_provider;
#line 85 "certtool.gaa"
int v1_cert;
#line 82 "certtool.gaa"
@@ -294,7 +301,7 @@ static int gaa_error = 0;
#define GAA_MULTIPLE_OPTION 3
#define GAA_REST 0
-#define GAA_NB_OPTION 49
+#define GAA_NB_OPTION 52
#define GAAOPTID_version 1
#define GAAOPTID_help 2
#define GAAOPTID_debug 3
@@ -312,38 +319,41 @@ static int gaa_error = 0;
#define GAAOPTID_hash 15
#define GAAOPTID_dsa 16
#define GAAOPTID_pkcs8 17
-#define GAAOPTID_to_p8 18
-#define GAAOPTID_to_p12 19
-#define GAAOPTID_v1 20
-#define GAAOPTID_fix_key 21
-#define GAAOPTID_pgp_key_info 22
-#define GAAOPTID_key_info 23
-#define GAAOPTID_smime_to_p7 24
-#define GAAOPTID_p7_info 25
-#define GAAOPTID_p12_info 26
-#define GAAOPTID_no_crq_extensions 27
-#define GAAOPTID_crq_info 28
-#define GAAOPTID_crl_info 29
-#define GAAOPTID_pgp_ring_info 30
-#define GAAOPTID_pgp_certificate_info 31
-#define GAAOPTID_certificate_info 32
-#define GAAOPTID_password 33
-#define GAAOPTID_load_ca_certificate 34
-#define GAAOPTID_load_ca_privkey 35
-#define GAAOPTID_load_certificate 36
-#define GAAOPTID_load_request 37
-#define GAAOPTID_load_privkey 38
-#define GAAOPTID_get_dh_params 39
-#define GAAOPTID_generate_dh_params 40
-#define GAAOPTID_verify_crl 41
-#define GAAOPTID_verify_chain 42
-#define GAAOPTID_generate_request 43
-#define GAAOPTID_generate_privkey 44
-#define GAAOPTID_update_certificate 45
-#define GAAOPTID_generate_crl 46
-#define GAAOPTID_generate_proxy 47
-#define GAAOPTID_generate_certificate 48
-#define GAAOPTID_generate_self_signed 49
+#define GAAOPTID_pkcs11_list 18
+#define GAAOPTID_pkcs11_url 19
+#define GAAOPTID_pkcs11_provider 20
+#define GAAOPTID_to_p8 21
+#define GAAOPTID_to_p12 22
+#define GAAOPTID_v1 23
+#define GAAOPTID_fix_key 24
+#define GAAOPTID_pgp_key_info 25
+#define GAAOPTID_key_info 26
+#define GAAOPTID_smime_to_p7 27
+#define GAAOPTID_p7_info 28
+#define GAAOPTID_p12_info 29
+#define GAAOPTID_no_crq_extensions 30
+#define GAAOPTID_crq_info 31
+#define GAAOPTID_crl_info 32
+#define GAAOPTID_pgp_ring_info 33
+#define GAAOPTID_pgp_certificate_info 34
+#define GAAOPTID_certificate_info 35
+#define GAAOPTID_password 36
+#define GAAOPTID_load_ca_certificate 37
+#define GAAOPTID_load_ca_privkey 38
+#define GAAOPTID_load_certificate 39
+#define GAAOPTID_load_request 40
+#define GAAOPTID_load_privkey 41
+#define GAAOPTID_get_dh_params 42
+#define GAAOPTID_generate_dh_params 43
+#define GAAOPTID_verify_crl 44
+#define GAAOPTID_verify_chain 45
+#define GAAOPTID_generate_request 46
+#define GAAOPTID_generate_privkey 47
+#define GAAOPTID_update_certificate 48
+#define GAAOPTID_generate_crl 49
+#define GAAOPTID_generate_proxy 50
+#define GAAOPTID_generate_certificate 51
+#define GAAOPTID_generate_self_signed 52
#line 168 "gaa.skel"
@@ -503,12 +513,31 @@ static int gaa_getint(char *arg)
return tmp;
}
+static char gaa_getchar(char *arg)
+{
+ if(strlen(arg) != 1)
+ {
+ printf("Option %s: '%s' isn't an character\n", gaa_current_option, arg);
+ GAAERROR(-1);
+ }
+ return arg[0];
+}
static char* gaa_getstr(char *arg)
{
return arg;
}
-
+static float gaa_getfloat(char *arg)
+{
+ float tmp;
+ char a;
+ if(sscanf(arg, "%f%c", &tmp, &a) < 1)
+ {
+ printf("Option %s: '%s' isn't a float number\n", gaa_current_option, arg);
+ GAAERROR(-1);
+ }
+ return tmp;
+}
/* option structures */
struct GAAOPTION_debug
@@ -553,6 +582,18 @@ struct GAAOPTION_hash
int size1;
};
+struct GAAOPTION_pkcs11_url
+{
+ char* arg1;
+ int size1;
+};
+
+struct GAAOPTION_pkcs11_provider
+{
+ char* arg1;
+ int size1;
+};
+
struct GAAOPTION_password
{
char* arg1;
@@ -625,6 +666,8 @@ static int gaa_get_option_num(char *str, int status)
GAA_CHECK1STR("", GAAOPTID_outfile);
GAA_CHECK1STR("", GAAOPTID_bits);
GAA_CHECK1STR("", GAAOPTID_hash);
+ GAA_CHECK1STR("", GAAOPTID_pkcs11_url);
+ GAA_CHECK1STR("", GAAOPTID_pkcs11_provider);
GAA_CHECK1STR("", GAAOPTID_password);
GAA_CHECK1STR("", GAAOPTID_load_ca_certificate);
GAA_CHECK1STR("", GAAOPTID_load_ca_privkey);
@@ -643,6 +686,7 @@ static int gaa_get_option_num(char *str, int status)
GAA_CHECK1STR("", GAAOPTID_export_ciphers);
GAA_CHECK1STR("", GAAOPTID_dsa);
GAA_CHECK1STR("8", GAAOPTID_pkcs8);
+ GAA_CHECK1STR("", GAAOPTID_pkcs11_list);
GAA_CHECK1STR("", GAAOPTID_to_p8);
GAA_CHECK1STR("", GAAOPTID_to_p12);
GAA_CHECK1STR("", GAAOPTID_v1);
@@ -690,6 +734,9 @@ static int gaa_get_option_num(char *str, int status)
GAA_CHECKSTR("hash", GAAOPTID_hash);
GAA_CHECKSTR("dsa", GAAOPTID_dsa);
GAA_CHECKSTR("pkcs8", GAAOPTID_pkcs8);
+ GAA_CHECKSTR("pkcs11-list", GAAOPTID_pkcs11_list);
+ GAA_CHECKSTR("pkcs11-url", GAAOPTID_pkcs11_url);
+ GAA_CHECKSTR("pkcs11-provider", GAAOPTID_pkcs11_provider);
GAA_CHECKSTR("to-p8", GAAOPTID_to_p8);
GAA_CHECKSTR("to-p12", GAAOPTID_to_p12);
GAA_CHECKSTR("v1", GAAOPTID_v1);
@@ -741,6 +788,8 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
struct GAAOPTION_outfile GAATMP_outfile;
struct GAAOPTION_bits GAATMP_bits;
struct GAAOPTION_hash GAATMP_hash;
+ struct GAAOPTION_pkcs11_url GAATMP_pkcs11_url;
+ struct GAAOPTION_pkcs11_provider GAATMP_pkcs11_provider;
struct GAAOPTION_password GAATMP_password;
struct GAAOPTION_load_ca_certificate GAATMP_load_ca_certificate;
struct GAAOPTION_load_ca_privkey GAATMP_load_ca_privkey;
@@ -769,14 +818,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
{
case GAAOPTID_version:
OK = 0;
-#line 136 "certtool.gaa"
+#line 144 "certtool.gaa"
{ certtool_version(); exit(0); ;};
return GAA_OK;
break;
case GAAOPTID_help:
OK = 0;
-#line 134 "certtool.gaa"
+#line 142 "certtool.gaa"
{ gaa_help(); exit(0); ;};
return GAA_OK;
@@ -786,7 +835,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_debug.arg1, gaa_getint, GAATMP_debug.size1);
gaa_index++;
-#line 132 "certtool.gaa"
+#line 140 "certtool.gaa"
{ gaaval->debug = GAATMP_debug.arg1 ;};
return GAA_OK;
@@ -796,7 +845,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_pkcs_cipher.arg1, gaa_getstr, GAATMP_pkcs_cipher.size1);
gaa_index++;
-#line 128 "certtool.gaa"
+#line 136 "certtool.gaa"
{ gaaval->pkcs_cipher = GAATMP_pkcs_cipher.arg1 ;};
return GAA_OK;
@@ -806,7 +855,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_template.arg1, gaa_getstr, GAATMP_template.size1);
gaa_index++;
-#line 125 "certtool.gaa"
+#line 133 "certtool.gaa"
{ gaaval->template = GAATMP_template.arg1 ;};
return GAA_OK;
@@ -816,7 +865,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_infile.arg1, gaa_getstr, GAATMP_infile.size1);
gaa_index++;
-#line 122 "certtool.gaa"
+#line 130 "certtool.gaa"
{ gaaval->infile = GAATMP_infile.arg1 ;};
return GAA_OK;
@@ -826,14 +875,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_outfile.arg1, gaa_getstr, GAATMP_outfile.size1);
gaa_index++;
-#line 119 "certtool.gaa"
+#line 127 "certtool.gaa"
{ gaaval->outfile = GAATMP_outfile.arg1 ;};
return GAA_OK;
break;
case GAAOPTID_disable_quick_random:
OK = 0;
-#line 116 "certtool.gaa"
+#line 124 "certtool.gaa"
{ gaaval->quick_random = 0; ;};
return GAA_OK;
@@ -843,42 +892,42 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_bits.arg1, gaa_getint, GAATMP_bits.size1);
gaa_index++;
-#line 113 "certtool.gaa"
+#line 121 "certtool.gaa"
{ gaaval->bits = GAATMP_bits.arg1 ;};
return GAA_OK;
break;
case GAAOPTID_outraw:
OK = 0;
-#line 110 "certtool.gaa"
+#line 118 "certtool.gaa"
{ gaaval->outcert_format=1 ;};
return GAA_OK;
break;
case GAAOPTID_outder:
OK = 0;
-#line 109 "certtool.gaa"
+#line 117 "certtool.gaa"
{ gaaval->outcert_format=1 ;};
return GAA_OK;
break;
case GAAOPTID_inraw:
OK = 0;
-#line 106 "certtool.gaa"
+#line 114 "certtool.gaa"
{ gaaval->incert_format=1 ;};
return GAA_OK;
break;
case GAAOPTID_inder:
OK = 0;
-#line 105 "certtool.gaa"
+#line 113 "certtool.gaa"
{ gaaval->incert_format=1 ;};
return GAA_OK;
break;
case GAAOPTID_export_ciphers:
OK = 0;
-#line 102 "certtool.gaa"
+#line 110 "certtool.gaa"
{ gaaval->export=1 ;};
return GAA_OK;
@@ -888,25 +937,52 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
GAA_TESTMOREARGS;
GAA_FILL(GAATMP_hash.arg1, gaa_getstr, GAATMP_hash.size1);
gaa_index++;
-#line 99 "certtool.gaa"
+#line 107 "certtool.gaa"
{ gaaval->hash = GAATMP_hash.arg1 ;};
return GAA_OK;
break;
case GAAOPTID_dsa:
OK = 0;
-#line 96 "certtool.gaa"
+#line 104 "certtool.gaa"
{ gaaval->dsa=1 ;};
return GAA_OK;
break;
case GAAOPTID_pkcs8:
OK = 0;
-#line 93 "certtool.gaa"
+#line 101 "certtool.gaa"
{ gaaval->pkcs8=1 ;};
return GAA_OK;
break;
+ case GAAOPTID_pkcs11_list:
+ OK = 0;
+#line 98 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_LIST ;};
+
+ return GAA_OK;
+ break;
+ case GAAOPTID_pkcs11_url:
+ OK = 0;
+ GAA_TESTMOREARGS;
+ GAA_FILL(GAATMP_pkcs11_url.arg1, gaa_getstr, GAATMP_pkcs11_url.size1);
+ gaa_index++;
+#line 96 "certtool.gaa"
+{ gaaval->pkcs11_url = GAATMP_pkcs11_url.arg1 ;};
+
+ return GAA_OK;
+ break;
+ case GAAOPTID_pkcs11_provider:
+ OK = 0;
+ GAA_TESTMOREARGS;
+ GAA_FILL(GAATMP_pkcs11_provider.arg1, gaa_getstr, GAATMP_pkcs11_provider.size1);
+ gaa_index++;
+#line 93 "certtool.gaa"
+{ gaaval->pkcs11_provider = GAATMP_pkcs11_provider.arg1 ;};
+
+ return GAA_OK;
+ break;
case GAAOPTID_to_p8:
OK = 0;
#line 90 "certtool.gaa"
@@ -1159,29 +1235,27 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
int gaa(int argc, char **argv, gaainfo *gaaval)
{
int tmp1, tmp2;
- int l;
- size_t i, j;
+ int i, j;
char *opt_list;
- i = 0;
-
GAAargv = argv;
GAAargc = argc;
opt_list = (char*) gaa_malloc(GAA_NB_OPTION + 1);
- for(l = 0; l < GAA_NB_OPTION + 1; l++)
- opt_list[l] = 0;
+ for(i = 0; i < GAA_NB_OPTION + 1; i++)
+ opt_list[i] = 0;
/* initialization */
if(inited == 0)
{
-#line 138 "certtool.gaa"
+#line 146 "certtool.gaa"
{ gaaval->bits = 2048; gaaval->pkcs8 = 0; gaaval->privkey = NULL; gaaval->ca=NULL; gaaval->ca_privkey = NULL;
gaaval->debug=1; gaaval->request = NULL; gaaval->infile = NULL; gaaval->outfile = NULL; gaaval->cert = NULL;
gaaval->incert_format = 0; gaaval->outcert_format = 0; gaaval->action=-1; gaaval->pass = NULL; gaaval->v1_cert = 0;
gaaval->export = 0; gaaval->template = NULL; gaaval->hash=NULL; gaaval->fix_key = 0; gaaval->quick_random=1;
- gaaval->privkey_op = 0; gaaval->pkcs_cipher = "3des"; gaaval->crq_extensions=1; ;};
+ gaaval->privkey_op = 0; gaaval->pkcs_cipher = "3des"; gaaval->crq_extensions=1; gaaval->pkcs11_provider= NULL;
+ gaaval->pkcs11_url = NULL; ;};
}
inited = 1;
@@ -1192,27 +1266,27 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
gaa_arg_used = gaa_malloc(argc * sizeof(char));
}
- for(l = 1; l < argc; l++)
- gaa_arg_used[l] = 0;
- for(l = 1; l < argc; l++)
+ for(i = 1; i < argc; i++)
+ gaa_arg_used[i] = 0;
+ for(i = 1; i < argc; i++)
{
- if(gaa_arg_used[l] == 0)
+ if(gaa_arg_used[i] == 0)
{
j = 0;
- tmp1 = gaa_is_an_argument(GAAargv[l]);
+ tmp1 = gaa_is_an_argument(GAAargv[i]);
switch(tmp1)
{
case GAA_WORD_OPTION:
j++;
case GAA_LETTER_OPTION:
j++;
- tmp2 = gaa_get_option_num(argv[l]+j, tmp1);
+ tmp2 = gaa_get_option_num(argv[i]+j, tmp1);
if(tmp2 == GAA_ERROR_NOMATCH)
{
- printf("Invalid option '%s'\n", argv[l]+j);
+ printf("Invalid option '%s'\n", argv[i]+j);
return 0;
}
- switch(gaa_try(tmp2, l+1, gaaval, opt_list))
+ switch(gaa_try(tmp2, i+1, gaaval, opt_list))
{
case GAA_ERROR_NOTENOUGH_ARGS:
printf("'%s': not enough arguments\n",gaa_current_option);
@@ -1225,18 +1299,18 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
default:
printf("Unknown error\n");
}
- gaa_arg_used[l] = 1;
+ gaa_arg_used[i] = 1;
break;
case GAA_MULTIPLE_OPTION:
- for(j = 1; j < strlen(argv[l]); j++)
+ for(j = 1; j < strlen(argv[i]); j++)
{
- tmp2 = gaa_get_option_num(argv[l]+j, tmp1);
+ tmp2 = gaa_get_option_num(argv[i]+j, tmp1);
if(tmp2 == GAA_ERROR_NOMATCH)
{
- printf("Invalid option '%c'\n", *(argv[l]+j));
+ printf("Invalid option '%c'\n", *(argv[i]+j));
return 0;
}
- switch(gaa_try(tmp2, l+1, gaaval, opt_list))
+ switch(gaa_try(tmp2, i+1, gaaval, opt_list))
{
case GAA_ERROR_NOTENOUGH_ARGS:
printf("'%s': not enough arguments\n",gaa_current_option);
@@ -1250,7 +1324,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
printf("Unknown error\n");
}
}
- gaa_arg_used[l] = 1;
+ gaa_arg_used[i] = 1;
break;
default: break;
}
@@ -1276,9 +1350,9 @@ if(gaa_processing_file == 0)
}
#endif
}
- for(l = 1; l < argc; l++)
+ for(i = 1; i < argc; i++)
{
- if(gaa_arg_used[l] == 0)
+ if(gaa_arg_used[i] == 0)
{
printf("Too many arguments\n");
return 0;
@@ -1329,7 +1403,7 @@ static int gaa_internal_get_next_str(FILE *file, gaa_str_node *tmp_str, int argc
len++;
a = fgetc( file);
- if(a==EOF) return 0; /* a = ' '; */
+ if(a==EOF) return 0; //a = ' ';
}
len += 1;
diff --git a/src/certtool-gaa.h b/src/certtool-gaa.h
index 3d4ee83a0f..28e3cce57c 100644
--- a/src/certtool-gaa.h
+++ b/src/certtool-gaa.h
@@ -8,32 +8,36 @@ typedef struct _gaainfo gaainfo;
struct _gaainfo
{
-#line 131 "certtool.gaa"
+#line 139 "certtool.gaa"
int debug;
-#line 127 "certtool.gaa"
+#line 135 "certtool.gaa"
char *pkcs_cipher;
-#line 124 "certtool.gaa"
+#line 132 "certtool.gaa"
char *template;
-#line 121 "certtool.gaa"
+#line 129 "certtool.gaa"
char *infile;
-#line 118 "certtool.gaa"
+#line 126 "certtool.gaa"
char *outfile;
-#line 115 "certtool.gaa"
+#line 123 "certtool.gaa"
int quick_random;
-#line 112 "certtool.gaa"
+#line 120 "certtool.gaa"
int bits;
-#line 108 "certtool.gaa"
+#line 116 "certtool.gaa"
int outcert_format;
-#line 104 "certtool.gaa"
+#line 112 "certtool.gaa"
int incert_format;
-#line 101 "certtool.gaa"
+#line 109 "certtool.gaa"
int export;
-#line 98 "certtool.gaa"
+#line 106 "certtool.gaa"
char *hash;
-#line 95 "certtool.gaa"
+#line 103 "certtool.gaa"
int dsa;
-#line 92 "certtool.gaa"
+#line 100 "certtool.gaa"
int pkcs8;
+#line 95 "certtool.gaa"
+ char* pkcs11_url;
+#line 92 "certtool.gaa"
+ char* pkcs11_provider;
#line 85 "certtool.gaa"
int v1_cert;
#line 82 "certtool.gaa"
diff --git a/src/certtool.c b/src/certtool.c
index 13f5fa3639..c3adc67b20 100644
--- a/src/certtool.c
+++ b/src/certtool.c
@@ -25,6 +25,7 @@
#include <gnutls/x509.h>
#include <gnutls/openpgp.h>
#include <gnutls/pkcs12.h>
+#include <gnutls/pkcs11.h>
#include <gcrypt.h>
@@ -941,6 +942,25 @@ gaa_parser (int argc, char **argv)
if ((ret = gnutls_global_init ()) < 0)
error (EXIT_FAILURE, 0, "global_init: %s", gnutls_strerror (ret));
+
+ if (info.pkcs11_provider != NULL)
+ {
+ ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
+ if (ret < 0)
+ fprintf (stderr, "pkcs11_init: %s", gnutls_strerror (ret));
+ else {
+ ret = gnutls_pkcs11_add_provider(info.pkcs11_provider, NULL);
+ if (ret < 0)
+ error (EXIT_FAILURE, 0, "pkcs11_add_provider: %s", gnutls_strerror (ret));
+ }
+ }
+ else
+ {
+ ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL);
+ if (ret < 0)
+ fprintf (stderr, "pkcs11_init: %s", gnutls_strerror (ret));
+ }
+
if ((ret = gnutls_global_init_extra ()) < 0)
error (EXIT_FAILURE, 0, "global_init_extra: %s", gnutls_strerror (ret));
@@ -1007,6 +1027,9 @@ gaa_parser (int argc, char **argv)
case ACTION_GENERATE_PKCS8:
generate_pkcs8 ();
break;
+ case ACTION_PKCS11_LIST:
+ pkcs11_list(info.pkcs11_url);
+ break;
#ifdef ENABLE_OPENPGP
case ACTION_PGP_INFO:
pgp_certificate_info ();
@@ -1026,6 +1049,9 @@ gaa_parser (int argc, char **argv)
exit (0);
}
fclose (outfile);
+
+ gnutls_pkcs11_deinit();
+ gnutls_global_deinit();
}
#define MAX_CRTS 500
diff --git a/src/certtool.gaa b/src/certtool.gaa
index 096f119613..53d3ac169a 100644
--- a/src/certtool.gaa
+++ b/src/certtool.gaa
@@ -89,6 +89,14 @@ option (to-p12) { $action = ACTION_TO_PKCS12; } "Generate a PKCS #12 structure."
option (to-p8) { $action = ACTION_GENERATE_PKCS8; } "Generate a PKCS #8 key structure."
+#char* pkcs11_provider;
+option (pkcs11-provider) STR "Library" { $pkcs11_provider = $1 } "Specify the pkcs11 provider library"
+
+#char* pkcs11_url;
+option (pkcs11-url) STR "URL" { $pkcs11_url = $1 } "Specify a pkcs11 URL"
+
+option (pkcs11-list) { $action = ACTION_PKCS11_LIST } "List objects specified by a PKCS#11 URL"
+
#int pkcs8;
option (8, pkcs8) { $pkcs8=1 } "Use PKCS #8 format for private keys."
@@ -139,4 +147,5 @@ init { $bits = 2048; $pkcs8 = 0; $privkey = NULL; $ca=NULL; $ca_privkey = NULL;
$debug=1; $request = NULL; $infile = NULL; $outfile = NULL; $cert = NULL;
$incert_format = 0; $outcert_format = 0; $action=-1; $pass = NULL; $v1_cert = 0;
$export = 0; $template = NULL; $hash=NULL; $fix_key = 0; $quick_random=1;
- $privkey_op = 0; $pkcs_cipher = "3des"; $crq_extensions=1; }
+ $privkey_op = 0; $pkcs_cipher = "3des"; $crq_extensions=1; $pkcs11_provider= NULL;
+ $pkcs11_url = NULL; }
diff --git a/src/pkcs11.c b/src/pkcs11.c
new file mode 100644
index 0000000000..fc3953d5dc
--- /dev/null
+++ b/src/pkcs11.c
@@ -0,0 +1,50 @@
+#include <config.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/extra.h>
+#include <gnutls/pkcs11.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "certtool-common.h"
+
+void pkcs11_list( const char* url)
+{
+gnutls_pkcs11_crt_t *crt_list;
+unsigned int crt_list_size = 0;
+int ret;
+char* output;
+int i;
+
+ if (url == NULL)
+ url = "pkcs11:";
+
+ ret = gnutls_pkcs11_crt_list_import( NULL, &crt_list_size, url, GNUTLS_PKCS11_CRT_ATTR_ALL);
+ if (ret != 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+ fprintf(stderr, "Error in crt_list_import (1): %s\n", gnutls_strerror(ret));
+ exit(1);
+ }
+
+ if (crt_list_size == 0) {
+ fprintf(stderr, "No matching certificates found\n");
+ exit(0);
+ }
+
+ crt_list = malloc(sizeof(*crt_list)*crt_list_size);
+ if (crt_list == NULL) {
+ fprintf(stderr, "Memory error\n");
+ exit(1);
+ }
+
+ ret = gnutls_pkcs11_crt_list_import( crt_list, &crt_list_size, url, GNUTLS_PKCS11_CRT_ATTR_ALL);
+ if (ret < 0) {
+ fprintf(stderr, "Error in crt_list_import: %s\n", gnutls_strerror(ret));
+ exit(1);
+ }
+
+ for (i=0;i<crt_list_size;i++) {
+ gnutls_pkcs11_crt_export_url(crt_list[i], &output);
+ fprintf(stderr, "cert[%d]: %s\n\n", i, output);
+ }
+
+ return;
+}