Fixed leaks in key generation and other cleanups. Patch by Tomas Mraz.
[gnutls.git] / lib / gnutls_v2_compat.c
blob64fd6d336a33d4b1efbedfd3f6ddec683bcc3ed0
1 /*
2 * Copyright (C) 2001, 2004, 2005, 2006, 2008, 2010 Free Software
3 * Foundation, Inc.
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 * USA
26 /* Functions to parse the SSLv2.0 hello message.
29 #include "gnutls_int.h"
30 #include "gnutls_errors.h"
31 #include "gnutls_dh.h"
32 #include "debug.h"
33 #include "gnutls_algorithms.h"
34 #include "gnutls_compress.h"
35 #include "gnutls_cipher.h"
36 #include "gnutls_buffers.h"
37 #include "gnutls_kx.h"
38 #include "gnutls_handshake.h"
39 #include "gnutls_num.h"
40 #include "gnutls_hash_int.h"
41 #include "gnutls_db.h"
42 #include "gnutls_extensions.h"
43 #include "gnutls_auth.h"
44 #include "gnutls_v2_compat.h"
45 #include "gnutls_constate.h"
47 /* This selects the best supported ciphersuite from the ones provided */
48 static int
49 _gnutls_handshake_select_v2_suite (gnutls_session_t session,
50 opaque * data, int datalen)
52 int i, j, ret;
53 opaque *_data;
54 int _datalen;
56 _gnutls_handshake_log ("HSK[%p]: Parsing a version 2.0 client hello.\n",
57 session);
59 _data = gnutls_malloc (datalen);
60 if (_data == NULL)
62 gnutls_assert ();
63 return GNUTLS_E_MEMORY_ERROR;
66 if (datalen % 3 != 0)
68 gnutls_assert ();
69 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
72 i = _datalen = 0;
73 for (j = 0; j < datalen; j += 3)
75 if (data[j] == 0)
77 memcpy (&_data[i], &data[j + 1], 2);
78 i += 2;
79 _datalen += 2;
83 ret = _gnutls_server_select_suite (session, _data, _datalen);
84 gnutls_free (_data);
86 return ret;
91 /* Read a v2 client hello. Some browsers still use that beast!
92 * However they set their version to 3.0 or 3.1.
94 int
95 _gnutls_read_client_hello_v2 (gnutls_session_t session, opaque * data,
96 int datalen)
98 uint16_t session_id_len = 0;
99 int pos = 0;
100 int ret = 0;
101 uint16_t sizeOfSuites;
102 gnutls_protocol_t adv_version;
103 opaque rnd[GNUTLS_RANDOM_SIZE];
104 int len = datalen;
105 int err;
106 uint16_t challenge;
107 opaque session_id[TLS_MAX_SESSION_ID_SIZE];
109 /* we only want to get here once - only in client hello */
110 session->internals.v2_hello = 0;
112 DECR_LEN (len, 2);
114 _gnutls_handshake_log
115 ("HSK[%p]: SSL 2.0 Hello: Client's version: %d.%d\n", session,
116 data[pos], data[pos + 1]);
118 set_adv_version (session, data[pos], data[pos + 1]);
120 adv_version = _gnutls_version_get (data[pos], data[pos + 1]);
122 ret = _gnutls_negotiate_version (session, adv_version);
123 if (ret < 0)
125 gnutls_assert ();
126 return ret;
129 pos += 2;
131 /* Read uint16_t cipher_spec_length */
132 DECR_LEN (len, 2);
133 sizeOfSuites = _gnutls_read_uint16 (&data[pos]);
134 pos += 2;
136 /* read session id length */
137 DECR_LEN (len, 2);
138 session_id_len = _gnutls_read_uint16 (&data[pos]);
139 pos += 2;
141 if (session_id_len > TLS_MAX_SESSION_ID_SIZE)
143 gnutls_assert ();
144 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
147 /* read challenge length */
148 DECR_LEN (len, 2);
149 challenge = _gnutls_read_uint16 (&data[pos]);
150 pos += 2;
152 if (challenge < 16 || challenge > GNUTLS_RANDOM_SIZE)
154 gnutls_assert ();
155 return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
158 /* call the user hello callback
160 ret = _gnutls_user_hello_func (session, adv_version);
161 if (ret < 0)
163 gnutls_assert ();
164 return ret;
167 /* find an appropriate cipher suite */
169 DECR_LEN (len, sizeOfSuites);
170 ret = _gnutls_handshake_select_v2_suite (session, &data[pos], sizeOfSuites);
172 pos += sizeOfSuites;
173 if (ret < 0)
175 gnutls_assert ();
176 return ret;
179 /* check if the credentials (username, public key etc.) are ok
181 if (_gnutls_get_kx_cred
182 (session,
183 _gnutls_cipher_suite_get_kx_algo (&session->
184 security_parameters.current_cipher_suite),
185 &err) == NULL && err != 0)
187 gnutls_assert ();
188 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
191 /* set the mod_auth_st to the appropriate struct
192 * according to the KX algorithm. This is needed since all the
193 * handshake functions are read from there;
195 session->internals.auth_struct =
196 _gnutls_kx_auth_struct (_gnutls_cipher_suite_get_kx_algo
197 (&session->
198 security_parameters.current_cipher_suite));
199 if (session->internals.auth_struct == NULL)
202 _gnutls_handshake_log
203 ("HSK[%p]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n",
204 session);
206 gnutls_assert ();
207 return GNUTLS_E_INTERNAL_ERROR;
212 /* read random new values -skip session id for now */
213 DECR_LEN (len, session_id_len); /* skip session id for now */
214 memcpy (session_id, &data[pos], session_id_len);
215 pos += session_id_len;
217 DECR_LEN (len, challenge);
218 memset (rnd, 0, GNUTLS_RANDOM_SIZE);
220 memcpy (&rnd[GNUTLS_RANDOM_SIZE - challenge], &data[pos], challenge);
222 _gnutls_set_client_random (session, rnd);
224 /* generate server random value */
226 _gnutls_tls_create_random (rnd);
227 _gnutls_set_server_random (session, rnd);
229 session->security_parameters.timestamp = gnutls_time (NULL);
232 /* RESUME SESSION */
234 DECR_LEN (len, session_id_len);
235 ret = _gnutls_server_restore_session (session, session_id, session_id_len);
237 if (ret == 0)
238 { /* resumed! */
239 /* get the new random values */
240 memcpy (session->internals.resumed_security_parameters.server_random,
241 session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);
242 memcpy (session->internals.resumed_security_parameters.client_random,
243 session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
245 session->internals.resumed = RESUME_TRUE;
246 return 0;
248 else
250 _gnutls_generate_session_id (session->security_parameters.session_id,
251 &session->
252 security_parameters.session_id_size);
253 session->internals.resumed = RESUME_FALSE;
256 session->internals.compression_method = GNUTLS_COMP_NULL;
257 _gnutls_epoch_set_compression (session, EPOCH_NEXT, session->internals.compression_method);
259 return 0;