summaryrefslogtreecommitdiffstats
path: root/lib/sslv2_compat.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/sslv2_compat.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/lib/sslv2_compat.c b/lib/sslv2_compat.c
new file mode 100644
index 0000000..c4a0143
--- /dev/null
+++ b/lib/sslv2_compat.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2001-2012 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* Functions to parse the SSLv2.0 hello message.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include "dh.h"
+#include "debug.h"
+#include "algorithms.h"
+#include "cipher.h"
+#include "buffers.h"
+#include "kx.h"
+#include "handshake.h"
+#include "num.h"
+#include "hash_int.h"
+#include "db.h"
+#include "hello_ext.h"
+#include "auth.h"
+#include "sslv2_compat.h"
+#include "constate.h"
+
+#ifdef ENABLE_SSL2
+/* This selects the best supported ciphersuite from the ones provided */
+static int
+_gnutls_handshake_select_v2_suite(gnutls_session_t session,
+ uint8_t * data, unsigned int datalen)
+{
+ unsigned int i, j;
+ int ret;
+ uint8_t *_data;
+ int _datalen;
+
+ _gnutls_handshake_log
+ ("HSK[%p]: Parsing a version 2.0 client hello.\n", session);
+
+ if (datalen % 3 != 0) {
+ gnutls_assert();
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ _data = gnutls_malloc(datalen);
+ if (_data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ i = _datalen = 0;
+ for (j = 0; j < datalen; j += 3) {
+ if (data[j] == 0) {
+ memcpy(&_data[i], &data[j + 1], 2);
+ i += 2;
+ _datalen += 2;
+ }
+ }
+
+ ret = _gnutls_server_select_suite(session, _data, _datalen, 0);
+ gnutls_free(_data);
+
+ return ret;
+
+}
+
+
+/* Read a v2 client hello. Some browsers still use that beast!
+ * However they set their version to 3.0 or 3.1.
+ */
+int
+_gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data,
+ unsigned int len)
+{
+ uint16_t session_id_len = 0;
+ int pos = 0;
+ int ret = 0, sret = 0;
+ uint16_t sizeOfSuites;
+ uint8_t rnd[GNUTLS_RANDOM_SIZE], major, minor;
+ int neg_version;
+ const version_entry_st *vers;
+ uint16_t challenge;
+ uint8_t session_id[GNUTLS_MAX_SESSION_ID_SIZE];
+
+ DECR_LEN(len, 2);
+
+ _gnutls_handshake_log
+ ("HSK[%p]: SSL 2.0 Hello: Client's version: %d.%d\n", session,
+ data[pos], data[pos + 1]);
+
+ major = data[pos];
+ minor = data[pos + 1];
+ set_adv_version(session, major, minor);
+
+ ret = _gnutls_negotiate_version(session, major, minor, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ vers = get_version(session);
+ if (vers == NULL)
+ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
+
+ neg_version = vers->id;
+
+ pos += 2;
+
+ /* Read uint16_t cipher_spec_length */
+ DECR_LEN(len, 2);
+ sizeOfSuites = _gnutls_read_uint16(&data[pos]);
+ pos += 2;
+
+ /* read session id length */
+ DECR_LEN(len, 2);
+ session_id_len = _gnutls_read_uint16(&data[pos]);
+ pos += 2;
+
+ if (session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) {
+ gnutls_assert();
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ /* read challenge length */
+ DECR_LEN(len, 2);
+ challenge = _gnutls_read_uint16(&data[pos]);
+ pos += 2;
+
+ if (challenge < 16 || challenge > GNUTLS_RANDOM_SIZE) {
+ gnutls_assert();
+ return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+ }
+
+ /* call the user hello callback
+ */
+ ret = _gnutls_user_hello_func(session, major, minor);
+ if (ret < 0) {
+ if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
+ sret = GNUTLS_E_INT_RET_0;
+ } else {
+ gnutls_assert();
+ return ret;
+ }
+ }
+
+ /* find an appropriate cipher suite */
+
+ DECR_LEN(len, sizeOfSuites);
+ ret =
+ _gnutls_handshake_select_v2_suite(session, &data[pos],
+ sizeOfSuites);
+
+ pos += sizeOfSuites;
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* check if the credentials (username, public key etc.) are ok
+ */
+ if (_gnutls_get_kx_cred
+ (session,
+ session->security_parameters.cs->kx_algorithm) == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ /* set the mod_auth_st to the appropriate struct
+ * according to the KX algorithm. This is needed since all the
+ * handshake functions are read from there;
+ */
+ session->internals.auth_struct =
+ _gnutls_kx_auth_struct(session->security_parameters.
+ cs->kx_algorithm);
+ if (session->internals.auth_struct == NULL) {
+
+ _gnutls_handshake_log
+ ("HSK[%p]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n",
+ session);
+
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ /* read random new values -skip session id for now */
+ DECR_LEN(len, session_id_len); /* skip session id for now */
+ memcpy(session_id, &data[pos], session_id_len);
+ pos += session_id_len;
+
+ DECR_LEN(len, challenge);
+ memset(rnd, 0, GNUTLS_RANDOM_SIZE);
+
+ memcpy(&rnd[GNUTLS_RANDOM_SIZE - challenge], &data[pos],
+ challenge);
+
+ _gnutls_set_client_random(session, rnd);
+
+ /* generate server random value */
+ ret = _gnutls_gen_server_random(session, neg_version);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->security_parameters.timestamp = gnutls_time(NULL);
+
+
+ /* RESUME SESSION */
+
+ DECR_LEN(len, session_id_len);
+ ret =
+ _gnutls_server_restore_session(session, session_id,
+ session_id_len);
+
+ if (ret == 0) { /* resumed! */
+ /* get the new random values */
+ memcpy(session->internals.resumed_security_parameters.
+ server_random,
+ session->security_parameters.server_random,
+ GNUTLS_RANDOM_SIZE);
+ memcpy(session->internals.resumed_security_parameters.
+ client_random,
+ session->security_parameters.client_random,
+ GNUTLS_RANDOM_SIZE);
+
+ session->internals.resumed = true;
+ return 0;
+ } else {
+ ret = _gnutls_generate_session_id(
+ session->security_parameters.session_id,
+ &session->security_parameters.session_id_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->internals.resumed = false;
+ }
+
+ return sret;
+}
+#endif