Blame lib/sslv2_compat.c

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