]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
* Corrected a parsing error in the Certificate request message.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Mon, 24 Mar 2003 17:56:15 +0000 (17:56 +0000)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Mon, 24 Mar 2003 17:56:15 +0000 (17:56 +0000)
* Corrected behaviour when a certificate request message is received.
  Now a certificate packet is always sent, and in SSL 3.0 cipher suites
  a no_certificate alert is sent instead.
* Some fixes in the certificate callback function.

NEWS
configure.in
lib/auth_cert.c
lib/gnutls_kx.c

diff --git a/NEWS b/NEWS
index 47c26fc7410e049ab5e515513e21be3c2c1836cc..43ee8f166ba387722c1d7a53ab447dfba5f4b3a5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,9 @@
+Version 0.8.6
+- Corrected a parsing error in the Certificate request message.
+- Corrected behaviour when a certificate request message is received.
+  Now a certificate packet is always sent, and in SSL 3.0 cipher suites
+  a no_certificate alert is sent instead.
+
 Version 0.8.5 (22/03/2003)
 - Allow larger MPI parameters in certificates.
 - Implemented the counter measure discussed in the paper "Attacking
index ea990b3930f873eb30277514ffe242ec55787adb..a2f8a28a99e6adb3a495151af51407265f30262d 100644 (file)
@@ -12,7 +12,7 @@ AC_DEFINE_UNQUOTED(T_OS, "$target_os", [OS name])
 dnl Gnutls Version
 GNUTLS_MAJOR_VERSION=0
 GNUTLS_MINOR_VERSION=8
-GNUTLS_MICRO_VERSION=5
+GNUTLS_MICRO_VERSION=6
 GNUTLS_VERSION=$GNUTLS_MAJOR_VERSION.$GNUTLS_MINOR_VERSION.$GNUTLS_MICRO_VERSION
 
 AC_DEFINE_UNQUOTED(GNUTLS_VERSION, "$GNUTLS_VERSION", [version of gnutls])
index 1c60942ffc2f0a89b4e59f1bc435413183eb0bd8..981d59d90cc0c9bb1795e95eaf5e3e287d3dc0fc 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  Copyright (C) 2001,2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2001,2002,2003 Nikos Mavroyanopoulos
  *
- *  This file is part of GNUTLS.
+ * This file is part of GNUTLS.
  *
  *  The GNUTLS library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public   
@@ -37,7 +37,9 @@
 #include <gnutls_algorithms.h>
 #include <gnutls_global.h>
 #include <gnutls_record.h>
+#include <x509_verify.h>
 #include <gnutls_sig.h>
+#include <x509_extensions.h>
 #include <gnutls_state.h>
 #include <gnutls_pk.h>
 #include <gnutls_x509.h>
@@ -45,8 +47,7 @@
 #include "debug.h"
 
 static int _gnutls_server_find_cert_list_index(gnutls_session session,
-                                              gnutls_pk_algorithm
-                                              requested_algo);
+                                       gnutls_pk_algorithm requested_algo);
 
 /* Copies data from a internal certificate struct (gnutls_cert) to 
  * exported certificate struct (CERTIFICATE_AUTH_INFO)
@@ -76,9 +77,9 @@ int _gnutls_copy_certificate_auth_info(CERTIFICATE_AUTH_INFO info,
                if (cert->raw.size > 0) {
                        ret =
                            _gnutls_set_datum(&info->
-                                             raw_certificate_list[i],
-                                             cert[i].raw.data,
-                                             cert[i].raw.size);
+                                            raw_certificate_list[i],
+                                            cert[i].raw.data,
+                                            cert[i].raw.size);
                        if (ret < 0) {
                                gnutls_assert();
                                goto clear;
@@ -101,16 +102,58 @@ int _gnutls_copy_certificate_auth_info(CERTIFICATE_AUTH_INFO info,
 }
 
 
+/* Returns the issuer's Distinguished name in odn, of the certificate 
+ * specified in cert.
+ */
+int _gnutls_find_dn(gnutls_datum * odn, gnutls_cert * cert)
+{
+       ASN1_TYPE dn;
+       int len, result;
+       int start, end;
+
+       if ((result=_gnutls_asn1_create_element
+           (_gnutls_get_pkix(), "PKIX1.Certificate", &dn,
+            "dn")) != ASN1_SUCCESS) {
+               gnutls_assert();
+               return _gnutls_asn2err(result);
+       }
+
+       result = asn1_der_decoding(&dn, cert->raw.data, cert->raw.size, NULL);
+       if (result != ASN1_SUCCESS) {
+               /* couldn't decode DER */
+               gnutls_assert();
+               asn1_delete_structure(&dn);
+               return _gnutls_asn2err(result);
+       }
+
+       result = asn1_der_decoding_startEnd(dn, cert->raw.data, cert->raw.size,
+                                       "dn.tbsCertificate.issuer", &start,
+                                       &end);
+
+       if (result != ASN1_SUCCESS) {
+               /* couldn't decode DER */
+               gnutls_assert();
+               asn1_delete_structure(&dn);
+               return _gnutls_asn2err(result);
+       }
+       asn1_delete_structure(&dn);
+
+       len = end - start + 1;
+
+       odn->size = len;
+       odn->data = &cert->raw.data[start];
+
+       return 0;
+}
 
 
 /* returns 0 if the algo_to-check exists in the pk_algos list,
  * -1 otherwise.
  */
 inline
