]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added initial PKCS #11 support. Certtool can now print lists of certificates
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 9 May 2010 15:20:40 +0000 (17:20 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 3 Jun 2010 17:40:27 +0000 (19:40 +0200)
available in system.

25 files changed:
lib/Makefile.am
lib/auth_srp.c
lib/configure.ac
lib/gnutls.pc.in
lib/gnutls_constate.c
lib/gnutls_errors.c
lib/gnutls_handshake.c
lib/gnutls_kx.c
lib/gnutls_psk.c
lib/gnutls_str.c
lib/gnutls_str.h
lib/includes/Makefile.am
lib/includes/gnutls/pkcs11.h [new file with mode: 0644]
lib/libgnutls.map
lib/openpgp/gnutls_openpgp.c
lib/pkcs11.c [new file with mode: 0644]
lib/x509/common.c
lib/x509/dn.c
src/Makefile.am
src/certtool-common.h
src/certtool-gaa.c
src/certtool-gaa.h
src/certtool.c
src/certtool.gaa
src/pkcs11.c [new file with mode: 0644]

index 8c88dd72db671f34a2a51cb9fba6a0664d0c7bec..e2cde097595a8f7a5a476af176cd71c0e2fe400f 100644 (file)
@@ -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 gnutls_mbuffers.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)
index d6c401bb9b0927dc29155a8282f147f461666bca..26f6cb94928fec6186c650aac4308ff4a0783368 100644 (file)
@@ -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);
 
index c28931c2c1b45385a575de5000f31550650f2fd2..af744502b5812e6bc9935ba16acf93cb033bc724 100644 (file)
@@ -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"
index a4a34954ff28dada8e0e0ec50c08aab279519c7c..5898ca1a725b9e1b7aa695cacfaad0b49803143c 100644 (file)
@@ -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}
index bd3622b8ea0842206fe4df3bc16a36568bbfdb7e..f6d58cc4301f3a4aa038ab6d908ea45d51dcd6b8 100644 (file)
@@ -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));
 
     }
 
index 8b0afd3bceea5adc87fd2d5c993a790c0e4f532c..1913420f0f652ed9fa64ebba10cab6d13aa1cf0a 100644 (file)
@@ -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);
index 7bf79b4af31b4cacc23d5dfa0f33937611d873bc..d5b8ab18ff8116efe8139155f14a443cd671ff2c 100644 (file)
@@ -1662,7 +1662,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 ==
@@ -2249,7 +2249,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);
@@ -2757,7 +2757,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)
index bec2ca34dbf5aab01a08bbfca856eb7d42fb6e86..1173160fd34e854b850be7c8f0cc1312435dd8df 100644 (file)
@@ -95,15 +95,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)
     {
@@ -147,7 +147,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,
@@ -157,7 +157,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);
@@ -209,7 +209,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;
 }
index 1a8d87dccf80a150068ac994ae71427d8f6e7dd8..a1f27740ac66ae219b99abaf6dba20595ffbc265 100644 (file)
@@ -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;
index 8e2ef85639a6cd7a97dafa9536754cff06fdbb01..2efe4c643f89dea84c64eeebfae114ae9cb34364 100644 (file)
@@ -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)
        {
index 53bd24058320f793a21273a2ce537d93d60cf182..a011f4a9ebfb6fc13f23b0b892575783768916e4 100644 (file)
@@ -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);
 
index 5c67d4331a4fdee796185c5371a4d527bfee592f..7798d463f69d0e493c93b8ef42587a0dd79c6df9 100644 (file)
@@ -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 (file)
index 0000000..092333a
--- /dev/null
@@ -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
index ad61d61ac66a89f1720c0222b1dd52e364036dcc..3e501e04fa10297cc4eabd2f50be9469f764a065 100644 (file)
@@ -602,6 +602,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:
index 90246f8964e0f85c2075df2086dabf526d940a4c..039a2e3f1d056ab6cfa69cd580687e61b06a4826 100644 (file)
@@ -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 (file)
index 0000000..c49e628
--- /dev/null
@@ -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
+
+
index c3e52f0867640cf4def5d5b59d58e0e175e01137..58aefda57aeeacfc361b9e5e61de760465d42b76 100644 (file)
@@ -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 ();
index 726d3e49f4dba8ef5e336cce193e232ecb735ff4..c97d4814f3ece7b09eb510ca7322ba040f98a890 100644 (file)
@@ -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));
index f518dc95f96cf943246a3d402cb484f01ebd9657..edd72231b0a90591594665f32a8d187f1e3b9c7c 100644 (file)
@@ -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)
index cb2e9ab1d7cd3fbbc6c01bf374fb5e10bc2b1215..07be84c5fc4b7b2e4a2697bc66002ea3131eb8f6 100644 (file)
@@ -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);
+
index 8ff1d81fcd8c203e4dd68af3ed21f551a07acca6..b0bfd3f73c670f04427508075c3ba988f7f9c3f2 100644 (file)
@@ -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,23 +937,50 @@ 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:
@@ -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;
index 3d4ee83a0f009c79d68a6234609f3edd78442601..28e3cce57c5fdf50816d7dc401b4944cdb7a11dc 100644 (file)
@@ -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"
index 860ab9012b238aede65fdbdd3dc2bf46f19b509f..b65386e027d4927db2a30078e399538128a18501 100644 (file)
@@ -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
index 096f119613556be04853a9f88ce8e547c2e8d055..53d3ac169af0efb6a718aaa02729fe2bee02cf6d 100644 (file)
@@ -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 (file)
index 0000000..fc3953d
--- /dev/null
@@ -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;
+}