]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added the callbacks gnutls_certificate_client_retrieve_function() and
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 18 Dec 2003 10:32:36 +0000 (10:32 +0000)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Thu, 18 Dec 2003 10:32:36 +0000 (10:32 +0000)
gnutls_certificate_server_retrieve_function(), to allow a client or a server
to specify certificates for the handshake without storing them to the
credentials structure.

18 files changed:
NEWS
lib/auth_cert.c
lib/auth_cert.h
lib/auth_dhe.c
lib/auth_rsa.c
lib/auth_rsa_export.c
lib/gnutls_cert.c
lib/gnutls_cert.h
lib/gnutls_int.h
lib/gnutls_state.c
lib/gnutls_ui.h
lib/gnutls_x509.c
lib/gnutls_x509.h
libextra/auth_srp_rsa.c
libextra/gnutls_extra.c
libextra/gnutls_extra.h
libextra/gnutls_openpgp.c
libextra/openpgp/gnutls_openpgp.h

diff --git a/NEWS b/NEWS
index d23d93efe64f91d0fb44a7e513a7f088f1c4bf1a..512b3a4e7fd77921ca0e38624f584b6a60645500 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ Version 1.1.0
 - The error codes GNUTLS_E_NO_TEMPORARY_DH_PARAMS and GNUTLS_E_NO_TEMPORARY_RSA_PARAMS
   are no longer returned by the handshake function. Ciphersuites that
   require temporary parameters are removed when such parameters do not exist.
+- Added the callbacks gnutls_certificate_client_retrieve_function() and
+  gnutls_certificate_server_retrieve_function(), to allow a client or a server
+  to specify certificates for the handshake without storing them to the
+  credentials structure.
 
 Version 1.0.1 (10/12/2003)
 - Some minor fixes in the makefiles. They now include CFLAGS
index 9a99c3948b91473fcdf8a4f8d75aa93d0a20975d..08d5c99260abe7d5635871de49adc1addb42b4ee 100644 (file)
 #include <gnutls_extra.h>
 #include "debug.h"
 
+static gnutls_cert *alloc_and_load_certs(const gnutls_datum * certs,
+        uint ncerts, gnutls_certificate_type type);
+static gnutls_privkey *alloc_and_load_key(const gnutls_datum * raw_key,
+         gnutls_certificate_type type);
+
+
 /* Copies data from a internal certificate struct (gnutls_cert) to 
  * exported certificate struct (CERTIFICATE_AUTH_INFO)
  */
 static
