]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added support to select a certificate based on the peer's cipher
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 27 Jan 2002 21:10:39 +0000 (21:10 +0000)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 27 Jan 2002 21:10:39 +0000 (21:10 +0000)
suite list. (ie if DSS cipher suites are requested and a DSA certificate
is available, then this will be used)

lib/auth_rsa.c
lib/auth_x509.c
lib/auth_x509.h
lib/gnutls_handshake.c
lib/gnutls_handshake.h
lib/gnutls_v2_compat.c

index 8ac3e5064c311110ab2820144d42df3ee60edda6..188fb5d347bb73ad7c9173d1b63398638c662531 100644 (file)
@@ -79,7 +79,7 @@ int proc_rsa_client_kx(GNUTLS_STATE state, opaque * data, int data_size)
        gnutls_sdatum plaintext;
        gnutls_datum ciphertext;
        int ret, dsize;
-       MPI params[2];
+       MPI params[RSA_PARAMS];
 
        if ( gnutls_protocol_get_version(state) == GNUTLS_SSL3) {
                /* SSL 3.0 */
@@ -99,7 +99,7 @@ int proc_rsa_client_kx(GNUTLS_STATE state, opaque * data, int data_size)
        params[0] = state->gnutls_key->A;
        params[1] = state->gnutls_key->u;
        ret =
-           _gnutls_pkcs1_rsa_decrypt(&plaintext, ciphertext, params, 2);               /* btype==2 */
+           _gnutls_pkcs1_rsa_decrypt(&plaintext, ciphertext, params, 2); /* btype==2 */
 
        if (ret < 0) {
                /* in case decryption fails then don't inform
@@ -109,7 +109,7 @@ int proc_rsa_client_kx(GNUTLS_STATE state, opaque * data, int data_size)
 
                gnutls_assert();
 
-               _gnutls_log( "RSA_auth: Possible PKCS-1 format attack\n");
+               _gnutls_log( "RSA_AUTH: Possible PKCS-1 format attack\n");
 
                RANDOMIZE_KEY(state->gnutls_key->key, gnutls_secure_malloc);
        } else {
index 8b5dc4931f0e48f975afe24a3a96a3ea657a27bb..68d524770a7b3f9589e12397260e5ebc30fd9175 100644 (file)
@@ -1370,7 +1370,7 @@ int gnutls_x509pki_verify_certificate( const gnutls_datum* cert_list, int cert_l
  * The 'appropriate' is defined by the user. 
  * (frontend to _gnutls_server_find_cert_index())
  */
-const gnutls_cert *_gnutls_server_find_x509_cert(GNUTLS_STATE state)
+const gnutls_cert *_gnutls_server_find_x509_cert(GNUTLS_STATE state, PKAlgorithm requested_algo)
 {
        int i;
        const GNUTLS_X509PKI_CREDENTIALS x509_cred;
@@ -1382,7 +1382,7 @@ const gnutls_cert *_gnutls_server_find_x509_cert(GNUTLS_STATE state)
                return NULL;
 
        i = _gnutls_server_find_x509_cert_list_index(state, x509_cred->cert_list,
-                                        x509_cred->ncerts);
+                                        x509_cred->ncerts, requested_algo);
 
        if (i < 0)
                return NULL;
@@ -1392,15 +1392,18 @@ const gnutls_cert *_gnutls_server_find_x509_cert(GNUTLS_STATE state)
 
 /* finds the most appropriate certificate in the cert list.
  * The 'appropriate' is defined by the user.
+ *
+ * requested_algo holds the parameters required by the peer (RSA, DSA
+ * or -1 for any).
  */
 int _gnutls_server_find_x509_cert_list_index(GNUTLS_STATE state,
                                        gnutls_cert ** cert_list,
-                                       int cert_list_length)
+                                       int cert_list_length, 
+                                       PKAlgorithm requested_algo)
 {
-       int i, index = -1;
+       int i, index = -1, j;
        const GNUTLS_X509PKI_CREDENTIALS cred;
-
-       state->gnutls_internals.selected_cert_index = 0;
+       int my_certs_length;
 
        cred = _gnutls_get_cred(state->gnutls_key, GNUTLS_X509PKI, NULL);
        if (cred == NULL) {
@@ -1408,9 +1411,21 @@ int _gnutls_server_find_x509_cert_list_index(GNUTLS_STATE state,
                return GNUTLS_E_INSUFICIENT_CRED;
        }
 
-       if (cred->ncerts > 0)
+       if (cred->ncerts > 0) {
+               state->gnutls_internals.selected_cert_index = 0;
                index = 0;      /* default is use the first certificate */
 
+               /* find one compatible certificate */
+               if (requested_algo>0) {
+                       for (i = 0; i < cred->ncerts; i++) {
+                               if (requested_algo==cred->cert_list[i][0].subject_pk_algorithm) {
+                                       state->gnutls_internals.selected_cert_index = i;
+                                       index = i;
+                               }
+                       }
+               }
+       }
+
        if (state->gnutls_internals.client_cert_callback != NULL && cred->ncerts > 0) { /* use the callback to get certificate */
                gnutls_datum *my_certs = NULL;
 
@@ -1418,15 +1433,25 @@ int _gnutls_server_find_x509_cert_list_index(GNUTLS_STATE state,
                    gnutls_malloc(cred->ncerts * sizeof(gnutls_datum));
                if (my_certs == NULL)
                        goto clear;
+               my_certs_length = cred->ncerts;
 
                /* put our certificate's issuer and dn into cdn, idn
                 */
-               for (i = 0; i < cred->ncerts; i++) {
-                       my_certs[i] = cred->cert_list[i][0].raw;
+               j=0;
+               for (i = 0; i < cred->ncerts; i++,j++) {
+                       /* Does not add incompatible certificates */
+                       if (requested_algo>0) {
+                               if (requested_algo!=cred->cert_list[i][0].subject_pk_algorithm) {
+                                       my_certs_length--;
+                                       j--;
+                                       continue;
+                               }
+                       }
+                       my_certs[j] = cred->cert_list[i][0].raw;
                }
                index =
                    state->gnutls_internals.server_cert_callback(state, my_certs,
-                                                                cred->ncerts);
+                                                                my_certs_length);
 
              clear:
                gnutls_free(my_certs);
index a4126877e04072ff9fd3cc18a04d5550fdb97c51..68967a075cca32d56c1114051952cd7bfd661b6b 100644 (file)
@@ -63,8 +63,8 @@ int _gnutls_proc_x509_client_cert_vrfy(GNUTLS_STATE, opaque *, int);
 int _gnutls_proc_x509_server_certificate(GNUTLS_STATE, opaque *, int);
 int _gnutls_find_apr_cert( GNUTLS_STATE state, gnutls_cert** apr_cert_list, int *apr_cert_list_length, gnutls_private_key** apr_pkey);
 int _gnutls_find_dn( gnutls_datum* odn, gnutls_cert* cert);
-const gnutls_cert* _gnutls_server_find_x509_cert( struct GNUTLS_STATE_INT*);
-int _gnutls_server_find_x509_cert_list_index( struct GNUTLS_STATE_INT*, gnutls_cert ** cert_list, int cert_list_length);
+const gnutls_cert* _gnutls_server_find_x509_cert( struct GNUTLS_STATE_INT*, PKAlgorithm);
+int _gnutls_server_find_x509_cert_list_index( struct GNUTLS_STATE_INT*, gnutls_cert ** cert_list, int cert_list_length, PKAlgorithm);
 
 #define _gnutls_proc_x509_client_certificate _gnutls_proc_x509_server_certificate
 
index 785d40d31520cf55e3eebbf7956fd959e46673e5..97dee40b7a7ba1863acd9af2a258bea4a3c482fb 100644 (file)
@@ -50,7 +50,6 @@
 #define TRUE 1
 #define FALSE 0
 
-static int _gnutls_server_select_suite(GNUTLS_STATE state, opaque *data, int datalen);
 int _gnutls_server_select_comp_method(GNUTLS_STATE state,
                                    opaque * data, int datalen);
 
@@ -492,16 +491,42 @@ int _gnutls_recv_finished(GNUTLS_STATE state)
        return ret;
 }
 
+/* returns PK_RSA if the given cipher suite list only supports,
+ * RSA algorithms, PK_DSA if DSS, and -1 if both or none.
+ */
+int _gnutls_find_pk_algos_in_ciphersuites( opaque* data, int datalen) {
+int j;
+PKAlgorithm algo=-1, prev_algo = 0;
+KXAlgorithm kx;
+
+       for (j = 0; j < datalen; j += 2) {
+               kx = _gnutls_cipher_suite_get_kx_algo(*((GNUTLS_CipherSuite *) & data[j]));
+               
+               if ( _gnutls_map_kx_get_cred( kx) == GNUTLS_X509PKI) {
+                       algo = _gnutls_map_pk_get_pk( kx);
+       
+                       if (algo!=prev_algo && prev_algo!=0) return -1;
+                       prev_algo = algo;
+               }
+       }
+
+       return algo;
+}
 
 
 /* This selects the best supported ciphersuite from the ones supported. Then
  * it adds the suite into the state and performs some checks. 
  */
-static int _gnutls_server_select_suite(GNUTLS_STATE state, opaque *data, int datalen)
+int _gnutls_server_select_suite(GNUTLS_STATE state, opaque *data, int datalen)
 {
        int x, i, j;
        GNUTLS_CipherSuite *ciphers;
        int retval, err;
+       PKAlgorithm pk_algo; /* will hold the pk algorithms
+                             * supported by the peer.
+                             */
+
+       pk_algo = _gnutls_find_pk_algos_in_ciphersuites( data, datalen);
 
        x = _gnutls_supported_ciphersuites(state, &ciphers);
 
@@ -509,7 +534,7 @@ static int _gnutls_server_select_suite(GNUTLS_STATE state, opaque *data, int dat
         * the certificate requested, or to the
         * authentication requested (eg SRP).
         */
-       x = _gnutls_remove_unwanted_ciphersuites(state, &ciphers, x);
+       x = _gnutls_remove_unwanted_ciphersuites(state, &ciphers, x, pk_algo);
 
 #ifdef HANDSHAKE_DEBUG
        _gnutls_handshake_log("HSK: Requested cipher suites: \n");
@@ -1258,7 +1283,7 @@ static int _gnutls_read_server_hello(GNUTLS_STATE state, char *data,
 }
 
 /* This function copies the appropriate ciphersuites, to a localy allocated buffer 
- * Needed in hello messages. Returns the new data length.
+ * Needed in client hello messages. Returns the new data length.
  */
 static int _gnutls_copy_ciphersuites(GNUTLS_STATE state,
                                     opaque ** ret_data)
@@ -1280,7 +1305,7 @@ static int _gnutls_copy_ciphersuites(GNUTLS_STATE state,
         */
        ret =
            _gnutls_remove_unwanted_ciphersuites(state, &cipher_suites,
-                                                ret);
+                                                ret, -1);
        if (ret < 0) {
                gnutls_assert();
                return ret;
@@ -2249,7 +2274,8 @@ int _gnutls_recv_hello_request(GNUTLS_STATE state, void *data,
  */
 int _gnutls_remove_unwanted_ciphersuites(GNUTLS_STATE state,
                                         GNUTLS_CipherSuite **
-                                        cipherSuites, int numCipherSuites)
+                                        cipherSuites, int numCipherSuites, 
+                                        PKAlgorithm requested_pk_algo)
 {
 
        int ret = 0;
@@ -2277,7 +2303,7 @@ int _gnutls_remove_unwanted_ciphersuites(GNUTLS_STATE state,
        cert = NULL;
 
        if (state->security_parameters.entity == GNUTLS_SERVER)
-               cert = _gnutls_server_find_x509_cert(state);
+               cert = _gnutls_server_find_x509_cert(state, requested_pk_algo);
 
        if (cert == NULL) {
                /* No certificate was found 
@@ -2304,6 +2330,8 @@ int _gnutls_remove_unwanted_ciphersuites(GNUTLS_STATE state,
                return GNUTLS_E_MEMORY_ERROR;
        }
 
+       /* now removes ciphersuites based on the KX algorithm
+        */
        for (i = 0; i < numCipherSuites; i++) {
                /* finds the key exchange algorithm in
                 * the ciphersuite
index 4909a365bac2b01d64164336e3e021db97349292..f337713c2d5c31fe888680143091694f8c21093b 100644 (file)
@@ -34,8 +34,10 @@ int gnutls_handshake_server( GNUTLS_STATE state);
 void _gnutls_set_server_random( GNUTLS_STATE state, uint8* random);
 void _gnutls_set_client_random( GNUTLS_STATE state, uint8* random);
 int _gnutls_create_random( opaque* dst);
-int _gnutls_remove_unwanted_ciphersuites( GNUTLS_STATE state, GNUTLS_CipherSuite ** cipherSuites, int numCipherSuites);
+int _gnutls_remove_unwanted_ciphersuites( GNUTLS_STATE state, GNUTLS_CipherSuite ** cipherSuites, int numCipherSuites, PKAlgorithm);
 void gnutls_handshake_set_max_packet_length( GNUTLS_STATE state, int max);
+int _gnutls_find_pk_algos_in_ciphersuites( opaque* data, int datalen);
+int _gnutls_server_select_suite(GNUTLS_STATE state, opaque *data, int datalen);
 
 #define STATE state->gnutls_internals.handshake_state
 /* This returns true if we have got there
index e5fbbb4356fa79f8e67516e98738c9da1daedacb..4c77bc1789744d6ed2ab20ac9fd2ce8c7c3408c9 100644 (file)
 #include "gnutls_random.h"
 #include "gnutls_auth_int.h"
 
-int _gnutls_SelectCompMethod(GNUTLS_STATE state, CompressionMethod * ret, opaque * data, int datalen);
-
 /* This selects the best supported ciphersuite from the ones provided */
-static int SelectSuite_v2(GNUTLS_STATE state, opaque ret[2], char *data,
-                         int datalen)
+static int _gnutls_handshake_select_v2_suite(GNUTLS_STATE state, char *data, int datalen)
 {
-       int x, i, j;
-       GNUTLS_CipherSuite *ciphers;
-
-       x = _gnutls_supported_ciphersuites(state, &ciphers);
-       x = _gnutls_remove_unwanted_ciphersuites( state, &ciphers, x);
-
-#ifdef HANDSHAKE_DEBUG
-       _gnutls_handshake_log( "HSK: Requested cipher suites [v2 hello]: \n");
-       for (j = 0; j < datalen; j += 3) {
-               if (data[j] == 0) {     /* only print if in v2 compat mode */
-                       _gnutls_handshake_log( "\t%s\n",
-                               _gnutls_cipher_suite_get_name(*
-                                                             ((GNUTLS_CipherSuite *) & data[j+1])));
-               }
+       int i, j, ret;
+       char* _data;
+       int _datalen;
+       
+       _data = gnutls_malloc( datalen);
+       if (_data==NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
        }
-       _gnutls_handshake_log( "HSK: Supported cipher suites: \n");
-       for (j = 0; j < x; j++)
-               _gnutls_handshake_log( "\t%s\n",
-                       _gnutls_cipher_suite_get_name(ciphers[j]));
-#endif
-       memset(ret, '\0', 2);
 
+       _gnutls_handshake_log( "HSK: Parsing a version 2.0 client hello.\n");
+
+       i = _datalen = 0;
        for (j = 0; j < datalen; j += 3) {
-               for (i = 0; i < x; i++) {
-                       if (data[j] == 0)
-                               if ( memcmp(ciphers[i].CipherSuite, &data[j+1],
-                                    2) == 0) {
-
-                                       _gnutls_handshake_log(
-                                               "HSK: Selected cipher suite: ");
-                                       _gnutls_handshake_log( "%s\n",
-                                               _gnutls_cipher_suite_get_name
-                                               (*
-                                                ((GNUTLS_CipherSuite *) &
-                                                 data[j+1])));
-
-                                       memcpy(ret,
-                                               ciphers[i].CipherSuite,
-                                               2);
-                                       gnutls_free(ciphers);
-
-                                       return 0;
-                               }
+               if (data[j] == 0) {
+                       memcpy( &_data[i], &data[j+1], 2);
+                       i+=2;
+                       _datalen+=2;
                }
        }
 
+       ret = _gnutls_server_select_suite( state, _data, _datalen);
+       gnutls_free(_data);
 
-       gnutls_free(ciphers);
-       gnutls_assert();
-       return GNUTLS_E_UNKNOWN_CIPHER_SUITE;
+       return ret;
 
 }
 
@@ -118,7 +90,7 @@ int _gnutls_read_client_hello_v2(GNUTLS_STATE state, opaque * data,
 
        DECR_LEN(len, 2);
 
-       _gnutls_handshake_log( "HSK: V2 Hello: Client's version: %d.%d\n", data[pos],
+       _gnutls_handshake_log( "HSK: SSL 2.0 Hello: Client's version: %d.%d\n", data[pos],
                data[pos + 1]);
 
        set_adv_version( state, data[pos], data[pos+1]);
@@ -170,9 +142,7 @@ int _gnutls_read_client_hello_v2(GNUTLS_STATE state, opaque * data,
        /* find an appropriate cipher suite */
 
        DECR_LEN(len, sizeOfSuites);
-       ret = SelectSuite_v2(state, state->security_parameters.
-                                 current_cipher_suite.CipherSuite,
-                                 &data[pos], sizeOfSuites);
+       ret = _gnutls_handshake_select_v2_suite(state, &data[pos], sizeOfSuites);
 
        pos += sizeOfSuites;
        if (ret < 0) {
@@ -198,7 +168,7 @@ int _gnutls_read_client_hello_v2(GNUTLS_STATE state, opaque * data,
        if (state->gnutls_internals.auth_struct == NULL) {
 
                _gnutls_handshake_log(
-                       "HSK: V2 Hello: Cannot find the appropriate handler for the KX algorithm\n");
+                       "HSK: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n");
 
                gnutls_assert();
                return GNUTLS_E_UNKNOWN_CIPHER_TYPE;