]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added gnutls_pkcs11_privkey_t and gnutls_privkey_t types. Those are
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 15 May 2010 20:00:22 +0000 (22:00 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 3 Jun 2010 17:41:28 +0000 (19:41 +0200)
an abstract private key type that can be used to sign/encrypt any private key
of pkcs11,x509 or openpgp types. Added support for PKCS11 in gnutls-cli/gnutls-serv.

41 files changed:
doc/manpages/Makefile.am
lib/Makefile.am
lib/auth_cert.c
lib/auth_cert.h
lib/auth_dhe.c
lib/auth_rsa.c
lib/auth_rsa_export.c
lib/auth_srp_rsa.c
lib/gnutls_cert.c
lib/gnutls_cert.h
lib/gnutls_global.c
lib/gnutls_int.h
lib/gnutls_privkey.c [new file with mode: 0644]
lib/gnutls_sig.c
lib/gnutls_sig.h
lib/gnutls_state.c
lib/gnutls_str.c
lib/gnutls_x509.c
lib/gnutls_x509.h
lib/includes/gnutls/compat.h
lib/includes/gnutls/gnutls.h.in
lib/includes/gnutls/openpgp.h
lib/includes/gnutls/pkcs11.h
lib/includes/gnutls/privkey.h [new file with mode: 0644]
lib/includes/gnutls/x509.h
lib/libgnutls.map
lib/openpgp/gnutls_openpgp.c
lib/openpgp/gnutls_openpgp.h
lib/openpgp/openpgp_int.h
lib/pkcs11.c
lib/pkcs11_int.h [new file with mode: 0644]
lib/pkcs11_privkey.c [new file with mode: 0644]
lib/x509/privkey.c
lib/x509/sign.c
lib/x509/sign.h [new file with mode: 0644]
lib/x509/x509_int.h
src/cli.c
src/common.c
src/common.h
src/pkcs11.c
src/serv.c

index 6afff0ae5a9f113e2e5a6fb9c9c90b64b8acb681..49f13fd61e1e1c00a66448b1ca3b611ed90452eb 100644 (file)
@@ -178,6 +178,7 @@ APIMANS += gnutls_priority_deinit.3
 APIMANS += gnutls_priority_set_direct.3
 APIMANS += gnutls_set_default_priority.3
 APIMANS += gnutls_set_default_export_priority.3
+APIMANS += gnutls_privkey_sign_data.3
 APIMANS += gnutls_psk_free_client_credentials.3
 APIMANS += gnutls_psk_allocate_client_credentials.3
 APIMANS += gnutls_psk_set_client_credentials.3
@@ -273,6 +274,8 @@ APIMANS += gnutls_certificate_set_x509_crl_file.3
 APIMANS += gnutls_certificate_set_x509_simple_pkcs12_file.3
 APIMANS += gnutls_certificate_set_x509_simple_pkcs12_mem.3
 APIMANS += gnutls_certificate_free_crls.3
+APIMANS += gnutls_pkcs11_privkey_sign_data.3
+APIMANS += gnutls_pkcs11_privkey_decrypt_data.3
 APIMANS += gnutls_pem_base64_encode.3
 APIMANS += gnutls_pem_base64_encode_alloc.3
 APIMANS += gnutls_pem_base64_decode.3
@@ -422,8 +425,9 @@ APIMANS += gnutls_x509_privkey_export_rsa_raw.3
 APIMANS += gnutls_x509_privkey_export_dsa_raw.3
 APIMANS += gnutls_x509_privkey_generate.3
 APIMANS += gnutls_x509_privkey_get_key_id.3
-APIMANS += gnutls_x509_privkey_sign_data.3
+APIMANS += gnutls_x509_privkey_sign_data2.3
 APIMANS += gnutls_x509_privkey_sign_hash.3
+APIMANS += gnutls_x509_privkey_sign_data.3
 APIMANS += gnutls_x509_privkey_verify_data.3
 APIMANS += gnutls_x509_privkey_fix.3
 APIMANS += gnutls_x509_privkey_export_pkcs8.3
@@ -523,6 +527,7 @@ APIMANS += gnutls_certificate_set_openpgp_keyring_file.3
 APIMANS += gnutls_certificate_set_openpgp_keyring_mem.3
 APIMANS += gnutls_openpgp_set_recv_key_function.3
 APIMANS += gnutls_openpgp_privkey_sign_hash.3
+APIMANS += gnutls_openpgp_privkey_decrypt_data.3
 APIMANS += gnutls_openpgp_crt_print.3
 APIMANS += gnutls_openpgp_crt_init.3
 APIMANS += gnutls_openpgp_crt_deinit.3
index e2cde097595a8f7a5a476af176cd71c0e2fe400f..8716db6129482a32456a93e4c87897362cd07c70 100644 (file)
@@ -82,10 +82,10 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c gnutls_cipher.c        \
        auth_dh_common.c gnutls_helper.c gnutls_supplemental.c          \
        crypto.c random.c pk-libgcrypt.c mpi-libgcrypt.c cryptodev.c    \
        rnd-libgcrypt.c cipher-libgcrypt.c mac-libgcrypt.c ext_signature.c \
-       crypto-api.c ext_safe_renegotiation.c gnutls_mbuffers.c
+       crypto-api.c ext_safe_renegotiation.c gnutls_mbuffers.c gnutls_privkey.c
 
 if ENABLE_PKCS11
-COBJECTS += pkcs11.c
+COBJECTS += pkcs11.c pkcs11_privkey.c
 endif
 
 if ENABLE_OPRFI
index 89ec4bd23f935001e8527834f079f3b68ec0c1f9..2b7169886ceaf82a43b20eb5a803968e11e41bbf 100644 (file)
 #include <gnutls_state.h>
 #include <gnutls_pk.h>
 #include <gnutls_x509.h>
+#include <gnutls/privkey.h>
 #include "debug.h"
 
 #ifdef ENABLE_OPENPGP
 # include "openpgp/gnutls_openpgp.h"
 
-static gnutls_privkey *alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t
-                                              key);
+static gnutls_privkey_t alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t
+                                              key, int deinit);
 static gnutls_cert *alloc_and_load_pgp_certs (gnutls_openpgp_crt_t cert);
 
 #endif
 
 static gnutls_cert *alloc_and_load_x509_certs (gnutls_x509_crt_t * certs,
                                               unsigned);
-static gnutls_privkey *alloc_and_load_x509_key (gnutls_x509_privkey_t key);
+static gnutls_privkey_t alloc_and_load_x509_key (gnutls_x509_privkey_t key, int deinit);
 
+static gnutls_privkey_t alloc_and_load_pkcs11_key ( gnutls_pkcs11_privkey_t key, int deinit);
 
 
 /* Copies data from a internal certificate struct (gnutls_cert) to 
@@ -409,21 +411,47 @@ get_issuers (gnutls_session_t session,
   return 0;
 }
 
+static void st_to_st2(gnutls_retr2_st *st2, gnutls_retr_st* st)
+{
+       st2->cert_type = st->type;
+       if (st->type == GNUTLS_CRT_OPENPGP) {
+               st2->key_type = GNUTLS_PRIVKEY_OPENPGP;
+       } else {
+               st2->key_type = GNUTLS_PRIVKEY_X509;
+       }
+       st2->ncerts = st->ncerts;
+       st2->deinit_all = st->deinit_all;
+       
+       switch(st2->cert_type) {
+               case GNUTLS_CRT_OPENPGP:
+                       st2->cert.pgp = st->cert.pgp;
+                       st2->key.pgp = st->key.pgp;
+                       break;
+               case GNUTLS_CRT_X509:
+                       st2->cert.x509 = st->cert.x509;
+                       st2->key.x509 = st->key.x509;
+                       break;
+               default:
+                       return;
+       }
+
+}
+
 /* Calls the client get callback.
  */
 static int
 call_get_cert_callback (gnutls_session_t session,
-                       gnutls_datum_t * issuers_dn,
+                       const gnutls_datum_t * issuers_dn,
                        int issuers_dn_length,
                        gnutls_pk_algorithm_t * pk_algos, int pk_algos_length)
 {
   unsigned i;
   gnutls_cert *local_certs = NULL;
-  gnutls_privkey *local_key = NULL;
-  gnutls_retr_st st;
+  gnutls_privkey_t local_key = NULL;
   int ret = GNUTLS_E_INTERNAL_ERROR;
   gnutls_certificate_type_t type = gnutls_certificate_type_get (session);
   gnutls_certificate_credentials_t cred;
+  gnutls_retr2_st st2;
 
   cred = (gnutls_certificate_credentials_t)
     _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
@@ -433,29 +461,42 @@ call_get_cert_callback (gnutls_session_t session,
       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     }
 
-  memset (&st, 0, sizeof (st));
+  memset (&st2, 0, sizeof (st2));
 
-  if (session->security_parameters.entity == GNUTLS_SERVER)
-    {
-      if (cred->server_get_cert_callback == NULL)
+  if (cred->get_cert_callback)
        {
-         gnutls_assert ();
-         return GNUTLS_E_INTERNAL_ERROR;
+               ret = cred->get_cert_callback( session, issuers_dn, issuers_dn_length,
+                                       pk_algos, pk_algos_length, &st2);
+
        }
-      ret = cred->server_get_cert_callback (session, &st);
-    }
   else
-    {                          /* CLIENT */
-      if (cred->client_get_cert_callback == NULL)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_INTERNAL_ERROR;
+    { /* compatibility mode */
+         gnutls_retr_st st;
+         memset (&st, 0, sizeof (st));
+         if (session->security_parameters.entity == GNUTLS_SERVER)
+               {
+                       if (cred->server_get_cert_callback == NULL)
+                               {
+                                 gnutls_assert ();
+                                 return GNUTLS_E_INTERNAL_ERROR;
+                               }
+                       ret = cred->server_get_cert_callback (session, &st);
+                       if (ret >= 0) st_to_st2(&st2, &st);
+               }
+         else
+               {                               /* CLIENT */
+
+                 if (cred->client_get_cert_callback == NULL)
+                       {
+                         gnutls_assert ();
+                         return GNUTLS_E_INTERNAL_ERROR;
+                       }
+                 ret = cred->client_get_cert_callback (session,
+                                               issuers_dn, issuers_dn_length,
+                                               pk_algos, pk_algos_length, &st);
+                 if (ret >= 0) st_to_st2(&st2, &st);
+               }
        }
-      ret =
-       cred->client_get_cert_callback (session,
-                                       issuers_dn, issuers_dn_length,
-                                       pk_algos, pk_algos_length, &st);
-    }
 
   if (ret < 0)
     {
@@ -463,87 +504,119 @@ call_get_cert_callback (gnutls_session_t session,
       return GNUTLS_E_INTERNAL_ERROR;
     }
 
-  if (st.ncerts == 0)
+  if (st2.ncerts == 0)
     return 0;                  /* no certificate was selected */
 
-  if (type != st.type)
+  if (type != st2.cert_type)
     {
       gnutls_assert ();
       ret = GNUTLS_E_INVALID_REQUEST;
       goto cleanup;
     }
 
+
   if (type == GNUTLS_CRT_X509)
     {
-      local_certs = alloc_and_load_x509_certs (st.cert.x509, st.ncerts);
-      if (local_certs != NULL && st.key.x509 != NULL)
-       {
-         local_key = alloc_and_load_x509_key (st.key.x509);
-         if (local_key == NULL)
-           {
-             gnutls_assert ();
-             ret = GNUTLS_E_INTERNAL_ERROR;
-             goto cleanup;
-           }
-       }
-
+      local_certs = alloc_and_load_x509_certs (st2.cert.x509, st2.ncerts);
     }
   else
     {                          /* PGP */
-      if (st.ncerts > 1)
-       {
-         gnutls_assert ();
-         ret = GNUTLS_E_INVALID_REQUEST;
-         goto cleanup;
-       }
-
+      if (st2.ncerts > 1)
+               {
+                 gnutls_assert ();
+                 ret = GNUTLS_E_INVALID_REQUEST;
+                 goto cleanup;
+               }
 #ifdef ENABLE_OPENPGP
-      {
-       local_certs = alloc_and_load_pgp_certs (st.cert.pgp);
-       if (local_certs != NULL && st.key.pgp != NULL)
          {
-           local_key = alloc_and_load_pgp_key (st.key.pgp);
-           if (local_key == NULL)
-             {
-               gnutls_assert ();
-               ret = GNUTLS_E_INTERNAL_ERROR;
-               goto cleanup;
-             }
-         }
+               local_certs = alloc_and_load_pgp_certs (st2.cert.pgp);
       }
+#else
+               ret = GNUTLS_E_UNIMPLEMENTED_FEATURE;
+               goto cleanup;
 #endif
     }
 
+  if (local_certs == NULL) {
+         gnutls_assert();
+         ret = GNUTLS_E_MEMORY_ERROR;
+         goto cleanup;
+  }
+
+  switch(st2.key_type) {
+         case GNUTLS_PRIVKEY_OPENPGP:
+#ifdef ENABLE_OPENPGP
+               if (st2.key.pgp != NULL)
+                 {
+                       local_key = alloc_and_load_pgp_key (st2.key.pgp, st2.deinit_all);
+                       if (local_key == NULL)
+                         {
+                               gnutls_assert ();
+                               ret = GNUTLS_E_INTERNAL_ERROR;
+                               goto cleanup;
+                         }
+                 }
+                 break;
+#endif
+         case GNUTLS_PRIVKEY_PKCS11:
+               if (st2.key.pkcs11 != NULL)
+                 {
+                       local_key = alloc_and_load_pkcs11_key (st2.key.pkcs11, st2.deinit_all);
+                       if (local_key == NULL)
+                         {
+                               gnutls_assert ();
+                               ret = GNUTLS_E_INTERNAL_ERROR;
+                               goto cleanup;
+                         }
+                 }
+                 break;
+         case GNUTLS_PRIVKEY_X509:
+                 if (st2.key.x509 != NULL)
+                       {
+                         local_key = alloc_and_load_x509_key (st2.key.x509, st2.deinit_all);
+                         if (local_key == NULL)
+                               {
+                                 gnutls_assert ();
+                                 ret = GNUTLS_E_INTERNAL_ERROR;
+                                 goto cleanup;
+                               }
+                       }
+                       break;
+       }
+
   _gnutls_selected_certs_set (session, local_certs,
-                             (local_certs != NULL) ? st.ncerts : 0,
+                             (local_certs != NULL) ? st2.ncerts : 0,
                              local_key, 1);
 
   ret = 0;
 
 cleanup:
 
-  if (st.type == GNUTLS_CRT_X509)
+  if (st2.cert_type == GNUTLS_CRT_X509)
     {
-      if (st.deinit_all)
-       {
-         for (i = 0; i < st.ncerts; i++)
-           {
-             gnutls_x509_crt_deinit (st.cert.x509[i]);
-           }
-         gnutls_free (st.cert.x509);
-         gnutls_x509_privkey_deinit (st.key.x509);
-       }
+      if (st2.deinit_all)
+               {
+                 for (i = 0; i < st2.ncerts; i++)
+                       {
+                         gnutls_x509_crt_deinit (st2.cert.x509[i]);
+                       }
+               }
     }
   else
     {
 #ifdef ENABLE_OPENPGP
-      if (st.deinit_all)
-       {
-         gnutls_openpgp_crt_deinit (st.cert.pgp);
-         gnutls_openpgp_privkey_deinit (st.key.pgp);
-       }
+       if (st2.deinit_all)
+               {
+                 gnutls_openpgp_crt_deinit (st2.cert.pgp);
+               }
 #endif
     }
+    
+  if (ret < 0)
+    {
+      if (local_key != NULL)
+        gnutls_privkey_deinit(local_key);
+    }
 
   return ret;
 }
@@ -576,7 +649,7 @@ _select_client_cert (gnutls_session_t session,
       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     }
 
-  if (cred->client_get_cert_callback != NULL)
+  if (cred->client_get_cert_callback != NULL || cred->get_cert_callback != NULL)
     {
 
       /* use a callback to get certificate 
@@ -646,7 +719,7 @@ _select_client_cert (gnutls_session_t session,
          _gnutls_selected_certs_set (session,
                                      &cred->cert_list[indx][0],
                                      cred->cert_list_length[indx],
-                                     &cred->pkey[indx], 0);
+                                     cred->pkey[indx], 0);
        }
       else
        {
@@ -671,7 +744,7 @@ _gnutls_gen_x509_crt (gnutls_session_t session, opaque ** data)
   int ret, i;
   opaque *pdata;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
 
   /* find the appropriate certificate 
@@ -730,7 +803,7 @@ _gnutls_gen_openpgp_certificate (gnutls_session_t session, opaque ** data)
   int ret;
   opaque *pdata;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
 
   /* find the appropriate certificate */
@@ -804,7 +877,7 @@ _gnutls_gen_openpgp_certificate_fpr (gnutls_session_t session, opaque ** data)
   size_t fpr_size;
   opaque *pdata;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
 
   /* find the appropriate certificate */
@@ -1443,7 +1516,7 @@ _gnutls_gen_cert_client_cert_vrfy (gnutls_session_t session, opaque ** data)
 {
   int ret;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length, size;
   gnutls_datum_t signature;
   int total_data;
@@ -1685,7 +1758,7 @@ int
 _gnutls_get_selected_cert (gnutls_session_t session,
                           gnutls_cert ** apr_cert_list,
                           int *apr_cert_list_length,
-                          gnutls_privkey ** apr_pkey)
+                          gnutls_privkey_t * apr_pkey)
 {
   if (session->security_parameters.entity == GNUTLS_SERVER)
     {
@@ -1764,26 +1837,27 @@ alloc_and_load_x509_certs (gnutls_x509_crt_t * certs, unsigned ncerts)
 /* converts the given x509 key to gnutls_privkey* and allocates
  * space for it.
  */
-static gnutls_privkey *
-alloc_and_load_x509_key (gnutls_x509_privkey_t key)
+static gnutls_privkey_t
+alloc_and_load_x509_key (gnutls_x509_privkey_t key, int deinit)
 {
-  gnutls_privkey *local_key;
+  gnutls_privkey_t local_key;
   int ret = 0;
 
   if (key == NULL)
     return NULL;
 
-  local_key = gnutls_malloc (sizeof (gnutls_privkey));
-  if (local_key == NULL)
+  ret = gnutls_privkey_init(&local_key);
+  if (ret < 0) 
     {
       gnutls_assert ();
       return NULL;
     }
 
-  ret = _gnutls_x509_privkey_to_gkey (local_key, key);
+  ret = gnutls_privkey_import_x509 (local_key, key, deinit?GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE:0);
   if (ret < 0)
     {
       gnutls_assert ();
+      gnutls_privkey_deinit(local_key);
       return NULL;
     }
 
@@ -1838,26 +1912,27 @@ alloc_and_load_pgp_certs (gnutls_openpgp_crt_t cert)
 /* converts the given raw key to gnutls_privkey* and allocates
  * space for it.
  */
-static gnutls_privkey *
-alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t key)
+static gnutls_privkey_t
+alloc_and_load_pgp_key ( gnutls_openpgp_privkey_t key, int deinit)
 {
-  gnutls_privkey *local_key;
+  gnutls_privkey_t local_key;
   int ret = 0;
 
   if (key == NULL)
     return NULL;
 
-  local_key = gnutls_malloc (sizeof (gnutls_privkey));
-  if (local_key == NULL)
+  ret = gnutls_privkey_init(&local_key);
+  if (ret < 0)
     {
       gnutls_assert ();
       return NULL;
     }
 
-  ret = _gnutls_openpgp_privkey_to_gkey (local_key, key);
+  ret = gnutls_privkey_import_openpgp (local_key, key, deinit?GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE:0);
   if (ret < 0)
     {
       gnutls_assert ();
+      gnutls_privkey_deinit(local_key);
       return NULL;
     }
 
@@ -1865,6 +1940,36 @@ alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t key)
 }
 #endif
 
+/* converts the given raw key to gnutls_privkey* and allocates
+ * space for it.
+ */
+static gnutls_privkey_t
+alloc_and_load_pkcs11_key ( gnutls_pkcs11_privkey_t key, int deinit)
+{
+  gnutls_privkey_t local_key;
+  int ret = 0;
+
+  if (key == NULL)
+    return NULL;
+
+  ret = gnutls_privkey_init(&local_key);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return NULL;
+    }
+
+  ret = gnutls_privkey_import_pkcs11 (local_key, key, deinit?GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE:0);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      gnutls_privkey_deinit(local_key);
+      return NULL;
+    }
+
+  return local_key;
+}
+
 void
 _gnutls_selected_certs_deinit (gnutls_session_t session)
 {
@@ -1880,12 +1985,7 @@ _gnutls_selected_certs_deinit (gnutls_session_t session)
       session->internals.selected_cert_list = NULL;
       session->internals.selected_cert_list_length = 0;
 
-      _gnutls_gkey_deinit (session->internals.selected_key);
-      if (session->internals.selected_key)
-       {
-         gnutls_free (session->internals.selected_key);
-         session->internals.selected_key = NULL;
-       }
+      session->internals.selected_key = NULL;
     }
 
   return;
@@ -1894,7 +1994,7 @@ _gnutls_selected_certs_deinit (gnutls_session_t session)
 void
 _gnutls_selected_certs_set (gnutls_session_t session,
                            gnutls_cert * certs, int ncerts,
-                           gnutls_privkey * key, int need_free)
+                           gnutls_privkey_t key, int need_free)
 {
   _gnutls_selected_certs_deinit (session);
 
@@ -1979,7 +2079,7 @@ _gnutls_server_select_cert (gnutls_session_t session,
       _gnutls_selected_certs_set (session,
                                  &cred->cert_list[idx][0],
                                  cred->cert_list_length[idx],
-                                 &cred->pkey[idx], 0);
+                                 cred->pkey[idx], 0);
     }
   else
     /* Certificate does not support REQUESTED_ALGO.  */