-int _gnutls_copy_certificate_auth_info(CERTIFICATE_AUTH_INFO info, 
-       gnutls_cert * cert, int ncerts)
+int _gnutls_copy_certificate_auth_info(CERTIFICATE_AUTH_INFO info,
+                                      gnutls_cert * cert, int ncerts)
 {
        /* Copy peer's information to AUTH_INFO
         */
@@ -60,7 +66,7 @@ int _gnutls_copy_certificate_auth_info(CERTIFICATE_AUTH_INFO info,
                info->ncerts = 0;
                return 0;
        }
-       
+
        info->raw_certificate_list =
            gnutls_calloc(1, sizeof(gnutls_datum) * ncerts);
        if (info->raw_certificate_list == NULL) {
@@ -146,7 +152,9 @@ static int _find_x509_cert(const gnutls_certificate_credentials cred,
                for (i = 0; i < cred->ncerts; i++) {
                        for (j = 0; j < cred->cert_list_length[i]; j++) {
                                if ((result =
-                                    _gnutls_cert_get_dn( &cred->cert_list[i][j], &odn)) < 0) {
+                                    _gnutls_cert_get_dn(&cred->
+                                                        cert_list[i][j],
+                                                        &odn)) < 0) {
                                        gnutls_assert();
                                        return result;
                                }
@@ -158,10 +166,14 @@ static int _find_x509_cert(const gnutls_certificate_credentials cred,
                                 * the *_SIGN algorithm matches
                                 * the cert is our cert!
                                 */
-                               cert_pk = cred->cert_list[i][0].subject_pk_algorithm;
+                               cert_pk =
+                                   cred->cert_list[i][0].
+                                   subject_pk_algorithm;
 
                                if ((memcmp(odn.data, data, size) == 0) &&
-                                   (_gnutls_check_pk_algo_in_list(pk_algos, pk_algos_length, cert_pk) == 0)) {
+                                   (_gnutls_check_pk_algo_in_list
+                                    (pk_algos, pk_algos_length,
+                                     cert_pk) == 0)) {
                                        *indx = i;
                                        break;
                                }
@@ -215,9 +227,213 @@ static int _find_openpgp_cert(const gnutls_certificate_credentials cred,
        return 0;
 }
 
-/* Some upper limit to protect alloca();
+/* Returns the number of issuers in the server's
+ * certificate request packet.
+ */
+static int get_issuers_num( gnutls_session session, opaque * data, ssize_t data_size)
+{
+int issuers_dn_len, result;
+uint size;
+
+       /* Count the number of the given issuers;
+        * This is used to allocate the issuers_dn without
+        * using realloc().
+        */
+
+       if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
+               return 0;
+
+       do {
+               /* This works like DECR_LEN() 
+                */
+               result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+               DECR_LENGTH_COM(data_size, 2, goto error);
+               size = _gnutls_read_uint16(data);
+
+               result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+               DECR_LENGTH_COM(data_size, size, goto error);
+
+               data += 2;
+
+               if (size > 0) {
+                       issuers_dn_len++;
+                       data += size;
+               }
+
+               if (data_size == 0)
+                       break;
+
+       } while (1);
+
+       return issuers_dn_len;
+       
+       error:
+               return result;
+}
+
+/* Returns the issuers in the server's certificate request
+ * packet.
+ */
+static int get_issuers( gnutls_session session,
+       gnutls_datum* issuers_dn, int issuers_len, 
+       opaque * data, size_t data_size)
+{
+int i;
+uint size;
+
+       if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
+               return 0;
+
+       /* put the requested DNs to req_dn, only in case
+        * of X509 certificates.
+        */
+       if (issuers_len > 0) {
+
+               for (i = 0; i < issuers_len; i++) {
+                       /* The checks here for the buffer boundaries
+                        * are not needed since the buffer has been
+                        * parsed above.
+                        */
+                       data_size -= 2;
+
+                       size = _gnutls_read_uint16(data);
+
+                       data += 2;
+
+                       issuers_dn[i].data = data;
+                       issuers_dn[i].size = size;
+
+                       data += size;
+               }
+       }
+
+       return 0;
+}
+
+
+/* Calls the client_cert_callback() to select an index for the
+ * certificate to use.
+ */
+static int call_client_cert_callback(gnutls_session session,
+       const gnutls_certificate_credentials cred, gnutls_pk_algorithm * pk_algos,
+       int pk_algos_length, gnutls_datum * issuers_dn, uint issuers_dn_len)
+{
+       uint i, j;
+       int indx, result;
+       int *ij_map = NULL;
+       gnutls_datum *my_certs = NULL;
+
+       if (cred->ncerts != 0) {
+               my_certs =
+                   gnutls_alloca(cred->ncerts *
+                                 sizeof(gnutls_datum));
+               if (my_certs == NULL) {
+                       result = GNUTLS_E_MEMORY_ERROR;
+                       gnutls_assert();
+                       goto error;
+               }
+
+
+               /* maps j -> i 
+                */
+               ij_map = gnutls_alloca(sizeof(int) * cred->ncerts);
+               if (ij_map == NULL) {
+                       result = GNUTLS_E_MEMORY_ERROR;
+                       gnutls_assert();
+                       goto error;
+               }
+       }
+
+       /* put our certificate's issuer and dn into cdn, idn
+        * Note that the certificates we provide to the callback
+        * are not all the certificates we have. Only the certificates
+        * that are requested by the server (certificate type - and sign
+        * algorithm matches), are provided.
+        */
+       for (j = i = 0; i < cred->ncerts; i++) {
+               if ((cred->cert_list[i][0].cert_type ==
+                    gnutls_certificate_type_get(session)) &&
+                   (_gnutls_check_pk_algo_in_list(pk_algos,
+                                                  pk_algos_length,
+                                                  cred->
+                                                  cert_list[i][0].
+                                                  subject_pk_algorithm)
+                    == 0)) {
+                       /* Add a certificate ONLY if it is allowed
+                        * by the peer.
+                        */
+                       ij_map[j] = i;
+                       my_certs[j++] = cred->cert_list[i][0].raw;
+               }
+       }
+
+       indx =
+           session->internals.client_cert_callback(session,
+                                                   my_certs,
+                                                   j,
+                                                   issuers_dn,
+                                                   issuers_dn_len);
+
+       /* the indx returned by the user is relative
+        * to the certificates we provided him.
+        * This will make it relative to the certificates
+        * we've got.
+        */
+       if (indx != -1 && cred->ncerts != 0)
+               indx = ij_map[indx];
+       else
+               indx = -1;
+
+       
+       result = indx;
+
+      error:
+       if (my_certs != NULL) {
+               gnutls_afree(my_certs);
+       }
+       if (ij_map != NULL) {
+               gnutls_afree(ij_map);
+       }
+       return result;
+
+}
+
+/* Calls the client get callback.
  */
-#define MAX_ISSUERS 512
+static int call_client_get_cert_callback( gnutls_session session,
+       gnutls_datum* issuers_dn, int issuers_dn_length)
+{
+gnutls_datum *certs, key;
+uint ncerts, i;
+gnutls_certificate_type type =
+    gnutls_certificate_type_get(session);
+gnutls_cert *local_certs = NULL;
+gnutls_privkey *local_key = NULL;
+int ret;
+
+       ret =
+           session->internals.client_get_cert_callback(session,
+                       issuers_dn, issuers_dn_length,
+                       &certs, &ncerts, &key);
+       if (ret < 0) {
+               gnutls_assert();
+               return GNUTLS_E_INTERNAL_ERROR;
+       }
+
+       local_certs = alloc_and_load_certs(certs, ncerts, type);
+       if (local_certs != NULL)
+               local_key = alloc_and_load_key(&key, type);
+
+       for (i = 0; i < ncerts; i++) {
+               _gnutls_free_datum(&certs[i]);
+       }
+       _gnutls_free_datum(&key);
+
+       _gnutls_selected_certs_set(session, local_certs, ncerts,
+                                  local_key, 1);
+
+       return 0;
+}
 
 /* Finds the appropriate certificate depending on the cA Distinguished name
  * advertized by the server. If none matches then returns 0 and -1 as index.
@@ -227,18 +443,17 @@ static int _find_openpgp_cert(const gnutls_certificate_credentials cred,
  * algorithm (only in automatic mode).
  */
 static int _select_client_cert(gnutls_session session,
-              opaque * _data, size_t _data_size, int *ind,
-              gnutls_pk_algorithm *pk_algos, int pk_algos_length)
+                              opaque * _data, size_t _data_size,
+                              gnutls_pk_algorithm * pk_algos,
+                              int pk_algos_length)
 {
-       int result, size;
+       int result;
        int indx = -1;
-       uint i, j;
-       int *ij_map = NULL;
        const gnutls_certificate_credentials cred;
        opaque *data = _data;
        ssize_t data_size = _data_size;
-       gnutls_datum *my_certs = NULL;
-       gnutls_datum *issuers_dn = NULL;
+       int issuers_dn_length;
+       gnutls_datum * issuers_dn = NULL;
 
        cred =
            _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
@@ -247,9 +462,44 @@ static int _select_client_cert(gnutls_session session,
                return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }
 
-       /* If we have no callback.
-        */
-       if (session->internals.client_cert_callback == NULL) {
+       if (session->internals.client_get_cert_callback != NULL ||
+               session->internals.client_cert_callback != NULL) {
+
+               /* use a callback to get certificate 
+                */
+               issuers_dn_length = get_issuers_num( session, data, data_size);
+               if (issuers_dn_length < 0) {
+                       gnutls_assert();
+                       return issuers_dn_length;
+               }
+               
+               if (issuers_dn_length > 0) {
+                       issuers_dn = gnutls_malloc( sizeof(gnutls_datum)*issuers_dn_length);
+                       if (issuers_dn == NULL) {
+                               gnutls_assert();
+                               return GNUTLS_E_MEMORY_ERROR;
+                       }
+               
+                       result = get_issuers( session, issuers_dn, issuers_dn_length, data, data_size);
+                       if (result < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
+               }
+
+               if (session->internals.client_get_cert_callback) {
+                       result = call_client_get_cert_callback( session, issuers_dn, issuers_dn_length);
+                       goto cleanup;
+               }
+
+               /* in case of the callback that returns an index:
+                */
+               indx = call_client_cert_callback(session, cred, pk_algos, 
+                       pk_algos_length, issuers_dn, issuers_dn_length);
+
+       } else {
+               /* If we have no callbacks, try to guess.
+                */
                result = 0;
 
                if (session->security_parameters.cert_type ==
@@ -270,162 +520,22 @@ static int _select_client_cert(gnutls_session session,
                        gnutls_assert();
                        return result;
                }
-       } else /* If the callback is set, then use it. */
-       if (session->internals.client_cert_callback != NULL) {
-               /* use a callback to get certificate 
-                */
-               uint issuers_dn_len = 0;
-               opaque *dataptr = data;
-               ssize_t dataptr_size = data_size;
-
-               /* Count the number of the given issuers;
-                * This is used to allocate the issuers_dn without
-                * using realloc().
-                */
-
-               if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
-
-                       /* Makes the issuers_dn stuff.
-                        */
-                       do {
-                               /* This works like DECR_LEN() 
-                                */
-                               result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
-                               DECR_LENGTH_COM(dataptr_size, 2, goto error);
-                               size = _gnutls_read_uint16(dataptr);
-
-                               result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
-                               DECR_LENGTH_COM(dataptr_size, size, goto error);
-
-                               dataptr += 2;
-               
-                               if (size > 0) {
-                                       issuers_dn_len++;
-                                       dataptr += size;
-                               }
-
-                               if (dataptr_size == 0)
-                                       break;
-
-                       } while (issuers_dn_len < MAX_ISSUERS);
-
-                       if (cred->ncerts != 0) {
-                               my_certs =
-                                   gnutls_alloca(cred->ncerts * sizeof(gnutls_datum));
-                               if (my_certs == NULL) {
-                                       result = GNUTLS_E_MEMORY_ERROR;
-                                       gnutls_assert();
-                                       goto error;
-                               }
-                       }
-
-                       /* put the requested DNs to req_dn, only in case
-                        * of X509 certificates.
-                        */
-                       if (issuers_dn_len > 0) {
-                               data = _data;
-                               data_size = _data_size;
-
-                               issuers_dn =
-                                   gnutls_alloca(issuers_dn_len *
-                                                 sizeof(gnutls_datum));
-                               if (issuers_dn == NULL) {
-                                       result = GNUTLS_E_MEMORY_ERROR;
-                                       gnutls_assert();
-                                       goto error;
-                               }
-
-                               for (i = 0; i < issuers_dn_len; i++) {
-                                       /* The checks here for the buffer boundaries
-                                        * are not needed since the buffer has been
-                                        * parsed above.
-                                        */
-                                       data_size -= 2;
-
-                                       size = _gnutls_read_uint16(data);
-
-                                       data += 2;
-
-                                       issuers_dn[i].data = data;
-                                       issuers_dn[i].size = size;
-       
-                                       data += size;
-
-                               }
-                       }
-
-               } else { /* Other certificate types */
-                       issuers_dn_len = 0;
-                       issuers_dn = NULL;
-               }
-
-               /* If not certificates are present.
-                */
-               /* maps j -> i 
-                */
-
-               if (cred->ncerts != 0) {
-                       ij_map = gnutls_alloca(sizeof(int) * cred->ncerts);
-                       if (ij_map == NULL) {
-                               result = GNUTLS_E_MEMORY_ERROR;
-                               gnutls_assert();
-                               goto error;
-                       }
-               }
-
-               /* put our certificate's issuer and dn into cdn, idn
-                * Note that the certificates we provide to the callback
-                * are not all the certificates we have. Only the certificates
-                * that are requested by the server (certificate type - and sign
-                * algorithm matches), are provided.
-                */
-               for (j = i = 0; i < cred->ncerts; i++) {
-                       if ((cred->cert_list[i][0].cert_type ==
-                            gnutls_certificate_type_get(session)) &&
-                           (_gnutls_check_pk_algo_in_list(pk_algos,
-                                                          pk_algos_length,
-                                                          cred->
-                                                          cert_list[i][0].
-                                                          subject_pk_algorithm)
-                            == 0)) {
-                               /* Add a certificate ONLY if it is allowed
-                                * by the peer.
-                                */
-                               ij_map[j] = i;
-                               my_certs[j++] = cred->cert_list[i][0].raw;
-                       }
-               }
-
-               indx =
-                   session->internals.client_cert_callback(session,
-                                                           my_certs,
-                                                           j,
-                                                           issuers_dn,
-                                                           issuers_dn_len);
-
-               /* the indx returned by the user is relative
-                * to the certificates we provided him.
-                * This will make it relative to the certificates
-                * we've got.
-                */
-               if (indx != -1 && cred->ncerts != 0)
-                       indx = ij_map[indx];
-               else
-                       indx = -1;
+       }
 
-               if (my_certs) { gnutls_afree(my_certs); }
-               if (ij_map) { gnutls_afree(ij_map); }
-               if (issuers_dn) { gnutls_afree(issuers_dn); }
+       if (indx >= 0) {
+               _gnutls_selected_certs_set(session,
+                                          &cred->cert_list[indx][0],
+                                          cred->cert_list_length[indx],
+                                          &cred->pkey[indx], 0);
+       } else {
+               _gnutls_selected_certs_set(session, NULL, 0, NULL, 0);
        }
 
-       *ind = indx;
-       return 0;
+       result = 0;
 
-       error:
-               if (my_certs != NULL) { gnutls_afree(my_certs); }
-               if (ij_map != NULL) { gnutls_afree(ij_map); }
-               if (issuers_dn != NULL) { gnutls_afree(issuers_dn); }
-               return result;
+cleanup:
+       gnutls_free( issuers_dn);
+       return result;
 
 }
 
@@ -444,8 +554,8 @@ int _gnutls_gen_x509_crt(gnutls_session session, opaque ** data)
         */
        if ((ret =
             _gnutls_get_selected_cert(session, &apr_cert_list,
-                                  &apr_cert_list_length,
-                                  &apr_pkey)) < 0) {
+                                      &apr_cert_list_length,
+                                      &apr_pkey)) < 0) {
                gnutls_assert();
                return ret;
        }
@@ -490,14 +600,14 @@ int _gnutls_gen_openpgp_certificate(gnutls_session session, opaque ** data)
        int ret;
        opaque *pdata;
        gnutls_cert *apr_cert_list;
-       gnutls_privkeyapr_pkey;
+       gnutls_privkey *apr_pkey;
        int apr_cert_list_length;
 
        /* find the appropriate certificate */
        if ((ret =
             _gnutls_get_selected_cert(session, &apr_cert_list,
-                                  &apr_cert_list_length,
-                                  &apr_pkey)) < 0) {
+                                      &apr_cert_list_length,
+                                      &apr_pkey)) < 0) {
                gnutls_assert();
                return ret;
        }
@@ -541,14 +651,14 @@ int _gnutls_gen_openpgp_certificate_fpr(gnutls_session session,
        size_t fpr_size;
        opaque *pdata;
        gnutls_cert *apr_cert_list;
-       gnutls_privkeyapr_pkey;
+       gnutls_privkey *apr_pkey;
        int apr_cert_list_length;
 
        /* find the appropriate certificate */
        if ((ret =
             _gnutls_get_selected_cert(session, &apr_cert_list,
-                                  &apr_cert_list_length,
-                                  &apr_pkey)) < 0) {
+                                      &apr_cert_list_length,
+                                      &apr_pkey)) < 0) {
                gnutls_assert();
                return ret;
        }
@@ -637,7 +747,7 @@ int _gnutls_gen_cert_server_certificate(gnutls_session session,
 /* Process server certificate
  */
 
-#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_free_cert(&peer_certificate_list[x])
+#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_cert_deinit(&peer_certificate_list[x])
 int _gnutls_proc_x509_server_certificate(gnutls_session session,
                                         opaque * data, size_t data_size)
 {
@@ -733,7 +843,8 @@ int _gnutls_proc_x509_server_certificate(gnutls_session session,
                if ((ret =
                     _gnutls_x509_cert2gnutls_cert(&peer_certificate_list
                                                   [j], &tmp,
-                                                  CERT_ONLY_EXTENSIONS)) < 0) {
+                                                  CERT_ONLY_EXTENSIONS)) <
+                   0) {
                        gnutls_assert();
                        goto cleanup;
                }
@@ -743,30 +854,31 @@ int _gnutls_proc_x509_server_certificate(gnutls_session session,
 
 
        if ((ret =
-            _gnutls_copy_certificate_auth_info(info, 
+            _gnutls_copy_certificate_auth_info(info,
                                                peer_certificate_list,
-                                               peer_certificate_list_size)) < 0) {
+                                               peer_certificate_list_size))
+           < 0) {
                gnutls_assert();
                goto cleanup;
        }
 
        if ((ret =
             _gnutls_check_key_usage(&peer_certificate_list[0],
-                                         gnutls_kx_get(session))) < 0) {
+                                    gnutls_kx_get(session))) < 0) {
                gnutls_assert();
                goto cleanup;
        }
 
        ret = 0;
 