-    static int _gnutls_check_pk_algo_in_list(gnutls_pk_algorithm *
-                                            pk_algos, int pk_algos_length,
-                                            gnutls_pk_algorithm
-                                            algo_to_check)
+    static int _gnutls_check_pk_algo_in_list(gnutls_pk_algorithm * pk_algos,
+                                            int pk_algos_length,
+                                            gnutls_pk_algorithm algo_to_check)
 {
        int i;
        for (i = 0; i < pk_algos_length; i++) {
@@ -121,22 +164,20 @@ inline
        return -1;
 }
 
-
-
 /* Locates the most appropriate x509 certificate using the
  * given DN. If indx == -1 then no certificate was found.
  */
 static int _find_x509_cert(const gnutls_certificate_credentials cred,
                           opaque * _data, size_t _data_size,
-                          gnutls_pk_algorithm * pk_algos,
-                          int pk_algos_length, int *indx)
+                          gnutls_pk_algorithm * pk_algos, int pk_algos_length,
+                          int *indx)
 {
        uint size;
        gnutls_datum odn;
        opaque *data = _data;
        ssize_t data_size = _data_size;
        uint i, j;
-       int result, cert_pk;
+       int result;
 
        *indx = -1;
 
@@ -150,7 +191,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_find_dn(&odn,
+                                                    &cred->cert_list[i]
+                                                    [j])) < 0) {
                                        gnutls_assert();
                                        return result;
                                }
