Line data Source code
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 <https://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 "errors.h"
28 : #include "dh.h"
29 : #include "debug.h"
30 : #include "algorithms.h"
31 : #include "cipher.h"
32 : #include "buffers.h"
33 : #include "kx.h"
34 : #include "handshake.h"
35 : #include "num.h"
36 : #include "hash_int.h"
37 : #include "db.h"
38 : #include "hello_ext.h"
39 : #include "auth.h"
40 : #include "sslv2_compat.h"
41 : #include "constate.h"
42 :
43 : #ifdef ENABLE_SSL2
44 : /* This selects the best supported ciphersuite from the ones provided */
45 : static int
46 676 : _gnutls_handshake_select_v2_suite(gnutls_session_t session,
47 : uint8_t * data, unsigned int datalen)
48 : {
49 676 : unsigned int i, j;
50 676 : int ret;
51 676 : uint8_t *_data;
52 676 : int _datalen;
53 :
54 676 : _gnutls_handshake_log
55 : ("HSK[%p]: Parsing a version 2.0 client hello.\n", session);
56 :
57 676 : if (datalen % 3 != 0) {
58 3 : gnutls_assert();
59 3 : return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
60 : }
61 :
62 673 : _data = gnutls_malloc(datalen);
63 673 : if (_data == NULL) {
64 0 : gnutls_assert();
65 0 : return GNUTLS_E_MEMORY_ERROR;
66 : }
67 :
68 : i = _datalen = 0;
69 7494 : for (j = 0; j < datalen; j += 3) {
70 6821 : if (data[j] == 0) {
71 4923 : memcpy(&_data[i], &data[j + 1], 2);
72 4923 : i += 2;
73 4923 : _datalen += 2;
74 : }
75 : }
76 :
77 673 : ret = _gnutls_server_select_suite(session, _data, _datalen, 0);
78 673 : gnutls_free(_data);
79 :
80 673 : return ret;
81 :
82 : }
83 :
84 :
85 : /* Read a v2 client hello. Some browsers still use that beast!
86 : * However they set their version to 3.0 or 3.1.
87 : */
88 : int
89 735 : _gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data,
90 : unsigned int len)
91 : {
92 735 : uint16_t session_id_len = 0;
93 735 : int pos = 0;
94 735 : int ret = 0, sret = 0;
95 735 : uint16_t sizeOfSuites;
96 735 : uint8_t rnd[GNUTLS_RANDOM_SIZE], major, minor;
97 735 : int neg_version;
98 735 : const version_entry_st *vers;
99 735 : uint16_t challenge;
100 735 : uint8_t session_id[GNUTLS_MAX_SESSION_ID_SIZE];
101 :
102 735 : DECR_LEN(len, 2);
103 :
104 735 : _gnutls_handshake_log
105 : ("HSK[%p]: SSL 2.0 Hello: Client's version: %d.%d\n", session,
106 : data[pos], data[pos + 1]);
107 :
108 735 : major = data[pos];
109 735 : minor = data[pos + 1];
110 735 : set_adv_version(session, major, minor);
111 :
112 735 : ret = _gnutls_negotiate_version(session, major, minor, 0);
113 735 : if (ret < 0) {
114 39 : gnutls_assert();
115 39 : return ret;
116 : }
117 :
118 696 : vers = get_version(session);
119 696 : if (vers == NULL)
120 0 : return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
121 :
122 696 : neg_version = vers->id;
123 :
124 696 : pos += 2;
125 :
126 : /* Read uint16_t cipher_spec_length */
127 696 : DECR_LEN(len, 2);
128 693 : sizeOfSuites = _gnutls_read_uint16(&data[pos]);
129 693 : pos += 2;
130 :
131 : /* read session id length */
132 693 : DECR_LEN(len, 2);
133 689 : session_id_len = _gnutls_read_uint16(&data[pos]);
134 689 : pos += 2;
135 :
136 689 : if (session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) {
137 3 : gnutls_assert();
138 3 : return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
139 : }
140 :
141 : /* read challenge length */
142 686 : DECR_LEN(len, 2);
143 683 : challenge = _gnutls_read_uint16(&data[pos]);
144 683 : pos += 2;
145 :
146 683 : if (challenge < 16 || challenge > GNUTLS_RANDOM_SIZE) {
147 4 : gnutls_assert();
148 4 : return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
149 : }
150 :
151 : /* call the user hello callback
152 : */
153 679 : ret = _gnutls_user_hello_func(session, major, minor);
154 679 : if (ret < 0) {
155 0 : if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
156 : sret = GNUTLS_E_INT_RET_0;
157 : } else {
158 0 : gnutls_assert();
159 0 : return ret;
160 : }
161 : }
162 :
163 : /* find an appropriate cipher suite */
164 :
165 679 : DECR_LEN(len, sizeOfSuites);
166 676 : ret =
167 676 : _gnutls_handshake_select_v2_suite(session, &data[pos],
168 : sizeOfSuites);
169 :
170 676 : pos += sizeOfSuites;
171 676 : if (ret < 0) {
172 146 : gnutls_assert();
173 146 : return ret;
174 : }
175 :
176 : /* check if the credentials (username, public key etc.) are ok
177 : */
178 530 : if (_gnutls_get_kx_cred
179 : (session,
180 530 : session->security_parameters.cs->kx_algorithm) == NULL) {
181 0 : gnutls_assert();
182 0 : return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
183 : }
184 :
185 : /* set the mod_auth_st to the appropriate struct
186 : * according to the KX algorithm. This is needed since all the
187 : * handshake functions are read from there;
188 : */
189 1060 : session->internals.auth_struct =
190 530 : _gnutls_kx_auth_struct(session->security_parameters.
191 : cs->kx_algorithm);
192 530 : if (session->internals.auth_struct == NULL) {
193 :
194 0 : _gnutls_handshake_log
195 : ("HSK[%p]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n",
196 : session);
197 :
198 0 : gnutls_assert();
199 0 : return GNUTLS_E_INTERNAL_ERROR;
200 : }
201 :
202 : /* read random new values -skip session id for now */
203 530 : DECR_LEN(len, session_id_len); /* skip session id for now */
204 527 : memcpy(session_id, &data[pos], session_id_len);
205 527 : pos += session_id_len;
206 :
207 527 : DECR_LEN(len, challenge);
208 521 : memset(rnd, 0, GNUTLS_RANDOM_SIZE);
209 :
210 521 : memcpy(&rnd[GNUTLS_RANDOM_SIZE - challenge], &data[pos],
211 : challenge);
212 :
213 521 : _gnutls_set_client_random(session, rnd);
214 :
215 : /* generate server random value */
216 521 : ret = _gnutls_gen_server_random(session, neg_version);
217 521 : if (ret < 0)
218 0 : return gnutls_assert_val(ret);
219 :
220 521 : session->security_parameters.timestamp = gnutls_time(NULL);
221 :
222 :
223 : /* RESUME SESSION */
224 :
225 521 : DECR_LEN(len, session_id_len);
226 518 : ret =
227 518 : _gnutls_server_restore_session(session, session_id,
228 : session_id_len);
229 :
230 518 : if (ret == 0) { /* resumed! */
231 : /* get the new random values */
232 0 : memcpy(session->internals.resumed_security_parameters.
233 : server_random,
234 0 : session->security_parameters.server_random,
235 : GNUTLS_RANDOM_SIZE);
236 0 : memcpy(session->internals.resumed_security_parameters.
237 : client_random,
238 0 : session->security_parameters.client_random,
239 : GNUTLS_RANDOM_SIZE);
240 :
241 0 : session->internals.resumed = RESUME_TRUE;
242 0 : return 0;
243 : } else {
244 1036 : ret = _gnutls_generate_session_id(
245 518 : session->security_parameters.session_id,
246 : &session->security_parameters.session_id_size);
247 518 : if (ret < 0)
248 0 : return gnutls_assert_val(ret);
249 :
250 518 : session->internals.resumed = RESUME_FALSE;
251 : }
252 :
253 518 : return sret;
254 : }
255 : #endif
|