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 */ |
45 | static 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 | */ |
92 | int |
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 | |