-cleanup:
+      cleanup:
        CLEAR_CERTS;
        gnutls_free(peer_certificate_list);
        return ret;
 
 }
 
-#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_free_cert(&peer_certificate_list[x])
+#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_cert_deinit(&peer_certificate_list[x])
 int _gnutls_proc_openpgp_server_certificate(gnutls_session session,
                                            opaque * data,
                                            size_t data_size)
@@ -906,28 +1018,29 @@ int _gnutls_proc_openpgp_server_certificate(gnutls_session session,
 
        if ((ret =
             _gnutls_copy_certificate_auth_info(info,
-                                               peer_certificate_list, 
-                                               peer_certificate_list_size)) < 0) {
+                                               peer_certificate_list,
+                                               peer_certificate_list_size))
+           < 0) {
                gnutls_assert();
                goto cleanup;
        }
 
        if ((ret =
             _gnutls_check_key_usage(&peer_certificate_list[0],
-                                         gnutls_kx_get(session))) < 0) {
+                                    gnutls_kx_get(session))) < 0) {
                gnutls_assert();
                goto cleanup;
        }
 
        ret = 0;
-       
-cleanup:
+
+      cleanup:
 
        _gnutls_free_datum(&akey);
        CLEAR_CERTS;
        gnutls_afree(peer_certificate_list);
        return ret;
-       
+
 }
 
 int _gnutls_proc_cert_server_certificate(gnutls_session session,
@@ -976,7 +1089,7 @@ int _gnutls_proc_cert_cert_req(gnutls_session session, opaque * data,
        const gnutls_certificate_credentials cred;
        CERTIFICATE_AUTH_INFO info;
        ssize_t dsize = data_size;
-       int i, j, ind;
+       int i, j;
        gnutls_pk_algorithm pk_algos[MAX_SIGN_ALGOS];
        int pk_algos_length;
 
@@ -1034,22 +1147,10 @@ int _gnutls_proc_cert_cert_req(gnutls_session session, opaque * data,
         */
        if ((ret =
             _select_client_cert(session, p, size,
-                                &ind, pk_algos,
-                                pk_algos_length)) < 0) {
+                                pk_algos, pk_algos_length)) < 0) {
                gnutls_assert();
                return ret;
        }
-       /* put the index of the client certificate to use
-        */
-       if (ind >= 0) {
-               session->internals.selected_cert_list_length = cred->cert_list_length[ind];
-               session->internals.selected_cert_list = &cred->cert_list[ind][0];
-               session->internals.selected_key = &cred->pkey[ind];
-       } else {
-               session->internals.selected_cert_list_length = 0;
-               session->internals.selected_cert_list = NULL;
-               session->internals.selected_key = NULL;
-       }
 
        /* We should reply with a certificate message, 
         * even if we have no certificate to send.
@@ -1064,7 +1165,7 @@ int _gnutls_gen_cert_client_cert_vrfy(gnutls_session session,
 {
        int ret;
        gnutls_cert *apr_cert_list;
-       gnutls_privkeyapr_pkey;
+       gnutls_privkey *apr_pkey;
        int apr_cert_list_length, size;
        gnutls_datum signature;
 
@@ -1073,8 +1174,8 @@ int _gnutls_gen_cert_client_cert_vrfy(gnutls_session session,
        /* find the appropriate certificate */
        if ((ret =
             _gnutls_get_selected_cert(session, &apr_cert_list,
-                                  &apr_cert_list_length,
-                                  &apr_pkey)) < 0) {
+                                      &apr_cert_list_length,
+                                      &apr_pkey)) < 0) {
                gnutls_assert();
                return ret;
        }
