summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2012-06-07 18:12:59 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2012-06-20 19:56:02 +0200
commit5b15314d535e6fb76d3aa50d7174fd240b52c525 (patch)
treee82c578037d4724c66e8e499845d2230002b5370 /lib
parent2b9810f19cec0cc474e56c11110c86809bf8ec02 (diff)
downloadgnutls-5b15314d535e6fb76d3aa50d7174fd240b52c525.tar.gz
Added support for an old version of the DTLS protocol
used by openconnect vpn client for compatibility with Cisco's AnyConnect SSL VPN. It is marked as GNUTLS_DTLS0_9. Do not use it for newer protocols as it has issues. Conflicts: NEWS lib/libgnutls.map
Diffstat (limited to 'lib')
-rw-r--r--lib/algorithms.h5
-rw-r--r--lib/algorithms/ciphersuites.c29
-rw-r--r--lib/algorithms/protocols.c3
-rw-r--r--lib/gnutls_constate.c2
-rw-r--r--lib/gnutls_handshake.c57
-rw-r--r--lib/gnutls_int.h4
-rw-r--r--lib/gnutls_kx.c25
-rw-r--r--lib/gnutls_session_pack.c70
-rw-r--r--lib/includes/gnutls/gnutls.h.in13
-rw-r--r--lib/libgnutls.map1
10 files changed, 186 insertions, 23 deletions
diff --git a/lib/algorithms.h b/lib/algorithms.h
index 9fe0272541..748629c17c 100644
--- a/lib/algorithms.h
+++ b/lib/algorithms.h
@@ -69,6 +69,11 @@ gnutls_kx_algorithm_t _gnutls_cipher_suite_get_kx_algo (const uint8_t suite[2]);
gnutls_mac_algorithm_t _gnutls_cipher_suite_get_mac_algo (const
uint8_t suite[2]);
+int
+_gnutls_cipher_suite_get_id (gnutls_kx_algorithm_t kx_algorithm,
+ gnutls_cipher_algorithm_t cipher_algorithm,
+ gnutls_mac_algorithm_t mac_algorithm, uint8_t suite[2]);
+
/* Functions for ciphers. */
int _gnutls_cipher_is_block (gnutls_cipher_algorithm_t algorithm);
int _gnutls_cipher_algo_is_aead (gnutls_cipher_algorithm_t algorithm);
diff --git a/lib/algorithms/ciphersuites.c b/lib/algorithms/ciphersuites.c
index 3c5a79d06d..678812e6dc 100644
--- a/lib/algorithms/ciphersuites.c
+++ b/lib/algorithms/ciphersuites.c
@@ -726,6 +726,35 @@ const gnutls_cipher_suite_entry * ce;
return ce->name + sizeof ("GNUTLS_") - 1;
}
+/*-
+ * _gnutls_cipher_suite_get_id:
+ * @kx_algorithm: is a Key exchange algorithm
+ * @cipher_algorithm: is a cipher algorithm
+ * @mac_algorithm: is a MAC algorithm
+ * @suite: The id to be returned
+ *
+ * It fills @suite with the ID of the ciphersuite of the provided parameters.
+ *
+ * Returns: 0 on success or a negative error code otherwise.
+ -*/
+int
+_gnutls_cipher_suite_get_id (gnutls_kx_algorithm_t kx_algorithm,
+ gnutls_cipher_algorithm_t cipher_algorithm,
+ gnutls_mac_algorithm_t mac_algorithm, uint8_t suite[2])
+{
+const gnutls_cipher_suite_entry * ce;
+
+ ce = cipher_suite_get (kx_algorithm, cipher_algorithm, mac_algorithm);
+ if (ce == NULL)
+ return GNUTLS_E_INVALID_REQUEST;
+ else
+ {
+ suite[0] = ce->id[0];
+ suite[1] = ce->id[1];
+ }
+ return 0;
+}
+
/**
* gnutls_cipher_suite_info:
* @idx: index of cipher suite to get information about, starts on 0.
diff --git a/lib/algorithms/protocols.c b/lib/algorithms/protocols.c
index a152901a5d..01203d8903 100644
--- a/lib/algorithms/protocols.c
+++ b/lib/algorithms/protocols.c
@@ -43,6 +43,7 @@ static const gnutls_version_entry sup_versions[] = {
{"TLS1.0", GNUTLS_TLS1, 3, 1, GNUTLS_STREAM, 1},
{"TLS1.1", GNUTLS_TLS1_1, 3, 2, GNUTLS_STREAM, 1},
{"TLS1.2", GNUTLS_TLS1_2, 3, 3, GNUTLS_STREAM, 1},
+ {"DTLS0.9", GNUTLS_DTLS0_9, 1, 0, GNUTLS_DGRAM, 1}, /* Cisco AnyConnect (based on about OpenSSL 0.9.8e) */
{"DTLS1.0", GNUTLS_DTLS1_0, 254, 255, GNUTLS_DGRAM, 1}, /* 1.1 over datagram */
{0, 0, 0, 0, 0}
};
@@ -242,6 +243,7 @@ _gnutls_version_has_selectable_prf (gnutls_protocol_t version)
{
switch (version)
{
+ case GNUTLS_DTLS0_9:
case GNUTLS_DTLS1_0:
case GNUTLS_TLS1_1:
case GNUTLS_TLS1_0:
@@ -259,6 +261,7 @@ _gnutls_version_has_selectable_sighash (gnutls_protocol_t version)
{
switch (version)
{
+ case GNUTLS_DTLS0_9:
case GNUTLS_DTLS1_0:
case GNUTLS_TLS1_1:
case GNUTLS_TLS1_0:
diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c
index 5ef0c74f53..c4aa4bca21 100644
--- a/lib/gnutls_constate.c
+++ b/lib/gnutls_constate.c
@@ -466,7 +466,7 @@ _gnutls_epoch_set_keys (gnutls_session_t session, uint16_t epoch)
dst->timestamp = src->timestamp; \
dst->max_record_recv_size = src->max_record_recv_size; \
dst->max_record_send_size = src->max_record_send_size; \
- dst->version = src->version
+ dst->version = src->version;
static void
_gnutls_set_resumed_parameters (gnutls_session_t session)
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index 25520c40b6..8256e141d0 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -1191,7 +1191,8 @@ _gnutls_handshake_hash_add_recvd (gnutls_session_t session,
{
int ret;
- if (recv_type == GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST ||
+ if ((gnutls_protocol_get_version (session) != GNUTLS_DTLS0_9 &&
+ recv_type == GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST) ||
recv_type == GNUTLS_HANDSHAKE_HELLO_REQUEST)
return 0;
@@ -1199,11 +1200,13 @@ _gnutls_handshake_hash_add_recvd (gnutls_session_t session,
session->internals.handshake_hash_buffer_prev_len = session->internals.handshake_hash_buffer.length;
- ret = _gnutls_buffer_append_data(&session->internals.handshake_hash_buffer,
- header, header_size);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
+ if (gnutls_protocol_get_version (session) != GNUTLS_DTLS0_9)
+ {
+ ret = _gnutls_buffer_append_data(&session->internals.handshake_hash_buffer,
+ header, header_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
if (datalen > 0)
{
ret = _gnutls_buffer_append_data(&session->internals.handshake_hash_buffer,
@@ -1231,6 +1234,18 @@ _gnutls_handshake_hash_add_sent (gnutls_session_t session,
{
CHECK_SIZE(datalen);
+ if (gnutls_protocol_get_version (session) == GNUTLS_DTLS0_9)
+ {
+ /* Old DTLS doesn't include the header in the MAC */
+ if (datalen <= 12)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+ dataptr += 12;
+ datalen -= 12;
+ }
+
ret = _gnutls_buffer_append_data(&session->internals.handshake_hash_buffer,
dataptr, datalen);
if (ret < 0)
@@ -1402,7 +1417,8 @@ _gnutls_client_set_ciphersuite (gnutls_session_t session, uint8_t suite[2])
/* check if the credentials (username, public key etc.) are ok.
* Actually checks if they exist.
*/
- if (_gnutls_get_kx_cred
+ if (!session->internals.premaster_set &&
+ _gnutls_get_kx_cred
(session,
_gnutls_cipher_suite_get_kx_algo
(session->security_parameters.cipher_suite), &err) == NULL
@@ -1823,6 +1839,8 @@ _gnutls_send_client_hello (gnutls_session_t session, int again)
*/
if (!IS_DTLS(session))
_gnutls_record_set_default_version (session, 3, 0);
+ else if (gnutls_protocol_get_version (session) == GNUTLS_DTLS0_9)
+ _gnutls_record_set_default_version (session, 1, 0);
else
_gnutls_record_set_default_version (session, 254, 255);
}
@@ -2580,12 +2598,20 @@ send_change_cipher_spec (gnutls_session_t session, int again)
if (bufel == NULL)
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
- _mbuffer_set_uhead_size(bufel, 1);
+ if (gnutls_protocol_get_version (session) == GNUTLS_DTLS0_9)
+ _mbuffer_set_uhead_size(bufel, 3);
+ else
+ _mbuffer_set_uhead_size(bufel, 1);
_mbuffer_set_udata_size(bufel, 0);
data = _mbuffer_get_uhead_ptr (bufel);
data[0] = 1;
+ if (gnutls_protocol_get_version (session) == GNUTLS_DTLS0_9)
+ {
+ _gnutls_write_uint16 (session->internals.dtls.hsk_write_seq, &data[1]);
+ session->internals.dtls.hsk_write_seq++;
+ }
ret = _gnutls_handshake_io_cache_int (session, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, bufel);
if (ret < 0)
@@ -2669,7 +2695,7 @@ _gnutls_recv_handshake_final (gnutls_session_t session, int init)
{
int ret = 0;
uint8_t ch;
-
+ unsigned int ccs_len = 1;
switch (STATE)
{
@@ -2689,7 +2715,10 @@ _gnutls_recv_handshake_final (gnutls_session_t session, int init)
return gnutls_assert_val(ret);
}
- ret = _gnutls_recv_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, &ch, 1, NULL);
+ if (gnutls_protocol_get_version (session) == GNUTLS_DTLS0_9)
+ ccs_len = 3;
+
+ ret = _gnutls_recv_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, &ch, ccs_len, NULL);
if (ret <= 0)
{
ERR ("recv ChangeCipherSpec", ret);
@@ -2697,6 +2726,9 @@ _gnutls_recv_handshake_final (gnutls_session_t session, int init)
return (ret < 0) ? ret : GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
+ if (gnutls_protocol_get_version (session) == GNUTLS_DTLS0_9)
+ session->internals.dtls.hsk_read_seq++;
+
/* Initialize the connection session (start encryption) - in case of server */
if (init == TRUE)
{
@@ -2714,7 +2746,7 @@ _gnutls_recv_handshake_final (gnutls_session_t session, int init)
gnutls_assert ();
return ret;
}
-
+
case STATE31:
STATE = STATE31;
@@ -3149,7 +3181,8 @@ _gnutls_remove_unwanted_ciphersuites (gnutls_session_t session,
/* if it is defined but had no credentials
*/
- if (_gnutls_get_kx_cred (session, kx, NULL) == NULL)
+ if (!session->internals.premaster_set &&
+ _gnutls_get_kx_cred (session, kx, NULL) == NULL)
{
delete = 1;
}
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 4a60ae0d8f..02c4f9524c 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -863,6 +863,10 @@ typedef struct
/* DTLS session state */
dtls_st dtls;
+
+ /* if set it means that the master key was set using
+ * gnutls_session_set_master() rather than being negotiated. */
+ unsigned int premaster_set:1;
unsigned int cb_tls_unique_len;
unsigned char cb_tls_unique[MAX_VERIFY_DATA_SIZE];
diff --git a/lib/gnutls_kx.c b/lib/gnutls_kx.c
index c38de186f2..0cebd385f2 100644
--- a/lib/gnutls_kx.c
+++ b/lib/gnutls_kx.c
@@ -73,27 +73,34 @@ send_handshake (gnutls_session_t session, uint8_t * data, size_t size,
#define MASTER_SECRET "master secret"
#define MASTER_SECRET_SIZE (sizeof(MASTER_SECRET)-1)
-static int generate_normal_master (gnutls_session_t session, int);
+static int generate_normal_master (gnutls_session_t session, gnutls_datum_t*, int);
int
_gnutls_generate_master (gnutls_session_t session, int keep_premaster)
{
if (session->internals.resumed == RESUME_FALSE)
- return generate_normal_master (session, keep_premaster);
+ return generate_normal_master (session, &session->key->key, keep_premaster);
+ else if (session->internals.premaster_set)
+ {
+ gnutls_datum_t premaster;
+ premaster.size = sizeof(session->internals.resumed_security_parameters.master_secret);
+ premaster.data = session->internals.resumed_security_parameters.master_secret;
+ return generate_normal_master(session, &premaster, 1);
+ }
return 0;
}
/* here we generate the TLS Master secret.
*/
-#define PREMASTER session->key->key
static int
-generate_normal_master (gnutls_session_t session, int keep_premaster)
+generate_normal_master (gnutls_session_t session, gnutls_datum_t *premaster,
+ int keep_premaster)
{
int ret = 0;
char buf[512];
- _gnutls_hard_log ("INT: PREMASTER SECRET[%d]: %s\n", PREMASTER.size,
- _gnutls_bin2hex (PREMASTER.data, PREMASTER.size, buf,
+ _gnutls_hard_log ("INT: PREMASTER SECRET[%d]: %s\n", premaster->size,
+ _gnutls_bin2hex (premaster->data, premaster->size, buf,
sizeof (buf), NULL));
_gnutls_hard_log ("INT: CLIENT RANDOM[%d]: %s\n", 32,
_gnutls_bin2hex (session->
@@ -114,7 +121,7 @@ generate_normal_master (gnutls_session_t session, int keep_premaster)
session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);
ret =
- _gnutls_ssl3_generate_random (PREMASTER.data, PREMASTER.size,
+ _gnutls_ssl3_generate_random (premaster->data, premaster->size,
rnd, 2 * GNUTLS_RANDOM_SIZE,
GNUTLS_MASTER_SIZE,
session->
@@ -131,14 +138,14 @@ generate_normal_master (gnutls_session_t session, int keep_premaster)
session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);
ret =
- _gnutls_PRF (session, PREMASTER.data, PREMASTER.size,
+ _gnutls_PRF (session, premaster->data, premaster->size,
MASTER_SECRET, MASTER_SECRET_SIZE,
rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE,
session->security_parameters.master_secret);
}
if (!keep_premaster)
- _gnutls_free_datum (&PREMASTER);
+ _gnutls_free_datum (premaster);
if (ret < 0)
return ret;
diff --git a/lib/gnutls_session_pack.c b/lib/gnutls_session_pack.c
index 3e89b981e8..2588873453 100644
--- a/lib/gnutls_session_pack.c
+++ b/lib/gnutls_session_pack.c
@@ -40,6 +40,7 @@
#include <gnutls_num.h>
#include <gnutls_extensions.h>
#include <gnutls_constate.h>
+#include <algorithms.h>
static int pack_certificate_auth_info (gnutls_session_t,
gnutls_buffer_st * packed_session);
@@ -860,3 +861,72 @@ unpack_security_parameters (gnutls_session_t session, gnutls_buffer_st * ps)
error:
return ret;
}
+
+/**
+ * gnutls_session_set_premaster:
+ * @session: is a #gnutls_session_t structure.
+ * @entity: GNUTLS_SERVER or GNUTLS_CLIENT
+ * @version: the TLS protocol version
+ * @kx: the key exchange method
+ * @cipher: the cipher
+ * @mac: the MAC algorithm
+ * @comp: the compression method
+ * @master: the master key to use
+ * @session_id: the session identifier
+ *
+ * This function sets the premaster secret in a session. This is
+ * a function intended for exceptional uses. Do not use this
+ * function unless you are implementing a legacy protocol.
+ * Use gnutls_session_set_data() instead.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
+ * an error code is returned.
+ **/
+int
+gnutls_session_set_premaster (gnutls_session_t session, unsigned int entity,
+ gnutls_protocol_t version,
+ gnutls_kx_algorithm_t kx,
+ gnutls_cipher_algorithm_t cipher,
+ gnutls_mac_algorithm_t mac,
+ gnutls_compression_method_t comp,
+ const gnutls_datum_t* master,
+ const gnutls_datum_t * session_id)
+{
+ int ret;
+
+ memset (&session->internals.resumed_security_parameters, 0,
+ sizeof (session->internals.resumed_security_parameters));
+
+ session->internals.resumed_security_parameters.entity = entity;
+ session->internals.resumed_security_parameters.kx_algorithm = kx;
+
+ ret = _gnutls_cipher_suite_get_id(kx, cipher, mac, session->internals.resumed_security_parameters.cipher_suite);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->internals.resumed_security_parameters.compression_method = comp;
+ session->internals.resumed_security_parameters.cert_type = GNUTLS_CRT_UNKNOWN;
+ session->internals.resumed_security_parameters.version = version;
+
+ if (master->size != GNUTLS_MASTER_SIZE)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ memcpy(session->internals.resumed_security_parameters.master_secret, master->data, master->size);
+
+ if (session_id->size > GNUTLS_MAX_SESSION_ID)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ session->internals.resumed_security_parameters.session_id_size = session_id->size;
+ memcpy(session->internals.resumed_security_parameters.session_id, session_id->data, session_id->size);
+
+ session->internals.resumed_security_parameters.max_record_send_size =
+ session->internals.resumed_security_parameters.max_record_recv_size = DEFAULT_MAX_RECORD_SIZE;
+
+ session->internals.resumed_security_parameters.timestamp = time(0);
+
+ session->internals.resumed_security_parameters.ecc_curve = GNUTLS_ECC_CURVE_INVALID;
+
+ session->internals.premaster_set = 1;
+
+ return 0;
+}
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 9d78967681..02832bfcae 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -503,6 +503,7 @@ extern "C"
* @GNUTLS_TLS1_1: TLS version 1.1.
* @GNUTLS_TLS1_2: TLS version 1.2.
* @GNUTLS_DTLS1_0: DTLS version 1.0.
+ * @GNUTLS_DTLS0_9: DTLS version 0.9 (Cisco AnyConnect / OpenSSL 0.9.8e).
* @GNUTLS_VERSION_MAX: Maps to the highest supported TLS version.
* @GNUTLS_VERSION_UNKNOWN: Unknown SSL/TLS version.
*
@@ -516,7 +517,8 @@ extern "C"
GNUTLS_TLS1_1 = 3,
GNUTLS_TLS1_2 = 4,
GNUTLS_DTLS1_0 = 5,
- GNUTLS_VERSION_MAX = GNUTLS_DTLS1_0,
+ GNUTLS_DTLS0_9 = 6,
+ GNUTLS_VERSION_MAX = GNUTLS_DTLS0_9,
GNUTLS_VERSION_UNKNOWN = 0xff
} gnutls_protocol_t;
@@ -965,6 +967,15 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session);
void gnutls_session_get_random (gnutls_session_t session, gnutls_datum_t* client,
gnutls_datum_t* server);
+ int gnutls_session_set_premaster (gnutls_session_t session, unsigned int entity,
+ gnutls_protocol_t version,
+ gnutls_kx_algorithm_t kx,
+ gnutls_cipher_algorithm_t cipher,
+ gnutls_mac_algorithm_t mac,
+ gnutls_compression_method_t comp,
+ const gnutls_datum_t* master,
+ const gnutls_datum_t * session_id);
+
/* returns the session ID */
#define GNUTLS_MAX_SESSION_ID 32
int gnutls_session_get_id (gnutls_session_t session, void *session_id,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index b2b9825368..108c765808 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -788,6 +788,7 @@ GNUTLS_3_0_0 {
gnutls_pubkey_verify_hash2;
gnutls_pk_to_sign;
gnutls_certificate_set_x509_system_trust;
+ gnutls_session_set_premaster;
} GNUTLS_2_12;
GNUTLS_PRIVATE {