@@ -162,10 +205,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;
-
-                               if ((memcmp(odn.data, data, size) == 0) &&
-                                   (_gnutls_check_pk_algo_in_list(pk_algos, pk_algos_length, cert_pk) == 0)) {
+                               if ((memcmp(odn.data,
+                                           data, size) == 0) &&
+                                   (_gnutls_check_pk_algo_in_list
+                                    (pk_algos, pk_algos_length,
+                                     cred->cert_list[i][0].
+                                     subject_pk_algorithm) == 0)
+                                   && (cred->cert_list[i][0].cert_type ==
+                                       GNUTLS_CRT_X509)) {
                                        *indx = i;
                                        break;
                                }
@@ -189,8 +236,8 @@ static int _find_x509_cert(const gnutls_certificate_credentials cred,
 /* Locates the most appropriate openpgp cert
  */
 static int _find_openpgp_cert(const gnutls_certificate_credentials cred,
-                             gnutls_pk_algorithm * pk_algos,
-                             int pk_algos_length, int *indx)
+                             gnutls_pk_algorithm * pk_algos, int pk_algos_length,
+                             int *indx)
 {
        uint i, j;
 
@@ -229,28 +276,38 @@ static int _find_openpgp_cert(const gnutls_certificate_credentials cred,
 static int _gnutls_find_acceptable_client_cert(gnutls_session session,
                                               opaque * _data,
                                               size_t _data_size, int *ind,
-                                              gnutls_pk_algorithm *
-                                              pk_algos,
+                                              gnutls_pk_algorithm * pk_algos,
                                               int pk_algos_length)
 {
        int result, size;
        int indx = -1;
        uint i, j;
-       int *ij_map = NULL;
+       int try = 0, *ij_map = NULL;
        const gnutls_certificate_credentials cred;
        opaque *data = _data;
        ssize_t data_size = _data_size;
 
        cred =
-           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE,
+                            NULL);
        if (cred == NULL) {
                gnutls_assert();
                return GNUTLS_E_INSUFICIENT_CREDENTIALS;
        }
 
-       /* If we have no callback.
-        */
-       if (session->internals.client_cert_callback == NULL) {
+       if (session->internals.client_cert_callback != NULL) {
+               /* if try>=0 then the client wants automatic
+                * choose of certificate, otherwise (-1), he
+                * will be prompted to choose one.
+                */
+               try =
+                   session->internals.client_cert_callback(session,
+                                                                NULL, 0,
+                                                                NULL, 0);
+       }
+
+
+       if (try >= 0) {
                result = 0;
 
                if (session->security_parameters.cert_type ==
@@ -271,14 +328,16 @@ static int _gnutls_find_acceptable_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 
-                */
+       }
+
+
+       /* use the callback 
+        */
+       if (indx == -1 && session->internals.client_cert_callback != NULL && cred->ncerts > 0) {        /* use a callback to get certificate */
                gnutls_datum *my_certs = NULL;
                gnutls_datum *issuers_dn = NULL;
                uint issuers_dn_len = 0;
-               opaque *dataptr = data;
+               opaquedataptr = data;
                ssize_t dataptr_size = data_size;
 
                /* Count the number of the given issuers;
@@ -287,10 +346,10 @@ static int _gnutls_find_acceptable_client_cert(gnutls_session session,
                 */
                do {
                        /* This works like DECR_LEN() */
-                       DECR_LENGTH_COM(dataptr_size, 2, goto clear);
-                       size = _gnutls_read_uint16(data);
+                       DECR_LENGTH_COM( dataptr_size, 2, goto clear);
+                       size = _gnutls_read_uint16(dataptr);
 
-                       DECR_LENGTH_COM(dataptr_size, size, goto clear);
+                       DECR_LENGTH_COM( dataptr_size, size, goto clear);
 
                        dataptr += 2;
 
@@ -298,7 +357,7 @@ static int _gnutls_find_acceptable_client_cert(gnutls_session session,
                                issuers_dn_len++;
                                dataptr += size;
                        }
-
+                       
                        if (dataptr_size == 0)
                                break;
 
@@ -313,18 +372,15 @@ static int _gnutls_find_acceptable_client_cert(gnutls_session session,
                /* put the requested DNs to req_dn, only in case
                 * of X509 certificates.
                 */
-               if (gnutls_certificate_type_get(session) ==
-                   GNUTLS_CRT_X509 && issuers_dn_len > 0) {
+               if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
                        data = _data;
                        data_size = _data_size;
 
-                       issuers_dn =
-                           gnutls_alloca(issuers_dn_len *
-                                         sizeof(gnutls_datum));
+                       issuers_dn = gnutls_alloca( issuers_dn_len * sizeof(gnutls_datum));
                        if (issuers_dn == NULL)
                                goto clear;
 
-                       for (i = 0; i < issuers_dn_len; i++) {
+                       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.
@@ -342,14 +398,14 @@ static int _gnutls_find_acceptable_client_cert(gnutls_session session,
 
                        }
 
-               } else { /* Other certificate types */
+               } else {        /* Other certificate types */
                        issuers_dn_len = 0;
                        issuers_dn = NULL;
                }
 
                /* maps j -> i */
                ij_map = gnutls_alloca(sizeof(int) * cred->ncerts);
-               if (ij_map == NULL) {
+               if (ij_map==NULL) {
                        gnutls_assert();
                        goto clear;
                }
@@ -357,7 +413,7 @@ static int _gnutls_find_acceptable_client_cert(gnutls_session session,
                /* 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
+                * that are requested by the server (CA matches - and sign
                 * algorithm matches), are provided.
                 */
                for (j = i = 0; i < cred->ncerts; i++) {
@@ -379,10 +435,10 @@ static int _gnutls_find_acceptable_client_cert(gnutls_session session,
 
                indx =
                    session->internals.client_cert_callback(session,
-                                                           my_certs,
-                                                           j,
-                                                           issuers_dn,
-                                                           issuers_dn_len);
+                                                                my_certs,
+                                                                j,
+                                                                issuers_dn,
+                                                                issuers_dn_len);
 
                /* the indx returned by the user is relative
                 * to the certificates we provided him.
@@ -405,7 +461,7 @@ static int _gnutls_find_acceptable_client_cert(gnutls_session session,
 /* Generate client certificate
  */
 
-int _gnutls_gen_x509_crt(gnutls_session session, opaque ** data)
+int _gnutls_gen_x509_certificate(gnutls_session session, opaque ** data)
 {
        int ret, i;
        opaque *pdata;
@@ -457,7 +513,8 @@ int _gnutls_gen_x509_crt(gnutls_session session, opaque ** data)
 
 enum PGPKeyDescriptorType { PGP_KEY_FINGERPRINT, PGP_KEY };
 
-int _gnutls_gen_openpgp_certificate(gnutls_session session, opaque ** data)
+int _gnutls_gen_openpgp_certificate(gnutls_session session,
+                                          opaque ** data)
 {
        int ret;
        opaque *pdata;
@@ -507,7 +564,7 @@ OPENPGP_KEY_REQUEST _E_gnutls_openpgp_request_key = NULL;
 extern OPENPGP_CERT2GNUTLS_CERT _E_gnutls_openpgp_cert2gnutls_cert;
 
 int _gnutls_gen_openpgp_certificate_fpr(gnutls_session session,
-                                       opaque ** data)
+                                              opaque ** data)
 {
        int ret, fpr_size, packet_size;
        opaque *pdata;
@@ -552,14 +609,12 @@ int _gnutls_gen_openpgp_certificate_fpr(gnutls_session session,
 
        fpr_size = 20;
 
-       if (_E_gnutls_openpgp_fingerprint == NULL) {
+       if (_E_gnutls_openpgp_fingerprint==NULL) {
                gnutls_assert();
                return GNUTLS_E_INIT_LIBEXTRA;
        }
 
-       if ((ret =
-            _E_gnutls_openpgp_fingerprint(&apr_cert_list[0].raw, pdata,
-                                          &fpr_size)) < 0) {
+       if ( (ret=_E_gnutls_openpgp_fingerprint( &apr_cert_list[0].raw, pdata, &fpr_size)) < 0) {
                gnutls_assert();
                return ret;
        }
@@ -569,21 +624,21 @@ int _gnutls_gen_openpgp_certificate_fpr(gnutls_session session,
 
 
 
-int _gnutls_gen_cert_client_certificate(gnutls_session session,
-                                       opaque ** data)
+int _gnutls_gen_cert_client_certificate(gnutls_session session, opaque ** data)
 {
        switch (session->security_parameters.cert_type) {
        case GNUTLS_CRT_OPENPGP:
                if (_gnutls_openpgp_send_fingerprint(session) == 0)
                        return
-                           _gnutls_gen_openpgp_certificate(session, data);
+                           _gnutls_gen_openpgp_certificate(session,
+                                                                  data);
                else
                        return
                            _gnutls_gen_openpgp_certificate_fpr
                            (session, data);
 
        case GNUTLS_CRT_X509:
-               return _gnutls_gen_x509_crt(session, data);
+               return _gnutls_gen_x509_certificate(session, data);
 
        default:
                gnutls_assert();
@@ -591,14 +646,13 @@ int _gnutls_gen_cert_client_certificate(gnutls_session session,
        }
 }
 
-int _gnutls_gen_cert_server_certificate(gnutls_session session,
-                                       opaque ** data)
+int _gnutls_gen_cert_server_certificate(gnutls_session session, opaque ** data)
 {
        switch (session->security_parameters.cert_type) {
        case GNUTLS_CRT_OPENPGP:
                return _gnutls_gen_openpgp_certificate(session, data);
        case GNUTLS_CRT_X509:
-               return _gnutls_gen_x509_crt(session, data);
+               return _gnutls_gen_x509_certificate(session, data);
        default:
                gnutls_assert();
                return GNUTLS_E_INTERNAL_ERROR;
@@ -608,9 +662,9 @@ 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])
-int _gnutls_proc_x509_server_certificate(gnutls_session session,
-                                        opaque * data, size_t data_size)
+#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_free_cert(peer_certificate_list[x])
+int _gnutls_proc_x509_server_certificate(gnutls_session session, opaque * data,
+                                        size_t data_size)
 {
        int size, len, ret;
        opaque *p = data;
@@ -623,7 +677,8 @@ int _gnutls_proc_x509_server_certificate(gnutls_session session,
        gnutls_datum tmp;
 
        cred =
-           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE,
+                            NULL);
        if (cred == NULL) {
                gnutls_assert();
                return GNUTLS_E_INSUFICIENT_CREDENTIALS;
@@ -657,7 +712,7 @@ int _gnutls_proc_x509_server_certificate(gnutls_session session,
        }
 
        i = dsize;
-       while (i > 0) {
+       while(i > 0) {
                DECR_LEN(dsize, 3);
                len = _gnutls_read_uint24(p);
                p += 3;
@@ -677,15 +732,15 @@ int _gnutls_proc_x509_server_certificate(gnutls_session session,
         */
 
        peer_certificate_list =
-           gnutls_alloca(sizeof(gnutls_cert) *
+           gnutls_alloca( sizeof(gnutls_cert) *
                          (peer_certificate_list_size));
 
        if (peer_certificate_list == NULL) {
                gnutls_assert();
                return GNUTLS_E_MEMORY_ERROR;
        }
-       memset(peer_certificate_list, 0, sizeof(gnutls_cert) *
-              peer_certificate_list_size);
+       memset( peer_certificate_list, 0, sizeof(gnutls_cert)*
+                                       peer_certificate_list_size);
 
        p = data + 3;
 
@@ -694,7 +749,7 @@ int _gnutls_proc_x509_server_certificate(gnutls_session session,
         * been parsed before.
         */
 
-       for (j = 0; j < peer_certificate_list_size; j++) {
+       for (j=0;j<peer_certificate_list_size;j++) {
                len = _gnutls_read_uint24(p);
                p += 3;
 
@@ -703,9 +758,7 @@ int _gnutls_proc_x509_server_certificate(gnutls_session session,
 
                if ((ret =
                     _gnutls_x509_cert2gnutls_cert(&peer_certificate_list
-                                                  [j], &tmp,
-                                                  CERT_ONLY_EXTENSIONS)) <
-                   0) {
+                                                  [j], tmp, CERT_ONLY_EXTENSIONS)) < 0) {
                        gnutls_assert();
                        CLEAR_CERTS;
                        gnutls_afree(peer_certificate_list);
@@ -728,7 +781,7 @@ int _gnutls_proc_x509_server_certificate(gnutls_session session,
        }
 
        if ((ret =
-            _gnutls_check_key_usage(&peer_certificate_list[0],
+            _gnutls_check_x509_key_usage(&peer_certificate_list[0],
                                          gnutls_kx_get(session)))
            < 0) {
                gnutls_assert();
@@ -743,10 +796,9 @@ int _gnutls_proc_x509_server_certificate(gnutls_session session,
        return 0;
 }
 
-#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_free_cert(peer_certificate_list[x])
 int _gnutls_proc_openpgp_server_certificate(gnutls_session session,
-                                           opaque * data,
-                                           size_t data_size)
+                                           opaque * data, size_t data_size)
 {
        int size, ret, len;
        opaque *p = data;
@@ -759,7 +811,8 @@ int _gnutls_proc_openpgp_server_certificate(gnutls_session session,
        gnutls_datum tmp, akey = { NULL, 0 };
 
        cred =
-           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE,
+                            NULL);
        if (cred == NULL) {
                gnutls_assert();
                return GNUTLS_E_INSUFICIENT_CREDENTIALS;
@@ -793,37 +846,35 @@ int _gnutls_proc_openpgp_server_certificate(gnutls_session session,
 
        /* Read PGPKeyDescriptor */
        DECR_LEN(dsize, 1);
-       if (*p == PGP_KEY_FINGERPRINT) {        /* the fingerprint */
+       if (*p == PGP_KEY_FINGERPRINT) { /* the fingerprint */
                p++;
-
+               
                DECR_LEN(dsize, 1);
-               len = (uint8) * p;
-               p++;
-
+               len = (uint8) *p;
+                p++;
+               
                if (len != 20) {
                        gnutls_assert();
                        return GNUTLS_E_UNIMPLEMENTED_FEATURE;
                }
-
-               DECR_LEN(dsize, 20);
+               
+               DECR_LEN( dsize, 20);
 
                /* request the actual key from our database, or
                 * a key server or anything.
                 */
-               if (_E_gnutls_openpgp_request_key == NULL) {
+               if (_E_gnutls_openpgp_request_key==NULL) {
                        gnutls_assert();
                        return GNUTLS_E_INIT_LIBEXTRA;
                }
-               if ((ret =
-                    _E_gnutls_openpgp_request_key(session, &akey, cred, p,
-                                                  20)) < 0) {
+               if ( (ret=_E_gnutls_openpgp_request_key( session, &akey, cred, p, 20)) < 0) {
                        gnutls_assert();
                        return ret;
                }
                tmp = akey;
                peer_certificate_list_size++;
 
-       } else if (*p == PGP_KEY) {     /* the whole key */
+       } else if (*p == PGP_KEY) { /* the whole key */
 
                p++;
 
@@ -854,38 +905,38 @@ int _gnutls_proc_openpgp_server_certificate(gnutls_session session,
 
        if (peer_certificate_list_size == 0) {
                gnutls_assert();
-               _gnutls_free_datum(&akey);
+               _gnutls_free_datum( &akey);
                return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
        }
 
        peer_certificate_list =
-           gnutls_alloca(sizeof(gnutls_cert) *
+           gnutls_alloca( sizeof(gnutls_cert) *
                          (peer_certificate_list_size));
-       if (peer_certificate_list == NULL) {
+               if (peer_certificate_list == NULL) {
                gnutls_assert();
                return GNUTLS_E_MEMORY_ERROR;
        }
-       memset(peer_certificate_list, 0, sizeof(gnutls_cert) *
-              peer_certificate_list_size);
+       memset( peer_certificate_list, 0, sizeof(gnutls_cert)*
+                       peer_certificate_list_size);
 
-       if (_E_gnutls_openpgp_cert2gnutls_cert == NULL) {
+       if (_E_gnutls_openpgp_cert2gnutls_cert==NULL) {
                gnutls_assert();
-               _gnutls_free_datum(&akey);
+               _gnutls_free_datum( &akey);
                CLEAR_CERTS;
                gnutls_afree(peer_certificate_list);
                return GNUTLS_E_INIT_LIBEXTRA;
        }
-
+       
        if ((ret =
             _E_gnutls_openpgp_cert2gnutls_cert(&peer_certificate_list[0],
-                                               &tmp)) < 0) {
+                                             tmp)) < 0) {
                gnutls_assert();
-               _gnutls_free_datum(&akey);
+               _gnutls_free_datum( &akey);
                CLEAR_CERTS;
                gnutls_afree(peer_certificate_list);
                return ret;
        }
-       _gnutls_free_datum(&akey);
+       _gnutls_free_datum( &akey);
 
        if ((ret =
             _gnutls_copy_certificate_auth_info(info,
@@ -899,7 +950,7 @@ int _gnutls_proc_openpgp_server_certificate(gnutls_session session,
        }
 
        if ((ret =
-            _gnutls_check_key_usage(&peer_certificate_list[0],
+            _gnutls_check_x509_key_usage(&peer_certificate_list[0],
                                          gnutls_kx_get(session)))
            < 0) {
                gnutls_assert();
@@ -914,13 +965,12 @@ int _gnutls_proc_openpgp_server_certificate(gnutls_session session,
        return 0;
 }
 
-int _gnutls_proc_cert_server_certificate(gnutls_session session,
-                                        opaque * data, size_t data_size)
+int _gnutls_proc_cert_server_certificate(gnutls_session session, opaque * data,
+                                        size_t data_size)
 {
        switch (session->security_parameters.cert_type) {
        case GNUTLS_CRT_OPENPGP:
-               return _gnutls_proc_openpgp_server_certificate(session,
-                                                              data,
+               return _gnutls_proc_openpgp_server_certificate(session, data,
                                                               data_size);
        case GNUTLS_CRT_X509:
                return _gnutls_proc_x509_server_certificate(session, data,
@@ -965,7 +1015,8 @@ int _gnutls_proc_cert_cert_req(gnutls_session session, opaque * data,
        int pk_algos_length;
 
        cred =
-           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE,
+                            NULL);
        if (cred == NULL) {
                gnutls_assert();
                return GNUTLS_E_INSUFICIENT_CREDENTIALS;
@@ -1027,14 +1078,15 @@ int _gnutls_proc_cert_cert_req(gnutls_session session, opaque * data,
         */
        session->internals.selected_cert_index = ind;
 
-       if (ind >= 0)
-               session->key->certificate_requested = 1;
+       /* We should reply with a certificate message,
+        * even if we have no certificate to send.
+        */
+       session->key->certificate_requested = 1;
 
        return 0;
 }
 
-int _gnutls_gen_cert_client_cert_vrfy(gnutls_session session,
-                                     opaque ** data)
+int _gnutls_gen_cert_client_cert_vrfy(gnutls_session session, opaque ** data)
 {
        int ret;
        gnutls_cert *apr_cert_list;
@@ -1082,8 +1134,8 @@ int _gnutls_gen_cert_client_cert_vrfy(gnutls_session session,
        return size + 2;
 }
 
-int _gnutls_proc_cert_client_cert_vrfy(gnutls_session session,
-                                      opaque * data, size_t data_size)
+int _gnutls_proc_cert_client_cert_vrfy(gnutls_session session, opaque * data,
+                                      size_t data_size)
 {
        int size, ret;
        ssize_t dsize = data_size;
@@ -1111,20 +1163,19 @@ int _gnutls_proc_cert_client_cert_vrfy(gnutls_session session,
        case GNUTLS_CRT_X509:
                ret =
                    _gnutls_x509_cert2gnutls_cert(&peer_cert,
-                                                 &info->
-                                                 raw_certificate_list[0],
-                                                 CERT_NO_COPY);
+                                                 info->
+                                                 raw_certificate_list[0], CERT_NO_COPY);
                break;
        case GNUTLS_CRT_OPENPGP:
-               if (_E_gnutls_openpgp_cert2gnutls_cert == NULL) {
+               if (_E_gnutls_openpgp_cert2gnutls_cert==NULL) {
                        gnutls_assert();
                        return GNUTLS_E_INIT_LIBEXTRA;
                }
                ret =
                    _E_gnutls_openpgp_cert2gnutls_cert(&peer_cert,
-                                                      &info->
-                                                      raw_certificate_list
-                                                      [0]);
+                                                    info->
+                                                    raw_certificate_list
+                                                    [0]);
                break;
        default:
                gnutls_assert();
@@ -1139,17 +1190,16 @@ 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_free_cert(peer_cert);
                return ret;
        }
-       _gnutls_free_cert(&peer_cert);
+       _gnutls_free_cert(peer_cert);
 
        return 0;
 }
 
 #define CERTTYPE_SIZE 3
-int _gnutls_gen_cert_server_cert_req(gnutls_session session,
-                                    opaque ** data)
+int _gnutls_gen_cert_server_cert_req(gnutls_session session, opaque ** data)
 {
        const gnutls_certificate_credentials cred;
        int size;
@@ -1161,7 +1211,8 @@ int _gnutls_gen_cert_server_cert_req(gnutls_session session,
         */
 
        cred =
-           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE,
+                            NULL);
        if (cred == NULL) {
                gnutls_assert();
                return GNUTLS_E_INSUFICIENT_CREDENTIALS;
@@ -1170,8 +1221,7 @@ int _gnutls_gen_cert_server_cert_req(gnutls_session session,
        size = CERTTYPE_SIZE + 2;       /* 2 for gnutls_certificate_type + 2 for size of rdn_seq 
                                         */
 
-       if (session->security_parameters.cert_type == GNUTLS_CRT_X509 &&
-               session->internals.ignore_rdn_sequence == 0)
+       if (session->security_parameters.cert_type == GNUTLS_CRT_X509)
                size += cred->x509_rdn_sequence.size;
 
        (*data) = gnutls_malloc(size);
@@ -1188,8 +1238,7 @@ int _gnutls_gen_cert_server_cert_req(gnutls_session session,
        pdata[2] = DSA_SIGN;    /* only these for now */
        pdata += CERTTYPE_SIZE;
 
-       if (session->security_parameters.cert_type == GNUTLS_CRT_X509 &&
-               session->internals.ignore_rdn_sequence == 0) {
+       if (session->security_parameters.cert_type == GNUTLS_CRT_X509) {
                _gnutls_write_datum16(pdata, cred->x509_rdn_sequence);
                pdata += cred->x509_rdn_sequence.size + 2;
        }
@@ -1201,15 +1250,16 @@ int _gnutls_gen_cert_server_cert_req(gnutls_session session,
 /* This function will return the appropriate certificate to use. The return
  * value depends on the side (client or server).
  */
-int _gnutls_find_apr_cert(gnutls_session session,
-                         gnutls_cert ** apr_cert_list,
+int _gnutls_find_apr_cert(gnutls_session session, gnutls_cert ** apr_cert_list,
                          int *apr_cert_list_length,
                          gnutls_private_key ** apr_pkey)
 {
        const gnutls_certificate_credentials cred;
        int ind;
 
-       cred = _gnutls_get_kx_cred(session, GNUTLS_CRD_CERTIFICATE, NULL);
+       cred =
+           _gnutls_get_kx_cred(session, GNUTLS_CRD_CERTIFICATE,
+                               NULL);
 
        if (cred == NULL) {
                gnutls_assert();
@@ -1280,19 +1330,20 @@ int _gnutls_find_apr_cert(gnutls_session session,
  * (frontend to _gnutls_server_find_cert_index())
  */
 const gnutls_cert *_gnutls_server_find_cert(gnutls_session session,
-                                           gnutls_pk_algorithm
-                                           requested_algo)
+                                           gnutls_pk_algorithm requested_algo)
 {
        int i;
        const gnutls_certificate_credentials x509_cred;
 
        x509_cred =
-           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE,
+                            NULL);
 
        if (x509_cred == NULL)
                return NULL;
 
-       i = _gnutls_server_find_cert_list_index(session, requested_algo);
+       i = _gnutls_server_find_cert_list_index(session,
+                                               requested_algo);
 
        if (i < 0)
                return NULL;
@@ -1307,8 +1358,7 @@ const gnutls_cert *_gnutls_server_find_cert(gnutls_session session,
  * or -1 for any).
  */
 static int _gnutls_server_find_cert_list_index(gnutls_session session,
-                                              gnutls_pk_algorithm
-                                              requested_algo)
+                                       gnutls_pk_algorithm requested_algo)
 {
        uint i, j;
        int index = -1;
@@ -1317,7 +1367,8 @@ static int _gnutls_server_find_cert_list_index(gnutls_session session,
        int *ij_map = NULL;
 
        cred =
-           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+           _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE,
+                            NULL);
        if (cred == NULL) {
                gnutls_assert();
                return GNUTLS_E_INSUFICIENT_CREDENTIALS;
@@ -1327,7 +1378,7 @@ static int _gnutls_server_find_cert_list_index(gnutls_session session,
 
        for (i = 0; i < cred->ncerts; i++) {
                /* find one compatible certificate */
-               if (requested_algo == (gnutls_pk_algorithm) - 1 ||
+               if (requested_algo == (gnutls_pk_algorithm)-1 ||
                    requested_algo ==
                    cred->cert_list[i][0].subject_pk_algorithm) {
                        /* if cert type matches */
@@ -1340,9 +1391,7 @@ static int _gnutls_server_find_cert_list_index(gnutls_session session,
 
        }
 
-       if (session->internals.server_cert_callback != NULL && cred->ncerts > 0) {      
-               /* use the callback to get certificate 
-                */
+       if (session->internals.server_cert_callback != NULL && cred->ncerts > 0) {      /* use the callback to get certificate */
                gnutls_datum *my_certs = NULL;
 
                my_certs =
@@ -1358,13 +1407,12 @@ static int _gnutls_server_find_cert_list_index(gnutls_session session,
                j = 0;
                for (i = 0; i < cred->ncerts; i++) {
                        /* Add compatible certificates */
-                       if (requested_algo == (gnutls_pk_algorithm) - 1 ||
+                       if (requested_algo == (gnutls_pk_algorithm)-1 ||
                            requested_algo ==
                            cred->cert_list[i][0].subject_pk_algorithm) {
 
                                /* if cert type matches */
-                               if (session->security_parameters.
-                                   cert_type ==
+                               if (session->security_parameters.cert_type ==
                                    cred->cert_list[i][0].cert_type) {
 
                                        ij_map[j] = i;
@@ -1377,8 +1425,8 @@ static int _gnutls_server_find_cert_list_index(gnutls_session session,
 
                index =
                    session->internals.server_cert_callback(session,
-                                                           my_certs,
-                                                           my_certs_length);
+                                                                my_certs,
+                                                                my_certs_length);
 
                if (index != -1)
                        index = ij_map[index];
index 395b5019c61accc7fecff8f6f9b9478d700fa7c5..40558206b3db13a5eb19f0399f15b1dc1d37340b 100644 (file)
@@ -356,17 +356,34 @@ int _gnutls_send_client_certificate( gnutls_session session, int again)
        data_size = 0;
 
        if (again == 0) {
-               data_size = session->internals.auth_struct->gnutls_generate_client_certificate( session, &data);
+               if (gnutls_protocol_get_version( session) != GNUTLS_SSL3 ||
+                       session->internals.selected_cert_index >= 0) {
+                       /* TLS 1.0 or SSL 3.0 with a valid certificate
+                        */
+                       data_size = session->internals.auth_struct->gnutls_generate_client_certificate( session, &data);
 
-               if (data_size < 0) {
-                       gnutls_assert();
-                       return data_size;
+                       if (data_size < 0) {
+                               gnutls_assert();
+                               return data_size;
+                       }
                }
        }
-       ret = _gnutls_send_handshake( session, data, data_size, GNUTLS_CERTIFICATE_PKT);
-       gnutls_free(data);
+
+       /* In the SSL 3.0 protocol we need to send a
+        * no certificate alert instead of an
+        * empty certificate.
+        */
+       if (gnutls_protocol_get_version( session) == GNUTLS_SSL3 &&
+               session->internals.selected_cert_index < 0)
+       {
+               ret = gnutls_alert_send( session, GNUTLS_AL_WARNING, GNUTLS_A_SSL3_NO_CERTIFICATE);
+       } else { /* TLS 1.0 or SSL 3.0 with a valid certificate
+                 */
+               ret = _gnutls_send_handshake( session, data, data_size, GNUTLS_CERTIFICATE_PKT);
+               gnutls_free(data);
+       }
        
-       if (ret<0) {
+       if (ret < 0) {
                gnutls_assert();
                return ret;
        }