@@ -1082,9 +1183,8 @@ int _gnutls_gen_cert_client_cert_vrfy(gnutls_session session,
        if (apr_pkey != NULL) {
                if ((ret =
                     _gnutls_tls_sign_hdata(session,
-                                                    &apr_cert_list[0],
-                                                    apr_pkey,
-                                                    &signature)) < 0) {
+                                           &apr_cert_list[0],
+                                           apr_pkey, &signature)) < 0) {
                        gnutls_assert();
                        return ret;
                }
@@ -1165,10 +1265,10 @@ int _gnutls_proc_cert_client_cert_vrfy(gnutls_session session,
        if ((ret =
             _gnutls_verify_sig_hdata(session, &peer_cert, &sig)) < 0) {
                gnutls_assert();
-               _gnutls_free_cert(&peer_cert);
+               _gnutls_cert_deinit(&peer_cert);
                return ret;
        }
-       _gnutls_free_cert(&peer_cert);
+       _gnutls_cert_deinit(&peer_cert);
 
        return 0;
 }
@@ -1197,7 +1297,7 @@ int _gnutls_gen_cert_server_cert_req(gnutls_session session,
                                         */
 
        if (session->security_parameters.cert_type == GNUTLS_CRT_X509 &&
-               session->internals.ignore_rdn_sequence == 0)
+           session->internals.ignore_rdn_sequence == 0)
                size += cred->x509_rdn_sequence.size;
 
        (*data) = gnutls_malloc(size);