index cdc91c0336d33b167d9d78bc770bcf4413e0e701..a0a82e721347249d3062dfc8e7f579571cf2c049 100644 (file)
@@ -30,6 +30,8 @@
 # include "auth_dh_common.h"
 # include "x509/x509_int.h"
 # include "openpgp/openpgp_int.h"
+# include <gnutls/privkey.h>
+# include <gnutls/compat.h>
 
 /* This structure may be complex, but it's the only way to
  * support a server that has multiple certificates
@@ -57,7 +59,7 @@ typedef struct gnutls_certificate_credentials_st
                                 * This is the same with the number of pkeys.
                                 */
 
-  gnutls_privkey *pkey;
+  gnutls_privkey_t *pkey;
   /* private keys. It contains ncerts private
    * keys. pkey[i] corresponds to certificate in
    * cert_list[i][0].
@@ -91,9 +93,11 @@ typedef struct gnutls_certificate_credentials_st
    */
   gnutls_datum_t x509_rdn_sequence;
 
-  gnutls_certificate_client_retrieve_function *client_get_cert_callback;
-  gnutls_certificate_server_retrieve_function *server_get_cert_callback;
+  gnutls_certificate_client_retrieve_function *client_get_cert_callback; /* deprecated */
+  gnutls_certificate_server_retrieve_function *server_get_cert_callback; /* deprecated */
   gnutls_certificate_verify_function *verify_callback;
+
+  gnutls_certificate_retrieve_function *get_cert_callback;
 } certificate_credentials_st;
 
 typedef struct rsa_info_st
@@ -141,14 +145,14 @@ int _gnutls_proc_cert_server_certificate (gnutls_session_t, opaque *, size_t);
 int _gnutls_get_selected_cert (gnutls_session_t session,
                               gnutls_cert ** apr_cert_list,
                               int *apr_cert_list_length,
-                              gnutls_privkey ** apr_pkey);
+                              gnutls_privkey_t * apr_pkey);
 
 int _gnutls_server_select_cert (struct gnutls_session_int *,
                                gnutls_pk_algorithm_t);
 void _gnutls_selected_certs_deinit (gnutls_session_t session);
 void _gnutls_selected_certs_set (gnutls_session_t session,
                                 gnutls_cert * certs, int ncerts,
-                                gnutls_privkey * key, int need_free);
+                                gnutls_privkey_t key, int need_free);
 
 #define _gnutls_proc_cert_client_certificate _gnutls_proc_cert_server_certificate
 
index 224adfb621053586f931d1ddff46358892936cb4..0a3c286e007084ed94bdb5b3821481d292d3d8b2 100644 (file)
@@ -87,7 +87,7 @@ gen_dhe_server_kx (gnutls_session_t session, opaque ** data)
   const bigint_t *mpis;
   int ret = 0, data_size;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
   gnutls_datum_t signature, ddata;
   gnutls_certificate_credentials_t cred;
index 7d22a9151f249f6347083273a11b6b0e905973da..261803952f712757273305ee68bf97f58ed2dc0f 100644 (file)
@@ -44,7 +44,7 @@
 #include <gnutls_mpi.h>
 
 int _gnutls_gen_rsa_client_kx (gnutls_session_t, opaque **);
-int _gnutls_proc_rsa_client_kx (gnutls_session_t, opaque *, size_t);
+static int proc_rsa_client_kx (gnutls_session_t, opaque *, size_t);
 
 const mod_auth_st rsa_auth_struct = {
   "RSA",
@@ -58,7 +58,7 @@ const mod_auth_st rsa_auth_struct = {
   _gnutls_proc_cert_server_certificate,
   _gnutls_proc_cert_client_certificate,
   NULL,                                /* proc server kx */
-  _gnutls_proc_rsa_client_kx,  /* proc client kx */
+  proc_rsa_client_kx,  /* proc client kx */
   _gnutls_proc_cert_client_cert_vrfy,  /* proc client cert vrfy */
   _gnutls_proc_cert_cert_req   /* proc server cert request */
 };
@@ -144,76 +144,13 @@ _gnutls_get_public_rsa_params (gnutls_session_t session,
   return 0;
 }
 
-/* This function reads the RSA parameters from the private key
- */
 static int
-_gnutls_get_private_rsa_params (gnutls_session_t session,
-                               bigint_t ** params, int *params_size)
-{
-  int bits;
-  gnutls_certificate_credentials_t cred;
-  gnutls_rsa_params_t rsa_params;
-
-  cred = (gnutls_certificate_credentials_t)
-    _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
-  if (cred == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
-    }
-
-  if (session->internals.selected_cert_list == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
-    }
-
-  bits =
-    _gnutls_mpi_get_nbits (session->internals.
-                          selected_cert_list[0].params[0]);
-
-  if (_gnutls_cipher_suite_get_kx_algo
-      (&session->security_parameters.current_cipher_suite)
-      == GNUTLS_KX_RSA_EXPORT && bits > 512)
-    {
-
-      rsa_params =
-       _gnutls_certificate_get_rsa_params (cred->rsa_params,
-                                           cred->params_func, session);
-      /* EXPORT case: */
-      if (rsa_params == NULL)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS;
-       }
-
-      /* In the export case, we do use temporary RSA params
-       * of 512 bits size. The params in the certificate are
-       * used to sign this temporary stuff.
-       */
-      *params_size = RSA_PRIVATE_PARAMS;
-      *params = rsa_params->params;
-
-      return 0;
-    }
-
-  /* non export cipher suites. */
-
-  *params_size = session->internals.selected_key->params_size;
-  *params = session->internals.selected_key->params;
-
-  return 0;
-}
-
-int
-_gnutls_proc_rsa_client_kx (gnutls_session_t session, opaque * data,
+proc_rsa_client_kx (gnutls_session_t session, opaque * data,
                            size_t _data_size)
 {
   gnutls_datum_t plaintext;
   gnutls_datum_t ciphertext;
   int ret, dsize;
-  bigint_t *params;
-  int params_len;
   int randomize_key = 0;
   ssize_t data_size = _data_size;
 
@@ -240,14 +177,7 @@ _gnutls_proc_rsa_client_kx (gnutls_session_t session, opaque * data,
       ciphertext.size = dsize;
     }
 
-  ret = _gnutls_get_private_rsa_params (session, &params, &params_len);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-
-  ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, params_len, 2);    /* btype==2 */
+  ret = gnutls_privkey_decrypt_data (session->internals.selected_key, 0, &ciphertext, &plaintext);
 
   if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE)
     {
index ba61db63d0fc9fac4801eedfd8a65c402859768b..fc738b7146ae088ef01e3ae7c570bce175b39677 100644 (file)
 #include <gnutls_x509.h>
 #include <gnutls_rsa_export.h>
 #include <gnutls_state.h>
+#include <random.h>
 
 int _gnutls_gen_rsa_client_kx (gnutls_session_t, opaque **);
-int _gnutls_proc_rsa_client_kx (gnutls_session_t, opaque *, size_t);
 static int gen_rsa_export_server_kx (gnutls_session_t, opaque **);
 static int proc_rsa_export_server_kx (gnutls_session_t, opaque *, size_t);
+static int proc_rsa_export_client_kx (gnutls_session_t session, opaque * data,
+                           size_t _data_size);
 
 const mod_auth_st rsa_export_auth_struct = {
   "RSA EXPORT",
@@ -60,11 +62,176 @@ const mod_auth_st rsa_export_auth_struct = {
   _gnutls_proc_cert_server_certificate,
   _gnutls_proc_cert_client_certificate,
   proc_rsa_export_server_kx,
-  _gnutls_proc_rsa_client_kx,  /* proc client kx */
+  proc_rsa_export_client_kx,   /* proc client kx */
   _gnutls_proc_cert_client_cert_vrfy,  /* proc client cert vrfy */
   _gnutls_proc_cert_cert_req   /* proc server cert request */
 };
 
+/* This function reads the RSA parameters from the private key
+ */
+static int
+_gnutls_get_private_rsa_params (gnutls_session_t session,
+                               bigint_t ** params, int *params_size)
+{
+  int bits;
+  gnutls_certificate_credentials_t cred;
+  gnutls_rsa_params_t rsa_params;
+
+  cred = (gnutls_certificate_credentials_t)
+    _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+  if (cred == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+    }
+
+  if (session->internals.selected_cert_list == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+    }
+
+  bits =
+    _gnutls_mpi_get_nbits (session->internals.
+                          selected_cert_list[0].params[0]);
+
+  if (_gnutls_cipher_suite_get_kx_algo
+      (&session->security_parameters.current_cipher_suite)
+      != GNUTLS_KX_RSA_EXPORT || bits < 512)
+    {
+      gnutls_assert();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  rsa_params =
+      _gnutls_certificate_get_rsa_params (cred->rsa_params,
+                                           cred->params_func, session);
+  /* EXPORT case: */
+  if (rsa_params == NULL)
+    {
+         gnutls_assert ();
+         return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS;
+    }
+
+  /* In the export case, we do use temporary RSA params
+   * of 512 bits size. The params in the certificate are
+   * used to sign this temporary stuff.
+   */
+  *params_size = RSA_PRIVATE_PARAMS;
+  *params = rsa_params->params;
+
+  return 0;
+}
+
+int proc_rsa_export_client_kx (gnutls_session_t session, opaque * data,
+                           size_t _data_size)
+{
+  gnutls_datum_t plaintext;
+  gnutls_datum_t ciphertext;
+  int ret, dsize;
+  bigint_t *params;
+  int params_len;
+  int randomize_key = 0;
+  ssize_t data_size = _data_size;
+
+  if (gnutls_protocol_get_version (session) == GNUTLS_SSL3)
+    {
+      /* SSL 3.0 
+       */
+      ciphertext.data = data;
+      ciphertext.size = data_size;
+    }
+  else
+    {
+      /* TLS 1.0
+       */
+      DECR_LEN (data_size, 2);
+      ciphertext.data = &data[2];
+      dsize = _gnutls_read_uint16 (data);
+
+      if (dsize != data_size)
+       {
+         gnutls_assert ();
+         return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+       }
+      ciphertext.size = dsize;
+    }
+
+  ret = _gnutls_get_private_rsa_params (session, &params, &params_len);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
+
+  ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, params_len, 2);    /* btype==2 */
+
+  if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE)
+    {
+      /* In case decryption fails then don't inform
+       * the peer. Just use a random key. (in order to avoid
+       * attack against pkcs-1 formating).
+       */
+      gnutls_assert ();
+      _gnutls_x509_log ("auth_rsa: Possible PKCS #1 format attack\n");
+      randomize_key = 1;
+    }
+  else
+    {
+      /* If the secret was properly formatted, then
+       * check the version number.
+       */
+      if (_gnutls_get_adv_version_major (session) != plaintext.data[0]
+         || _gnutls_get_adv_version_minor (session) != plaintext.data[1])
+       {
+         /* No error is returned here, if the version number check
+          * fails. We proceed normally.
+          * That is to defend against the attack described in the paper
+          * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima,
+          * Ondej Pokorny and Tomas Rosa.
+          */
+         gnutls_assert ();
+         _gnutls_x509_log
+           ("auth_rsa: Possible PKCS #1 version check format attack\n");
+       }
+    }
+
+  if (randomize_key != 0)
+    {
+      session->key->key.size = GNUTLS_MASTER_SIZE;
+      session->key->key.data = gnutls_malloc (session->key->key.size);
+      if (session->key->key.data == NULL)
+       {
+         gnutls_assert ();
+         return GNUTLS_E_MEMORY_ERROR;
+       }
+
+      /* we do not need strong random numbers here.
+       */
+      ret = _gnutls_rnd (GNUTLS_RND_NONCE, session->key->key.data,
+                        session->key->key.size);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
+
+    }
+  else
+    {
+      session->key->key.data = plaintext.data;
+      session->key->key.size = plaintext.size;
+    }
+
+  /* This is here to avoid the version check attack
+   * discussed above.
+   */
+  session->key->key.data[0] = _gnutls_get_adv_version_major (session);
+  session->key->key.data[1] = _gnutls_get_adv_version_minor (session);
+
+  return 0;
+}
+
 static int
 gen_rsa_export_server_kx (gnutls_session_t session, opaque ** data)
 {
@@ -74,11 +241,12 @@ gen_rsa_export_server_kx (gnutls_session_t session, opaque ** data)
   uint8_t *data_e, *data_m;
   int ret = 0, data_size;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
   gnutls_datum_t signature, ddata;
   gnutls_certificate_credentials_t cred;
   gnutls_sign_algorithm_t sign_algo;
+  unsigned int bits = 0;
 
   cred = (gnutls_certificate_credentials_t)
     _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
@@ -100,7 +268,8 @@ gen_rsa_export_server_kx (gnutls_session_t session, opaque ** data)
   /* abort sending this message if we have a certificate
    * of 512 bits or less.
    */
-  if (apr_pkey && _gnutls_mpi_get_nbits (apr_pkey->params[0]) <= 512)
+  gnutls_privkey_get_pk_algorithm(apr_pkey, &bits);
+  if (apr_pkey && bits <= 512)
     {
       gnutls_assert ();
       return GNUTLS_E_INT_RET_0;
index caf84a64109138dfbe847c252de6995868bce9ae..3967c57211a0d2e4beac90200db799d37dcb8a34 100644 (file)
@@ -86,7 +86,7 @@ gen_srp_cert_server_kx (gnutls_session_t session, opaque ** data)
   gnutls_datum_t signature, ddata;
   gnutls_certificate_credentials_t cred;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
   gnutls_sign_algorithm_t sign_algo;
 
index 5072c8ec17a6fdc81da1dfdfddf7a80d22574dad..2f41f28af341db66c8e7d010a6a001aad42bd69e 100644 (file)
@@ -76,7 +76,7 @@ gnutls_certificate_free_keys (gnutls_certificate_credentials_t sc)
 
   for (i = 0; i < sc->ncerts; i++)
     {
-      _gnutls_gkey_deinit (&sc->pkey[i]);
+      gnutls_privkey_deinit (sc->pkey[i]);
     }
 
   gnutls_free (sc->pkey);
@@ -425,6 +425,46 @@ void gnutls_certificate_server_set_retrieve_function
   cred->server_get_cert_callback = func;
 }
 
+/**
+ * gnutls_certificate_set_retrieve_function:
+ * @cred: is a #gnutls_certificate_credentials_t structure.
+ * @func: is the callback function
+ *
+ * This function sets a callback to be called in order to retrieve the
+ * certificate to be used in the handshake.
+ *
+ * The callback's function prototype is:
+ * int (*callback)(gnutls_session_t, const gnutls_datum_t* req_ca_dn, int nreqs,
+ * const gnutls_pk_algorithm_t* pk_algos, int pk_algos_length, gnutls_retr2_st* st);
+ *
+ * @req_ca_cert is only used in X.509 certificates.
+ * Contains a list with the CA names that the server considers trusted.
+ * Normally we should send a certificate that is signed
+ * by one of these CAs. These names are DER encoded. To get a more
+ * meaningful value use the function gnutls_x509_rdn_get().
+ *
+ * @pk_algos contains a list with server's acceptable signature algorithms.
+ * The certificate returned should support the server's given algorithms.
+ *
+ * @st should contain the certificates and private keys.
+ *
+ * If the callback function is provided then gnutls will call it, in the
+ * handshake, after the certificate request message has been received.
+ *
+ * In server side pk_algos and req_ca_dn are NULL.
+ *
+ * The callback function should set the certificate list to be sent,
+ * and return 0 on success. If no certificate was selected then the
+ * number of certificates should be set to zero. The value (-1)
+ * indicates error and the handshake will be terminated.
+ **/
+void gnutls_certificate_set_retrieve_function
+  (gnutls_certificate_credentials_t cred,
+   gnutls_certificate_retrieve_function * func)
+{
+  cred->get_cert_callback = func;
+}
+
 /**
  * gnutls_certificate_set_verify_function:
  * @cred: is a #gnutls_certificate_credentials_t structure.
index 7280899121339d18fe1a5f3e30d8ca39361d4ac6..4217d298e6a05c52ba17816afa6415a5e39a52dd 100644 (file)
@@ -82,28 +82,6 @@ typedef struct gnutls_cert
 #endif
 } gnutls_cert;
 
-typedef struct gnutls_privkey_int
-{
-  /* the size of params depends on the public
-   * key algorithm
-   * RSA: [0] is modulus
-   *      [1] is public exponent
-   *      [2] is private exponent
-   *      [3] is prime1 (p)
-   *      [4] is prime2 (q)
-   *      [5] is coefficient (u == inverse of p mod q)
-   * DSA: [0] is p
-   *      [1] is q
-   *      [2] is g
-   *      [3] is y (public key)
-   *      [4] is x (private key)
-   */
-  bigint_t params[MAX_PRIV_PARAMS_SIZE];
-  int params_size;             /* holds the number of params */
-
-  gnutls_pk_algorithm_t pk_algorithm;
-} gnutls_privkey;
-
 /* because gnutls_session_t is not defined when this file is included */
 struct gnutls_session_int;
 
@@ -120,7 +98,6 @@ int _gnutls_x509_raw_cert_to_gcert (gnutls_cert * gcert,
 int _gnutls_x509_crt_to_gcert (gnutls_cert * gcert, gnutls_x509_crt_t cert,
                               unsigned int flags);
 
-void _gnutls_gkey_deinit (gnutls_privkey * key);
 void _gnutls_gcert_deinit (gnutls_cert * cert);
 
 int _gnutls_selected_cert_supported_kx (struct gnutls_session_int *session,
index e74c161d121aacdd0f6c2ab5be6c13e02c9373c1..360bf1c54f740b0a0601b21b37ecbbeed083645b 100644 (file)
@@ -29,6 +29,7 @@
 #include <gnutls_dh.h>
 #include <random.h>
 #include <gcrypt.h>
+#include <gnutls/pkcs11.h>
 
 #include <gnutls_extensions.h> /* for _gnutls_ext_init */
 #include <gnutls_cryptodev.h>
@@ -249,6 +250,8 @@ gnutls_global_init (void)
       goto out;
     }
 
+  gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL);
+  
   _gnutls_cryptodev_init ();
 
 out:
@@ -276,6 +279,7 @@ gnutls_global_deinit (void)
       asn1_delete_structure (&_gnutls_pkix1_asn);
       _gnutls_crypto_deregister ();
       _gnutls_cryptodev_deinit ();
+      gnutls_pkcs11_deinit();
     }
   _gnutls_init--;
 }
