1/*
2 * Copyright (C) 2001-2012 Free Software Foundation, Inc.
3 *
4 * Author: Nikos Mavrogiannopoulos
5 *
6 * This file is part of GnuTLS.
7 *
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
20 *
21 */
22
23/* Functions to parse the SSLv2.0 hello message.
24 */
25
26#include "gnutls_int.h"
27#include "gnutls_errors.h"
28#include "gnutls_dh.h"
29#include "debug.h"
30#include "algorithms.h"
31#include "gnutls_compress.h"
32#include "gnutls_cipher.h"
33#include "gnutls_buffers.h"
34#include "gnutls_kx.h"
35#include "gnutls_handshake.h"
36#include "gnutls_num.h"
37#include "gnutls_hash_int.h"
38#include "gnutls_db.h"
39#include "gnutls_extensions.h"
40#include "gnutls_auth.h"
41#include "gnutls_v2_compat.h"
42#include "gnutls_constate.h"
43
44/* This selects the best supported ciphersuite from the ones provided */
45static int
46_gnutls_handshake_select_v2_suite (gnutls_session_t session,
47 uint8_t * data, unsigned int datalen)
48{
49 unsigned int i, j;
50 int ret;
51 uint8_t *_data;
52 int _datalen;
53
54 _gnutls_handshake_log ("HSK[%p]: Parsing a version 2.0 client hello.\n",
55 session);
56
57 _data = gnutls_malloc (datalen);
58 if (_data == NULL)
59 {
60 gnutls_assert ();
61 return GNUTLS_E_MEMORY_ERROR;
62 }
63
64 if (datalen % 3 != 0)
65 {
66 gnutls_assert ();
67 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
68 }
69
70 i = _datalen = 0;
71 for (j = 0; j < datalen; j += 3)
72 {
73 if (data[j] == 0)
74 {
75 memcpy (&_data[i], &data[j + 1], 2);
76 i += 2;
77 _datalen += 2;
78 }
79 }
80
81 ret = _gnutls_server_select_suite (session, _data, _datalen);
82 gnutls_free (_data);
83
84 return ret;
85
86}
87
88
89/* Read a v2 client hello. Some browsers still use that beast!
90 * However they set their version to 3.0 or 3.1.
91 */
92int
93_gnutls_read_client_hello_v2 (gnutls_session_t session, uint8_t * data,
94 unsigned int datalen)
95{
96 uint16_t session_id_len = 0;
97 int pos = 0;
98 int ret = 0;
99 uint16_t sizeOfSuites;
100 gnutls_protocol_t adv_version;
101 uint8_t rnd[GNUTLS_RANDOM_SIZE];
102 int len = datalen;
103 int err;
104 uint16_t challenge;
105 uint8_t session_id[TLS_MAX_SESSION_ID_SIZE];
106
107 DECR_LEN (len, 2);
108
109 _gnutls_handshake_log
110 ("HSK[%p]: SSL 2.0 Hello: Client's version: %d.%d\n", session,
111 data[pos], data[pos + 1]);
112
113 set_adv_version (session, data[pos], data[pos + 1]);
114
115 adv_version = _gnutls_version_get (data[pos], data[pos + 1]);
116
117 ret = _gnutls_negotiate_version (session, adv_version);
118 if (ret < 0)
119 {
120 gnutls_assert ();
121 return ret;
122 }
123
124 pos += 2;
125
126 /* Read uint16_t cipher_spec_length */
127 DECR_LEN (len, 2);
128 sizeOfSuites = _gnutls_read_uint16 (&data[pos]);
129 pos += 2;
130
131 /* read session id length */
132 DECR_LEN (len, 2);
133 session_id_len = _gnutls_read_uint16 (&data[pos]);
134 pos += 2;
135
136 if (session_id_len > TLS_MAX_SESSION_ID_SIZE)
137 {
138 gnutls_assert ();
139 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
140 }
141
142 /* read challenge length */
143 DECR_LEN (len, 2);
144 challenge = _gnutls_read_uint16 (&data[pos]);
145 pos += 2;
146
147 if (challenge < 16 || challenge > GNUTLS_RANDOM_SIZE)
148 {
149 gnutls_assert ();
150 return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
151 }
152
153 /* call the user hello callback
154 */
155 ret = _gnutls_user_hello_func (session, adv_version);
156 if (ret < 0)
157 {
158 gnutls_assert ();
159 return ret;
160 }
161
162 /* find an appropriate cipher suite */
163
164 DECR_LEN (len, sizeOfSuites);
165 ret = _gnutls_handshake_select_v2_suite (session, &data[pos], sizeOfSuites);
166
167 pos += sizeOfSuites;
168 if (ret < 0)
169 {
170 gnutls_assert ();
171 return ret;
172 }
173
174 /* check if the credentials (username, public key etc.) are ok
175 */
176 if (_gnutls_get_kx_cred
177 (session,
178 _gnutls_cipher_suite_get_kx_algo (session->
179 security_parameters.cipher_suite),
180 &err) == NULL && err != 0)
181 {
182 gnutls_assert ();
183 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
184 }
185
186 /* set the mod_auth_st to the appropriate struct
187 * according to the KX algorithm. This is needed since all the
188 * handshake functions are read from there;
189 */
190 session->internals.auth_struct =
191 _gnutls_kx_auth_struct (_gnutls_cipher_suite_get_kx_algo
192 (session->
193 security_parameters.cipher_suite));
194 if (session->internals.auth_struct == NULL)
195 {
196
197 _gnutls_handshake_log
198 ("HSK[%p]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n",
199 session);
200
201 gnutls_assert ();
202 return GNUTLS_E_INTERNAL_ERROR;
203 }
204
205 /* read random new values -skip session id for now */
206 DECR_LEN (len, session_id_len); /* skip session id for now */
207 memcpy (session_id, &data[pos], session_id_len);
208 pos += session_id_len;
209
210 DECR_LEN (len, challenge);
211 memset (rnd, 0, GNUTLS_RANDOM_SIZE);
212
213 memcpy (&rnd[GNUTLS_RANDOM_SIZE - challenge], &data[pos], challenge);
214
215 ret = _gnutls_set_client_random (session, rnd);
216 if (ret < 0)
217 return gnutls_assert_val(ret);
218
219 /* generate server random value */
220 ret = _gnutls_set_server_random (session, NULL);
221 if (ret < 0)
222 return gnutls_assert_val(ret);
223
224 session->security_parameters.timestamp = gnutls_time (NULL);
225
226
227 /* RESUME SESSION */
228
229 DECR_LEN (len, session_id_len);
230 ret = _gnutls_server_restore_session (session, session_id, session_id_len);
231
232 if (ret == 0)
233 { /* resumed! */
234 /* get the new random values */
235 memcpy (session->internals.resumed_security_parameters.server_random,
236 session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);
237 memcpy (session->internals.resumed_security_parameters.client_random,
238 session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
239
240 session->internals.resumed = RESUME_TRUE;
241 return 0;
242 }
243 else
244 {
245 _gnutls_generate_session_id (session->security_parameters.session_id,
246 &session->
247 security_parameters.session_id_size);
248 session->internals.resumed = RESUME_FALSE;
249 }
250
251 _gnutls_epoch_set_compression (session, EPOCH_NEXT, GNUTLS_COMP_NULL);
252 session->security_parameters.compression_method = GNUTLS_COMP_NULL;
253
254 return 0;
255}
256