]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
additions in order for gnutls server to support client authentication
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Tue, 7 Aug 2001 12:16:24 +0000 (12:16 +0000)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Tue, 7 Aug 2001 12:16:24 +0000 (12:16 +0000)
15 files changed:
doc/TODO
lib/auth_anon.c
lib/auth_rsa.c
lib/auth_srp.c
lib/auth_x509.h
lib/gnutls.h.in
lib/gnutls_auth.h
lib/gnutls_cert.c
lib/gnutls_errors.c
lib/gnutls_errors_int.h
lib/gnutls_handshake.c
lib/gnutls_int.h
lib/gnutls_kx.c
lib/gnutls_kx.h
src/serv.c

index 3c7610a804c0aed23ed7f6ebeafdb0347c0a35d9..8e1ce52f342b6ef6ebfb4ab4f7d1845a3dac2503 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -1,5 +1,3 @@
-* Add Client Certificate support in X509 authentication
-* Use the KeyUsage X509v3 extension to disable algorithms 
 * Add DHE_* ciphersuites
 * Tools for processing/generating certificates (fabio.fiorina@alcatel.it is working on that)
 * Documentation (of existing functions + Manual)
index 1b510bbef1df125c837f2b9e3b99f723dd780047..f0977b07f1758eeb9403843dd045e872050cb70b 100644 (file)
@@ -36,6 +36,7 @@ int proc_anon_client_kx( GNUTLS_STATE, opaque*, int);
 MOD_AUTH_STRUCT anon_auth_struct = {
        "ANON",
        NULL,
+       NULL,
        gen_anon_server_kx,
        NULL,
        NULL,
@@ -43,6 +44,7 @@ MOD_AUTH_STRUCT anon_auth_struct = {
        NULL,
        NULL,
 
+       NULL,
        NULL, /* certificate */
        proc_anon_server_kx,
        NULL,
index 69e6e4689ff1d61d195065d85b38f10142116b94..d5876d42b3c5f566ed3dad44860d459f7942e040 100644 (file)
 #include "debug.h"
 #include <gnutls_sig.h>
 
-int gen_rsa_certificate(GNUTLS_STATE, opaque **);
+int gen_rsa_server_certificate(GNUTLS_STATE, opaque **);
+int gen_rsa_client_certificate(GNUTLS_STATE, opaque **);
 int gen_rsa_client_cert_vrfy(GNUTLS_STATE, opaque **);
 int proc_rsa_cert_req(GNUTLS_STATE, opaque *, int);
 int gen_rsa_client_kx(GNUTLS_STATE, opaque **);
+int gen_rsa_server_cert_req(GNUTLS_STATE, opaque **);
 int proc_rsa_client_kx(GNUTLS_STATE, opaque *, int);
-int proc_rsa_certificate(GNUTLS_STATE, opaque *, int);
+int proc_rsa_client_cert_vrfy(GNUTLS_STATE, opaque *, int);
+
+int proc_rsa_server_certificate(GNUTLS_STATE, opaque *, int);
+#define proc_rsa_client_certificate proc_rsa_server_certificate
 
 MOD_AUTH_STRUCT rsa_auth_struct =
 {
        "RSA",
-       gen_rsa_certificate,
+       gen_rsa_server_certificate,
+       gen_rsa_client_certificate,
        NULL,                   /* gen server kx */
        NULL,                   /* gen server kx2 */
        NULL,                   /* gen client kx0 */
        gen_rsa_client_kx,
        gen_rsa_client_cert_vrfy, /* gen client cert vrfy */
-       NULL,
+       gen_rsa_server_cert_req, /* server cert request */
 
-       proc_rsa_certificate,
+       proc_rsa_server_certificate,
+       proc_rsa_client_certificate,
        NULL,                   /* proc server kx */
        NULL,                   /* proc server kx2 */
        NULL,                   /* proc client kx0 */
        proc_rsa_client_kx,     /* proc client kx */
-       NULL,                   /* proc client cert vrfy */
+       proc_rsa_client_cert_vrfy, /* proc client cert vrfy */
        proc_rsa_cert_req       /* proc server cert request */
 };
 
@@ -214,7 +221,76 @@ static int _gnutls_get_private_rsa_params(GNUTLS_KEY key,
 }
 
 
-int gen_rsa_certificate(GNUTLS_STATE state, opaque ** data)
+int gen_rsa_client_certificate(GNUTLS_STATE state, opaque ** data)
+{
+       const X509PKI_CREDENTIALS cred;
+       int ret, i, ind, pdatasize;
+       opaque *pdata;
+       gnutls_cert *apr_cert_list;
+       gnutls_private_key *apr_pkey;
+       int apr_cert_list_length;
+
+       cred = _gnutls_get_cred(state->gnutls_key, GNUTLS_X509PKI, NULL);
+       if (cred == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INSUFICIENT_CRED;
+       }
+       if (cred->ncerts == 0) {
+               apr_cert_list = NULL;
+               apr_cert_list_length = 0;
+               apr_pkey = NULL;
+       } else {
+               ind = state->gnutls_internals.client_certificate_index;
+
+               if (ind < 0) {
+                       apr_cert_list = NULL;
+                       apr_cert_list_length = 0;
+                       apr_pkey = NULL;
+               } else {
+                       apr_cert_list = cred->cert_list[ind];
+                       apr_cert_list_length = cred->cert_list_length[ind];
+                       apr_pkey = &cred->pkey[ind];
+               }
+       }
+
+       ret = 3;
+       for (i = 0; i < apr_cert_list_length; i++) {
+               ret += apr_cert_list[i].raw.size + 3;
+               /* hold size
+                * for uint24 */
+       }
+
+       (*data) = gnutls_malloc(ret);
+       pdata = (*data);
+
+       if (pdata == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+       WRITEuint24(ret - 3, pdata);
+       pdata += 3;
+       for (i = 0; i < apr_cert_list_length; i++) {
+               WRITEdatum24(pdata, apr_cert_list[i].raw);
+               pdata += (3 + apr_cert_list[i].raw.size);
+       }
+       pdatasize = ret;
+
+       /* read the rsa parameters now, since later we will
+        * not know which certificate we used!
+        */
+       if (i != 0)             /* if we parsed at least one certificate */
+               ret = _gnutls_get_private_rsa_params(state->gnutls_key, apr_pkey);
+       else
+               ret = 0;
+
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+       return pdatasize;
+}
+
+int gen_rsa_server_certificate(GNUTLS_STATE state, opaque ** data)
 {
        const X509PKI_CREDENTIALS cred;
        int ret, i, ind, pdatasize;
@@ -233,10 +309,7 @@ int gen_rsa_certificate(GNUTLS_STATE state, opaque ** data)
                apr_cert_list_length = 0;
                apr_pkey = NULL;
        } else {
-               if (state->security_parameters.entity == GNUTLS_CLIENT)
-                       ind = state->gnutls_internals.client_certificate_index;
-               else /* server */
-                       ind = _gnutls_find_cert_list_index(cred->cert_list, cred->ncerts, state->security_parameters.extensions.dnsname);
+               ind = _gnutls_find_cert_list_index(cred->cert_list, cred->ncerts, state->security_parameters.extensions.dnsname);
 
                if (ind < 0) {
                        apr_cert_list = NULL;
@@ -356,7 +429,7 @@ return ret;
 }
 
 
-int proc_rsa_certificate(GNUTLS_STATE state, opaque * data, int data_size)
+int proc_rsa_server_certificate(GNUTLS_STATE state, opaque * data, int data_size)
 {
        int size, len, ret;
        opaque *p = data;
@@ -369,7 +442,6 @@ int proc_rsa_certificate(GNUTLS_STATE state, opaque * data, int data_size)
        gnutls_datum tmp;
        CertificateStatus verify;
 
-#warning "NO SERVER SIDE YET"
        cred = _gnutls_get_cred(state->gnutls_key, GNUTLS_X509PKI, NULL);
        if (cred == NULL) {
                gnutls_assert();
@@ -389,7 +461,7 @@ int proc_rsa_certificate(GNUTLS_STATE state, opaque * data, int data_size)
 
        if (size == 0) {
                gnutls_assert();
-               return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+               return GNUTLS_E_NO_CERTIFICATE_FOUND;
        }
        info = state->gnutls_key->auth_info;
        i = dsize;
@@ -471,6 +543,7 @@ int proc_rsa_certificate(GNUTLS_STATE state, opaque * data, int data_size)
        return 0;
 }
 
+
 /* return RSA(random) using the peers public key 
  */
 int gen_rsa_client_kx(GNUTLS_STATE state, opaque ** data)
@@ -524,16 +597,52 @@ int gen_rsa_client_kx(GNUTLS_STATE state, opaque ** data)
 
 }
 
+int _gnutls_find_dn( gnutls_datum* odn, gnutls_cert* cert) {
+node_asn* dn;
+int len, result;
+int start, end;
+
+       if (asn1_create_structure(_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &dn, "dn") != ASN_OK) {
+               gnutls_assert();
+               return GNUTLS_E_ASN1_ERROR;
+       }
+
+       result = asn1_get_der( dn, cert->raw.data, cert->raw.size);
+       if (result != ASN_OK) {
+               /* couldn't decode DER */
+               gnutls_assert();
+               asn1_delete_structure( dn);
+               return GNUTLS_E_ASN1_PARSING_ERROR;
+       }
+                               
+       result = asn1_get_start_end_der( dn, cert->raw.data, cert->raw.size,
+               "dn.tbsCertificate.issuer", &start, &end);
+                                               
+       if (result != ASN_OK) {
+               /* couldn't decode DER */
+               gnutls_assert();
+               asn1_delete_structure( dn);
+               return GNUTLS_E_ASN1_PARSING_ERROR;
+       }
+       asn1_delete_structure( dn);
+
+       len = end - start + 1;
+
+       odn->size = len;
+       odn->data = &cert->raw.data[start];
+
+       return 0;
+}
+
 /* Finds the appropriate certificate depending on the cA Distinguished name
  * advertized by the server
  */
 static int _gnutls_find_acceptable_client_cert( const X509PKI_CREDENTIALS cred, const opaque* data, 
        int data_size, int *ind) {
-node_asn *dn;
 int result, size;
 int indx = -1;
-int start, end, len, i, j;
-
+int i, j;
+gnutls_datum odn;
 
        do {
 
@@ -544,37 +653,16 @@ int start, end, len, i, j;
                for(i=0;i<cred->ncerts;i++) {
                        
                        for (j=0;j<cred->cert_list_length[i];j++) {
-                               if (asn1_create_structure(_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &dn, "dn") != ASN_OK) {
+                               if ( (result=_gnutls_find_dn( &odn, &cred->cert_list[i][j])) < 0) {
                                        gnutls_assert();
-                                       return GNUTLS_E_ASN1_ERROR;
-                               }
-
-                               result = asn1_get_der( dn, cred->cert_list[i][j].raw.data, cred->cert_list[i][j].raw.size);
-                               if (result != ASN_OK) {
-                                       /* couldn't decode DER */
-                                       gnutls_assert();
-                                       asn1_delete_structure( dn);
-                                       return GNUTLS_E_ASN1_PARSING_ERROR;
+                                       return result;
                                }
                                
-                               result = asn1_get_start_end_der( dn, cred->cert_list[i][j].raw.data, cred->cert_list[i][j].raw.size,
-                                               "dn.tbsCertificate.issuer", &start, &end);
-                                               
-                               if (result != ASN_OK) {
-                                       /* couldn't decode DER */
-                                       gnutls_assert();
-                                       asn1_delete_structure( dn);
-                                       return GNUTLS_E_ASN1_PARSING_ERROR;
-                               }
-                               asn1_delete_structure( dn);
-
-                               len = end - start + 1;
-
-                               if ( len != size) continue;
+                               if ( odn.size != size) continue;
                        
                                if (memcmp( 
-                                       &cred->cert_list[i][j].raw.data[start],
-                                       data, len) == 0 ) {
+                                       odn.data,
+                                       data, size) == 0 ) {
                                        indx = i;
                                        break;
                                }
@@ -728,3 +816,66 @@ int gen_rsa_client_cert_vrfy(GNUTLS_STATE state, opaque ** data)
 
        return size+2;
 }
+
+int proc_rsa_client_cert_vrfy(GNUTLS_STATE state, opaque * data, int data_size)
+{
+       #warning "CHECK THE CERT VERIFY MESSAGE"
+       
+       return 0;
+}
+
+#define CERTTYPE_SIZE 2
+int gen_rsa_server_cert_req(GNUTLS_STATE state, opaque ** data)
+{
+       const X509PKI_CREDENTIALS cred;
+       int ret, i, size;
+       opaque *pdata;
+       gnutls_datum dn;
+
+       cred = _gnutls_get_cred(state->gnutls_key, GNUTLS_X509PKI, NULL);
+       if (cred == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INSUFICIENT_CRED;
+       }
+       
+       size = CERTTYPE_SIZE+2; /* 2 for CertType + 2 for size */
+       
+       for (i = 0; i < cred->ncas; i++) {
+               size += cred->ca_list[i].raw.size + 2;
+               /* hold size
+                * for uint16 */
+       }
+
+       (*data) = gnutls_malloc(size);
+       pdata = (*data);
+
+       if (pdata == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+
+       pdata[0] = CERTTYPE_SIZE - 1;
+       pdata[1] = RSA_SIGN; /* only this for now */
+       pdata += CERTTYPE_SIZE;
+       size = CERTTYPE_SIZE;
+
+       /* leave space to write the actual size */
+       pdata += 2;
+       size += 2;
+
+       for (i = 0; i < cred->ncas; i++) {
+               if ( (ret=_gnutls_find_dn( &dn, &cred->ca_list[i])) < 0) {
+                       gnutls_free( (*data));
+                       gnutls_assert();
+                       return ret;
+               }
+               WRITEdatum16(pdata, dn);
+               pdata += (2 + dn.size);
+               size += (2 + dn.size);
+       }
+
+       /* write the recalculated size */
+       WRITEuint16( size-CERTTYPE_SIZE-2, &(*data)[CERTTYPE_SIZE]);
+       
+       return size;
+}
index 8497c4d9abcb092cc153500d557b861722938518..08fafd9daeb908383c24aa93a9f313394f8fe1e8 100644 (file)
@@ -38,12 +38,14 @@ MOD_AUTH_STRUCT srp_auth_struct = {
        "SRP",
        NULL,
        NULL,
+       NULL,
        gen_srp_server_kx2,
        gen_srp_client_kx0,
        NULL,
        NULL,
        NULL,
 
+       NULL,
        NULL, /* certificate */
        NULL,
        proc_srp_server_kx2,
index cc3bdc6d14f2483661015e3574ca81dd20d56a5a..d584000c85e7705f70488f2bde97db69c1a8909a 100644 (file)
@@ -44,6 +44,7 @@ typedef struct X509PKI_CLIENT_AUTH_INFO_INT {
 } *X509PKI_CLIENT_AUTH_INFO;
 
 typedef struct X509PKI_CLIENT_AUTH_INFO_INT X509PKI_CLIENT_AUTH_INFO_INT;
+typedef X509PKI_CLIENT_AUTH_INFO X509PKI_SERVER_AUTH_INFO;
 
 void _gnutls_copy_x509_client_auth_info( X509PKI_CLIENT_AUTH_INFO info, gnutls_cert* cert, CertificateStatus verify);
 
index 55891e2f4fe8ea40f614b8d2ca27dcfee9bc4cd5..4ea10a2bd9c0a8dd7bdcd5d00bb4f310f594d68f 100644 (file)
@@ -28,17 +28,21 @@ typedef enum CredType { GNUTLS_X509PKI=1, GNUTLS_ANON, GNUTLS_SRP } CredType;
 typedef enum MACAlgorithm { GNUTLS_NULL_MAC=1, GNUTLS_MAC_MD5, GNUTLS_MAC_SHA } MACAlgorithm;
 typedef enum CompressionMethod { GNUTLS_NULL_COMPRESSION=1, GNUTLS_ZLIB } CompressionMethod;
 typedef enum ConnectionEnd { GNUTLS_SERVER=1, GNUTLS_CLIENT } ConnectionEnd;
+typedef enum AlertLevel { GNUTLS_WARNING=1, GNUTLS_FATAL } AlertLevel;
 typedef enum AlertDescription { GNUTLS_CLOSE_NOTIFY, GNUTLS_UNEXPECTED_MESSAGE=10, GNUTLS_BAD_RECORD_MAC=20,
                        GNUTLS_DECRYPTION_FAILED, GNUTLS_RECORD_OVERFLOW,  GNUTLS_DECOMPRESSION_FAILURE=30,
-                       GNUTLS_HANDSHAKE_FAILURE=40, GNUTLS_BAD_CERTIFICATE=42, GNUTLS_UNSUPPORTED_CERTIFICATE,
+                       GNUTLS_HANDSHAKE_FAILURE=40, GNUTLS_NETSCAPE_NO_CLIENT_CERTIFICATE=41,
+                       GNUTLS_BAD_CERTIFICATE=42, GNUTLS_UNSUPPORTED_CERTIFICATE,
                        GNUTLS_CERTIFICATE_REVOKED, GNUTLS_CERTIFICATE_EXPIRED, GNUTLS_CERTIFICATE_UNKNOWN,
                        GNUTLS_ILLEGAL_PARAMETER, GNUTLS_UNKNOWN_CA, GNUTLS_ACCESS_DENIED, GNUTLS_DECODE_ERROR=50,
                        GNUTLS_DECRYPT_ERROR, GNUTLS_EXPORT_RESTRICTION=60, GNUTLS_PROTOCOL_VERSION=70,
                        GNUTLS_INSUFFICIENT_SECURITY, GNUTLS_INTERNAL_ERROR=80, GNUTLS_USER_CANCELED=90,
                        GNUTLS_NO_RENEGOTIATION=100
                        } AlertDescription;
-typedef enum AlertLevel { GNUTLS_WARNING=1, GNUTLS_FATAL } AlertLevel;
+
+
 typedef enum CertificateStatus { GNUTLS_CERT_TRUSTED=1, GNUTLS_CERT_NOT_TRUSTED, GNUTLS_CERT_EXPIRED, GNUTLS_CERT_INVALID } CertificateStatus;
+typedef enum CertificateRequest { GNUTLS_CERT_REQUEST=1, GNUTLS_CERT_REQUIRE } CertificateRequest;
 
 typedef enum GNUTLS_Version { GNUTLS_SSL3=1, GNUTLS_TLS1 } GNUTLS_Version;
 
@@ -105,7 +109,7 @@ int gnutls_set_mac_priority( GNUTLS_STATE state, LIST);
 int gnutls_set_compression_priority( GNUTLS_STATE state, LIST);
 int gnutls_set_kx_priority( GNUTLS_STATE state, LIST);
 int gnutls_set_protocol_priority( GNUTLS_STATE state, LIST);
-
+int gnutls_set_certificate_request( GNUTLS_STATE, CertificateRequest);
 
 /* set our version - 0 for TLS 1.0 and 1 for SSL3 */
 GNUTLS_Version gnutls_get_current_version(GNUTLS_STATE state);
@@ -211,6 +215,8 @@ void gnutls_global_set_recv_func( RECV_FUNC recv_func);
 /* Auth_Info structures */
 
 typedef struct X509PKI_CLIENT_AUTH_INFO_INT *X509PKI_CLIENT_AUTH_INFO;
+typedef X509PKI_CLIENT_AUTH_INFO X509PKI_SERVER_AUTH_INFO;
+
 typedef struct SRP_CLIENT_AUTH_INFO_INT *SRP_CLIENT_AUTH_INFO;
 typedef struct SRP_SERVER_AUTH_INFO_INT *SRP_SERVER_AUTH_INFO;
 typedef struct ANON_CLIENT_AUTH_INFO_INT *ANON_CLIENT_AUTH_INFO;
index 8017c50eb8f6acee0622d921b4607f33391b1740..2a9442ce53d87816942732fdf279ebd9c4b13abd 100644 (file)
@@ -3,7 +3,8 @@
 
 typedef struct MOD_AUTH_STRUCT_INT {
        char* name; /* null terminated */
-       int (*gnutls_generate_certificate)( GNUTLS_STATE, opaque**);
+       int (*gnutls_generate_server_certificate)( GNUTLS_STATE, opaque**);
+       int (*gnutls_generate_client_certificate)( GNUTLS_STATE, opaque**);
        int (*gnutls_generate_server_kx)( GNUTLS_STATE, opaque**);
        int (*gnutls_generate_server_kx2)( GNUTLS_STATE, opaque**); /* used in SRP */
        int (*gnutls_generate_client_kx0)( GNUTLS_STATE, opaque**);
@@ -11,7 +12,8 @@ typedef struct MOD_AUTH_STRUCT_INT {
        int (*gnutls_generate_client_cert_vrfy) ( GNUTLS_STATE, opaque**);
        int (*gnutls_generate_server_certificate_request) ( GNUTLS_STATE, opaque**);
        
-       int (*gnutls_process_certificate)( GNUTLS_STATE, opaque*, int);
+       int (*gnutls_process_server_certificate)( GNUTLS_STATE, opaque*, int);
+       int (*gnutls_process_client_certificate)( GNUTLS_STATE, opaque*, int);
        int (*gnutls_process_server_kx)( GNUTLS_STATE, opaque*, int);
        int (*gnutls_process_server_kx2)( GNUTLS_STATE, opaque*, int);
        int (*gnutls_process_client_kx0)( GNUTLS_STATE, opaque*, int);
index 6f3b74f58c649ef02a57da4e6347639092cd77e3..f87139eac35c27c6731adb544585e0744643a257 100644 (file)
@@ -900,3 +900,19 @@ int _gnutls_find_cert_list_index(gnutls_cert ** cert_list,
        return index;
 }
 
+/**
+  * gnutls_set_certificate_request - Used to set whether to request a client certificate
+  * @state: is an &GNUTLS_STATE structure.
+  * @req: is one of GNUTLS_CERT_REQUEST, GNUTLS_CERT_REQUIRE
+  *
+  * This function specifies if we (in case of a server) are going
+  * to send a certificate request message to the client. If 'req'
+  * is GNUTLS_CERT_REQUIRE then the server will return an error if
+  * the peer does not provide a certificate. If you do not
+  * call this function then the client will not be asked to
+  * send a certificate.
+  **/
+int gnutls_set_certificate_request( GNUTLS_STATE state, CertificateRequest req) {
+       state->gnutls_internals.send_cert_req = req;
+       return 0;
+}
index 6e2289bfa9d337ab1cb296402201d5e4214b6b35..3e8dafa7050452d01a93e3effc06886a53372dbc 100644 (file)
@@ -74,6 +74,7 @@ static gnutls_error_entry error_algorithms[] = {
        GNUTLS_ERROR_ENTRY( GNUTLS_E_HASH_FAILED, 1),
        GNUTLS_ERROR_ENTRY( GNUTLS_E_PARSING_ERROR, 1),
        GNUTLS_ERROR_ENTRY( GNUTLS_E_AUTH_FAILED, 1),
+       GNUTLS_ERROR_ENTRY( GNUTLS_E_NO_CERTIFICATE_FOUND, 1),
        GNUTLS_ERROR_ENTRY( GNUTLS_E_RECORD_LIMIT_REACHED, 1),
        GNUTLS_ERROR_ENTRY( GNUTLS_E_ASN1_PARSING_ERROR, 1),
        GNUTLS_ERROR_ENTRY( GNUTLS_E_ASN1_ERROR, 1),
index 066ea2c839e7f482a343772efb0c4edaabc3811e..5eaeaf2ad3d0f08395b7bf985af20b847e12c18f 100644 (file)
@@ -50,5 +50,6 @@
 #define GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION -47
 #define GNUTLS_E_X509_KEY_USAGE_VIOLATION -48
 #define GNUTLS_E_PKCS1_WRONG_PAD -48
+#define GNUTLS_E_NO_CERTIFICATE_FOUND -49
 
 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -250
index 6cbf35a114933facd18126c65a403f61bac97624..2f425202f75b281ecaa11dbb6810df5655e2a130 100644 (file)
@@ -712,6 +712,8 @@ int _gnutls_recv_handshake(SOCKET cd, GNUTLS_STATE state, uint8 ** data,
        if (ret < 0) {
                if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET && optional==OPTIONAL_PACKET) {
                        gnutls_assert();
+                       *datalen = 0;
+                       *data = NULL;
                        return 0; /* ok just ignore the packet */
                }
                gnutls_assert();
@@ -722,7 +724,8 @@ int _gnutls_recv_handshake(SOCKET cd, GNUTLS_STATE state, uint8 ** data,
 
        if (length32 > 0)
                dataptr = gnutls_malloc(length32);
-
+       else
+fprintf(stderr, "recv_type: %d\nLenght: %d\n", recv_type, length32);
                
        if (dataptr == NULL) {
                gnutls_assert();
@@ -1292,7 +1295,7 @@ int gnutls_handshake_begin(SOCKET cd, GNUTLS_STATE state) {
 
                /* RECV CERTIFICATE */
                if (state->gnutls_internals.resumed == RESUME_FALSE)    /* if we are not resuming */
-                       ret = _gnutls_recv_certificate(cd, state);
+                       ret = _gnutls_recv_server_certificate(cd, state);
                if (ret < 0) {
                        gnutls_assert();
                        ERR("recv server certificate", ret);
@@ -1323,7 +1326,7 @@ int gnutls_handshake_begin(SOCKET cd, GNUTLS_STATE state) {
                /* SEND CERTIFICATE + KEYEXCHANGE + CERTIFICATE_REQUEST */
 
                if (state->gnutls_internals.resumed == RESUME_FALSE)
-                       ret = _gnutls_send_certificate(cd, state);
+                       ret = _gnutls_send_server_certificate(cd, state);
                if (ret < 0) {
                        ERR("send server certificate", ret);
                        gnutls_assert();
@@ -1339,7 +1342,16 @@ int gnutls_handshake_begin(SOCKET cd, GNUTLS_STATE state) {
                        gnutls_clearHashDataBuffer(state);
                        return ret;
                }
-               /* FIXME: Send certificate request */
+
+               /* Send certificate request - if requested to */
+               if (state->gnutls_internals.resumed == RESUME_FALSE)
+                       ret = _gnutls_send_server_certificate_request(cd, state);
+               if (ret < 0) {
+                       ERR("send server cert request", ret);
+                       gnutls_assert();
+                       gnutls_clearHashDataBuffer(state);
+                       return ret;
+               }
 
 /* Added for SRP which uses a different handshake */
                /* receive the client key exchange message */
@@ -1351,6 +1363,7 @@ int gnutls_handshake_begin(SOCKET cd, GNUTLS_STATE state) {
                        gnutls_clearHashDataBuffer(state);
                        return ret;
                }
+
                /* send server key exchange (B) */
                if (state->gnutls_internals.resumed == RESUME_FALSE)
                        ret = _gnutls_send_server_kx_message2(cd, state);
@@ -1554,6 +1567,16 @@ int gnutls_handshake_finish(SOCKET cd, GNUTLS_STATE state) {
                }
                /* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */
 
+               /* receive the client certificate message */
+               if (state->gnutls_internals.resumed == RESUME_FALSE)    /* if we are not resuming */
+                       ret = _gnutls_recv_client_certificate(cd, state);
+               if (ret < 0) {
+                       gnutls_assert();
+                       ERR("recv client certificate", ret);
+                       gnutls_clearHashDataBuffer(state);
+                       return ret;
+               }
+
                /* receive the client key exchange message */
                if (state->gnutls_internals.resumed == RESUME_FALSE)    /* if we are not resuming */
                        ret = _gnutls_recv_client_kx_message(cd, state);
@@ -1563,6 +1586,16 @@ int gnutls_handshake_finish(SOCKET cd, GNUTLS_STATE state) {
                        gnutls_clearHashDataBuffer(state);
                        return ret;
                }
+
+               /* receive the client certificate verify message */
+               if (state->gnutls_internals.resumed == RESUME_FALSE)    /* if we are not resuming */
+                       ret = _gnutls_recv_client_certificate_verify_message(cd, state);
+               if (ret < 0) {
+                       gnutls_assert();
+                       ERR("recv client certificate verify", ret);
+                       gnutls_clearHashDataBuffer(state);
+                       return ret;
+               }
        }
 
        /* send and recv the change cipher spec and finished messages */
index 7fc8242ff591598f2424af7c18fbe421326359b7..315078cec234408d88f9a681fed74da1ac84dbc4 100644 (file)
@@ -81,7 +81,8 @@ typedef enum ChangeCipherSpecType { GNUTLS_TYPE_CHANGE_CIPHER_SPEC=1 } ChangeCip
 typedef enum AlertLevel { GNUTLS_WARNING=1, GNUTLS_FATAL } AlertLevel;
 typedef enum AlertDescription { GNUTLS_CLOSE_NOTIFY, GNUTLS_UNEXPECTED_MESSAGE=10, GNUTLS_BAD_RECORD_MAC=20,
                        GNUTLS_DECRYPTION_FAILED, GNUTLS_RECORD_OVERFLOW,  GNUTLS_DECOMPRESSION_FAILURE=30,
-                       GNUTLS_HANDSHAKE_FAILURE=40, GNUTLS_BAD_CERTIFICATE=42, GNUTLS_UNSUPPORTED_CERTIFICATE,
+                       GNUTLS_HANDSHAKE_FAILURE=40, GNUTLS_NETSCAPE_NO_CLIENT_CERTIFICATE=41,
+                       GNUTLS_BAD_CERTIFICATE=42, GNUTLS_UNSUPPORTED_CERTIFICATE,
                        GNUTLS_CERTIFICATE_REVOKED, GNUTLS_CERTIFICATE_EXPIRED, GNUTLS_CERTIFICATE_UNKNOWN,
                        GNUTLS_ILLEGAL_PARAMETER, GNUTLS_UNKNOWN_CA, GNUTLS_ACCESS_DENIED, GNUTLS_DECODE_ERROR=50,
                        GNUTLS_DECRYPT_ERROR, GNUTLS_EXPORT_RESTRICTION=60, GNUTLS_PROTOCOL_VERSION=70,
@@ -89,6 +90,7 @@ typedef enum AlertDescription { GNUTLS_CLOSE_NOTIFY, GNUTLS_UNEXPECTED_MESSAGE=1
                        GNUTLS_NO_RENEGOTIATION=100
                        } AlertDescription;
 typedef enum CertificateStatus { GNUTLS_CERT_TRUSTED=1, GNUTLS_CERT_NOT_TRUSTED, GNUTLS_CERT_EXPIRED, GNUTLS_CERT_INVALID } CertificateStatus;
+typedef enum CertificateRequest { GNUTLS_CERT_REQUEST=1, GNUTLS_CERT_REQUIRE } CertificateRequest;
 
 typedef enum HandshakeType { GNUTLS_HELLO_REQUEST, GNUTLS_CLIENT_HELLO, GNUTLS_SERVER_HELLO,
                     GNUTLS_CERTIFICATE=11, GNUTLS_SERVER_KEY_EXCHANGE,
@@ -178,6 +180,9 @@ struct GNUTLS_KEY_INT {
                                         * to provide client authentication.
                                         * 1 if client auth was requested
                                         * by the peer, 0 otherwise
+                                        *** In case of a server this
+                                        * holds 1 if we should wait
+                                        * for a client certificate verify
                                         */
 };
 typedef struct GNUTLS_KEY_INT* GNUTLS_KEY;
@@ -315,10 +320,11 @@ typedef struct {
 
        /* sockets internals */
        int                             lowat;
+
        /* gdbm */
        char*                           db_name;
        int                             expire_time;
-       struct MOD_AUTH_STRUCT_INT*             auth_struct; /* used in handshake packets and KX algorithms */
+       struct MOD_AUTH_STRUCT_INT*     auth_struct; /* used in handshake packets and KX algorithms */
        int                             v2_hello; /* set 0 normally - 1 if v2 hello was received - server side only */
 #ifdef HAVE_LIBGDBM
        GDBM_FILE                       db_reader;
@@ -336,6 +342,12 @@ typedef struct {
         */
        uint8                           adv_version_major;
        uint8                           adv_version_minor;
+
+       /* if this is non zero a certificate request message
+        * will be sent to the client. - only if the ciphersuite
+        * supports it.
+        */
+       int                             send_cert_req;
 } GNUTLS_INTERNALS;
 
 struct GNUTLS_STATE_INT {
index 4e55b35f87e991c479cb8de8cb9459bd934997d7..49786440ddbe9a868c599c21e9e051e66dbc97cb 100644 (file)
 #include "gnutls_algorithms.h"
 #include "debug.h"
 #include "gnutls_gcry.h"
+#include <gnutls_record.h>
+
+/* This file contains important thing for the TLS handshake procedure.
+ */
 
 #define MASTER_SECRET "master secret"
 static int generate_normal_master( GNUTLS_STATE state);
@@ -116,6 +120,43 @@ int _gnutls_send_server_kx_message(SOCKET cd, GNUTLS_STATE state)
        return data_size;
 }
 
+/* This function sends a certificate request message to the
+ * client.
+ */
+int _gnutls_send_server_certificate_request(SOCKET cd, GNUTLS_STATE state)
+{
+       uint8 *data = NULL;
+       int data_size = 0;
+       int ret = 0;
+
+       if (state->gnutls_internals.auth_struct->gnutls_generate_server_certificate_request==NULL) 
+               return 0;
+
+       if (state->gnutls_internals.send_cert_req <= 0)
+               return 0;
+               
+#ifdef HANDSHAKE_DEBUG
+       _gnutls_log( "Sending server Certificate request message\n");
+#endif
+
+
+       data_size = state->gnutls_internals.auth_struct->gnutls_generate_server_certificate_request( state, &data);
+
+       if (data_size < 0) {
+               gnutls_assert();
+               return data_size;
+       }
+
+       ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_CERTIFICATE_REQUEST);
+       gnutls_free(data);
+
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+       return data_size;
+}
+
 /* Currently only used in SRP */
 int _gnutls_send_server_kx_message2(SOCKET cd, GNUTLS_STATE state)
 {
@@ -298,9 +339,11 @@ int _gnutls_recv_server_certificate_request(SOCKET cd, GNUTLS_STATE state)
                    _gnutls_recv_handshake(cd, state, &data,
                                   &datasize,
                                   GNUTLS_CERTIFICATE_REQUEST, OPTIONAL_PACKET);
-               if (ret <= 0)
+               if (ret < 0)
                        return ret;
 
+               if (ret==0 && datasize == 0)
+                       return 0; /* ignored */
                
                ret = state->gnutls_internals.auth_struct->gnutls_process_server_certificate_request( state, data, datasize);
                gnutls_free(data);
@@ -404,21 +447,59 @@ int _gnutls_recv_client_kx_message0(SOCKET cd, GNUTLS_STATE state)
 
 /* This is called when we want send our certificate
  */
-int _gnutls_send_certificate(SOCKET cd, GNUTLS_STATE state)
+int _gnutls_send_client_certificate(SOCKET cd, GNUTLS_STATE state)
+{
+       uint8 *data = NULL;
+       int data_size = 0;
+       int ret = 0;
+
+
+       if (state->gnutls_key->certificate_requested == 0)
+               return 0;
+
+       if (state->gnutls_internals.auth_struct->gnutls_generate_client_certificate==NULL) 
+               return 0;
+
+#ifdef HANDSHAKE_DEBUG
+       _gnutls_log( "Sending client certificate message\n");
+#endif
+
+       data_size = state->gnutls_internals.auth_struct->gnutls_generate_client_certificate( state, &data);
+
+       if (data_size < 0) {
+               gnutls_assert();
+               return data_size;
+       }
+
+       ret = _gnutls_send_handshake(cd, state, data, data_size, GNUTLS_CERTIFICATE);
+       gnutls_free(data);
+       
+       if (ret<0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       return data_size;
+}
+
+
+/* This is called when we want send our certificate
+ */
+int _gnutls_send_server_certificate(SOCKET cd, GNUTLS_STATE state)
 {
        uint8 *data = NULL;
        int data_size = 0;
        int ret = 0;
 
 
-       if (state->gnutls_internals.auth_struct->gnutls_generate_certificate==NULL) 
+       if (state->gnutls_internals.auth_struct->gnutls_generate_server_certificate==NULL) 
                return 0;
 
 #ifdef HANDSHAKE_DEBUG
        _gnutls_log( "Sending certificate message\n");
 #endif
 
-       data_size = state->gnutls_internals.auth_struct->gnutls_generate_certificate( state, &data);
+       data_size = state->gnutls_internals.auth_struct->gnutls_generate_server_certificate( state, &data);
 
        if (data_size < 0) {
                gnutls_assert();
@@ -436,13 +517,83 @@ int _gnutls_send_certificate(SOCKET cd, GNUTLS_STATE state)
        return data_size;
 }
 
-int _gnutls_recv_certificate(SOCKET cd, GNUTLS_STATE state)
+
+int _gnutls_recv_client_certificate(SOCKET cd, GNUTLS_STATE state)
 {
        int datasize;
        opaque * data;
        int ret = 0;
+       int optional;
+
+       if (state->gnutls_internals.auth_struct->gnutls_process_client_certificate!=NULL) {
+
+               /* if we have not requested a certificate then just return
+                */
+               if ( state->gnutls_internals.send_cert_req == 0) {
+                       return 0;
+               }
 
-       if (state->gnutls_internals.auth_struct->gnutls_process_certificate!=NULL) {
+               if ( state->gnutls_internals.send_cert_req == GNUTLS_CERT_REQUIRE)
+                       optional = MANDATORY_PACKET;
+               else 
+                       optional = OPTIONAL_PACKET;
+
+               ret =
+                   _gnutls_recv_handshake(cd, state, &data,
+                                          &datasize,
+                                          GNUTLS_CERTIFICATE, optional);
+               if (ret < 0) {
+                       if (optional == OPTIONAL_PACKET &&
+                               ret==GNUTLS_E_WARNING_ALERT_RECEIVED && 
+                               gnutls_get_last_alert(state)==GNUTLS_NETSCAPE_NO_CLIENT_CERTIFICATE) {
+
+                               /* netscape does not send an empty certificate,
+                                * but this alert. So we just ignore it.
+                                */
+                               gnutls_assert();
+                               return 0;
+                       }
+                       /* certificate was required */
+                       gnutls_send_alert( cd, state, GNUTLS_FATAL, GNUTLS_BAD_CERTIFICATE);
+                       gnutls_assert();
+                       return ret;
+               }
+
+               if (ret == 0 && datasize == 0 && optional == OPTIONAL_PACKET) {
+                       /* well I'm not sure we should accept this
+                        * behaviour.
+                        */
+                       gnutls_assert();
+                       return 0;
+               }
+
+
+               ret = state->gnutls_internals.auth_struct->gnutls_process_client_certificate( state, data, datasize);
+               gnutls_free(data);
+               if (ret < 0 && ret != GNUTLS_E_NO_CERTIFICATE_FOUND) {
+                       gnutls_assert();
+                       return ret;
+               }
+
+               /* ok we should expect a certificate verify message now 
+                */
+               if (ret==GNUTLS_E_NO_CERTIFICATE_FOUND && optional == OPTIONAL_PACKET)
+                       ret = 0;
+               else
+                       state->gnutls_key->certificate_requested = 1;
+
+       }
+
+       return ret;
+}
+
+int _gnutls_recv_server_certificate(SOCKET cd, GNUTLS_STATE state)
+{
+       int datasize;
+       opaque * data;
+       int ret = 0;
+
+       if (state->gnutls_internals.auth_struct->gnutls_process_server_certificate!=NULL) {
 
                ret =
                    _gnutls_recv_handshake(cd, state, &data,
@@ -453,7 +604,7 @@ int _gnutls_recv_certificate(SOCKET cd, GNUTLS_STATE state)
                        return ret;
                }
 
-               ret = state->gnutls_internals.auth_struct->gnutls_process_certificate( state, data, datasize);
+               ret = state->gnutls_internals.auth_struct->gnutls_process_server_certificate( state, data, datasize);
                gnutls_free(data);
                if (ret < 0) {
                        gnutls_assert();
@@ -464,15 +615,48 @@ int _gnutls_recv_certificate(SOCKET cd, GNUTLS_STATE state)
        return ret;
 }
 
-int _gnutls_send_client_certificate(SOCKET cd, GNUTLS_STATE state)
+
+/* Recv the client certificate verify. This packet may not
+ * arrive if the peer did not send us a certificate.
+ */
+int _gnutls_recv_client_certificate_verify_message(SOCKET cd, GNUTLS_STATE state)
 {
+       uint8 *data;
+       int datasize;
+       int ret = 0;
 
-       if (state->gnutls_key->certificate_requested == 0)
-               return 0;
+
+       if (state->gnutls_internals.auth_struct->gnutls_process_client_cert_vrfy != NULL) {
 
 #ifdef HANDSHAKE_DEBUG
-       _gnutls_log( "Sending Client Certificate\n");
+               _gnutls_log( "Receiving client certificate verify message\n");
 #endif
 
-       return _gnutls_send_certificate(cd, state);
+               if ( state->gnutls_internals.send_cert_req == 0 ||
+                       state->gnutls_key->certificate_requested == 0) {
+                       return 0;
+               }
+
+               ret =
+                   _gnutls_recv_handshake(cd, state, &data,
+                                          &datasize,
+                                          GNUTLS_CLIENT_KEY_EXCHANGE, OPTIONAL_PACKET);
+               if (ret < 0)
+                       return ret;
+
+               if (ret==0 && datasize == 0 && state->gnutls_internals.send_cert_req == GNUTLS_CERT_REQUIRE) {
+                       /* certificate was required */
+                       gnutls_send_alert( cd, state, GNUTLS_FATAL, GNUTLS_BAD_CERTIFICATE);
+                       gnutls_assert();
+                       return GNUTLS_E_NO_CERTIFICATE_FOUND;
+               } 
+               
+               ret = state->gnutls_internals.auth_struct->gnutls_process_client_cert_vrfy( state, data, datasize);
+               gnutls_free(data);
+               if (ret < 0)
+                       return ret;
+
+       }
+
+       return ret;
 }
index 010d528d5a22f0224199edcd3fbb9daebc6996ec..a84ff0b4be9246b5df679015954966b6f129175c 100644 (file)
@@ -27,9 +27,12 @@ int _gnutls_recv_server_kx_message2(int cd, GNUTLS_STATE state);
 int _gnutls_recv_client_kx_message(int cd, GNUTLS_STATE state);
 int _gnutls_recv_client_kx_message0(int cd, GNUTLS_STATE state);
 int _gnutls_send_client_certificate_verify(int cd, GNUTLS_STATE state);
-int _gnutls_send_certificate(int cd, GNUTLS_STATE state);
+int _gnutls_send_server_certificate(int cd, GNUTLS_STATE state);
 int _gnutls_generate_master( GNUTLS_STATE state);
-int _gnutls_recv_certificate(SOCKET cd, GNUTLS_STATE state);
+int _gnutls_recv_client_certificate(SOCKET cd, GNUTLS_STATE state);
+int _gnutls_recv_server_certificate(SOCKET cd, GNUTLS_STATE state);
 int _gnutls_send_client_certificate(SOCKET cd, GNUTLS_STATE state);
 int _gnutls_recv_server_certificate_request(SOCKET cd, GNUTLS_STATE state);
+int _gnutls_send_server_certificate_request(SOCKET cd, GNUTLS_STATE state);
+int _gnutls_recv_client_certificate_verify_message(SOCKET cd, GNUTLS_STATE state);
 
index 659ed85966c0adbc26c47447683bfe9e29d0174d..ab958033521b3debc396288c29917fffd4d42c58 100644 (file)
@@ -105,6 +105,8 @@ GNUTLS_STATE initialize_state()
 
        gnutls_set_mac_priority(state, GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0);
 
+       gnutls_set_certificate_request( state, GNUTLS_CERT_REQUIRE);
+
        return state;
 }
 
@@ -269,6 +271,16 @@ fprintf(stderr, "\n");
        return n;
 }
 
+void check_alert( GNUTLS_STATE state, int ret) {
+       if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
+               ret = gnutls_get_last_alert(state);
+               if (ret == GNUTLS_NO_RENEGOTIATION)
+                       printf("* Received NO_RENEGOTIATION alert. Client Does not support renegotiation.\n");
+               else
+                       printf("* Received alert '%d'.\n", ret);
+       }
+}
+
 int main(int argc, char **argv)
 {
        int err, listen_sd, i;
@@ -351,6 +363,7 @@ int main(int argc, char **argv)
                        gnutls_deinit(state);
                        fprintf(stderr, "*** Handshake has failed (%s)\n\n",
                                gnutls_strerror(ret));
+                       check_alert( state, ret);
                        continue;
                }
                printf("- Handshake was completed\n");
@@ -394,17 +407,7 @@ int main(int argc, char **argv)
                        if (i == 10)
                                ret = gnutls_rehandshake(sd, state);
 #endif
-                       if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
-                           || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
-                               ret = gnutls_get_last_alert(state);
-                               if (ret == GNUTLS_NO_RENEGOTIATION)
-                                       printf
-                                           ("* Received NO_RENEGOTIATION alert. Client Does not support renegotiation.\n");
-                               else
-                                       printf("* Received alert '%d'.\n",
-                                              ret);
-                       }
-
+                       check_alert( state, ret);
                        if (http != 0) {
                                break;  /* close the connection */
                        }