diff options
-rw-r--r-- | lib/algorithms.h | 7 | ||||
-rw-r--r-- | lib/algorithms/ciphersuites.c | 123 | ||||
-rw-r--r-- | lib/gnutls_handshake.c | 152 |
3 files changed, 92 insertions, 190 deletions
diff --git a/lib/algorithms.h b/lib/algorithms.h index 7a436daca8..507581d407 100644 --- a/lib/algorithms.h +++ b/lib/algorithms.h @@ -31,6 +31,9 @@ #define GNUTLS_RENEGO_PROTECTION_REQUEST_MAJOR 0x00 #define GNUTLS_RENEGO_PROTECTION_REQUEST_MINOR 0xFF +/* would allow for 256 ciphersuites */ +#define MAX_CIPHERSUITE_SIZE 512 + /* Functions for version handling. */ gnutls_protocol_t _gnutls_version_lowest (gnutls_session_t session); gnutls_protocol_t _gnutls_version_max (gnutls_session_t session); @@ -55,9 +58,9 @@ const char *_gnutls_x509_mac_to_oid (gnutls_mac_algorithm_t mac); /* Functions for cipher suites. */ int _gnutls_supported_ciphersuites (gnutls_session_t session, - cipher_suite_st ** ciphers); + uint8_t* cipher_suites, int max_cipher_suite_size); int _gnutls_supported_ciphersuites_sorted (gnutls_session_t session, - cipher_suite_st ** ciphers); + uint8_t* cipher_suites, int max_cipher_suite_size); const char *_gnutls_cipher_suite_get_name (cipher_suite_st * algorithm); gnutls_mac_algorithm_t _gnutls_cipher_suite_get_prf (const cipher_suite_st * suite); gnutls_cipher_algorithm_t _gnutls_cipher_suite_get_cipher_algo (const diff --git a/lib/algorithms/ciphersuites.c b/lib/algorithms/ciphersuites.c index c371733fe6..ed9855730a 100644 --- a/lib/algorithms/ciphersuites.c +++ b/lib/algorithms/ciphersuites.c @@ -236,11 +236,6 @@ typedef struct #define CIPHER_SUITES_COUNT (sizeof(cs_algorithms)/sizeof(gnutls_cipher_suite_entry)-1) -/* FIXME: what we don't handle here is TLS 1.2 requirement - * that each ciphersuite has it's own PRF algorithm. Now we - * assume that each one uses the SHA-256 PRF in TLS 1.2. - */ - static const gnutls_cipher_suite_entry cs_algorithms[] = { /* ANON_DH */ GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_ANON_DH_ARCFOUR_MD5, @@ -805,118 +800,73 @@ _gnutls_cipher_suite_is_ok (cipher_suite_st * suite) int _gnutls_supported_ciphersuites_sorted (gnutls_session_t session, - cipher_suite_st ** ciphers) + uint8_t* cipher_suites, int max_cipher_suites_size) { int count; - count = _gnutls_supported_ciphersuites (session, ciphers); - if (count <= 0) - { - gnutls_assert (); - return count; - } + count = _gnutls_supported_ciphersuites (session, cipher_suites, max_cipher_suites_size); + if (count < 0) + return gnutls_assert_val(count); - _gnutls_qsort (session, *ciphers, count, - sizeof (cipher_suite_st), compare_algo); + _gnutls_qsort (session, cipher_suites, count/2, + 2, compare_algo); return count; } int _gnutls_supported_ciphersuites (gnutls_session_t session, - cipher_suite_st ** _ciphers) + uint8_t *cipher_suites, int max_cipher_suite_size) { unsigned int i, ret_count, j; - unsigned int count = CIPHER_SUITES_COUNT; - cipher_suite_st *tmp_ciphers; - cipher_suite_st *ciphers; - - if (count == 0) - { - return 0; - } - tmp_ciphers = gnutls_malloc (count * sizeof (cipher_suite_st)); - if (tmp_ciphers == NULL) - return GNUTLS_E_MEMORY_ERROR; + if (max_cipher_suite_size < (CIPHER_SUITES_COUNT)*2) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - ciphers = gnutls_malloc (count * sizeof (cipher_suite_st)); - if (ciphers == NULL) - { - gnutls_free (tmp_ciphers); - return GNUTLS_E_MEMORY_ERROR; - } - - for (i = 0; i < count; i++) - { - memcpy (&tmp_ciphers[i], &cs_algorithms[i].id, - sizeof (cipher_suite_st)); - } - - for (i = j = 0; i < count; i++) + for (i = j = 0; i < CIPHER_SUITES_COUNT; i++) { /* remove private cipher suites, if requested. */ - if (tmp_ciphers[i].suite[0] == 0xFF && + if (cs_algorithms[i].id.suite[0] == 0xFF && session->internals.enable_private == 0) continue; /* remove cipher suites which do not support the * protocol version used. */ - if (_gnutls_cipher_suite_is_version_supported (session, &tmp_ciphers[i]) + if (_gnutls_cipher_suite_is_version_supported (session, &cs_algorithms[i].id) == 0) continue; if (_gnutls_kx_priority - (session, _gnutls_cipher_suite_get_kx_algo (&tmp_ciphers[i])) < 0) + (session, _gnutls_cipher_suite_get_kx_algo (&cs_algorithms[i].id)) < 0) continue; if (_gnutls_mac_priority - (session, _gnutls_cipher_suite_get_mac_algo (&tmp_ciphers[i])) < 0) + (session, _gnutls_cipher_suite_get_mac_algo (&cs_algorithms[i].id)) < 0) continue; if (_gnutls_cipher_priority (session, - _gnutls_cipher_suite_get_cipher_algo (&tmp_ciphers[i])) < 0) + _gnutls_cipher_suite_get_cipher_algo (&cs_algorithms[i].id)) < 0) continue; - memcpy (&ciphers[j], &tmp_ciphers[i], sizeof (cipher_suite_st)); - j++; + memcpy (&cipher_suites[j], &cs_algorithms[i].id.suite, 2); + j+=2; } ret_count = j; -#if 0 /* expensive */ - if (ret_count > 0 && ret_count != count) - { - ciphers = - gnutls_realloc_fast (ciphers, ret_count * sizeof (cipher_suite_st)); - } - else - { - if (ret_count != count) - { - gnutls_free (ciphers); - ciphers = NULL; - } - } -#endif - - gnutls_free (tmp_ciphers); - /* This function can no longer return 0 cipher suites. * It returns an error code instead. */ if (ret_count == 0) { gnutls_assert (); - gnutls_free (ciphers); return GNUTLS_E_NO_CIPHER_SUITES; } - *_ciphers = ciphers; return ret_count; } @@ -1007,23 +957,28 @@ static int compare_algo (gnutls_session_t session, const void *i_A1, const void *i_A2) { - gnutls_kx_algorithm_t kA1 = - _gnutls_cipher_suite_get_kx_algo ((const cipher_suite_st *) i_A1); - gnutls_kx_algorithm_t kA2 = - _gnutls_cipher_suite_get_kx_algo ((const cipher_suite_st *) i_A2); - gnutls_cipher_algorithm_t cA1 = - _gnutls_cipher_suite_get_cipher_algo ((const cipher_suite_st *) i_A1); - gnutls_cipher_algorithm_t cA2 = - _gnutls_cipher_suite_get_cipher_algo ((const cipher_suite_st *) i_A2); - gnutls_mac_algorithm_t mA1 = - _gnutls_cipher_suite_get_mac_algo ((const cipher_suite_st *) i_A1); - gnutls_mac_algorithm_t mA2 = - _gnutls_cipher_suite_get_mac_algo ((const cipher_suite_st *) i_A2); - - int p1 = (_gnutls_kx_priority (session, kA1) + 1) * 64; - int p2 = (_gnutls_kx_priority (session, kA2) + 1) * 64; - p1 += (_gnutls_cipher_priority (session, cA1) + 1) * 8; - p2 += (_gnutls_cipher_priority (session, cA2) + 1) * 8; + cipher_suite_st A1, A2; + gnutls_kx_algorithm_t kA1, kA2; + gnutls_cipher_algorithm_t cA1, cA2; + gnutls_mac_algorithm_t mA1, mA2; + int p1, p2; + + memcpy(A1.suite, i_A1, 2); + memcpy(A2.suite, i_A2, 2); + + kA1 = _gnutls_cipher_suite_get_kx_algo (&A1); + kA2 = _gnutls_cipher_suite_get_kx_algo (&A2); + + cA1 = _gnutls_cipher_suite_get_cipher_algo (&A1); + cA2 = _gnutls_cipher_suite_get_cipher_algo (&A2); + + mA1 = _gnutls_cipher_suite_get_mac_algo (&A1); + mA2 = _gnutls_cipher_suite_get_mac_algo (&A2); + + p1 = (_gnutls_kx_priority (session, kA1) + 1) * 256; + p2 = (_gnutls_kx_priority (session, kA2) + 1) * 256; + p1 += (_gnutls_cipher_priority (session, cA1) + 1) * 16; + p2 += (_gnutls_cipher_priority (session, cA2) + 1) * 16; p1 += _gnutls_mac_priority (session, mA1); p2 += _gnutls_mac_priority (session, mA2); diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c index bb2932f811..13f20fac60 100644 --- a/lib/gnutls_handshake.c +++ b/lib/gnutls_handshake.c @@ -70,8 +70,8 @@ static int _gnutls_server_select_comp_method (gnutls_session_t session, opaque * data, int datalen); static int _gnutls_remove_unwanted_ciphersuites (gnutls_session_t session, - cipher_suite_st ** cipherSuites, - int numCipherSuites, + uint8_t * cipher_suites, + int cipher_suites_size, gnutls_pk_algorithm_t *pk_algos, size_t pk_algos_size); @@ -818,9 +818,10 @@ int _gnutls_server_select_suite (gnutls_session_t session, opaque * data, int datalen) { - int x, i, j, ret; + int i, j, ret, cipher_suites_size; size_t pk_algos_size; - cipher_suite_st *ciphers, cs; + cipher_suite_st cs; + uint8_t cipher_suites[MAX_CIPHERSUITE_SIZE]; int retval, err; gnutls_pk_algorithm_t pk_algos[MAX_ALGOS]; /* will hold the pk algorithms * supported by the peer. @@ -856,28 +857,27 @@ _gnutls_server_select_suite (gnutls_session_t session, opaque * data, if (ret < 0) return gnutls_assert_val(ret); - ret = _gnutls_supported_ciphersuites (session, &ciphers); + ret = _gnutls_supported_ciphersuites (session, cipher_suites, sizeof(cipher_suites)); if (ret < 0) return gnutls_assert_val(ret); - x = ret; + cipher_suites_size = ret; /* Here we remove any ciphersuite that does not conform * the certificate requested, or to the * authentication requested (e.g. SRP). */ - ret = _gnutls_remove_unwanted_ciphersuites (session, &ciphers, x, pk_algos, pk_algos_size); + ret = _gnutls_remove_unwanted_ciphersuites (session, cipher_suites, cipher_suites_size, pk_algos, pk_algos_size); if (ret <= 0) { gnutls_assert (); - gnutls_free (ciphers); if (ret < 0) return ret; else return GNUTLS_E_UNKNOWN_CIPHER_SUITE; } - x = ret; + cipher_suites_size = ret; /* Data length should be zero mod 2 since * every ciphersuite is 2 bytes. (this check is needed @@ -898,15 +898,15 @@ _gnutls_server_select_suite (gnutls_session_t session, opaque * data, { memcpy (&cs.suite, &data[j], 2); _gnutls_handshake_log ("\t0x%.2x, 0x%.2x %s\n", data[j], data[j+1], _gnutls_cipher_suite_get_name (&cs)); - for (i = 0; i < x; i++) + for (i = 0; i < cipher_suites_size; i+=2) { - if (memcmp (ciphers[i].suite, &data[j], 2) == 0) + if (memcmp (&cipher_suites[i], &data[j], 2) == 0) { _gnutls_handshake_log ("HSK[%p]: Selected cipher suite: %s\n", session, _gnutls_cipher_suite_get_name (&cs)); memcpy (session->security_parameters.current_cipher_suite.suite, - ciphers[i].suite, 2); + &cipher_suites[i], 2); _gnutls_epoch_set_cipher_suite (session, EPOCH_NEXT, &session-> security_parameters.current_cipher_suite); @@ -919,7 +919,6 @@ _gnutls_server_select_suite (gnutls_session_t session, opaque * data, } finish: - gnutls_free (ciphers); if (retval != 0) { @@ -1330,19 +1329,19 @@ static int _gnutls_client_set_ciphersuite (gnutls_session_t session, opaque suite[2]) { uint8_t z; - cipher_suite_st *cipher_suites; - int cipher_suite_num; + uint8_t cipher_suites[MAX_CIPHERSUITE_SIZE]; + int cipher_suite_size; int i, err; z = 1; - cipher_suite_num = _gnutls_supported_ciphersuites (session, &cipher_suites); - if (cipher_suite_num < 0) + cipher_suite_size = _gnutls_supported_ciphersuites (session, cipher_suites, sizeof(cipher_suites)); + if (cipher_suite_size < 0) { gnutls_assert (); - return cipher_suite_num; + return cipher_suite_size; } - for (i = 0; i < cipher_suite_num; i++) + for (i = 0; i < cipher_suite_size; i+=2) { if (memcmp (&cipher_suites[i], suite, 2) == 0) { @@ -1351,8 +1350,6 @@ _gnutls_client_set_ciphersuite (gnutls_session_t session, opaque suite[2]) } } - gnutls_free (cipher_suites); - if (z != 0) { gnutls_assert (); @@ -1624,92 +1621,46 @@ _gnutls_copy_ciphersuites (gnutls_session_t session, gnutls_buffer_st * cdata, int add_scsv) { - int ret, i; - cipher_suite_st *cipher_suites; - uint16_t cipher_num; - uint16_t loop_max; + int ret; + uint8_t cipher_suites[MAX_CIPHERSUITE_SIZE+2]; + int cipher_suites_size; size_t init_length = cdata->length; - ret = _gnutls_supported_ciphersuites_sorted (session, &cipher_suites); + ret = _gnutls_supported_ciphersuites_sorted (session, cipher_suites, sizeof(cipher_suites)-2); if (ret < 0) - { - gnutls_assert (); - return ret; - } + return gnutls_assert_val(ret); /* Here we remove any ciphersuite that does not conform * the certificate requested, or to the * authentication requested (eg SRP). */ ret = - _gnutls_remove_unwanted_ciphersuites (session, &cipher_suites, ret, NULL, 0); + _gnutls_remove_unwanted_ciphersuites (session, cipher_suites, ret, NULL, 0); if (ret < 0) - { - gnutls_assert (); - gnutls_free (cipher_suites); - return ret; - } + return gnutls_assert_val(ret); /* If no cipher suites were enabled. */ if (ret == 0) - { - gnutls_assert (); - gnutls_free (cipher_suites); - return GNUTLS_E_INSUFFICIENT_CREDENTIALS; - } + return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS); + cipher_suites_size = ret; if (add_scsv) - ++ret; - - cipher_num = ret; - - cipher_num *= sizeof (uint16_t); /* in order to get bytes */ - - ret = _gnutls_buffer_append_prefix(cdata, 16, cipher_num); - if (ret < 0) { - gnutls_assert(); - goto cleanup; - } - - - loop_max = add_scsv ? cipher_num - 2 : cipher_num; - for (i = 0; i < (loop_max / 2); i++) - { - ret = _gnutls_buffer_append_data( cdata, cipher_suites[i].suite, 2); - if (ret < 0) - { - gnutls_assert(); - goto cleanup; - } - } - - if (add_scsv) - { - uint8_t p[2]; - /* Safe renegotiation signalling CS value is { 0x00, 0xff } */ - p[0] = 0x00; - p[1] = 0xff; - ret = _gnutls_buffer_append_data( cdata, p, 2); - if (ret < 0) - { - gnutls_assert(); - goto cleanup; - } + cipher_suites[cipher_suites_size] = 0x00; + cipher_suites[cipher_suites_size+1] = 0xff; + cipher_suites_size += 2; ret = _gnutls_ext_sr_send_cs (session); if (ret < 0) - { - gnutls_assert (); - goto cleanup; - } + return gnutls_assert_val(ret); } - ret = cdata->length - init_length; + ret = _gnutls_buffer_append_data_prefix(cdata, 16, cipher_suites, cipher_suites_size); + if (ret < 0) + return gnutls_assert_val(ret); -cleanup: - gnutls_free (cipher_suites); + ret = cdata->length - init_length; return ret; } @@ -3061,15 +3012,15 @@ check_server_params (gnutls_session_t session, */ static int _gnutls_remove_unwanted_ciphersuites (gnutls_session_t session, - cipher_suite_st ** cipherSuites, - int numCipherSuites, + uint8_t * cipher_suites, + int cipher_suites_size, gnutls_pk_algorithm_t *pk_algos, size_t pk_algos_size) { int ret = 0; - cipher_suite_st *newSuite, cs; - int newSuiteSize = 0, i; + cipher_suite_st cs; + int i, new_suites_size; gnutls_certificate_credentials_t cert_cred; gnutls_kx_algorithm_t kx; int server = session->security_parameters.entity == GNUTLS_SERVER ? 1 : 0; @@ -3112,23 +3063,20 @@ _gnutls_remove_unwanted_ciphersuites (gnutls_session_t session, return ret; } - newSuite = gnutls_malloc (numCipherSuites * sizeof (cipher_suite_st)); - if (newSuite == NULL) - { - gnutls_assert (); - return GNUTLS_E_MEMORY_ERROR; - } + new_suites_size = 0; /* now removes ciphersuites based on the KX algorithm */ - for (i = 0; i < numCipherSuites; i++) + for (i = 0; i < cipher_suites_size; i+=2) { int delete = 0; /* finds the key exchange algorithm in * the ciphersuite */ - kx = _gnutls_cipher_suite_get_kx_algo (&(*cipherSuites)[i]); + cs.suite[0] = cipher_suites[i]; + cs.suite[1] = cipher_suites[i+1]; + kx = _gnutls_cipher_suite_get_kx_algo (&cs); /* if it is defined but had no credentials */ @@ -3167,8 +3115,6 @@ _gnutls_remove_unwanted_ciphersuites (gnutls_session_t session, } } - memcpy (&cs.suite, &(*cipherSuites)[i].suite, 2); - if (delete == 0) { @@ -3176,8 +3122,9 @@ _gnutls_remove_unwanted_ciphersuites (gnutls_session_t session, session, _gnutls_cipher_suite_get_name (&cs)); - memcpy (newSuite[newSuiteSize].suite, (*cipherSuites)[i].suite, 2); - newSuiteSize++; + if (i != new_suites_size) + memmove( &cipher_suites[new_suites_size], &cipher_suites[i], 2); + new_suites_size+=2; } else { @@ -3188,10 +3135,7 @@ _gnutls_remove_unwanted_ciphersuites (gnutls_session_t session, } } - gnutls_free (*cipherSuites); - *cipherSuites = newSuite; - - ret = newSuiteSize; + ret = new_suites_size; return ret; |