index a89f13741fe7b4397f360569f4709a537bd24c5e..1ca2e12e4e596a9a50d6048afe776697efae75e9 100644 (file)
@@ -672,7 +672,7 @@ typedef struct
    */
   gnutls_cert *selected_cert_list;
   int selected_cert_list_length;
-  gnutls_privkey *selected_key;
+  struct gnutls_privkey_st *selected_key;
   int selected_need_free;
 
   /* holds the extensions we sent to the peer
diff --git a/lib/gnutls_privkey.c b/lib/gnutls_privkey.c
new file mode 100644 (file)
index 0000000..9917f71
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ * 
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * 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>
+#include <pkcs11_int.h>
+#include <gnutls/privkey.h>
+#include <sign.h>
+#include <gnutls_pk.h>
+#include <x509_int.h>
+#include <openpgp/openpgp_int.h>
+
+struct gnutls_privkey_st {
+       gnutls_privkey_type_t type;
+       gnutls_pk_algorithm_t pk_algorithm;
+       
+       union {
+               gnutls_x509_privkey_t x509;
+               gnutls_pkcs11_privkey_t pkcs11;
+               gnutls_openpgp_privkey_t openpgp;
+       } key;
+       
+       unsigned int flags;
+};
+
+int gnutls_privkey_get_type (gnutls_privkey_t key)
+{
+       return key->type;
+}
+
+int gnutls_privkey_get_pk_algorithm (gnutls_privkey_t key, unsigned int* bits)
+{
+       switch(key->type) {
+               case GNUTLS_PRIVKEY_OPENPGP:
+                       return gnutls_openpgp_privkey_get_pk_algorithm(key->key.openpgp, bits);
+               case GNUTLS_PRIVKEY_PKCS11:
+                       return gnutls_pkcs11_privkey_get_pk_algorithm(key->key.pkcs11, bits);
+               case GNUTLS_PRIVKEY_X509:
+                        if (bits)
+                                *bits = _gnutls_mpi_get_nbits (key->key.x509->params[0]);
+                       return gnutls_x509_privkey_get_pk_algorithm(key->key.x509);
+               default:
+                       gnutls_assert();
+                       return GNUTLS_E_INVALID_REQUEST;
+       }
+
+}
+
+int gnutls_privkey_init(gnutls_privkey_t * key)
+{
+       *key = gnutls_calloc(1, sizeof(struct gnutls_privkey_st));
+       if (*key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+       
+       return 0;
+}
+
+void gnutls_privkey_deinit(gnutls_privkey_t key)
+{
+       if (key->flags & GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE)
+               switch(key->type) {
+                       case GNUTLS_PRIVKEY_OPENPGP:
+                               return gnutls_openpgp_privkey_deinit(key->key.openpgp);
+                       case GNUTLS_PRIVKEY_PKCS11:
+                               return gnutls_pkcs11_privkey_deinit(key->key.pkcs11);
+                       case GNUTLS_PRIVKEY_X509:
+                               return gnutls_x509_privkey_deinit(key->key.x509);
+               }
+       gnutls_free(key);
+}
+
+int gnutls_privkey_import_pkcs11 (gnutls_privkey_t pkey, gnutls_pkcs11_privkey_t key, unsigned int flags)
+{
+       pkey->key.pkcs11 = key;
+       pkey->type = GNUTLS_PRIVKEY_PKCS11;
+       pkey->pk_algorithm = gnutls_pkcs11_privkey_get_pk_algorithm(key, NULL);
+       pkey->flags = flags;
+
+       return 0;
+}
+
+int gnutls_privkey_import_x509 (gnutls_privkey_t pkey, gnutls_x509_privkey_t key, unsigned int flags)
+{
+        pkey->key.x509 = key;
+       pkey->type = GNUTLS_PRIVKEY_X509;
+       pkey->pk_algorithm = gnutls_x509_privkey_get_pk_algorithm(key);
+       pkey->flags = flags;
+
+       return 0;
+}
+
+int gnutls_privkey_import_openpgp (gnutls_privkey_t pkey, gnutls_openpgp_privkey_t key, unsigned int flags)
+{
+       pkey->key.openpgp = key;
+       pkey->type = GNUTLS_PRIVKEY_OPENPGP;
+       pkey->pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm(key, NULL);
+       pkey->flags = flags;
+       
+       return 0;
+}
+
+/**
+ * gnutls_privkey_sign_data:
+ * @signer: Holds the key
+ * @digest: should be MD5 or SHA1
+ * @flags: should be 0 for now
+ * @data: holds the data to be signed
+ * @signature: will contain the signature allocate with gnutls_malloc()
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key. Signature algorithms are always used
+ * together with a hash functions.  Different hash functions may be
+ * used for the RSA algorithm, but only SHA-1 for the DSA keys.
+ *
+ * If the buffer provided is not long enough to hold the output, then
+ * *@signature_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER will
+ * be returned.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_privkey_sign_data(gnutls_privkey_t signer,
+                               gnutls_digest_algorithm_t hash,
+                               unsigned int flags,
+                               const gnutls_datum_t * data,
+                               gnutls_datum_t * signature)
+{
+       int ret;
+       gnutls_datum_t digest;
+
+       switch (signer->pk_algorithm) {
+       case GNUTLS_PK_RSA:
+               ret = pk_pkcs1_rsa_hash(hash, data, &digest);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               break;
+       case GNUTLS_PK_DSA:
+               ret = pk_dsa_hash(data, &digest);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+
+               break;
+       default:
+               gnutls_assert();
+               return GNUTLS_E_INTERNAL_ERROR;
+       }
+
+       ret = gnutls_privkey_sign_hash(signer, &digest, signature);
+       _gnutls_free_datum(&digest);
+
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       return 0;
+}
+
+int gnutls_privkey_sign_hash (gnutls_privkey_t key,
+                                const gnutls_datum_t * hash,
+                                gnutls_datum_t * signature)
+{
+       switch(key->type) {
+               case GNUTLS_PRIVKEY_OPENPGP:
+                       return gnutls_openpgp_privkey_sign_hash(key->key.openpgp, hash, signature);
+               case GNUTLS_PRIVKEY_PKCS11:
+                       return gnutls_pkcs11_privkey_sign_hash(key->key.pkcs11, hash, signature);
+               case GNUTLS_PRIVKEY_X509:
+                       return gnutls_x509_privkey_sign_hash(key->key.x509, hash, signature);
+               default:
+                       gnutls_assert();
+                       return GNUTLS_E_INVALID_REQUEST;
+       }
+}
+
+int gnutls_privkey_decrypt_data(gnutls_privkey_t key,
+                               unsigned int flags,
+                               const gnutls_datum_t * ciphertext,
+                               gnutls_datum_t * plaintext)
+{
+       if (key->pk_algorithm != GNUTLS_PK_RSA) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+       
+       switch(key->type) {
+               case GNUTLS_PRIVKEY_OPENPGP:
+                       return gnutls_openpgp_privkey_decrypt_data(key->key.openpgp, flags, ciphertext, plaintext);
+               case GNUTLS_PRIVKEY_X509:
+                       return _gnutls_pkcs1_rsa_decrypt (plaintext, ciphertext, key->key.x509->params, key->key.x509->params_size, 2);
+               case GNUTLS_PRIVKEY_PKCS11:
+                       return gnutls_pkcs11_privkey_decrypt_data(key->key.pkcs11, flags, ciphertext, plaintext);
+               default:
+                       gnutls_assert();
+                       return GNUTLS_E_INVALID_REQUEST;
+       }
+}
+
+
+
index e7285ce68264e7cb94f27dac6808abef86e5f40b..5c3ff369171effe85417e9d8be4268360afc225f 100644 (file)
@@ -43,7 +43,7 @@
 
 static int
 _gnutls_tls_sign (gnutls_session_t session,
-                 gnutls_cert * cert, gnutls_privkey * pkey,
+                 gnutls_cert * cert, gnutls_privkey_t pkey,
                  const gnutls_datum_t * hash_concat,
                  gnutls_datum_t * signature);
 
@@ -127,7 +127,7 @@ _gnutls_rsa_encode_sig (gnutls_mac_algorithm_t algo,
  */
 int
 _gnutls_handshake_sign_data (gnutls_session_t session, gnutls_cert * cert,
-                            gnutls_privkey * pkey, gnutls_datum_t * params,
+                            gnutls_privkey_t pkey, gnutls_datum_t * params,
                             gnutls_datum_t * signature,
                             gnutls_sign_algorithm_t * sign_algo)
 {
@@ -232,7 +232,7 @@ _gnutls_handshake_sign_data (gnutls_session_t session, gnutls_cert * cert,
  * given data. The output will be allocated and be put in signature.
  */
 int
-_gnutls_sign (gnutls_pk_algorithm_t algo, bigint_t * params,
+_gnutls_soft_sign (gnutls_pk_algorithm_t algo, bigint_t * params,
              int params_size, const gnutls_datum_t * data,
              gnutls_datum_t * signature)
 {
@@ -273,7 +273,7 @@ _gnutls_sign (gnutls_pk_algorithm_t algo, bigint_t * params,
  */
 static int
 _gnutls_tls_sign (gnutls_session_t session,
-                 gnutls_cert * cert, gnutls_privkey * pkey,
+                 gnutls_cert * cert, gnutls_privkey_t pkey,
                  const gnutls_datum_t * hash_concat,
                  gnutls_datum_t * signature)
 {
@@ -291,7 +291,7 @@ _gnutls_tls_sign (gnutls_session_t session,
          }
 
       /* External signing. */
-      if (!pkey || pkey->params_size == 0)
+      if (!pkey)
        {
          if (!session->internals.sign_func)
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
@@ -302,8 +302,7 @@ _gnutls_tls_sign (gnutls_session_t session,
        }
     }
 
-  return _gnutls_sign (pkey->pk_algorithm, pkey->params,
-                      pkey->params_size, hash_concat, signature);
+  return gnutls_privkey_sign_hash(pkey, hash_concat, signature);
 }
 
 static int
@@ -623,7 +622,7 @@ _gnutls_handshake_verify_cert_vrfy (gnutls_session_t session,
  */
 static int
 _gnutls_handshake_sign_cert_vrfy12 (gnutls_session_t session,
-                                   gnutls_cert * cert, gnutls_privkey * pkey,
+                                   gnutls_cert * cert, gnutls_privkey_t pkey,
                                    gnutls_datum_t * signature)
 {
   gnutls_datum_t dconcat;
@@ -705,7 +704,7 @@ _gnutls_handshake_sign_cert_vrfy12 (gnutls_session_t session,
  */
 int
 _gnutls_handshake_sign_cert_vrfy (gnutls_session_t session,
-                                 gnutls_cert * cert, gnutls_privkey * pkey,
+                                 gnutls_cert * cert, gnutls_privkey_t pkey,
                                  gnutls_datum_t * signature)
 {
   gnutls_datum_t dconcat;
index f4539fb03421caf05810bf46bf2fe2d1af15b93c..ca8324ae2904153ed2c2d6907bb61ebbd02eddf3 100644 (file)
 #ifndef GNUTLS_SIG_H
 # define GNUTLS_SIG_H
 
+#include <gnutls/privkey.h>
+
 int _gnutls_handshake_sign_cert_vrfy (gnutls_session_t session,
                                      gnutls_cert * cert,
-                                     gnutls_privkey * pkey,
+                                     gnutls_privkey_t pkey,
                                      gnutls_datum_t * signature);
 
 int _gnutls_handshake_sign_data (gnutls_session_t session,
                                 gnutls_cert * cert,
-                                gnutls_privkey * pkey,
+                                gnutls_privkey_t  pkey,
                                 gnutls_datum_t * params,
                                 gnutls_datum_t * signature,
                                 gnutls_sign_algorithm_t * algo);
@@ -49,7 +51,7 @@ int _gnutls_handshake_verify_data (gnutls_session_t session,
                                   gnutls_datum_t * signature,
                                   gnutls_sign_algorithm_t algo);
 
-int _gnutls_sign (gnutls_pk_algorithm_t algo,
+int _gnutls_soft_sign (gnutls_pk_algorithm_t algo,
                  bigint_t * params, int params_size,
                  const gnutls_datum_t * data, gnutls_datum_t * signature);
 
index c99150228bf715ad8b278f0e5193240c3a557b2f..daa25c29a143fde923310e00b0c94664a8c994ba 100644 (file)
@@ -158,7 +158,7 @@ _gnutls_session_cert_type_supported (gnutls_session_t session,
       if (cred == NULL)
        return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
 
-      if (cred->server_get_cert_callback == NULL)
+      if (cred->server_get_cert_callback == NULL && cred->get_cert_callback == NULL)
        {
          for (i = 0; i < cred->ncerts; i++)
            {
index 4c8aca36f764e2bf9606c94e5b636d6cc753f092..c5c8493934eaa3bd313c96b8d3cbd8d249b30f20 100644 (file)
@@ -372,8 +372,6 @@ int _gnutls_string_unescape(gnutls_string * dest)
 
         rv = 0;
 
-    cleanup:
-
         return rv;
 }
 
@@ -389,7 +387,6 @@ _gnutls_bin2hex (const void *_old, size_t oldlen,
 {
   unsigned int i, j;
   const opaque *old = _old;
-  int init = 0;
   int step = 2;
   const char empty[] = "";
   
index d93406a422eef6d7d9b64df357b84bde5f4ee2c9..4e43ed1930172e0758732020d9724bcaceb03eff 100644 (file)
@@ -46,6 +46,9 @@
 #include "x509/x509_int.h"
 #include "read-file.h"
 
+static int append_crt_list( gnutls_certificate_credentials_t res, gnutls_cert *crt, int nr);
+static int append_pkey( gnutls_certificate_credentials_t res, gnutls_privkey_t pkey);
+
 /*
  * some x509 certificate parsing functions.
  */
@@ -209,127 +212,73 @@ _gnutls_x509_cert_verify_peers (gnutls_session_t session,
 static int
 _gnutls_check_key_cert_match (gnutls_certificate_credentials_t res)
 {
-  gnutls_datum_t cid;
-  gnutls_datum_t kid;
-  unsigned pk = res->cert_list[res->ncerts - 1][0].subject_pk_algorithm;
-
-  if (res->pkey[res->ncerts - 1].pk_algorithm != pk)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
-    }
-
-  if (pk == GNUTLS_PK_RSA)
-    {
-      _gnutls_x509_write_rsa_params (res->pkey[res->ncerts - 1].params,
-                                    res->pkey[res->ncerts -
-                                              1].params_size, &kid);
-
+  unsigned int pk = res->cert_list[res->ncerts - 1][0].subject_pk_algorithm;
 
-      _gnutls_x509_write_rsa_params (res->
-                                    cert_list[res->ncerts - 1][0].params,
-                                    res->cert_list[res->ncerts -
-                                                   1][0].params_size, &cid);
-    }
-  else if (pk == GNUTLS_PK_DSA)
-    {
-
-      _gnutls_x509_write_dsa_params (res->pkey[res->ncerts - 1].params,
-                                    res->pkey[res->ncerts -
-                                              1].params_size, &kid);
-
-      _gnutls_x509_write_dsa_params (res->
-                                    cert_list[res->ncerts - 1][0].params,
-                                    res->cert_list[res->ncerts -
-                                                   1][0].params_size, &cid);
-    }
-
-  if (cid.size != kid.size)
+  if (gnutls_privkey_get_pk_algorithm(res->pkey[res->ncerts - 1], NULL) != pk)
     {
       gnutls_assert ();
-      _gnutls_free_datum (&kid);
-      _gnutls_free_datum (&cid);
       return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
     }
 
-  if (memcmp (kid.data, cid.data, kid.size) != 0)
-    {
-      gnutls_assert ();
-      _gnutls_free_datum (&kid);
-      _gnutls_free_datum (&cid);
-      return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
-    }
-
-  _gnutls_free_datum (&kid);
-  _gnutls_free_datum (&cid);
   return 0;
 }
 
 /* Reads a DER encoded certificate list from memory and stores it to a
- * gnutls_cert structure.  Returns the number of certificates parsed.
+ * gnutls_cert structure. Returns the number of certificates parsed.
  */
 static int
-parse_crt_mem (gnutls_cert ** cert_list, unsigned *ncerts,
-              gnutls_x509_crt_t cert)
+parse_der_cert_mem (gnutls_certificate_credentials_t res, 
+                   const void *input_cert, int input_cert_size)
 {
-  int i;
+  gnutls_datum_t tmp;
+  gnutls_x509_crt_t crt;
+  gnutls_cert *ccert;
   int ret;
 
-  i = *ncerts + 1;
-
-  *cert_list =
-    (gnutls_cert *) gnutls_realloc_fast (*cert_list,
-                                        i * sizeof (gnutls_cert));
-
-  if (*cert_list == NULL)
+  ccert = gnutls_malloc(sizeof(*ccert));
+  if (ccert == NULL)
     {
-      gnutls_assert ();
+      gnutls_assert();
       return GNUTLS_E_MEMORY_ERROR;
     }
 
-  ret = _gnutls_x509_crt_to_gcert (&cert_list[0][i - 1], cert, 0);
+  ret = gnutls_x509_crt_init (&crt);
   if (ret < 0)
     {
       gnutls_assert ();
+      gnutls_free(ccert);
       return ret;
     }
 
-  *ncerts = i;
-
-  return 1;                    /* one certificate parsed */
-}
-
-/* Reads a DER encoded certificate list from memory and stores it to a
- * gnutls_cert structure. Returns the number of certificates parsed.
- */
-static int
-parse_der_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
-                   const void *input_cert, int input_cert_size)
-{
-  gnutls_datum_t tmp;
-  gnutls_x509_crt_t cert;
-  int ret;
+  tmp.data = (opaque *) input_cert;
+  tmp.size = input_cert_size;
 
-  ret = gnutls_x509_crt_init (&cert);
+  ret = gnutls_x509_crt_import (crt, &tmp, GNUTLS_X509_FMT_DER);
   if (ret < 0)
     {
       gnutls_assert ();
+      gnutls_x509_crt_deinit (crt);
+      gnutls_free(ccert);
       return ret;
     }
 
-  tmp.data = (opaque *) input_cert;
-  tmp.size = input_cert_size;
-
-  ret = gnutls_x509_crt_import (cert, &tmp, GNUTLS_X509_FMT_DER);
+  ret = _gnutls_x509_crt_to_gcert (ccert, crt, 0);
+  gnutls_x509_crt_deinit (crt);
+  
   if (ret < 0)
     {
-      gnutls_assert ();
-      gnutls_x509_crt_deinit (cert);
+      gnutls_assert();
+      gnutls_free(ccert);
+      return ret;
+    }
+  
+  ret = append_crt_list(res, ccert, 1);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(ccert);
       return ret;
     }
-
-  ret = parse_crt_mem (cert_list, ncerts, cert);
-  gnutls_x509_crt_deinit (cert);
 
   return ret;
 }
@@ -338,14 +287,15 @@ parse_der_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
  * a gnutls_cert structure. Returns the number of certificate parsed.
  */
 static int
-parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
+parse_pem_cert_mem (gnutls_certificate_credentials_t res,
                    const char *input_cert, int input_cert_size)
 {
-  int size, siz2, i;
+  int size, siz2;
   const char *ptr;
   opaque *ptr2;
   gnutls_datum_t tmp;
   int ret, count;
+  gnutls_cert* certs = NULL;
 
   /* move to the certificate
    */
@@ -362,7 +312,6 @@ parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
     }
   size = input_cert_size - (ptr - input_cert);
 
-  i = *ncerts + 1;
   count = 0;
 
   do
@@ -376,11 +325,9 @@ parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
          return GNUTLS_E_BASE64_DECODING_ERROR;
        }
 
-      *cert_list =
-       (gnutls_cert *) gnutls_realloc_fast (*cert_list,
-                                            i * sizeof (gnutls_cert));
+      certs = gnutls_realloc_fast (certs, (count+1) * sizeof (gnutls_cert));
 
-      if (*cert_list == NULL)
+      if (certs == NULL)
        {
          gnutls_assert ();
          return GNUTLS_E_MEMORY_ERROR;
@@ -389,12 +336,14 @@ parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
       tmp.data = ptr2;
       tmp.size = siz2;
 
-      ret = _gnutls_x509_raw_cert_to_gcert (&cert_list[0][i - 1], &tmp, 0);
+      ret = _gnutls_x509_raw_cert_to_gcert (&certs[count], &tmp, 0);
       if (ret < 0)
        {
          gnutls_assert ();
+         gnutls_free(certs);
          return ret;
        }
+
       _gnutls_free_datum (&tmp);       /* free ptr2 */
 
       /* now we move ptr after the pem header 
@@ -418,13 +367,18 @@ parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
       else
        ptr = NULL;
 
-      i++;
       count++;
 
     }
   while (ptr != NULL);
 
-  *ncerts = i - 1;
+  ret = append_crt_list(res, certs, count);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(certs);
+      return ret;
+    }
 
   return count;
 }
@@ -439,38 +393,12 @@ read_cert_mem (gnutls_certificate_credentials_t res, const void *cert,
 {
   int ret;
 
-  /* allocate space for the certificate to add
-   */
-  res->cert_list = gnutls_realloc_fast (res->cert_list,
-                                       (1 +
-                                        res->ncerts) *
-                                       sizeof (gnutls_cert *));
-  if (res->cert_list == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
-  res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
-                                              (1 +
-                                               res->ncerts) * sizeof (int));
-  if (res->cert_list_length == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
-  res->cert_list[res->ncerts] = NULL;  /* for realloc */
-  res->cert_list_length[res->ncerts] = 0;
-
   if (type == GNUTLS_X509_FMT_DER)
-    ret = parse_der_cert_mem (&res->cert_list[res->ncerts],
-                             &res->cert_list_length[res->ncerts],
+    ret = parse_der_cert_mem (res,
                              cert, cert_size);
   else
-    ret = parse_pem_cert_mem (&res->cert_list[res->ncerts],
-                             &res->cert_list_length[res->ncerts], cert,
-                             cert_size);
+    ret = parse_pem_cert_mem (res,
+                             cert, cert_size);
 
   if (ret < 0)
     {
@@ -481,55 +409,8 @@ read_cert_mem (gnutls_certificate_credentials_t res, const void *cert,
   return ret;
 }
 
-
-int
-_gnutls_x509_privkey_to_gkey (gnutls_privkey * dest,
-                             gnutls_x509_privkey_t src)
-{
-  int i, ret;
-
-  memset (dest, 0, sizeof (gnutls_privkey));
-
-  for (i = 0; i < src->params_size; i++)
-    {
-      dest->params[i] = _gnutls_mpi_copy (src->params[i]);
-      if (dest->params[i] == NULL)
-       {
-         gnutls_assert ();
-         ret = GNUTLS_E_MEMORY_ERROR;
-         goto cleanup;
-       }
-    }
-
-  dest->pk_algorithm = src->pk_algorithm;
-  dest->params_size = src->params_size;
-
-  return 0;
-
-cleanup:
-
-  for (i = 0; i < src->params_size; i++)
-    {
-      _gnutls_mpi_release (&dest->params[i]);
-    }
-  return ret;
-}
-
-void
-_gnutls_gkey_deinit (gnutls_privkey * key)
-{
-  int i;
-  if (key == NULL)
-    return;
-
-  for (i = 0; i < key->params_size; i++)
-    {
-      _gnutls_mpi_release (&key->params[i]);
-    }
-}
-
-int
-_gnutls_x509_raw_privkey_to_gkey (gnutls_privkey * privkey,
+static int
+_gnutls_x509_raw_privkey_to_privkey (gnutls_privkey_t *privkey,
                                  const gnutls_datum_t * raw_key,
                                  gnutls_x509_crt_fmt_t type)
 {
@@ -542,7 +423,7 @@ _gnutls_x509_raw_privkey_to_gkey (gnutls_privkey * privkey,
       gnutls_assert ();
       return ret;
     }
-
+    
   ret = gnutls_x509_privkey_import (tmpkey, raw_key, type);
 
 #ifdef ENABLE_PKI
@@ -559,16 +440,23 @@ _gnutls_x509_raw_privkey_to_gkey (gnutls_privkey * privkey,
       return ret;
     }
 
-  ret = _gnutls_x509_privkey_to_gkey (privkey, tmpkey);
+  ret = gnutls_privkey_init(privkey);
+  if (ret < 0) 
+    {
+      gnutls_assert();
+      gnutls_x509_privkey_deinit (tmpkey);
+      return ret;
+    }
+
+  ret = gnutls_privkey_import_x509 (*privkey, tmpkey, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
   if (ret < 0)
     {
       gnutls_assert ();
       gnutls_x509_privkey_deinit (tmpkey);
+      gnutls_privkey_deinit (*privkey);
       return ret;
     }
 
-  gnutls_x509_privkey_deinit (tmpkey);
-
   return 0;
 }
 
@@ -582,17 +470,7 @@ read_key_mem (gnutls_certificate_credentials_t res,
 {
   int ret;
   gnutls_datum_t tmp;
-
-  /* allocate space for the pkey list
-   */
-  res->pkey =
-    gnutls_realloc_fast (res->pkey,
-                        (res->ncerts + 1) * sizeof (gnutls_privkey));
-  if (res->pkey == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
+  gnutls_privkey_t privkey;
 
   if (key)
     {
@@ -600,18 +478,144 @@ read_key_mem (gnutls_certificate_credentials_t res,
       tmp.size = key_size;
 
       ret =
-       _gnutls_x509_raw_privkey_to_gkey (&res->pkey[res->ncerts], &tmp,
-                                         type);
+       _gnutls_x509_raw_privkey_to_privkey (&privkey, &tmp, type);
       if (ret < 0)
        {
          gnutls_assert ();
          return ret;
        }
+
+      ret = append_pkey(res, privkey);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         gnutls_privkey_deinit(privkey);
+         return ret;
+       }
+      
     }
   else
-    memset (&res->pkey[res->ncerts], 0, sizeof (gnutls_privkey));
+    {
+      gnutls_assert();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+  
+
+  return 0;
+}
+
+/* Reads a private key from a token.
+ */
+static int read_key_url (gnutls_certificate_credentials_t res, const char* url)
+{
+  int ret;
+  gnutls_pkcs11_privkey_t key1 = NULL;
+  gnutls_privkey_t pkey = NULL;
+
+  /* allocate space for the pkey list
+   */
+  
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+  ret = gnutls_pkcs11_privkey_init(&key1);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      return ret;
+    }
+    
+  ret = gnutls_pkcs11_privkey_import_url(key1, url);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }
+  
+  ret = gnutls_privkey_init(&pkey);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }
+
+  ret = gnutls_privkey_import_pkcs11(pkey, key1, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }
+    
+  ret = append_pkey(res, pkey);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }  
+
+  return 0;
+
+cleanup:
+  if (pkey)
+    gnutls_privkey_deinit(pkey);
+
+  if (key1)
+    gnutls_pkcs11_privkey_deinit(key1);
+
+  return ret;
+}
+
+/* Reads a private key from a token.
+ */
+static int read_cert_url (gnutls_certificate_credentials_t res, const char* url)
+{
+int ret;
+gnutls_x509_crt_t crt;
+gnutls_cert * ccert;
+
+fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+  ccert = gnutls_malloc(sizeof(*ccert));
+  if (ccert == NULL)
+    {
+      gnutls_assert();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  ret = gnutls_x509_crt_init(&crt);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(ccert);
+      return ret;
+    }
+  
+  ret = gnutls_x509_crt_import_pkcs11_url(crt, url);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(ccert);
+      gnutls_x509_crt_deinit(crt);
+      return ret;
+    }
+
+  ret = _gnutls_x509_crt_to_gcert (ccert, crt, 0);
+  gnutls_x509_crt_deinit(crt);
+
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(ccert);
+      return ret;
+    }
+  
+  ret = append_crt_list(res, ccert, 1);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(ccert);
+      return ret;
+    }
 
   return 0;
+
 }
 
 /* Reads a certificate file
@@ -622,7 +626,13 @@ read_cert_file (gnutls_certificate_credentials_t res,
 {
   int ret;
   size_t size;
-  char *data = read_binary_file (certfile, &size);
+  char *data;
+
+  if (strncmp(certfile, "pkcs11:", 7)==0) {
+    return read_cert_url(res, certfile);
+  }
+
+  data = read_binary_file (certfile, &size);
 
   if (data == NULL)
     {
@@ -648,7 +658,13 @@ read_key_file (gnutls_certificate_credentials_t res,
 {
   int ret;
   size_t size;
-  char *data = read_binary_file (keyfile, &size);
+  char* data;
+  
+  if (strncmp(keyfile, "pkcs11:", 7)==0) {
+    return read_key_url(res, keyfile);
+  }
+  
+  data = read_binary_file (keyfile, &size);
 
   if (data == NULL)
     {
@@ -720,6 +736,50 @@ gnutls_certificate_set_x509_key_mem (gnutls_certificate_credentials_t res,
   return 0;
 }
 
+static int append_crt_list( gnutls_certificate_credentials_t res, gnutls_cert *crt, int nr)
+{
+  res->cert_list = gnutls_realloc_fast (res->cert_list,
+                                       (1 +
+                                        res->ncerts) *
+                                       sizeof (gnutls_cert *));
+  if (res->cert_list == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
+                                              (1 +
+                                               res->ncerts) * sizeof (int));
+  if (res->cert_list_length == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  res->cert_list[res->ncerts] = crt;
+  res->cert_list_length[res->ncerts] = nr;
+
+  return 0;
+
+}
+
+static int append_pkey( gnutls_certificate_credentials_t res, gnutls_privkey_t pkey)
+{
+  res->pkey = gnutls_realloc_fast (res->pkey,
+                                       (1 + res->ncerts) *
+                                       sizeof (gnutls_privkey_t));
+  if (res->pkey == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  res->pkey[res->ncerts] = pkey;
+  return 0;
+
+}
+
 /**
  * gnutls_certificate_set_x509_key:
  * @res: is a #gnutls_certificate_credentials_t structure.
@@ -734,6 +794,8 @@ gnutls_certificate_set_x509_key_mem (gnutls_certificate_credentials_t res,
  * entity certificate (e.g., also an intermediate CA cert) then put
  * the certificate chain in @cert_list.
  *
+ * 
+ *
  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
  *
  * Since: 2.4.0
@@ -745,59 +807,57 @@ gnutls_certificate_set_x509_key (gnutls_certificate_credentials_t res,
                                 gnutls_x509_privkey_t key)
 {
   int ret, i;
+  gnutls_privkey_t pkey;
+  gnutls_cert* pcerts = NULL;
 
   /* this should be first
    */
-
-  res->pkey =
-    gnutls_realloc_fast (res->pkey,
-                        (res->ncerts + 1) * sizeof (gnutls_privkey));
-  if (res->pkey == NULL)
+  ret = gnutls_privkey_init(&pkey);
+  if (ret < 0)
     {
       gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
+      return ret;
     }
-
-  ret = _gnutls_x509_privkey_to_gkey (&res->pkey[res->ncerts], key);
+  
+  ret = gnutls_privkey_import_x509 (pkey, key, 0);
   if (ret < 0)
     {
       gnutls_assert ();
       return ret;
     }
-
-  res->cert_list = gnutls_realloc_fast (res->cert_list,
-                                       (1 +
-                                        res->ncerts) *
-                                       sizeof (gnutls_cert *));
-  if (res->cert_list == NULL)
+  
+  ret = append_pkey(res, pkey);
+  if (ret < 0)
     {
       gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
+      return ret;
     }
 
-  res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
-                                              (1 +
-                                               res->ncerts) * sizeof (int));
-  if (res->cert_list_length == NULL)
+  /* load certificates */
+  pcerts = gnutls_malloc(sizeof(gnutls_cert)*cert_list_size);
+  if (pcerts == NULL)
     {
-      gnutls_assert ();
+      gnutls_assert();
       return GNUTLS_E_MEMORY_ERROR;
     }
 
-  res->cert_list[res->ncerts] = NULL;  /* for realloc */
-  res->cert_list_length[res->ncerts] = 0;
-
-
   for (i = 0; i < cert_list_size; i++)
     {
-      ret = parse_crt_mem (&res->cert_list[res->ncerts],
-                          &res->cert_list_length[res->ncerts], cert_list[i]);
+      ret = _gnutls_x509_crt_to_gcert (&pcerts[i], cert_list[i], 0);
       if (ret < 0)
        {
          gnutls_assert ();
          return ret;
        }
     }
+    
+  ret = append_crt_list(res, pcerts, cert_list_size);
+  if (ret < 0) 
+    {
+      gnutls_assert();
+      return ret;
+    }
+  
   res->ncerts++;
 
   if ((ret = _gnutls_check_key_cert_match (res)) < 0)
@@ -2021,13 +2081,6 @@ int
        }
     }
 
-  /* check if the key and certificate found match */
-  if (key && (ret = _gnutls_check_key_cert_match (res)) < 0)
-    {
-      gnutls_assert ();
-      goto done;
-    }
-
   ret = 0;
 
 done:
index 0f56063fcf5797237ca398453d0bbe80e7738a0c..bdc6a369a2909e09e9c6428f214cfa963c338f81 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include <libtasn1.h>
+#include <gnutls/privkey.h>
 
 int _gnutls_x509_cert_verify_peers (gnutls_session_t session,
                                    unsigned int *status);
@@ -39,8 +40,6 @@ int _gnutls_x509_cert_verify_peers (gnutls_session_t session,
 int _gnutls_check_key_usage (const gnutls_cert * cert,
                             gnutls_kx_algorithm_t alg);
 
-int _gnutls_x509_raw_privkey_to_gkey (gnutls_privkey * privkey,
+int _gnutls_x509_raw_privkey_to_gkey (gnutls_privkey_t * privkey,
                                      const gnutls_datum_t * raw_key,
                                      gnutls_x509_crt_fmt_t type);
-int _gnutls_x509_privkey_to_gkey (gnutls_privkey * privkey,
-                                 gnutls_x509_privkey_t);
index 0232103c7cb493b7b3d04bb9e04cbdd668beedbd..23cec7495b30a0be1e15b0be52f46bbcfa019d68 100644 (file)
@@ -1,7 +1,7 @@
 /* Typedefs for more compatibility with older GnuTLS. */
 
-#ifndef GNUTLS_COMPAT_H
-# define GNUTLS_COMPAT_H
+#ifndef _GNUTLS_COMPAT_H
+# define _GNUTLS_COMPAT_H
 
 #define gnutls_cipher_algorithm gnutls_cipher_algorithm_t
 #define gnutls_kx_algorithm gnutls_kx_algorithm_t
 #define LIBGNUTLS_VERSION_NUMBER GNUTLS_VERSION_NUMBER
 #define LIBGNUTLS_EXTRA_VERSION GNUTLS_VERSION
 
-#endif /* GNUTLS_COMPAT_H */
+  typedef struct gnutls_retr_st
+  {
+    gnutls_certificate_type_t type;
+    union
+    {
+      gnutls_x509_crt_t *x509;
+      gnutls_openpgp_crt_t pgp;
+    } cert;
+    unsigned int ncerts;       /* one for pgp keys */
+
+    union
+    {
+      gnutls_x509_privkey_t x509;
+      gnutls_openpgp_privkey_t pgp;
+    } key;
+
+    unsigned int deinit_all;   /* if non zero all keys will be deinited */
+  } gnutls_retr_st;
+
+typedef int gnutls_certificate_client_retrieve_function (gnutls_session_t,
+                                                          const
+                                                          gnutls_datum_t *
+                                                          req_ca_rdn,
+                                                          int nreqs,
+                                                          const
+                                                          gnutls_pk_algorithm_t
+                                                          * pk_algos,
+                                                          int
+                                                          pk_algos_length,
+                                                          gnutls_retr_st *);
+typedef int gnutls_certificate_server_retrieve_function (gnutls_session_t,
+                                                          gnutls_retr_st *);
+
+void gnutls_certificate_client_set_retrieve_function
+    (gnutls_certificate_credentials_t cred,
+     gnutls_certificate_client_retrieve_function * func);
+void gnutls_certificate_server_set_retrieve_function
+    (gnutls_certificate_credentials_t cred,
+     gnutls_certificate_server_retrieve_function * func);
+
+#endif /* _GNUTLS_COMPAT_H */
index 9a129e3ccf0c82895024a044c6c51d8f9dbbcc72..4f8305d2c2c407d1fd7b4f08729404bf310f3794 100644 (file)
@@ -48,7 +48,6 @@
 #endif
 /* Get time_t. */
 #include <time.h>
-#include <gnutls/compat.h>
 #ifdef __cplusplus
 extern "C"
 {
@@ -1428,40 +1427,36 @@ extern "C"
   struct gnutls_openpgp_privkey_int;
   typedef struct gnutls_openpgp_privkey_int *gnutls_openpgp_privkey_t;
 
-  typedef struct gnutls_retr_st
+  struct gnutls_pkcs11_privkey_st;
+  typedef struct gnutls_pkcs11_privkey_st* gnutls_pkcs11_privkey_t;
+
+  typedef enum {
+        GNUTLS_PRIVKEY_X509, /* gnutls_x509_privkey_t */
+       GNUTLS_PRIVKEY_OPENPGP, /* gnutls_openpgp_privkey_t */
+       GNUTLS_PRIVKEY_PKCS11, /* gnutls_pkcs11_privkey_t */
+  } gnutls_privkey_type_t;
+
+  typedef struct gnutls_retr2_st
   {
-    gnutls_certificate_type_t type;
-    union cert
+    gnutls_certificate_type_t cert_type;
+    gnutls_privkey_type_t key_type;
+    
+    union
     {
       gnutls_x509_crt_t *x509;
       gnutls_openpgp_crt_t pgp;
     } cert;
     unsigned int ncerts;       /* one for pgp keys */
 
-    union key
+    union
     {
       gnutls_x509_privkey_t x509;
       gnutls_openpgp_privkey_t pgp;
+      gnutls_pkcs11_privkey_t pkcs11;
     } key;
 
     unsigned int deinit_all;   /* if non zero all keys will be deinited */
-  } gnutls_retr_st;
-
-  typedef int gnutls_certificate_client_retrieve_function (gnutls_session_t,
-                                                          const
-                                                          gnutls_datum_t *
-                                                          req_ca_rdn,
-                                                          int nreqs,
-                                                          const
-                                                          gnutls_pk_algorithm_t
-                                                          * pk_algos,
-                                                          int
-                                                          pk_algos_length,
-                                                          gnutls_retr_st *);
-  typedef int gnutls_certificate_server_retrieve_function (gnutls_session_t,
-                                                          gnutls_retr_st *);
-
-  typedef int gnutls_certificate_verify_function (gnutls_session_t);
+  } gnutls_retr2_st;
 
 
   /* Functions that allow auth_info_t structures handling
@@ -1508,13 +1503,25 @@ extern "C"
 
   /* These are set on the credentials structure.
    */
-  void gnutls_certificate_client_set_retrieve_function
-    (gnutls_certificate_credentials_t cred,
-     gnutls_certificate_client_retrieve_function * func);
-  void gnutls_certificate_server_set_retrieve_function
+
+  typedef int gnutls_certificate_retrieve_function (gnutls_session_t,
+                                                          const
+                                                          gnutls_datum_t *
+                                                          req_ca_rdn,
+                                                          int nreqs,
+                                                          const
+                                                          gnutls_pk_algorithm_t
+                                                          * pk_algos,
+                                                          int
+                                                          pk_algos_length,
+                                                          gnutls_retr2_st *);
+
+
+  void gnutls_certificate_set_retrieve_function
     (gnutls_certificate_credentials_t cred,
-     gnutls_certificate_server_retrieve_function * func);
+     gnutls_certificate_retrieve_function * func);
 
+  typedef int gnutls_certificate_verify_function (gnutls_session_t);
   void
     gnutls_certificate_set_verify_function (gnutls_certificate_credentials_t
                                            cred,
@@ -1745,4 +1752,6 @@ extern "C"
 }
 #endif
 
+#include <gnutls/compat.h>
+
 #endif                         /* GNUTLS_H */
index 78cec828a6a9e4676dd5f333e4bb803128951aa9..d45c81858e6bd6d57a566e3c12fee6422f93b2f8 100644 (file)
@@ -165,6 +165,10 @@ extern "C"
                                     gnutls_openpgp_crt_fmt_t format,
                                     const char *password,
                                     unsigned int flags);
+
+  int gnutls_openpgp_privkey_decrypt_data (gnutls_openpgp_privkey_t key,
+            unsigned int flags, const gnutls_datum_t * ciphertext,
+                                 gnutls_datum_t * plaintext);
   int gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t key,
                                        const gnutls_datum_t * hash,
                                        gnutls_datum_t * signature);
index 814be1e120eb624288a3dc099e1ba0d81dfccfb0..d912d320105eaa8782e27241b40b7e59d2337d4d 100644 (file)
@@ -68,11 +68,10 @@ typedef int (*gnutls_pkcs11_pin_callback_t)(void *userdata, int attempt,
  * @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 */
 
@@ -106,7 +105,7 @@ void gnutls_pkcs11_deinit (void);
  * @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);
+void gnutls_pkcs11_set_token_function(gnutls_pkcs11_token_callback_t fn, void *userdata);
 
 /**
  * @brief Set PIN prompt callback.
@@ -173,6 +172,7 @@ typedef enum {
        GNUTLS_PKCS11_CRT_TOKEN_SERIAL,
        GNUTLS_PKCS11_CRT_TOKEN_MANUFACTURER,
        GNUTLS_PKCS11_CRT_TOKEN_MODEL,
+       GNUTLS_PKCS11_CRT_ID,
 } gnutls_pkcs11_cert_info_t;
 
 int gnutls_pkcs11_crt_get_info(gnutls_pkcs11_crt_t crt, gnutls_pkcs11_cert_info_t itype, void* output, size_t* output_size);
@@ -220,24 +220,27 @@ int gnutls_x509_crt_list_import_pkcs11 (gnutls_x509_crt_t * 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);
+/* private key functions...*/
+int gnutls_pkcs11_privkey_init (gnutls_pkcs11_privkey_t * key);
+void gnutls_pkcs11_privkey_deinit (gnutls_pkcs11_privkey_t key);
+int gnutls_pkcs11_privkey_get_pk_algorithm (gnutls_pkcs11_privkey_t key, unsigned int* bits);
+int gnutls_pkcs11_privkey_get_info(gnutls_pkcs11_privkey_t crt, gnutls_pkcs11_cert_info_t itype, void* output, size_t* output_size);
+int gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t key,
+                                 const char* url);
+
+int
+gnutls_pkcs11_privkey_sign_data(gnutls_pkcs11_privkey_t signer,
+                               gnutls_digest_algorithm_t hash,
+                               unsigned int flags,
+                               const gnutls_datum_t * data,
+                               gnutls_datum_t * signature);
+int gnutls_pkcs11_privkey_sign_hash (gnutls_pkcs11_privkey_t key,
+                                const gnutls_datum_t * hash,
+                                gnutls_datum_t * signature);
+int
+gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
+                               unsigned int flags, const gnutls_datum_t * ciphertext,
+                               gnutls_datum_t * plaintext);
 
 /** @} */
 
diff --git a/lib/includes/gnutls/privkey.h b/lib/includes/gnutls/privkey.h
new file mode 100644 (file)
index 0000000..1f37325
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __GNUTLS_PRIVKEY_H
+#define __GNUTLS_PRIVKEY_H
+
+#include <stdarg.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/pkcs11.h>
+#include <gnutls/openpgp.h>
+
+struct gnutls_privkey_st;
+typedef struct gnutls_privkey_st* gnutls_privkey_t;
+
+int gnutls_privkey_init (gnutls_privkey_t * key);
+void gnutls_privkey_deinit (gnutls_privkey_t key);
+int gnutls_privkey_get_pk_algorithm (gnutls_privkey_t key, unsigned int* bits);
+int gnutls_privkey_get_type (gnutls_privkey_t key);
+
+#define GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE 1
+int gnutls_privkey_import_pkcs11 (gnutls_privkey_t pkey, gnutls_pkcs11_privkey_t key, unsigned int flags);
+int gnutls_privkey_import_x509 (gnutls_privkey_t pkey, gnutls_x509_privkey_t key, unsigned int flags);
+int gnutls_privkey_import_openpgp (gnutls_privkey_t pkey, gnutls_openpgp_privkey_t key, unsigned int flags);
+
+int gnutls_privkey_sign_data(gnutls_privkey_t signer,
+                               gnutls_digest_algorithm_t hash,
+                               unsigned int flags,
+                               const gnutls_datum_t * data,
+                               gnutls_datum_t * signature);
+int gnutls_privkey_sign_hash (gnutls_privkey_t key,
+                                const gnutls_datum_t * hash,
+                                gnutls_datum_t * signature);
+
+int gnutls_privkey_decrypt_data(gnutls_privkey_t signer,
+                               unsigned int flags,
+                               const gnutls_datum_t * ciphertext,
+                               gnutls_datum_t * plaintext);
+
+#endif
index 7ff7bde8cb129952a44538baf26edfaeabf9d872..54ba9e27931de2755d0a86fcb75472660760bdd4 100644 (file)
@@ -684,6 +684,11 @@ extern "C"
                                     const gnutls_datum_t * data,
                                     void *signature,
                                     size_t * signature_size);
+  int gnutls_x509_privkey_sign_data2 (gnutls_x509_privkey_t key,
+                                    gnutls_digest_algorithm_t digest,
+                                    unsigned int flags,
+                                    const gnutls_datum_t * data,
+                                    gnutls_datum_t *signature);
   int gnutls_x509_privkey_verify_data (gnutls_x509_privkey_t key,
                                       unsigned int flags,
                                       const gnutls_datum_t * data,
index fd9b9e400984ab0b2bcfdf5839e870d91c2df6ee..0cd6336b4b7963879f7d82569ffb4ba98e1b15df 100644 (file)
@@ -605,6 +605,7 @@ GNUTLS_2_10
 GNUTLS_2_11
 {
   global:
+       gnutls_certificate_set_retrieve_function;
         gnutls_pkcs11_init;
         gnutls_pkcs11_deinit;
         gnutls_pkcs11_set_pin_function;
@@ -622,6 +623,26 @@ GNUTLS_2_11
        gnutls_pkcs11_crt_get_info;
        gnutls_pkcs11_token_get_info;
        gnutls_pkcs11_token_get_url;
+       gnutls_pkcs11_privkey_init;
+       gnutls_pkcs11_privkey_deinit;
+       gnutls_pkcs11_privkey_get_pk_algorithm;
+       gnutls_pkcs11_privkey_get_info;
+       gnutls_pkcs11_privkey_import_url;
+       gnutls_pkcs11_privkey_sign_data;
+       gnutls_pkcs11_privkey_sign_hash;
+       gnutls_pkcs11_privkey_decrypt_data;
+
+       gnutls_privkey_init;
+       gnutls_privkey_deinit;
+       gnutls_privkey_get_pk_algorithm;
+       gnutls_privkey_get_type;
+       gnutls_privkey_import_pkcs11;
+       gnutls_privkey_import_x509;
+       gnutls_privkey_import_openpgp;
+       gnutls_privkey_sign_data;
+       gnutls_privkey_sign_hash;
+       gnutls_privkey_decrypt_data;
+
 } GNUTLS_2_10;
 
 GNUTLS_PRIVATE {
index 039a2e3f1d056ab6cfa69cd580687e61b06a4826..0d798f1aba674fe9bff3a8e2c800bf2620063940 100644 (file)
@@ -142,16 +142,24 @@ gnutls_certificate_set_openpgp_key (gnutls_certificate_credentials_t res,
 
   res->pkey = gnutls_realloc_fast (res->pkey,
                                   (res->ncerts + 1) *
-                                  sizeof (gnutls_privkey));
+                                  sizeof (gnutls_privkey_t));
   if (res->pkey == NULL)
     {
       gnutls_assert ();
       return GNUTLS_E_MEMORY_ERROR;
     }
 
-  ret = _gnutls_openpgp_privkey_to_gkey (&res->pkey[res->ncerts], pkey);
+  ret = gnutls_privkey_init(&res->pkey[res->ncerts]);
+  if (ret < 0) 
+    {
+      gnutls_assert();
+      return ret;
+    }
+
+  ret = gnutls_privkey_import_openpgp (res->pkey[res->ncerts], pkey, 0);
   if (ret < 0)
     {
+      gnutls_privkey_deinit(res->pkey[res->ncerts]);
       gnutls_assert ();
       return ret;
     }
@@ -163,6 +171,7 @@ gnutls_certificate_set_openpgp_key (gnutls_certificate_credentials_t res,
   if (res->cert_list == NULL)
     {
       gnutls_assert ();
+      /* memory leak here? */
       return GNUTLS_E_MEMORY_ERROR;
     }
 
@@ -720,73 +729,6 @@ gnutls_openpgp_set_recv_key_function (gnutls_session_t session,
 }
 
 
-/* Copies a gnutls_openpgp_privkey_t to a gnutls_privkey structure. */
-int
-_gnutls_openpgp_privkey_to_gkey (gnutls_privkey * dest,
-                                gnutls_openpgp_privkey_t src)
-{
-  int ret = 0;
-  gnutls_openpgp_keyid_t keyid;
-  char err_buf[33];
-
-  if (dest == NULL || src == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_CERTIFICATE_ERROR;
-    }
-
-  dest->params_size = MAX_PRIV_PARAMS_SIZE;
-
-  ret = gnutls_openpgp_privkey_get_preferred_key_id (src, keyid);
-
-  if (ret == 0)
-    {
-      int idx;
-      uint32_t kid32[2];
-
-      _gnutls_debug_log
-       ("Importing Openpgp key and using openpgp sub key: %s\n",
-        _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf), NULL));
-
-      KEYID_IMPORT (kid32, keyid);
-
-      idx = gnutls_openpgp_privkey_get_subkey_idx (src, keyid);
-      if (idx < 0)
-       {
-         gnutls_assert ();
-         return idx;
-       }
-
-      dest->pk_algorithm =
-       gnutls_openpgp_privkey_get_subkey_pk_algorithm (src, idx, NULL);
-
-      ret =
-       _gnutls_openpgp_privkey_get_mpis (src, kid32, dest->params,
-                                         &dest->params_size);
-    }
-  else
-    {
-      _gnutls_debug_log
-       ("Importing Openpgp key and using main openpgp key.\n");
-
-      dest->pk_algorithm =
-       gnutls_openpgp_privkey_get_pk_algorithm (src, NULL);
-      ret =
-       _gnutls_openpgp_privkey_get_mpis (src, NULL, dest->params,
-                                         &dest->params_size);
-    }
-
-
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-
-  return 0;
-
-}
-
 /* Converts a parsed gnutls_openpgp_crt_t to a gnutls_cert structure.
  */
 int
@@ -961,7 +903,81 @@ gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t key,
 
   pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL);
 
-  result = _gnutls_sign (pk_algorithm, params, params_size, hash, signature);
+  result = _gnutls_soft_sign (pk_algorithm, params, params_size, hash, signature);
+
+  for (i = 0; i < params_size; i++)
+    _gnutls_mpi_release (&params[i]);
+
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  return 0;
+}
+
+/**
+ * gnutls_openpgp_privkey_decrypt_data:
+ * @key: Holds the key
+ * @flags: zero for now
+ * @ciphertext: holds the data to be decrypted
+ * @plaintext: will contain newly allocated plaintext
+ *
+ * This function will sign the given hash using the private key.  You
+ * should use gnutls_openpgp_privkey_set_preferred_key_id() before
+ * calling this function to set the subkey to use.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_openpgp_privkey_decrypt_data (gnutls_openpgp_privkey_t key,
+      unsigned int flags, const gnutls_datum_t * ciphertext,
+                                 gnutls_datum_t * plaintext)
+{
+  int result, i;
+  bigint_t params[MAX_PUBLIC_PARAMS_SIZE];
+  int params_size = MAX_PUBLIC_PARAMS_SIZE;
+  int pk_algorithm;
+  gnutls_openpgp_keyid_t keyid;
+
+  if (key == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+  
+  result = gnutls_openpgp_privkey_get_preferred_key_id (key, keyid);
+  if (result == 0)
+    {
+      uint32_t kid[2];
+
+      KEYID_IMPORT (kid, keyid);
+      result = _gnutls_openpgp_privkey_get_mpis (key, kid,
+                                                params, &params_size);
+    }
+  else
+    {
+      result = _gnutls_openpgp_privkey_get_mpis (key, NULL,
+                                                params, &params_size);
+    }
+
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL);
+
+  if (pk_algorithm != GNUTLS_PK_RSA)
+    {
+      gnutls_assert();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  result = _gnutls_pkcs1_rsa_decrypt (plaintext, ciphertext, params, params_size, 2);
 
   for (i = 0; i < params_size; i++)
     _gnutls_mpi_release (&params[i]);
index 36ab8539d3c2449bcd2bd3e8ab31f87c89139a71..411c5aa1d5edc5b07f89b3aca82c7924774d2dbf 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <auth_cert.h>
 #include <opencdk.h>
+#include <gnutls/privkey.h>
 
 /* OpenCDK compatible */
 typedef enum
@@ -29,7 +30,7 @@ int _gnutls_openpgp_raw_crt_to_gcert (gnutls_cert * cert,
                                      const gnutls_openpgp_keyid_t);
 
 int
-_gnutls_openpgp_raw_privkey_to_gkey (gnutls_privkey * pkey,
+_gnutls_openpgp_raw_privkey_to_gkey (gnutls_privkey_t * pkey,
                                     const gnutls_datum_t * raw_key);
 
 int
index d5eb139cfb4ce73321ba9d899f2699b16c722c56..8071aa0098dc8f80a35d865b664e8117a578b190 100644 (file)
@@ -45,8 +45,6 @@ int _gnutls_openpgp_export (cdk_kbnode_t node,
 
 int _gnutls_openpgp_crt_to_gcert (gnutls_cert * gcert,
                                  gnutls_openpgp_crt_t cert);
-int _gnutls_openpgp_privkey_to_gkey (gnutls_privkey * dest,
-                                    gnutls_openpgp_privkey_t src);
 
 cdk_packet_t _gnutls_get_valid_subkey (cdk_kbnode_t knode, int key_type);
 
index 52fc4b5159455eeac1f660a69fae9d160c2799c3..e9127a0e8e33fe62be107a77e271d9ebc74538bc 100644 (file)
@@ -1,35 +1,35 @@
 /*
-   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
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ * 
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * 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>
+#include <pkcs11_int.h>
 
 #define MAX_PROVIDERS 16
-#define ID_SIZE 128
-#define LABEL_SIZE 128
 
 /* XXX: try to eliminate this */
 #define MAX_CERT_SIZE 8*1024
@@ -40,19 +40,6 @@ struct gnutls_pkcs11_provider_s {
     ck_slot_id_t *slots;
 };
 
-
-struct pkcs11_url_info
-{
-    /* everything here is null terminated strings */
-    opaque id[ID_SIZE*3+1]; /* hex with delimiters */
-    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];
-    opaque label[LABEL_SIZE+1];
-};
-
 struct gnutls_pkcs11_crt_st {
     gnutls_datum_t raw;
     gnutls_certificate_type_t type;
@@ -61,8 +48,6 @@ struct gnutls_pkcs11_crt_st {
 
 struct url_find_data_st {
     gnutls_pkcs11_crt_t crt;
-    char certid_raw[ID_SIZE];
-    size_t certid_raw_size;
 };
 
 struct crt_find_data_st {
@@ -73,18 +58,6 @@ struct crt_find_data_st {
     struct pkcs11_url_info info;
 };
 
-struct token_info {
-    struct ck_token_info tinfo;
-    struct ck_slot_info sinfo;
-    ck_slot_id_t sid;
-    struct gnutls_pkcs11_provider_s* prov;
-};
-
-/* thus function is called for every token in the traverse_tokens
- * function. Once everything is traversed it is called with NULL tinfo.
- * It should return 0 if found what it was looking for.
- */
-typedef int (*find_func_t)(pakchois_session_t *pks, struct token_info* tinfo, void* input);
 
 static struct gnutls_pkcs11_provider_s providers[MAX_PROVIDERS];
 static int active_providers = 0;
@@ -92,6 +65,9 @@ static int active_providers = 0;
 static gnutls_pkcs11_pin_callback_t pin_func;
 static void* pin_data;
 
+gnutls_pkcs11_token_callback_t token_func;
+void* token_data;
+
 int gnutls_pkcs11_add_provider (const char * name, const char * params)
 {
 
@@ -144,28 +120,46 @@ fail:
 int gnutls_pkcs11_crt_get_info(gnutls_pkcs11_crt_t crt, gnutls_pkcs11_cert_info_t itype,
     void* output, size_t* output_size)
 {
-    const char* str;
+    return pkcs11_get_info(&crt->info, itype, output, output_size);
+}
+
+int pkcs11_get_info(struct pkcs11_url_info *info, gnutls_pkcs11_cert_info_t itype, 
+    void* output, size_t* output_size)
+{
+    const char* str = NULL;
     size_t len;
 
     switch(itype) {
+        case GNUTLS_PKCS11_CRT_ID:
+            if (*output_size < info->certid_raw_size) {
+                *output_size = info->certid_raw_size;
+                return GNUTLS_E_SHORT_MEMORY_BUFFER;
+            }
+            if (output) memcpy(output, info->certid_raw, info->certid_raw_size);
+            *output_size = info->certid_raw_size;
+            
+            return 0;
         case GNUTLS_PKCS11_CRT_ID_HEX:
-            str = crt->info.id;
+            str = info->id;
             break;
         case GNUTLS_PKCS11_CRT_LABEL:
-            str = crt->info.label;
+            str = info->label;
             break;
         case GNUTLS_PKCS11_CRT_TOKEN_LABEL:
-            str = crt->info.token;
+            str = info->token;
             break;
         case GNUTLS_PKCS11_CRT_TOKEN_SERIAL:
-            str = crt->info.serial;
+            str = info->serial;
             break;
         case GNUTLS_PKCS11_CRT_TOKEN_MANUFACTURER:
-            str = crt->info.manufacturer;
+            str = info->manufacturer;
             break;
         case GNUTLS_PKCS11_CRT_TOKEN_MODEL:
-            str = crt->info.model;
+            str = info->model;
             break;
+        default:
+            gnutls_assert();
+            return GNUTLS_E_INVALID_REQUEST;
     }
 
     len = strlen(str);
@@ -182,11 +176,18 @@ int gnutls_pkcs11_crt_get_info(gnutls_pkcs11_crt_t crt, gnutls_pkcs11_cert_info_
     return 0;
 }
 
+static int init = 0;
 
 int gnutls_pkcs11_init(unsigned int flags, const char* configfile)
 {
     int ret;
     
+    if (init != 0) {
+        init++;
+        return 0;
+    }
+    init++;
+
     if (flags == GNUTLS_PKCS11_FLAG_MANUAL)
         return 0;
     else {
@@ -233,6 +234,15 @@ int gnutls_pkcs11_init(unsigned int flags, const char* configfile)
 void gnutls_pkcs11_deinit (void)
 {
     int i;
+
+    init--;
+    if (init > 0)
+        return;
+    if (init < 0)
+      {
+        init = 0;
+        return;
+      }
     
     for (i=0;i<active_providers;i++) {
         pakchois_module_destroy(providers[i].module);
@@ -247,6 +257,13 @@ void gnutls_pkcs11_set_pin_function(gnutls_pkcs11_pin_callback_t fn,
     pin_data = userdata;
 }
 
+void gnutls_pkcs11_set_token_function(gnutls_pkcs11_token_callback_t fn,
+                                void *userdata)
+{
+    token_func = fn;
+    token_data = userdata;
+}
+
 static int unescape_string (char* output, const char* input, size_t* size, char terminator)
 {
     gnutls_string str;
@@ -288,7 +305,7 @@ static int unescape_string (char* output, const char* input, size_t* size, char
     return ret;
 }
 
-static int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info)
+int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info)
 {
 int ret;
 char* p1, *p2;
@@ -369,6 +386,14 @@ size_t l;
 
         memcpy(info->id, p1, l);
         info->id[l] = 0;
+
+        /* convert to raw */
+        info->certid_raw_size = sizeof(info->certid_raw);
+        ret = _gnutls_hex2bin(info->id, strlen(info->id), info->certid_raw, &info->certid_raw_size);
+        if (ret < 0) {
+            gnutls_assert();
+            goto cleanup;
+        }
     }
     
     ret = 0;
@@ -423,7 +448,6 @@ 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);
 
@@ -496,12 +520,13 @@ cleanup:
 
 int gnutls_pkcs11_crt_init(gnutls_pkcs11_crt_t * crt)
 {
-    *crt = gnutls_malloc(sizeof(struct gnutls_pkcs11_crt_st));
+    *crt = gnutls_calloc(1, sizeof(struct gnutls_pkcs11_crt_st));
     if (*crt == NULL) {
         gnutls_assert();
         return GNUTLS_E_MEMORY_ERROR;
     }
  
+    return 0;
 }
 
 void gnutls_pkcs11_crt_deinit(gnutls_pkcs11_crt_t crt)
@@ -525,9 +550,8 @@ static void terminate_string(unsigned char *str, size_t len)
 }
 
 
-static int traverse_tokens (find_func_t find_func, void* input)
+int _pkcs11_traverse_tokens (find_func_t find_func, void* input, int leave_session)
 {
-    struct ck_attribute a[3];
     ck_rv_t rv;
     int found = 0, x, z, ret;
     pakchois_session_t *pks = NULL;
@@ -560,12 +584,12 @@ static int traverse_tokens (find_func_t find_func, void* input)
 
             ret = find_func(pks, &info, input);
             
-            pakchois_close_session(pks);
-            pks = NULL;
-            
             if (ret == 0) {
                 found = 1;
                 goto finish;
+            } else {
+                pakchois_close_session(pks);
+                pks = NULL;
             }
         }
     }
@@ -579,8 +603,11 @@ finish:
         ret = 0;
     }
 
-cleanup:
-    if (pks != NULL) pakchois_close_session(pks);
+    if (pks != NULL) {
+        if (leave_session==0 || ret != 0)  {
+            pakchois_close_session(pks);
+        }
+    }
    
     return ret;
 }
@@ -621,6 +648,9 @@ static int pkcs11_crt_import(gnutls_pkcs11_crt_t crt, const gnutls_datum_t* data
         gnutls_assert();
         return GNUTLS_E_PKCS11_ERROR;
     }
+    
+    memmove(crt->info.certid_raw, id->data, id->size);
+    crt->info.certid_raw_size = id->size;
 
     return 0;
 }
@@ -636,9 +666,8 @@ static int find_cert_url(pakchois_session_t *pks, struct token_info *info, void*
     ck_object_handle_t obj;
     unsigned long count;
     int found = 0, ret;
-    unsigned char value[MAX_CERT_SIZE];
-    char certid_tmp[ID_SIZE];
-    char label_tmp[LABEL_SIZE];
+    opaque* cert_data = NULL;
+    char label_tmp[PKCS11_LABEL_SIZE];
     
     if (info == NULL) { /* we don't support multiple calls */
         gnutls_assert();
@@ -676,6 +705,12 @@ static int find_cert_url(pakchois_session_t *pks, struct token_info *info, void*
 
     /* search the token for the id */
     
+    cert_data = gnutls_malloc(MAX_CERT_SIZE);
+    if (cert_data == NULL) {
+        gnutls_assert();
+        return GNUTLS_E_MEMORY_ERROR;
+    }
+    
     /* Find objects with cert class and X.509 cert type. */
     class = CKO_CERTIFICATE;
     type = CKC_X_509;
@@ -686,9 +721,12 @@ static int find_cert_url(pakchois_session_t *pks, struct token_info *info, void*
     a[1].type = CKA_CERTIFICATE_TYPE;
     a[1].value = &type;
     a[1].value_len = sizeof type;
+    a[2].type = CKA_ID;
+    a[2].value = find_data->crt->info.certid_raw;
+    a[2].value_len = find_data->crt->info.certid_raw_size;
 
         
-    rv = pakchois_find_objects_init(pks, a, 2);
+    rv = pakchois_find_objects_init(pks, a, 3);
     if (rv != CKR_OK) {
         gnutls_assert();
         _gnutls_debug_log("pk11: FindObjectsInit failed.\n");
@@ -700,31 +738,25 @@ static int find_cert_url(pakchois_session_t *pks, struct token_info *info, void*
            && 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_LABEL;
-        a[2].value = label_tmp;
-        a[2].value_len = sizeof(label_tmp);
-
-        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 };
-                gnutls_datum_t label = { a[2].value, a[2].value_len };
-                
-                ret = pkcs11_crt_import(find_data->crt, &data, &id, &label, &info->tinfo);
-                if (ret < 0) {
-                    gnutls_assert();
-                    goto cleanup;
-                }
-
-                found = 1;
-                break;
+        a[0].value = cert_data;
+        a[0].value_len = MAX_CERT_SIZE;
+        a[1].type = CKA_LABEL;
+        a[1].value = label_tmp;
+        a[1].value_len = sizeof(label_tmp);
+
+        if (pakchois_get_attribute_value(pks, obj, a, 2) == CKR_OK) {
+            gnutls_datum_t id = { find_data->crt->info.certid_raw, find_data->crt->info.certid_raw_size };
+            gnutls_datum_t data = { a[0].value, a[0].value_len };
+            gnutls_datum_t label = { a[1].value, a[1].value_len };
+            
+            ret = pkcs11_crt_import(find_data->crt, &data, &id, &label, &info->tinfo);
+            if (ret < 0) {
+                gnutls_assert();
+                goto cleanup;
             }
+
+            found = 1;
+            break;
         }
         else {
             _gnutls_debug_log("pk11: Skipped cert, missing attrs.\n");
@@ -739,6 +771,7 @@ static int find_cert_url(pakchois_session_t *pks, struct token_info *info, void*
     }
 
 cleanup:
+    gnutls_free(cert_data);
     pakchois_find_objects_final(pks);
     
     return ret;
@@ -758,15 +791,7 @@ int gnutls_pkcs11_crt_import_url (gnutls_pkcs11_crt_t cert, const char * url)
         return ret;
     }
 
-    find_data.certid_raw_size = sizeof(find_data.certid_raw);
-    
-    ret = _gnutls_hex2bin(cert->info.id, strlen(cert->info.id), find_data.certid_raw, &find_data.certid_raw_size);
-    if (ret < 0) {
-        gnutls_assert();
-        return ret;
-    }
-
-    ret = traverse_tokens(find_cert_url, &find_data);
+    ret = _pkcs11_traverse_tokens(find_cert_url, &find_data, 0);
     if (ret < 0) {
         gnutls_assert();
         return ret;
@@ -813,8 +838,8 @@ int gnutls_pkcs11_token_get_url (unsigned int seq, char** url)
 
     memset(&tn, 0, sizeof(tn));
     tn.seq = seq;
-
-    ret = traverse_tokens(find_token_num, &tn);
+    
+    ret = _pkcs11_traverse_tokens(find_token_num, &tn, 0);
     if (ret < 0) {
         gnutls_assert();
         return ret;
@@ -856,6 +881,9 @@ int gnutls_pkcs11_token_get_info(const char* url, gnutls_pkcs11_token_info_t tty
         case GNUTLS_PKCS11_TOKEN_MODEL:
             str = info.model;
             break;
+        default:
+            gnutls_assert();
+            return GNUTLS_E_INVALID_REQUEST;
     }
 
     len = strlen(str);
@@ -896,9 +924,8 @@ struct pkey_list {
     size_t key_ids_size;
 };
 
-static int pk11_login(pakchois_session_t *pks, struct token_info *info)
+int pkcs11_login(pakchois_session_t *pks, struct token_info *info)
 {
-    struct ck_token_info tinfo;
     int attempt = 0;
     ck_rv_t rv;
 
@@ -911,7 +938,8 @@ static int pk11_login(pakchois_session_t *pks, struct token_info *info)
     /* force login on HW tokens. Some tokens will not list private keys
      * if login has not been performed.
      */
-    if (!(info->sinfo.flags & CKF_HW_SLOT) && (tinfo.flags & CKF_LOGIN_REQUIRED) == 0) {
+//    if (!(info->sinfo.flags & CKF_HW_SLOT) && (info->tinfo.flags & CKF_LOGIN_REQUIRED) == 0) {
+    if ((info->tinfo.flags & CKF_LOGIN_REQUIRED) == 0) {
         gnutls_assert();
         _gnutls_debug_log( "pk11: No login required.\n");
         return 0;
@@ -920,7 +948,7 @@ static int pk11_login(pakchois_session_t *pks, struct token_info *info)
     /* 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 (info->tinfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
         if (pakchois_login(pks, CKU_USER, NULL, 0) == CKR_OK) {
             return 0;
         }
@@ -971,7 +999,6 @@ static int pk11_login(pakchois_session_t *pks, struct token_info *info)
         }
 
         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);
@@ -990,12 +1017,12 @@ static int find_privkeys(pakchois_session_t *pks, struct token_info* info, struc
     ck_rv_t rv;
     ck_object_handle_t obj;
     unsigned long count, current;
-    char certid_tmp[ID_SIZE];
+    char certid_tmp[PKCS11_ID_SIZE];
     int ret;
 
     class = CKO_PRIVATE_KEY;
 
-    ret = pk11_login(pks, info);
+    ret = pkcs11_login(pks, info);
     if (ret < 0) {
         gnutls_assert();
         return ret;
@@ -1083,9 +1110,9 @@ static int find_crts(pakchois_session_t *pks, struct token_info *info, void* inp
     ck_rv_t rv;
     ck_object_handle_t obj;
     unsigned long count;
-    unsigned char value[MAX_CERT_SIZE];
-    char certid_tmp[ID_SIZE];
-    char label_tmp[LABEL_SIZE];
+    opaque *cert_data;
+    char certid_tmp[PKCS11_ID_SIZE];
+    char label_tmp[PKCS11_LABEL_SIZE];
     int ret, i;
     struct pkey_list plist; /* private key holder */
 
@@ -1143,6 +1170,12 @@ static int find_crts(pakchois_session_t *pks, struct token_info *info, void* inp
         }
     }
 
+    cert_data = gnutls_malloc(MAX_CERT_SIZE);
+    if (cert_data == NULL) {
+        gnutls_assert();
+        return GNUTLS_E_MEMORY_ERROR;
+    }
+
     /* Find objects with cert class and X.509 cert type. */
     class = CKO_CERTIFICATE;
     type = CKC_X_509;
@@ -1175,8 +1208,8 @@ static int find_crts(pakchois_session_t *pks, struct token_info *info, void* inp
            && count == 1) {
 
         a[0].type = CKA_VALUE;
-        a[0].value = value;
-        a[0].value_len = sizeof value;
+        a[0].value = cert_data;
+        a[0].value_len = MAX_CERT_SIZE;
         a[1].type = CKA_ID;
         a[1].value = certid_tmp;
         a[1].value_len = sizeof(certid_tmp);
@@ -1223,11 +1256,13 @@ static int find_crts(pakchois_session_t *pks, struct token_info *info, void* inp
         }
     }
 
+    gnutls_free(cert_data);
     pakchois_find_objects_final(pks);
    
     return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; /* continue until all tokens have been checked */
 
 fail:
+    gnutls_free(cert_data);
     pakchois_find_objects_final(pks);
     if (plist.key_ids != NULL) {
         for (i=0;i<plist.key_ids_size;i++) {
@@ -1264,7 +1299,7 @@ int gnutls_pkcs11_crt_list_import_url (gnutls_pkcs11_crt_t * p_list, unsigned in
         return ret;
     }
 
-    ret = traverse_tokens(find_crts, &find_data);
+    ret = _pkcs11_traverse_tokens(find_crts, &find_data, 0);
     if (ret < 0) {
         gnutls_assert();
         return ret;
@@ -1366,184 +1401,3 @@ cleanup:
 */
 
 
-#if 0
-#define KEYTYPE_IS_DSA(kt) (kt == CKK_DSA)
-
-
-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/pkcs11_int.h b/lib/pkcs11_int.h
new file mode 100644 (file)
index 0000000..5f475c0
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef PKCS11_INT_H
+# define PKCS11_INT_H
+
+#include <pakchois/pakchois.h>
+#include <gnutls/pkcs11.h>
+
+#define PKCS11_ID_SIZE 128
+#define PKCS11_LABEL_SIZE 128
+
+struct token_info {
+    struct ck_token_info tinfo;
+    struct ck_slot_info sinfo;
+    ck_slot_id_t sid;
+    struct gnutls_pkcs11_provider_s* prov;
+};
+
+struct pkcs11_url_info
+{
+    /* everything here is null terminated strings */
+    opaque id[PKCS11_ID_SIZE*3+1]; /* hex with delimiters */
+    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];
+    opaque label[PKCS11_LABEL_SIZE+1];
+    
+    opaque certid_raw[PKCS11_ID_SIZE]; /* same as ID but raw */
+    size_t certid_raw_size;
+};
+
+/* thus function is called for every token in the traverse_tokens
+ * function. Once everything is traversed it is called with NULL tinfo.
+ * It should return 0 if found what it was looking for.
+ */
+typedef int (*find_func_t)(pakchois_session_t *pks, struct token_info* tinfo, void* input);
+
+int _pkcs11_traverse_tokens (find_func_t find_func, void* input, int leave_session);
+int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info);
+
+int pkcs11_get_info(struct pkcs11_url_info *info, gnutls_pkcs11_cert_info_t itype, 
+    void* output, size_t* output_size);
+int pkcs11_login(pakchois_session_t *pks, struct token_info *info);
+
+extern gnutls_pkcs11_token_callback_t token_func;
+extern void* token_data;
+
+
+#endif
diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c
new file mode 100644 (file)
index 0000000..039bcf1
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ * 
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * 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>
+#include <pkcs11_int.h>
+#include <sign.h>
+
+struct gnutls_pkcs11_privkey_st {
+       pakchois_session_t *pks;
+       ck_object_handle_t privkey;
+       gnutls_pk_algorithm_t pk_algorithm;
+       struct pkcs11_url_info info;
+};
+
+struct privkey_find_data_st {
+       gnutls_pkcs11_privkey_t privkey;
+};
+
+static int find_privkey_url(pakchois_session_t * pks,
+                           struct token_info *info, void *input);
+
+int gnutls_pkcs11_privkey_init(gnutls_pkcs11_privkey_t * key)
+{
+       *key = gnutls_calloc(1, sizeof(struct gnutls_pkcs11_privkey_st));
+       if (*key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+       (*key)->privkey = CK_INVALID_HANDLE;
+       
+       return 0;
+}
+
+void gnutls_pkcs11_privkey_deinit(gnutls_pkcs11_privkey_t key)
+{
+       if (key->pks) {
+fprintf(stderr, "xxx: close session %p at %d\n", key->pks, __LINE__);
+               pakchois_close_session(key->pks);
+        }
+       gnutls_free(key);
+}
+
+int gnutls_pkcs11_privkey_get_pk_algorithm(gnutls_pkcs11_privkey_t key, unsigned int *bits)
+{
+        if (bits)
+          *bits = 0; /* FIXME */
+       return key->pk_algorithm;
+}
+
+int gnutls_pkcs11_privkey_get_info(gnutls_pkcs11_privkey_t pkey,
+                                  gnutls_pkcs11_cert_info_t itype,
+                                  void *output, size_t * output_size)
+{
+       return pkcs11_get_info(&pkey->info, itype, output, output_size);
+}
+
+#define RETRY_BLOCK_START(key) struct privkey_find_data_st find_data; \
+       int retries = 0; find_data.privkey = key; retry:
+
+
+
+#define RETRY_CHECK(rv, label) { \
+               if (token_func && rv == CKR_SESSION_HANDLE_INVALID) { \
+                       ret = token_func(token_data, label, retries++); \
+                       if (ret == 0) { \
+                               _pkcs11_traverse_tokens(find_privkey_url, &find_data, 1); \
+                               goto retry; \
+                       } \
+               } \
+       }
+
+/**
+ * gnutls_pkcs11_privkey_sign_data:
+ * @signer: Holds the key
+ * @digest: should be MD5 or SHA1
+ * @flags: should be 0 for now
+ * @data: holds the data to be signed
+ * @signature: will contain the signature allocated with gnutls_malloc()
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key. Signature algorithms are always used
+ * together with a hash functions.  Different hash functions may be
+ * used for the RSA algorithm, but only SHA-1 for the DSA keys.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_pkcs11_privkey_sign_data(gnutls_pkcs11_privkey_t signer,
+                               gnutls_digest_algorithm_t hash,
+                               unsigned int flags,
+                               const gnutls_datum_t * data,
+                               gnutls_datum_t * signature)
+{
+       int ret;
+       gnutls_datum_t digest;
+
+       switch (signer->pk_algorithm) {
+       case GNUTLS_PK_RSA:
+               ret = pk_pkcs1_rsa_hash(hash, data, &digest);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               break;
+       case GNUTLS_PK_DSA:
+               ret = pk_dsa_hash(data, &digest);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+
+               break;
+       default:
+               gnutls_assert();
+               return GNUTLS_E_INTERNAL_ERROR;
+       }
+
+       ret = gnutls_pkcs11_privkey_sign_hash(signer, &digest, signature);
+       _gnutls_free_datum(&digest);
+
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       return 0;
+
+}
+
+
+int gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
+                                   const gnutls_datum_t * hash,
+                                   gnutls_datum_t * signature)
+{
+       ck_rv_t rv;
+       int ret;
+       struct ck_mechanism mech;
+       unsigned long siglen;
+
+       RETRY_BLOCK_START(key);
+
+       if (key->privkey == CK_INVALID_HANDLE) {
+               gnutls_assert();
+               return GNUTLS_E_PKCS11_ERROR;
+       }
+
+       mech.mechanism =
+           key->pk_algorithm == GNUTLS_PK_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(key->pks, &mech, key->privkey);
+       if (rv != CKR_OK) {
+               RETRY_CHECK(rv, key->info.label);
+               gnutls_assert();
+               return GNUTLS_E_PK_SIGN_FAILED;
+       }
+
+       /* Work out how long the signature must be: */
+       rv = pakchois_sign(key->pks, hash->data, hash->size, NULL,
+                          &siglen);
+       if (rv != CKR_OK) {
+               RETRY_CHECK(rv, key->info.label);
+               gnutls_assert();
+               return GNUTLS_E_PK_SIGN_FAILED;
+       }
+
+       signature->data = gnutls_malloc(siglen);
+       signature->size = siglen;
+
+       rv = pakchois_sign(key->pks, hash->data, hash->size,
+                          signature->data, &siglen);
+       if (rv != CKR_OK) {
+               gnutls_free(signature->data);
+               gnutls_assert();
+               return GNUTLS_E_PK_SIGN_FAILED;
+       }
+
+       signature->size = siglen;
+
+       return 0;
+}
+
+static int find_privkey_url(pakchois_session_t * pks,
+                           struct token_info *info, void *input)
+{
+       struct privkey_find_data_st *find_data = input;
+       struct ck_attribute a[4];
+       ck_object_class_t class;
+       ck_rv_t rv;
+       ck_object_handle_t obj;
+       unsigned long count;
+       int found = 0, ret;
+       ck_key_type_t keytype;
+
+       if (info == 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->privkey->info.manufacturer[0] != 0) {
+               if (strcmp
+                   (find_data->privkey->info.manufacturer,
+                    info->tinfo.manufacturer_id) != 0)
+                       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }
+
+       if (find_data->privkey->info.token[0] != 0) {
+               if (strcmp
+                   (find_data->privkey->info.token,
+                    info->tinfo.label) != 0)
+                       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }
+
+       if (find_data->privkey->info.model[0] != 0) {
+               if (strcmp
+                   (find_data->privkey->info.model,
+                    info->tinfo.model) != 0)
+                       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }
+
+       if (find_data->privkey->info.serial[0] != 0) {
+               if (strcmp
+                   (find_data->privkey->info.serial,
+                    info->tinfo.serial_number) != 0)
+                       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }
+
+       if (find_data->privkey->info.type[0] != 0) {
+               if (strcmp(find_data->privkey->info.type, "cert") != 0) {
+                       gnutls_assert();
+                       return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+               }
+       }
+
+       /* search the token for the id */
+        ret = pkcs11_login(pks, info);
+        if (ret < 0) {
+            gnutls_assert();
+            return ret;
+        }
+        
+       /* Find objects with cert class and X.509 cert type. */
+       class = CKO_PRIVATE_KEY;
+
+       a[0].type = CKA_CLASS;
+       a[0].value = &class;
+       a[0].value_len = sizeof class;
+
+       a[1].type = CKA_ID;
+       a[1].value = find_data->privkey->info.certid_raw;
+       a[1].value_len = find_data->privkey->info.certid_raw_size;
+
+
+       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_KEY_TYPE;
+               a[0].value = &keytype;
+               a[0].value_len = sizeof keytype;
+
+               if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+                       if (keytype == CKK_RSA)
+                               find_data->privkey->pk_algorithm = GNUTLS_PK_RSA;
+                       else if (keytype == CKK_DSA)
+                               find_data->privkey->pk_algorithm = GNUTLS_PK_DSA;
+                       else {
+                               gnutls_assert();
+                               ret =
+                                   GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
+                               goto cleanup;
+                       }
+                       find_data->privkey->pks = pks;
+                       find_data->privkey->privkey = obj;
+                       found = 1;
+               } 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_privkey_import_url(gnutls_pkcs11_privkey_t pkey,
+                                    const char *url)
+{
+       int ret;
+       struct privkey_find_data_st find_data;
+
+       /* fill in the find data structure */
+       find_data.privkey = pkey;
+
+       ret = pkcs11_url_to_info(url, &pkey->info);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       if (pkey->info.id[0] == 0) {
+               gnutls_assert();
+               return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }
+
+       ret = _pkcs11_traverse_tokens(find_privkey_url, &find_data, 1);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * gnutls_pkcs11_privkey_decrypt_data:
+ * @key: Holds the key
+ * @flags: should be 0 for now
+ * @ciphertext: holds the data to be signed
+ * @plaintext: will contain the plaintext, allocated with gnutls_malloc()
+ *
+ * This function will decrypt the given data using the public key algorithm
+ * supported by the private key. 
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
+  unsigned int flags, const gnutls_datum_t * ciphertext,
+                               gnutls_datum_t * plaintext)
+{
+       ck_rv_t rv;
+       int ret;
+       struct ck_mechanism mech;
+       unsigned long siglen;
+
+       RETRY_BLOCK_START(key);
+
+       if (key->privkey == CK_INVALID_HANDLE) {
+               gnutls_assert();
+               return GNUTLS_E_PKCS11_ERROR;
+       }
+
+       mech.mechanism =
+           key->pk_algorithm == GNUTLS_PK_DSA ? CKM_DSA : CKM_RSA_PKCS;
+       mech.parameter = NULL;
+       mech.parameter_len = 0;
+
+       /* Initialize signing operation; using the private key discovered
+        * earlier. */
+       rv = pakchois_decrypt_init(key->pks, &mech, key->privkey);
+       if (rv != CKR_OK) {
+               RETRY_CHECK(rv, key->info.label);
+               gnutls_assert();
+               return GNUTLS_E_PK_DECRYPTION_FAILED;
+       }
+
+       /* Work out how long the plaintext must be: */
+       rv = pakchois_decrypt(key->pks, ciphertext->data, ciphertext->size, NULL,
+                          &siglen);
+       if (rv != CKR_OK) {
+               RETRY_CHECK(rv, key->info.label);
+               gnutls_assert();
+               return GNUTLS_E_PK_DECRYPTION_FAILED;
+       }
+
+       plaintext->data = gnutls_malloc(siglen);
+       plaintext->size = siglen;
+
+       rv = pakchois_decrypt(key->pks, ciphertext->data, ciphertext->size,
+                          plaintext->data, &siglen);
+       if (rv != CKR_OK) {
+               gnutls_free(plaintext->data);
+               gnutls_assert();
+               return GNUTLS_E_PK_DECRYPTION_FAILED;
+       }
+
+       plaintext->size = siglen;
+
+       return 0;
+}
index f49380478b34eb06c0d86c8baf909613c17c6fd6..ce633db45c5e27d92f98415a347a9291ddce1184 100644 (file)
@@ -34,6 +34,7 @@
 #include <x509_b64.h>
 #include <x509_int.h>
 #include <gnutls_pk.h>
+#include <sign.h>
 
 static int _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params);
 
@@ -90,7 +91,7 @@ gnutls_x509_privkey_deinit (gnutls_x509_privkey_t key)
  * @src: The source key
  *
  * This function will copy a private key from source to destination
- * key.
+ * key. Destination has to be initialized.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
  *   negative error value.
@@ -1463,17 +1464,14 @@ cleanup:
   return result;
 }
 
-#ifdef ENABLE_PKI
 
 /**
- * gnutls_x509_privkey_sign_data:
- * @key: Holds the key
- * @digest: should be MD5 or SHAx. May be ignored.
+ * gnutls_x509_privkey_sign_data2:
+ * @signer: Holds the key
+ * @digest: should be MD5 or SHA1
  * @flags: should be 0 for now
  * @data: holds the data to be signed
- * @signature: will contain the signature
- * @signature_size: holds the size of signature (and will be replaced
- *   by the new size)
+ * @signature: will contain the signature allocate with gnutls_malloc()
  *
  * This function will sign the given data using a signature algorithm
  * supported by the private key. Signature algorithms are always used
@@ -1488,41 +1486,51 @@ cleanup:
  *   negative error value.
  **/
 int
-gnutls_x509_privkey_sign_data (gnutls_x509_privkey_t key,
-                              gnutls_digest_algorithm_t digest,
+gnutls_x509_privkey_sign_data2 (gnutls_x509_privkey_t signer,
+                              gnutls_digest_algorithm_t hash,
                               unsigned int flags,
                               const gnutls_datum_t * data,
-                              void *signature, size_t * signature_size)
+                              gnutls_datum_t * signature)
 {
-  int result;
-  gnutls_datum_t sig = { NULL, 0 };
-
-  if (key == NULL)
+  int ret;
+  gnutls_datum_t digest;
+  
+  switch (signer->pk_algorithm)
     {
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
-    }
+    case GNUTLS_PK_RSA:
+      ret =
+       pk_pkcs1_rsa_hash (hash, data, &digest);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
+      break;
+    case GNUTLS_PK_DSA:
+      ret = pk_dsa_hash (data,  &digest);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
 
-  result = _gnutls_x509_sign (data, digest, key, &sig);
-  if (result < 0)
-    {
+      break;
+    default:
       gnutls_assert ();
-      return result;
+      return GNUTLS_E_INTERNAL_ERROR;
     }
-
-  if (*signature_size < sig.size)
+    
+  ret = gnutls_x509_privkey_sign_hash(signer, &digest, signature);
+  _gnutls_free_datum (&digest);
+                    
+  if (ret < 0)
     {
-      *signature_size = sig.size;
-      _gnutls_free_datum (&sig);
-      return GNUTLS_E_SHORT_MEMORY_BUFFER;
+      gnutls_assert ();
+      return ret;
     }
 
-  *signature_size = sig.size;
-  memcpy (signature, sig.data, sig.size);
-
-  _gnutls_free_datum (&sig);
-
   return 0;
+
 }
 
 /**
@@ -1552,7 +1560,7 @@ gnutls_x509_privkey_sign_hash (gnutls_x509_privkey_t key,
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  result = _gnutls_sign (key->pk_algorithm, key->params,
+  result = _gnutls_soft_sign (key->pk_algorithm, key->params,
                         key->params_size, hash, signature);
   if (result < 0)
     {
@@ -1563,6 +1571,68 @@ gnutls_x509_privkey_sign_hash (gnutls_x509_privkey_t key,
   return 0;
 }
 
+#ifdef ENABLE_PKI
+/**
+ * gnutls_x509_privkey_sign_data:
+ * @key: Holds the key
+ * @digest: should be MD5 or SHA1
+ * @flags: should be 0 for now
+ * @data: holds the data to be signed
+ * @signature: will contain the signature
+ * @signature_size: holds the size of signature (and will be replaced
+ *   by the new size)
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key. Signature algorithms are always used
+ * together with a hash functions.  Different hash functions may be
+ * used for the RSA algorithm, but only SHA-1 for the DSA keys.
+ *
+ * If the buffer provided is not long enough to hold the output, then
+ * *@signature_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER will
+ * be returned.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_x509_privkey_sign_data (gnutls_x509_privkey_t key,
+                              gnutls_digest_algorithm_t digest,
+                              unsigned int flags,
+                              const gnutls_datum_t * data,
+                              void *signature, size_t * signature_size)
+{
+  int result;
+  gnutls_datum_t sig = { NULL, 0 };
+
+  if (key == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  result = gnutls_x509_privkey_sign_data2(key, digest, flags, data, &sig);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  if (*signature_size < sig.size)
+    {
+      *signature_size = sig.size;
+      _gnutls_free_datum (&sig);
+      return GNUTLS_E_SHORT_MEMORY_BUFFER;
+    }
+
+  *signature_size = sig.size;
+  memcpy (signature, sig.data, sig.size);
+
+  _gnutls_free_datum (&sig);
+
+  return 0;
+}
+
+
 /**
  * gnutls_x509_privkey_verify_data:
  * @key: Holds the key
index e74c48f00e160bd7c734a78f72523cfb810f8664..f272c08e6fab05d2f5ffd658d5c077bbb638eaa4 100644 (file)
@@ -41,6 +41,7 @@
 #include <gnutls_datum.h>
 #include <x509_int.h>
 #include <common.h>
+#include <sign.h>
 
 /* Writes the digest information and the digest in a DER encoded
  * structure. The digest info is allocated and stored into the info structure.
@@ -128,14 +129,13 @@ encode_ber_digest_info (gnutls_digest_algorithm_t hash,
  * params[0] is modulus
  * params[1] is public key
  */
-static int
-pkcs1_rsa_sign (gnutls_digest_algorithm_t hash, const gnutls_datum_t * text,
-               bigint_t * params, int params_len, gnutls_datum_t * signature)
+int
+pk_pkcs1_rsa_hash (gnutls_digest_algorithm_t hash, const gnutls_datum_t * text, gnutls_datum_t * output)
 {
   int ret;
   opaque _digest[MAX_HASH_SIZE];
   digest_hd_st hd;
-  gnutls_datum_t digest, info;
+  gnutls_datum_t digest;
 
   ret = _gnutls_hash_init (&hd, HASH2MAC (hash));
   if (ret < 0)
@@ -152,29 +152,17 @@ pkcs1_rsa_sign (gnutls_digest_algorithm_t hash, const gnutls_datum_t * text,
 
   /* Encode the digest as a DigestInfo
    */
-  if ((ret = encode_ber_digest_info (hash, &digest, &info)) != 0)
+  if ((ret = encode_ber_digest_info (hash, &digest, output)) != 0)
     {
       gnutls_assert ();
       return ret;
     }
 
-  if ((ret =
-       _gnutls_sign (GNUTLS_PK_RSA, params, params_len, &info,
-                    signature)) < 0)
-    {
-      gnutls_assert ();
-      _gnutls_free_datum (&info);
-      return ret;
-    }
-
-  _gnutls_free_datum (&info);
-
   return 0;
 }
 
-static int
-dsa_sign (const gnutls_datum_t * text,
-         bigint_t * params, int params_len, gnutls_datum_t * signature)
+int
+pk_dsa_hash (const gnutls_datum_t * text, gnutls_datum_t * hash)
 {
   int ret;
   opaque _digest[MAX_HASH_SIZE];
@@ -206,52 +194,6 @@ dsa_sign (const gnutls_datum_t * text,
   return 0;
 }
 
-/* Signs the given data using the parameters from the signer's
- * private key.
- *
- * returns 0 on success.
- * 
- * 'tbs' is the data to be signed
- * 'signature' will hold the signature!
- * 'hash' is only used in PKCS1 RSA signing.
- */
-int
-_gnutls_x509_sign (const gnutls_datum_t * tbs,
-                  gnutls_digest_algorithm_t hash,
-                  gnutls_x509_privkey_t signer, gnutls_datum_t * signature)
-{
-  int ret;
-
-  switch (signer->pk_algorithm)
-    {
-    case GNUTLS_PK_RSA:
-      ret =
-       pkcs1_rsa_sign (hash, tbs, signer->params, signer->params_size,
-                       signature);
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
-      return 0;
-      break;
-    case GNUTLS_PK_DSA:
-      ret = dsa_sign (tbs, signer->params, signer->params_size, signature);
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
-
-      return 0;
-      break;
-    default:
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-}
-
 /* This is the same as the _gnutls_x509_sign, but this one will decode
  * the ASN1_TYPE given, and sign the DER data. Actually used to get the DER
  * of the TBS and sign it on the fly.
@@ -289,7 +231,7 @@ _gnutls_x509_sign_tbs (ASN1_TYPE cert, const char *tbs_name,
   tbs.data = buf;
   tbs.size = buf_size;
 
-  result = _gnutls_x509_sign (&tbs, hash, signer, signature);
+  result = gnutls_x509_privkey_sign_data2 (signer, hash, 0, &tbs, signature);
   gnutls_free (buf);
 
   return result;
diff --git a/lib/x509/sign.h b/lib/x509/sign.h
new file mode 100644 (file)
index 0000000..291458d
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef GNUTLS_SIGN_H
+# define GNUTLS_SIGN_H
+
+int pk_pkcs1_rsa_hash (gnutls_digest_algorithm_t hash, const gnutls_datum_t * text, gnutls_datum_t * output);
+int pk_dsa_hash (const gnutls_datum_t * text, gnutls_datum_t * hash);
+
+#endif
index 6ea8ee880d66f9d4e4f52ec12c107ea6070cdb7f..ede4814bacf4f2ebf3e6d0e4a22c0fa4e063a3b6 100644 (file)
@@ -134,10 +134,6 @@ int _gnutls_x509_crl_get_raw_issuer_dn (gnutls_x509_crl_t crl,
                                        gnutls_datum_t * dn);
 
 /* sign.c */
-int _gnutls_x509_sign (const gnutls_datum_t * tbs,
-                      gnutls_digest_algorithm_t hash,
-                      gnutls_x509_privkey_t signer,
-                      gnutls_datum_t * signature);
 int _gnutls_x509_sign_tbs (ASN1_TYPE cert, const char *tbs_name,
                           gnutls_digest_algorithm_t hash,
                           gnutls_x509_privkey_t signer,
index 0e53bdcb538aeaa5a2c1e2e63498f87780eb1ce7..e256da22b3665aa2d351dfb5d36b49b5a1dd3b57 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -37,6 +37,7 @@
 #include <gnutls/extra.h>
 #include <gnutls/x509.h>
 #include <gnutls/openpgp.h>
+#include <gnutls/pkcs11.h>
 #include <gcrypt.h>
 
 /* Gnulib portability files. */
@@ -144,6 +145,8 @@ static unsigned int x509_crt_size;
 static gnutls_x509_crt_t x509_crt[MAX_CRT];
 static gnutls_x509_privkey_t x509_key = NULL;
 
+static gnutls_pkcs11_privkey_t pkcs11_key = NULL;
+
 static gnutls_openpgp_crt_t pgp_crt = NULL;
 static gnutls_openpgp_privkey_t pgp_key = NULL;
 
@@ -179,58 +182,86 @@ load_keys (void)
 
   if (x509_certfile != NULL && x509_keyfile != NULL)
     {
-      data = load_file (x509_certfile);
-      if (data.data == NULL)
+      if (strncmp (x509_certfile, "pkcs11:", 7) == 0)
        {
-         fprintf (stderr, "*** Error loading cert file.\n");
-         exit (1);
-       }
+         crt_num = 1;
+         gnutls_x509_crt_init (&x509_crt[0]);
 
-      crt_num = MAX_CRT;
-      ret =
-       gnutls_x509_crt_list_import (x509_crt, &crt_num, &data,
-                                    GNUTLS_X509_FMT_PEM,
-                                    GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
-      if (ret < 0)
-       {
-         if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+         ret =
+           gnutls_x509_crt_import_pkcs11_url (x509_crt[0], x509_certfile);
+         if (ret < 0)
            {
-             fprintf (stderr,
-                      "*** Error loading cert file: Too many certs %d\n",
-                      crt_num);
+             fprintf (stderr, "*** Error loading cert file.\n");
+             exit (1);
+           }
+         x509_crt_size = 1;
+       }
+      else
+       {
 
+         data = load_file (x509_certfile);
+         if (data.data == NULL)
+           {
+             fprintf (stderr, "*** Error loading cert file.\n");
+             exit (1);
            }
-         else
+
+         crt_num = MAX_CRT;
+         ret =
+           gnutls_x509_crt_list_import (x509_crt, &crt_num, &data,
+                                        GNUTLS_X509_FMT_PEM,
+                                        GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
+         if (ret < 0)
            {
-             fprintf (stderr,
-                      "*** Error loading cert file: %s\n",
-                      gnutls_strerror (ret));
+             if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+               {
+                 fprintf (stderr,
+                          "*** Error loading cert file: Too many certs %d\n",
+                          crt_num);
+
+               }
+             else
+               {
+                 fprintf (stderr,
+                          "*** Error loading cert file: %s\n",
+                          gnutls_strerror (ret));
+               }
+             exit (1);
            }
-         exit (1);
+         x509_crt_size = ret;
        }
-      x509_crt_size = ret;
       fprintf (stderr, "Processed %d client certificates...\n", ret);
 
       unload_file (data);
 
-      data = load_file (x509_keyfile);
-      if (data.data == NULL)
+      if (strncmp (x509_keyfile, "pkcs11:", 7) == 0)
        {
-         fprintf (stderr, "*** Error loading key file.\n");
-         exit (1);
+         gnutls_pkcs11_privkey_init (&pkcs11_key);
+
+         ret = gnutls_pkcs11_privkey_import_url (pkcs11_key, x509_keyfile);
        }
+      else
+       {
+         data = load_file (x509_keyfile);
+         if (data.data == NULL)
+           {
+             fprintf (stderr, "*** Error loading key file.\n");
+             exit (1);
+           }
 
-      gnutls_x509_privkey_init (&x509_key);
+         gnutls_x509_privkey_init (&x509_key);
 
-      ret = gnutls_x509_privkey_import (x509_key, &data, GNUTLS_X509_FMT_PEM);
-      if (ret < 0)
-       {
-         fprintf (stderr, "*** Error loading key file: %s\n",
-                  gnutls_strerror (ret));
-         exit (1);
-       }
+         ret =
+           gnutls_x509_privkey_import (x509_key, &data, GNUTLS_X509_FMT_PEM);
+         if (ret < 0)
+           {
+             fprintf (stderr, "*** Error loading key file: %s\n",
+                      gnutls_strerror (ret));
+             exit (1);
+           }
 
-      unload_file (data);
+         unload_file (data);
+       }
 
       fprintf (stderr, "Processed %d client X.509 certificates...\n",
               x509_crt_size);
@@ -259,27 +290,38 @@ load_keys (void)
 
       unload_file (data);
 
-      data = load_file (pgp_keyfile);
-      if (data.data == NULL)
+      if (strncmp (pgp_keyfile, "pkcs11:", 7) == 0)
        {
-         fprintf (stderr, "*** Error loading PGP key file.\n");
-         exit (1);
+         gnutls_pkcs11_privkey_init (&pkcs11_key);
+
+         ret = gnutls_pkcs11_privkey_import_url (pkcs11_key, pgp_keyfile);
        }
+      else
+       {
 
-      gnutls_openpgp_privkey_init (&pgp_key);
+         data = load_file (pgp_keyfile);
+         if (data.data == NULL)
+           {
+             fprintf (stderr, "*** Error loading PGP key file.\n");
+             exit (1);
+           }
 
-      ret =
-       gnutls_openpgp_privkey_import (pgp_key, &data,
-                                      GNUTLS_OPENPGP_FMT_BASE64, NULL, 0);
-      if (ret < 0)
-       {
-         fprintf (stderr,
-                  "*** Error loading PGP key file: %s\n",
-                  gnutls_strerror (ret));
-         exit (1);
-       }
+         gnutls_openpgp_privkey_init (&pgp_key);
 
-      unload_file (data);
+         ret =
+           gnutls_openpgp_privkey_import (pgp_key, &data,
+                                          GNUTLS_OPENPGP_FMT_BASE64, NULL,
+                                          0);
+         if (ret < 0)
+           {
+             fprintf (stderr,
+                      "*** Error loading PGP key file: %s\n",
+                      gnutls_strerror (ret));
+             exit (1);
+           }
+
+         unload_file (data);
+       }
 
       if (info.pgp_subkey != NULL)
        {
@@ -347,7 +389,7 @@ static int
 cert_callback (gnutls_session_t session,
               const gnutls_datum_t * req_ca_rdn, int nreqs,
               const gnutls_pk_algorithm_t * sign_algos,
-              int sign_algos_length, gnutls_retr_st * st)
+              int sign_algos_length, gnutls_retr2_st * st)
 {
   char issuer_dn[256];
   int i, ret;
@@ -355,7 +397,6 @@ cert_callback (gnutls_session_t session,
 
   if (verbose)
     {
-
       /* Print the server's trusted CAs
        */
       if (nreqs > 0)
@@ -381,12 +422,11 @@ cert_callback (gnutls_session_t session,
    * supported by the server.
    */
 
-  st->type = gnutls_certificate_type_get (session);
-
+  st->cert_type = gnutls_certificate_type_get (session);
 
   st->ncerts = 0;
 
-  if (st->type == GNUTLS_CRT_X509)
+  if (st->cert_type == GNUTLS_CRT_X509)
     {
       gnutls_sign_algorithm_t cert_algo, req_algo;
       int i, match = 0;
@@ -430,26 +470,56 @@ cert_callback (gnutls_session_t session,
            }
        }
 
-      if (x509_crt != NULL && x509_key != NULL)
+      if (x509_key != NULL)
+       {
+         st->key.x509 = x509_key;
+         st->key_type = GNUTLS_PRIVKEY_X509;
+       }
+      else if (pkcs11_key != NULL)
+       {
+         st->key.pkcs11 = pkcs11_key;
+         st->key_type = GNUTLS_PRIVKEY_PKCS11;
+       }
+      else
+       {
+         printf ("- Could not find a suitable key to send to server\n");
+         return -1;
+       }
+
+      if (x509_crt != NULL)
        {
          st->ncerts = x509_crt_size;
 
          st->cert.x509 = x509_crt;
-         st->key.x509 = x509_key;
 
          st->deinit_all = 0;
 
          return 0;
        }
     }
-  else if (st->type == GNUTLS_CRT_OPENPGP)
+  else if (st->cert_type == GNUTLS_CRT_OPENPGP)
     {
-      if (pgp_key != NULL && pgp_crt != NULL)
+      if (pgp_key != NULL)
+       {
+         st->key.pgp = pgp_key;
+         st->key_type = GNUTLS_PRIVKEY_OPENPGP;
+       }
+      else if (pkcs11_key != NULL)
+       {
+         st->key.pkcs11 = pkcs11_key;
+         st->key_type = GNUTLS_PRIVKEY_PKCS11;
+       }
+      else
+       {
+         printf ("- Could not find a suitable key to send to server\n");
+         return -1;
+       }
+
+      if (pgp_crt != NULL)
        {
          st->ncerts = 1;
 
          st->cert.pgp = pgp_crt;
-         st->key.pgp = pgp_key;
 
          st->deinit_all = 0;
 
@@ -510,7 +580,7 @@ init_tls_session (const char *hostname)
     gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
   gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, xcred);
 
-  gnutls_certificate_client_set_retrieve_function (xcred, cert_callback);
+  gnutls_certificate_set_retrieve_function (xcred, cert_callback);
   gnutls_certificate_set_verify_function (xcred, cert_verify_callback);
 
   /* send the fingerprint */
@@ -656,6 +726,7 @@ main (int argc, char **argv)
       exit (1);
     }
 
+  pkcs11_common ();
   gaa_parser (argc, argv);
   if (hostname == NULL)
     {
index 5de74738be901fc81ec7074e41dc397f04ea0a50..04d1356ff7550f79f47152fe8f0b145d79c788b0 100644 (file)
 #include <gnutls/openpgp.h>
 #include <time.h>
 #include <common.h>
+#include <gnutls/pkcs11.h>
 
 #define SU(x) (x!=NULL?x:"Unknown")
+#define MIN(x,y) ((x)<(y))?(x):(y)
 
 int print_cert;
 extern int verbose;
@@ -858,3 +860,35 @@ service_to_port (const char *service)
 
   return ntohs (server_port->s_port);
 }
+
+static int pin_callback(void* user, int attempt, const char *slot_descr,
+       const char *token_label, unsigned int flags, char* pin, size_t pin_max)
+{
+const char* password;
+int len;
+
+       printf("PIN required for token '%s' in slot '%s'\n", token_label, slot_descr);
+       if (flags & GNUTLS_PKCS11_PIN_FINAL_TRY)
+               printf("*** This is the final try before locking!\n");
+       if (flags & GNUTLS_PKCS11_PIN_COUNT_LOW)
+               printf("*** Only few tries left before locking!\n");
+       
+       password = getpass("Enter pin: ");
+       if (password==NULL || password[0] == 0) {
+               fprintf(stderr, "No password given\n");
+               exit(1);
+       }
+       
+       len = MIN(pin_max,strlen(password));
+       memcpy(pin, password, len);
+       pin[len] = 0;
+       
+       return 0;
+}
+
+void pkcs11_common(void)
+{
+
+       gnutls_pkcs11_set_pin_function (pin_callback, NULL);
+
+}
index 29a68a5e60f1c1848b367bf9ab7e2798ad9a73fc..fb04fedd7e2d13ad02fa69aeb5b4501695d38ebb 100644 (file)
@@ -40,5 +40,5 @@ void parse_protocols (char **protocols, int protocols_size,
                      int *protocol_priority);
 const char *raw_to_string (const unsigned char *raw, size_t raw_size);
 int service_to_port (const char *service);
-
+void pkcs11_common(void);
 void sockets_init (void);
index f7a9917aa4d0e666fd3469afb062f534407c05d6..b933799378009b389d433c0caab7c565012bf6b6 100644 (file)
@@ -15,6 +15,7 @@ static int pin_callback(void* user, int attempt, const char *slot_descr,
        const char *token_label, unsigned int flags, char* pin, size_t pin_max)
 {
 const char* password;
+int len;
 
        printf("PIN required for token '%s' in slot '%s'\n", token_label, slot_descr);
        if (flags & GNUTLS_PKCS11_PIN_FINAL_TRY)
@@ -27,8 +28,11 @@ const char* password;
                fprintf(stderr, "No password given\n");
                exit(1);
        }
-       memcpy(pin, password, MIN(pin_max,strlen(password)));
 
+       len = MIN(pin_max,strlen(password));
+       memcpy(pin, password, len);
+       pin[len] = 0;
+       
        return 0;
 }
 
index 0e95fcf9a4ad224e35904a922590a065ae173238..8b270df64a69506b4419a739c72b0d0d8f978a32 100644 (file)
@@ -916,6 +916,7 @@ main (int argc, char **argv)
       exit (1);
     }
 
+  pkcs11_common();
   gnutls_global_set_log_function (tls_log_func);
   gnutls_global_set_log_level (debug);