@@ -1215,7 +1315,7 @@ int _gnutls_gen_cert_server_cert_req(gnutls_session session,
        pdata += CERTTYPE_SIZE;
 
        if (session->security_parameters.cert_type == GNUTLS_CRT_X509 &&
-               session->internals.ignore_rdn_sequence == 0) {
+           session->internals.ignore_rdn_sequence == 0) {
                _gnutls_write_datum16(pdata, cred->x509_rdn_sequence);
                /* pdata += cred->x509_rdn_sequence.size + 2; */
        }
@@ -1232,9 +1332,9 @@ int _gnutls_gen_cert_server_cert_req(gnutls_session session,
  *
  */
 int _gnutls_get_selected_cert(gnutls_session session,
-                         gnutls_cert ** apr_cert_list,
-                         int *apr_cert_list_length,
-                         gnutls_privkey ** apr_pkey)
+                             gnutls_cert ** apr_cert_list,
+                             int *apr_cert_list_length,
+                             gnutls_privkey ** apr_pkey)
 {
        if (session->security_parameters.entity == GNUTLS_SERVER) {
 
@@ -1243,23 +1343,24 @@ int _gnutls_get_selected_cert(gnutls_session session,
 
                *apr_cert_list = session->internals.selected_cert_list;
                *apr_pkey = session->internals.selected_key;
-               *apr_cert_list_length = session->internals.selected_cert_list_length;
+               *apr_cert_list_length =
+                   session->internals.selected_cert_list_length;
 
-               if ( apr_cert_list_length == 0 || apr_pkey == NULL ||
-                       apr_cert_list == NULL) 
-               {
+               if (apr_cert_list_length == 0 || apr_pkey == NULL ||
+                   apr_cert_list == NULL) {
                        gnutls_assert();
                        return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
                }
 
-       } else { /* CLIENT SIDE 
-                 */
+       } else {                /* CLIENT SIDE 
+                                */
 
                /* we have already decided which certificate
                 * to send.
                 */
                *apr_cert_list = session->internals.selected_cert_list;
-               *apr_cert_list_length = session->internals.selected_cert_list_length;
+               *apr_cert_list_length =
+                   session->internals.selected_cert_list_length;
                *apr_pkey = session->internals.selected_key;
 
        }
@@ -1267,6 +1368,102 @@ int _gnutls_get_selected_cert(gnutls_session session,
        return 0;
 }
 
+/* converts the given raw certificate to gnutls_cert* and allocates
+ * space for them.
+ */
+static gnutls_cert *alloc_and_load_certs(const gnutls_datum * certs,
+                                        uint ncerts,
+                                        gnutls_certificate_type type)
+{
+       gnutls_cert *local_certs;
+       int ret = 0;
+       uint i, j;
+
+       local_certs = gnutls_malloc(sizeof(gnutls_cert) * ncerts);
+       if (local_certs == NULL) {
+               gnutls_assert();
+               return NULL;
+       }
+
+       for (i = 0; i < ncerts; i++) {
+               ret = _gnutls_cert2gnutls_cert(&local_certs[i], type,
+                                              &certs[i], 0);
+               if (ret < 0)
+                       break;
+       }
+
+       if (ret < 0) {
+               gnutls_assert();
+               for (j = 0; j < i; j++) {
+                       _gnutls_cert_deinit(&local_certs[j]);
+               }
+               gnutls_free(local_certs);
+               return NULL;
+       }
+
+       return local_certs;
+}
+
+/* converts the given raw key to gnutls_privkey* and allocates
+ * space for it.
+ */
+static gnutls_privkey *alloc_and_load_key(const gnutls_datum * raw_key,
+                                         gnutls_certificate_type type)
+{
+       gnutls_privkey *local_key;
+       int ret = 0;
+
+       local_key = gnutls_malloc(sizeof(gnutls_privkey));
+       if (local_key == NULL) {
+               gnutls_assert();
+               return NULL;
+       }
+
+       ret =
+           _gnutls_key2gnutls_key(local_key, type, raw_key,
+                                  GNUTLS_X509_FMT_DER);
+       if (ret < 0) {
+               gnutls_assert();
+               return NULL;
+       }
+
+       return local_key;
+}
+
+void _gnutls_selected_certs_deinit(gnutls_session session)
+{
+       if (session->internals.selected_need_free != 0) {
+               int i;
+
+               for (i = 0;
+                    i < session->internals.selected_cert_list_length;
+                    i++) {
+                       _gnutls_cert_deinit(&session->internals.
+                                           selected_cert_list[i]);
+               }
+               session->internals.selected_cert_list = NULL;
+               session->internals.selected_cert_list_length = 0;
+
+               _gnutls_privkey_deinit(session->internals.selected_key);
+       }
+
+       return;
+}
+
+void _gnutls_selected_certs_set(gnutls_session session,
+                               gnutls_cert * certs, int ncerts,
+                               gnutls_privkey * key, int need_free)
+{
+       _gnutls_selected_certs_deinit(session);
+
+       session->internals.selected_cert_list = certs;
+       session->internals.selected_cert_list_length = ncerts;
+       session->internals.selected_key = key;
+       session->internals.selected_need_free = need_free;
+
+}
+
+
 /* finds the most appropriate certificate in the cert list.
  * The 'appropriate' is defined by the user.
  *
@@ -1278,7 +1475,7 @@ int _gnutls_get_selected_cert(gnutls_session session,
  *
  */
 int _gnutls_server_select_cert(gnutls_session session,
-                      gnutls_pk_algorithm requested_algo)
+                              gnutls_pk_algorithm requested_algo)
 {
        uint i, j;
        int index, ret;
@@ -1311,7 +1508,43 @@ int _gnutls_server_select_cert(gnutls_session session,
 
        }
 
-       if (session->internals.server_cert_callback != NULL && cred->ncerts > 0) {      
+       /* If the callback which retrieves certificate has been
+        * set use it.
+        */
+       if (session->internals.server_get_cert_callback != NULL) {
+               gnutls_datum *certs, key;
+               uint ncerts;
+               gnutls_certificate_type type =
+                   gnutls_certificate_type_get(session);
+               gnutls_cert *local_certs = NULL;
+               gnutls_privkey *local_key = NULL;
+
+               ret =
+                   session->internals.server_get_cert_callback(session,
+                                                               &certs,
+                                                               &ncerts,
+                                                               &key);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return GNUTLS_E_INTERNAL_ERROR;
+               }
+
+               local_certs = alloc_and_load_certs(certs, ncerts, type);
+               if (local_certs != NULL)
+                       local_key = alloc_and_load_key(&key, type);
+
+               for (i = 0; i < ncerts; i++) {
+                       _gnutls_free_datum(&certs[i]);
+               }
+               _gnutls_free_datum(&key);
+
+               _gnutls_selected_certs_set(session, local_certs, ncerts,
+                                          local_key, 1);
+
+               return 0;
+
+       } else if (session->internals.server_cert_callback != NULL
+                  && cred->ncerts > 0) {
                /* use the callback to get certificate 
                 */
                gnutls_datum *my_certs;
@@ -1363,19 +1596,20 @@ int _gnutls_server_select_cert(gnutls_session session,
                ret = 0;
 
                gnutls_free(ij_map);
-               cleanup_certs:
+             cleanup_certs:
                gnutls_free(my_certs);
 
        }
 
-       out:
+      out:
        /* store the index for future use, in the handshake.
         * (This will allow not calling this callback again.)
         */
        if (index >= 0 && ret == 0) {
-               session->internals.selected_cert_list = &cred->cert_list[index][0];
-               session->internals.selected_cert_list_length = cred->cert_list_length[index];
-               session->internals.selected_key = &cred->pkey[index];
+               _gnutls_selected_certs_set(session,
+                                          &cred->cert_list[index][0],
+                                          cred->cert_list_length[index],
+                                          &cred->pkey[index], 0);
        }
 
        return ret;
index 8f58018cb90809497e3f7608e01d8d214aef5cd6..94085ca53d6ebf3fa62cfc46d7af79b7c2846d4c 100644 (file)
@@ -92,6 +92,10 @@ int _gnutls_proc_cert_server_certificate(gnutls_session, opaque *, size_t);
 int _gnutls_get_selected_cert( gnutls_session session, gnutls_cert** apr_cert_list, int *apr_cert_list_length, gnutls_privkey** apr_pkey);
 
 int _gnutls_server_select_cert( struct gnutls_session_int*, gnutls_pk_algorithm);
+void _gnutls_selected_certs_deinit( gnutls_session session);
+void _gnutls_selected_certs_set( gnutls_session session,
+        gnutls_cert* certs, int ncerts, gnutls_privkey* key,
+        int need_free);
 
 #define _gnutls_proc_cert_client_certificate _gnutls_proc_cert_server_certificate
 
index bf636df2d2cd83f43ab4a212b7dd7dadb3a3feca..885a8a9acab62db16b79b21cde6913dec9459085 100644 (file)
@@ -171,9 +171,6 @@ static int gen_dhe_server_kx(gnutls_session session, opaque ** data)
        return data_size;
 }
 
-
-OPENPGP_CERT2GNUTLS_CERT _E_gnutls_openpgp_cert2gnutls_cert = NULL;
-
 static int proc_dhe_server_kx(gnutls_session session, opaque * data,
                                  size_t _data_size)
 {
@@ -208,32 +205,11 @@ static int proc_dhe_server_kx(gnutls_session session, opaque * data,
        signature.data = &data[vparams.size + 2];
        signature.size = sigsize;
 
-       switch( session->security_parameters.cert_type) {
-               case GNUTLS_CRT_X509:
-                       if ((ret =
-                            _gnutls_x509_cert2gnutls_cert( &peer_cert,
-                                            &info->raw_certificate_list[0], CERT_NO_COPY)) < 0) {
-                               gnutls_assert();
-                               return ret;
-                       }
-                       break;
-
-               case GNUTLS_CRT_OPENPGP:
-                       if (_E_gnutls_openpgp_cert2gnutls_cert==NULL) {
-                               gnutls_assert();
-                               return GNUTLS_E_INIT_LIBEXTRA;
-                       }
-                       if ((ret =
-                            _E_gnutls_openpgp_cert2gnutls_cert( &peer_cert,
-                                            &info->raw_certificate_list[0])) < 0) {
-                               gnutls_assert();
-                               return ret;
-                       }
-                       break;
-
-               default:
-                       gnutls_assert();
-                       return GNUTLS_E_INTERNAL_ERROR;
+       if ((ret =
+            _gnutls_cert2gnutls_cert( &peer_cert, session->security_parameters.cert_type,
+                                    &info->raw_certificate_list[0], CERT_NO_COPY)) < 0) {
+               gnutls_assert();
+               return ret;
        }
 
        ret =
@@ -241,7 +217,7 @@ static int proc_dhe_server_kx(gnutls_session session, opaque * data,
                                      &peer_cert,
                                      &vparams, &signature);
        
-       _gnutls_free_cert( &peer_cert);
+       _gnutls_cert_deinit( &peer_cert);
        if (ret < 0) {
                gnutls_assert();
                return ret;
index 8dd219716e5d97b807ab8e604ad467b7dc3839dd..8be77e7e9e85df4d03fb8665bdd0fda878491234 100644 (file)
@@ -60,9 +60,6 @@ const MOD_AUTH_STRUCT rsa_auth_struct = {
        _gnutls_proc_cert_cert_req      /* proc server cert request */
 };
 
-/* in auth_dhe.c */
-extern OPENPGP_CERT2GNUTLS_CERT _E_gnutls_openpgp_cert2gnutls_cert;
-
 /* This function reads the RSA parameters from peer's certificate;
  */
 int _gnutls_get_public_rsa_params(gnutls_session session, 
@@ -82,32 +79,13 @@ int i;
                return GNUTLS_E_INTERNAL_ERROR;
        }
        
-       switch( session->security_parameters.cert_type) {
-               case GNUTLS_CRT_X509:
-                       if ((ret =
-                            _gnutls_x509_cert2gnutls_cert( &peer_cert,
-                                            &info->raw_certificate_list[0], CERT_ONLY_PUBKEY|CERT_NO_COPY)) < 0) {
-                               gnutls_assert();
-                               return ret;
-                       }
-                       break;
-
-               case GNUTLS_CRT_OPENPGP:
-                       if (_E_gnutls_openpgp_cert2gnutls_cert==NULL) {
-                               gnutls_assert();
-                               return GNUTLS_E_INIT_LIBEXTRA;
-                       }
-                       if ((ret =
-                            _E_gnutls_openpgp_cert2gnutls_cert( &peer_cert,
-                                            &info->raw_certificate_list[0])) < 0) {
-                               gnutls_assert();
-                               return ret;
-                       }
-                       break;
-
-               default:
+       ret =
+            _gnutls_cert2gnutls_cert( &peer_cert, session->security_parameters.cert_type,
+                       &info->raw_certificate_list[0], CERT_ONLY_PUBKEY|CERT_NO_COPY); 
+       
+       if (ret < 0) {
                        gnutls_assert();
-                       return GNUTLS_E_INTERNAL_ERROR;
+                       return ret;
        }
 
 
@@ -116,7 +94,7 @@ int i;
                 == GNUTLS_KX_RSA_EXPORT && 
                        _gnutls_mpi_get_nbits(peer_cert.params[0]) > 512) {
 
-               _gnutls_free_cert( &peer_cert);
+               _gnutls_cert_deinit( &peer_cert);
 
                if (session->key->rsa[0] == NULL ||
                        session->key->rsa[1] == NULL) {
@@ -147,7 +125,7 @@ int i;
        for (i=0;i<*params_len;i++) {
                params[i] = _gnutls_mpi_copy(peer_cert.params[i]);
        }
-       _gnutls_free_cert( &peer_cert);
+       _gnutls_cert_deinit( &peer_cert);
 
        return 0;
 }
index 9d61d63e6b2f2c08ae3e8c0dd063fa2b5c54751c..902e970061b5be9af27ad601d44ff2118931d9c1 100644 (file)
@@ -64,9 +64,6 @@ const MOD_AUTH_STRUCT rsa_export_auth_struct = {
        _gnutls_proc_cert_cert_req      /* proc server cert request */
 };
 
-extern OPENPGP_CERT2GNUTLS_CERT _E_gnutls_openpgp_cert2gnutls_cert;
-
-
 static int gen_rsa_export_server_kx(gnutls_session session, opaque ** data)
 {
        const GNUTLS_MPI *rsa_params;
@@ -191,47 +188,26 @@ CERTIFICATE_AUTH_INFO info = _gnutls_get_auth_info( session);
                return 0;
        }
 
-       switch( session->security_parameters.cert_type) {
-               case GNUTLS_CRT_X509:
-                       if ((ret =
-                            _gnutls_x509_cert2gnutls_cert( &peer_cert,
-                                            &info->raw_certificate_list[0], CERT_NO_COPY)) < 0) {
-                               gnutls_assert();
-                               return 0;
-                       }
-                       break;
-
-               case GNUTLS_CRT_OPENPGP:
-                       if (_E_gnutls_openpgp_cert2gnutls_cert==NULL) {
-                               gnutls_assert();
-                               return GNUTLS_E_INIT_LIBEXTRA;
-                       }
-                       if ((ret =
-                            _E_gnutls_openpgp_cert2gnutls_cert( &peer_cert,
-                                            &info->raw_certificate_list[0])) < 0) {
-                               gnutls_assert();
-                               return 0;
-                       }
-                       break;
-
-               default:
-                       gnutls_assert();
-                       return 0;
+       if ((ret =
+            _gnutls_cert2gnutls_cert( &peer_cert, session->security_parameters.cert_type,
+                            &info->raw_certificate_list[0], CERT_NO_COPY)) < 0) {
+               gnutls_assert();
+               return 0;
        }
 
        if (peer_cert.subject_pk_algorithm != GNUTLS_PK_RSA) {
                gnutls_assert();
-               _gnutls_free_cert( &peer_cert);
+               _gnutls_cert_deinit( &peer_cert);
                return 0;
        }
 
        if ( _gnutls_mpi_get_nbits( peer_cert.params[0]) 
                <= 512) {
-               _gnutls_free_cert( &peer_cert);
+               _gnutls_cert_deinit( &peer_cert);
                return 1;
        }
        
-       _gnutls_free_cert( &peer_cert);
+       _gnutls_cert_deinit( &peer_cert);
        
        return 0;
 }
@@ -308,32 +284,11 @@ static int proc_rsa_export_server_kx(gnutls_session session, opaque * data,
        signature.data = &data[vparams.size + 2];
        signature.size = sigsize;
 
-       switch( session->security_parameters.cert_type) {
-               case GNUTLS_CRT_X509:
-                       if ((ret =
-                            _gnutls_x509_cert2gnutls_cert( &peer_cert,
-                                            &info->raw_certificate_list[0], CERT_NO_COPY)) < 0) {
-                               gnutls_assert();
-                               return ret;
-                       }
-                       break;
-
-               case GNUTLS_CRT_OPENPGP:
-                       if (_E_gnutls_openpgp_cert2gnutls_cert==NULL) {
-                               gnutls_assert();
-                               return GNUTLS_E_INIT_LIBEXTRA;
-                       }
-                       if ((ret =
-                            _E_gnutls_openpgp_cert2gnutls_cert( &peer_cert,
-                                            &info->raw_certificate_list[0])) < 0) {
-                               gnutls_assert();
-                               return ret;
-                       }
-                       break;
-
-               default:
-                       gnutls_assert();
-                       return GNUTLS_E_INTERNAL_ERROR;
+       if ((ret =
+            _gnutls_cert2gnutls_cert( &peer_cert, session->security_parameters.cert_type,
+                            &info->raw_certificate_list[0], CERT_NO_COPY)) < 0) {
+               gnutls_assert();
+               return ret;
        }
 
        ret =
@@ -341,7 +296,7 @@ static int proc_rsa_export_server_kx(gnutls_session session, opaque * data,
                                      &peer_cert,
                                      &vparams, &signature);
        
-       _gnutls_free_cert( &peer_cert);
+       _gnutls_cert_deinit( &peer_cert);
        if (ret < 0) {
                gnutls_assert();
        }
index e9ff2a8df68aac60185b35cb92e518963055805d..26d2ad3ae61fbf7d5fdc25dd12ec07c49ed4ae5a 100644 (file)
@@ -59,7 +59,7 @@ void gnutls_certificate_free_keys(gnutls_certificate_credentials sc)
 
        for (i = 0; i < sc->ncerts; i++) {
                for (j = 0; j < sc->cert_list_length[i]; j++) {
-                       _gnutls_free_cert( &sc->cert_list[i][j]);
+                       _gnutls_cert_deinit( &sc->cert_list[i][j]);
                }
                gnutls_free( sc->cert_list[i]);
        }
@@ -255,7 +255,7 @@ void gnutls_certificate_server_set_request(gnutls_session session,
   * the raw certificates (DER for X.509 or binary for OpenPGP), of the
   * client.
   *
-  * @req_ca_cert, is only used in X.509 certificates. 
+  * @req_ca_dn, 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
@@ -317,6 +317,75 @@ void gnutls_certificate_server_set_select_function(gnutls_session session,
        session->internals.server_cert_callback = func;
 }
 
+/**
+  * gnutls_certificate_client_set_retrieve_function - Used to set a callback to retrieve the certificate
+  * @session: is a &gnutls_session 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, const gnutls_datum* req_ca_dn, int nreqs, 
+  * gnutls_datum **cert, unsigned int *ncerts, gnutls_key* key);
+  *
+  * @cert should contain @ncerts gnutls_datum structures which hold
+  * the raw certificates (DER for X.509 or binary for OpenPGP), of the
+  * client. Those should be allocated with gnutls_malloc(). The certificate
+  * type to be sent should be obtained using gnutls_certificate_type_get();
+  *
+  * @key should contain a private key.
+  *
+  * @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().
+  *
+  * If the callback function is provided then gnutls will call it, in the
+  * handshake, after the certificate request message has been received.
+  *
+  * The callback function should set the certificate list to be sent, and
+  * return 0 on success.  The value (-1) indicates error and the handshake
+  * will be terminated.
+  **/
+void gnutls_certificate_client_set_retrieve_function(gnutls_session session,
+                       gnutls_certificate_client_retrieve_function * func)
+{
+       session->internals.client_get_cert_callback = func;
+}
+
+/**
+  * gnutls_certificate_server_set_retrieve_function - Used to set a callback to retrieve the certificate
+  * @session: is a &gnutls_session 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, gnutls_datum **cert, unsigned int *ncerts
+  * gnutls_key* key);
+  *
+  * @cert should contain @ncerts gnutls_datum structures which hold
+  * the raw certificates (DER for X.509 or binary for OpenPGP), of the
+  * server. Those should be allocated with gnutls_malloc(). The certificate
+  * type to be sent should be obtained using gnutls_certificate_type_get();
+  *
+  * @key should contain a private key.
+  *
+  * If the callback function is provided then gnutls will call it, in the
+  * handshake, after the certificate request message has been received.
+  *
+  * The callback function should set the certificate list to be sent, and
+  * return 0 on success.  The value (-1) indicates error and the handshake
+  * will be terminated.
+  **/
+void gnutls_certificate_server_set_retrieve_function(gnutls_session session,
+                       gnutls_certificate_server_retrieve_function * func)
+{
+       session->internals.server_get_cert_callback = func;
+}
+
+
 /* These are set by the gnutls_extra library's initialization function.
  */
 
@@ -499,6 +568,51 @@ time_t gnutls_certificate_activation_time_peers(gnutls_session session)
        }
 }
 
+/* in auth_dhe.c */
+OPENPGP_CERT2GNUTLS_CERT _E_gnutls_openpgp_cert2gnutls_cert;
+OPENPGP_KEY2GNUTLS_KEY _E_gnutls_openpgp_key2gnutls_key;
+
+int _gnutls_cert2gnutls_cert(gnutls_cert * gcert, gnutls_certificate_type type,
+       const gnutls_datum *raw_cert, int flags /* OR of ConvFlags */)
+{
+       switch( type) {
+               case GNUTLS_CRT_X509:
+                       return _gnutls_x509_cert2gnutls_cert( gcert,
+                                            raw_cert, flags);
+               case GNUTLS_CRT_OPENPGP:
+                       if (_E_gnutls_openpgp_cert2gnutls_cert==NULL) {
+                               gnutls_assert();
+                               return GNUTLS_E_INIT_LIBEXTRA;
+                       }
+                       return
+                            _E_gnutls_openpgp_cert2gnutls_cert( gcert,
+                                            raw_cert);
+               default:
+                       gnutls_assert();
+                       return GNUTLS_E_INTERNAL_ERROR;
+       }
+}
+
+int _gnutls_key2gnutls_key(gnutls_privkey * key, gnutls_certificate_type type,
+       const gnutls_datum *raw_key, int key_enc /* DER or PEM */)
+{
+       switch( type) {
+               case GNUTLS_CRT_X509:
+                       return _gnutls_x509_key2gnutls_key( key,
+                                            raw_key, key_enc);
+               case GNUTLS_CRT_OPENPGP:
+                       if (_E_gnutls_openpgp_key2gnutls_key==NULL) {
+                               gnutls_assert();
+                               return GNUTLS_E_INIT_LIBEXTRA;
+                       }
+                       return
+                            _E_gnutls_openpgp_key2gnutls_key( key, raw_key);
+               default:
+                       gnutls_assert();
+                       return GNUTLS_E_INTERNAL_ERROR;
+       }
+}
+
 
 /* This function will convert a der certificate to a format
  * (structure) that gnutls can understand and use. Actually the
@@ -593,10 +707,12 @@ int _gnutls_x509_crt2gnutls_cert(gnutls_cert * gcert, gnutls_x509_crt cert,
 
 }
 
-void _gnutls_free_cert(gnutls_cert *cert)
+void _gnutls_cert_deinit(gnutls_cert *cert)
 {
        int i;
 
+       if (cert == NULL) return;
+
        for (i = 0; i < cert->params_size; i++) {
                _gnutls_mpi_release( &cert->params[i]);
        }
index 3de12ef48402f04ac15ef50598cf7f8ca7fad0b0..7c36b31cc9da37f0748979f699304caeda790201 100644 (file)
@@ -85,12 +85,16 @@ int _gnutls_x509_cert2gnutls_cert(gnutls_cert * gcert, const gnutls_datum *derCe
        int flags);
 int _gnutls_x509_crt2gnutls_cert(gnutls_cert * gcert, gnutls_x509_crt cert,
        unsigned int flags);
-void _gnutls_free_cert(gnutls_cert* cert);
 int _gnutls_cert_get_dn(gnutls_cert * cert, gnutls_datum * odn);
 
 void _gnutls_privkey_deinit(gnutls_privkey *key);
+void _gnutls_cert_deinit(gnutls_cert *cert);
 
 int _gnutls_selected_cert_supported_kx(struct gnutls_session_int* session, 
        gnutls_kx_algorithm ** alg, int *alg_size);
-                              
+int _gnutls_cert2gnutls_cert(gnutls_cert * gcert, gnutls_certificate_type type,
+        const gnutls_datum *raw_cert, int flags /* OR of ConvFlags */);
+int _gnutls_key2gnutls_key(gnutls_privkey * key, gnutls_certificate_type type,
+       const gnutls_datum *raw_key, int key_enc /* DER or PEM */);
+                                      
 #endif
index d61b7d5d36b12522658bae01ec6a40d3c3af642b..888fb17a3f13734b5183637042591e43fd6aa7a7 100644 (file)
@@ -221,6 +221,7 @@ typedef void (*LOG_FUNC)( int, const char*);
 typedef ssize_t (*gnutls_pull_func)(gnutls_transport_ptr, void*, size_t);
 typedef ssize_t (*gnutls_push_func)(gnutls_transport_ptr, const void*, size_t);
 
+
 /* Store & Retrieve functions defines: 
  */
 typedef int (*gnutls_db_store_func)(void*, gnutls_datum key, gnutls_datum data);
@@ -419,6 +420,16 @@ typedef int certificate_server_select_func(struct gnutls_session_int*,
 typedef int srp_server_select_func(struct gnutls_session_int*, 
        const char**, const char**, unsigned int);
 
+/* authentication function definitions:
+ */
+typedef int gnutls_certificate_client_retrieve_function(
+   struct gnutls_session_int*, const gnutls_datum* req_ca_cert, int nreqs,
+   gnutls_datum** certs, unsigned int* ncerts, gnutls_datum* key);
+
+typedef int gnutls_certificate_server_retrieve_function(
+   struct gnutls_session_int*, gnutls_datum **server_certs, unsigned int* ncerts,
+   gnutls_datum* key);
+
 typedef struct {
        opaque                          header[HANDSHAKE_HEADER_SIZE];
        /* this holds the number of bytes in the handshake_header[] */
@@ -538,6 +549,9 @@ typedef struct {
        certificate_client_select_func* client_cert_callback;
        certificate_server_select_func* server_cert_callback;
 
+       gnutls_certificate_client_retrieve_function*    client_get_cert_callback;
+       gnutls_certificate_server_retrieve_function*    server_get_cert_callback;
+
        /* Callback to select the proper password file
         */
        srp_server_select_func*         server_srp_callback;
@@ -573,13 +587,15 @@ typedef struct {
         */
        uint16                  proposed_record_size;
        
-       /* holds the index of the selected certificate.
-        * -1 if none.
+       /* holds the the selected certificate and key.
+        * use _gnutls_selected_certs_deinit() and _gnutls_selected_certs_set()
+        * to change them.
         */
        gnutls_cert*            selected_cert_list;
        int                     selected_cert_list_length;
        gnutls_privkey*         selected_key;
-       
+       int                     selected_need_free;
+
        /* holds the extensions we sent to the peer
         * (in case of a client)
         */
index 310f159ccb9730f34e2fe7d3aa52f62c898438e8..711a2fdd31ec7190b48c125ba9f7e696b474ac53 100644 (file)
@@ -273,6 +273,7 @@ void _gnutls_deinit(gnutls_session session)
        _gnutls_buffer_clear( &session->internals.record_send_buffer);
 
        gnutls_credentials_clear( session);
+       _gnutls_selected_certs_deinit( session);
 
        if (session->connection_state.read_cipher_state != NULL)
                _gnutls_cipher_deinit(session->connection_state.read_cipher_state);
index ef050f9aba8c08b36a118b991b9f84996b308abc..9700d1ff5862bbe40732f1bff8fafb750a594d0d 100644 (file)
@@ -17,6 +17,14 @@ typedef int gnutls_certificate_client_select_function(
 typedef int gnutls_certificate_server_select_function(
    gnutls_session, const gnutls_datum *server_certs, int ncerts);
 
+typedef int gnutls_certificate_client_retrieve_function(
+   gnutls_session, const gnutls_datum* req_ca_cert, int nreqs,
+   gnutls_datum** certs, unsigned int* ncerts, gnutls_datum* key);
+typedef int gnutls_certificate_server_retrieve_function(
+   gnutls_session, gnutls_datum **server_certs, unsigned int* ncerts
+   gnutls_datum* key);
+
+
 /* Functions that allow AUTH_INFO structures handling
  */
 
@@ -39,6 +47,9 @@ int gnutls_rsa_export_get_modulus_bits(gnutls_session session);
 void gnutls_certificate_client_set_select_function( gnutls_session, gnutls_certificate_client_select_function *);
 void gnutls_certificate_server_set_select_function( gnutls_session, gnutls_certificate_server_select_function *);
 
+void gnutls_certificate_client_set_retrieve_function( gnutls_session, gnutls_certificate_client_retrieve_function *);
+void gnutls_certificate_server_set_retrieve_function( gnutls_session, gnutls_certificate_server_retrieve_function *);
+
 void gnutls_certificate_server_set_request( gnutls_session, gnutls_certificate_request);
 
 /* X.509 certificate handling functions 
index 6ee494064bb8ba24fd2781734c46c7434cd22edc..eaca68d83e6a0b44abc82e5c2927b8b1ccda0895 100644 (file)
@@ -550,12 +550,43 @@ int i, ret;
 void _gnutls_privkey_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_key2gnutls_key( gnutls_privkey* privkey, const gnutls_datum* raw_key,
+       gnutls_x509_crt_fmt type)
+{
+gnutls_x509_privkey tmpkey;
+int ret;
+
+       ret = gnutls_x509_privkey_init( &tmpkey);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       ret = gnutls_x509_privkey_import( tmpkey, raw_key, type);
+       if (ret < 0) {
+               gnutls_assert();
+               gnutls_x509_privkey_deinit( tmpkey);
+               return ret;
+       }
+
+       ret = privkey_cpy( privkey, tmpkey);
+       if (ret < 0) {
+               gnutls_assert();
+               gnutls_x509_privkey_deinit( tmpkey);
+               return ret;
+       }
+
+       gnutls_x509_privkey_deinit( tmpkey);
+       
+       return 0;
+}
 
 /* Reads a PEM encoded PKCS-1 RSA private key from memory
  * 2002-01-26: Added ability to read DSA keys.
@@ -566,7 +597,6 @@ static int read_key_mem(gnutls_certificate_credentials res, const void *key, int
 {
        int ret;
        gnutls_datum tmp;
-       gnutls_x509_privkey tmpkey;
 
        /* allocate space for the pkey list
         */
@@ -576,33 +606,15 @@ static int read_key_mem(gnutls_certificate_credentials res, const void *key, int
                return GNUTLS_E_MEMORY_ERROR;
        }
 
-       ret = gnutls_x509_privkey_init( &tmpkey); //res->pkey[res->ncerts]);
-       if (ret < 0) {
-               gnutls_assert();
-               return ret;
-       }
-
        tmp.data = (opaque*)key;
        tmp.size = key_size;
 
-       ret = gnutls_x509_privkey_import( tmpkey, &tmp, type);
-       if (ret < 0) {
-               gnutls_assert();
-               gnutls_x509_privkey_deinit( tmpkey);
-
-               return ret;
-       }
-
-       ret = privkey_cpy( &res->pkey[res->ncerts], tmpkey);
+       ret = _gnutls_x509_key2gnutls_key( &res->pkey[res->ncerts], &tmp, type);
        if (ret < 0) {
                gnutls_assert();
-               gnutls_x509_privkey_deinit( tmpkey);
-
                return ret;
        }
 
-       gnutls_x509_privkey_deinit( tmpkey);
-
        return 0;
 }
 
index b48c2e1038b084d9b9c748a9016b39cb4aacb5e5..81379dbe190377522835b85a6d51076d24b853c1 100644 (file)
@@ -16,3 +16,5 @@ int _gnutls_check_key_usage( const gnutls_cert* cert, gnutls_kx_algorithm alg);
 int _gnutls_x509_read_rsa_params(opaque * der, int dersize, GNUTLS_MPI * params);
 int _gnutls_x509_read_dsa_pubkey(opaque * der, int dersize, GNUTLS_MPI * params);
 
+int _gnutls_x509_key2gnutls_key( gnutls_privkey* privkey, const gnutls_datum* raw_key,
+        gnutls_x509_crt_fmt type);
index 996d9f701f2d534efeb8030ef9ffcba4c7382b4f..725d7f5bc92ac26f83d566476fb5eaca7cc2f108 100644 (file)
@@ -203,7 +203,7 @@ opaque* p;
                                      &peer_cert,
                                      &vparams, &signature);
        
-       _gnutls_free_cert( &peer_cert);
+       _gnutls_cert_deinit( &peer_cert);
        if (ret < 0) {
                gnutls_assert();
                return ret;
index 30e52c01872f4bd1ca14e18071755061f28560a0..8044b5d7b0c52f09997aed2aa6d8875efad5277c 100644 (file)
@@ -153,6 +153,7 @@ extern OPENPGP_KEY_CREATION_TIME_FUNC _E_gnutls_openpgp_extract_key_creation_tim
 extern OPENPGP_KEY_EXPIRATION_TIME_FUNC _E_gnutls_openpgp_extract_key_expiration_time;
 extern OPENPGP_VERIFY_KEY_FUNC _E_gnutls_openpgp_verify_key;
 extern OPENPGP_CERT2GNUTLS_CERT _E_gnutls_openpgp_cert2gnutls_cert;
+extern OPENPGP_KEY2GNUTLS_KEY _E_gnutls_openpgp_key2gnutls_key;
 extern OPENPGP_FINGERPRINT _E_gnutls_openpgp_fingerprint;
 extern OPENPGP_KEY_REQUEST _E_gnutls_openpgp_request_key;
 
@@ -164,6 +165,7 @@ static void _gnutls_add_openpgp_functions(void) {
        _E_gnutls_openpgp_fingerprint = gnutls_openpgp_fingerprint;
        _E_gnutls_openpgp_request_key = _gnutls_openpgp_request_key;
        _E_gnutls_openpgp_cert2gnutls_cert = _gnutls_openpgp_cert2gnutls_cert;
+       _E_gnutls_openpgp_key2gnutls_key = _gnutls_openpgp_key2gnutls_key;
 #endif
 }
 
index a458512b9d618e4293a6e207eab7de13f35e519b..5da0886bc2076dcb55165076197724c6ba5e2ca9 100644 (file)
@@ -8,3 +8,4 @@ typedef int (*OPENPGP_KEY_REQUEST)(gnutls_session, gnutls_datum*,
        const gnutls_certificate_credentials, opaque*,int);
 typedef int (*OPENPGP_FINGERPRINT)(const gnutls_datum*, unsigned char*, size_t*);
 typedef int (*OPENPGP_CERT2GNUTLS_CERT)(gnutls_cert*, const gnutls_datum*);
+typedef int (*OPENPGP_KEY2GNUTLS_KEY)(gnutls_privkey*, const gnutls_datum*);
index b307e427837e72456b51d7be93282450e735c553..97fc9ac3bd911e1922deeae8dc692358494f9c0c 100644 (file)
@@ -292,7 +292,7 @@ openpgp_pk_to_gnutls_cert( gnutls_cert *cert, cdk_pkt_pubkey_t pk )
  -*/
 int
 _gnutls_openpgp_key2gnutls_key( gnutls_privkey *pkey,
-                                gnutls_datum *raw_key )
+                                const gnutls_datum *raw_key )
 {
     cdk_kbnode_t snode;
     CDK_PACKET *pkt;
index 23a974b3281042f4ffe532daefc5d94d47892e24..eabb52e97cb7b26c715f1ba2e0c91bc82cdb31b7 100644 (file)
@@ -72,6 +72,10 @@ int _gnutls_openpgp_cert2gnutls_cert(
     gnutls_cert *cert,
     const gnutls_datum *raw );
 
+int
+_gnutls_openpgp_key2gnutls_key( gnutls_privkey *pkey,
+                                const gnutls_datum *raw_key);
+
 int
 _gnutls_openpgp_request_key(
     gnutls_session,
@@ -93,6 +97,9 @@ int gnutls_openpgp_fingerprint(const gnutls_datum * cert,
 time_t gnutls_openpgp_extract_key_creation_time(const gnutls_datum * cert);
 time_t gnutls_openpgp_extract_key_expiration_time(const gnutls_datum * cert);
 
+int
+_gnutls_openpgp_key2gnutls_key( gnutls_privkey *pkey,
+                                const gnutls_datum *raw_key);
 
 #endif /*GNUTLS_OPENPGP_H*/