summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2011-06-05 10:15:55 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2011-06-05 10:17:46 +0200
commit841490a5dc7725c62111ee30c090517999a68ce8 (patch)
treeedfee2b5c2b015a5183bb1d730f9861cbef560bc
parent28784bdca2d34ecd4b45478a0f7ef456e3897994 (diff)
downloadgnutls-841490a5dc7725c62111ee30c090517999a68ce8.tar.gz
Avoid memory allocations when requesting the supported ciphersuites.
-rw-r--r--lib/algorithms.h7
-rw-r--r--lib/algorithms/ciphersuites.c123
-rw-r--r--lib/gnutls_handshake.c152
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;