Version 2.3.13.
[gnutls.git] / lib / gnutls_v2_compat.c
blob95cbd2ff65b9a8703ff276d00072acfa2e1d27f2
1 /*
2 * Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GNUTLS.
8 * The GNUTLS library 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.
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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * USA
25 /* Functions to parse the SSLv2.0 hello message.
28 #include "gnutls_int.h"
29 #include "gnutls_errors.h"
30 #include "gnutls_dh.h"
31 #include "debug.h"
32 #include "gnutls_algorithms.h"
33 #include "gnutls_compress.h"
34 #include "gnutls_cipher.h"
35 #include "gnutls_buffers.h"
36 #include "gnutls_kx.h"
37 #include "gnutls_handshake.h"
38 #include "gnutls_num.h"
39 #include "gnutls_hash_int.h"
40 #include "gnutls_db.h"
41 #include "gnutls_extensions.h"
42 #include "gnutls_auth_int.h"
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 opaque * data, int datalen)
49 int i, j, ret;
50 opaque *_data;
51 int _datalen;
53 _gnutls_handshake_log ("HSK[%x]: Parsing a version 2.0 client hello.\n",
54 session);
56 _data = gnutls_malloc (datalen);
57 if (_data == NULL)
59 gnutls_assert ();
60 return GNUTLS_E_MEMORY_ERROR;
63 if (datalen % 3 != 0)
65 gnutls_assert ();
66 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
69 i = _datalen = 0;
70 for (j = 0; j < datalen; j += 3)
72 if (data[j] == 0)
74 memcpy (&_data[i], &data[j + 1], 2);
75 i += 2;
76 _datalen += 2;
80 ret = _gnutls_server_select_suite (session, _data, _datalen);
81 gnutls_free (_data);
83 return ret;
88 /* Read a v2 client hello. Some browsers still use that beast!
89 * However they set their version to 3.0 or 3.1.
91 int
92 _gnutls_read_client_hello_v2 (gnutls_session_t session, opaque * data,
93 int datalen)
95 uint16_t session_id_len = 0;
96 int pos = 0;
97 int ret = 0;
98 uint16_t sizeOfSuites;
99 gnutls_protocol_t adv_version;
100 opaque rnd[TLS_RANDOM_SIZE];
101 int len = datalen;
102 int err;
103 uint16_t challenge;
104 opaque session_id[TLS_MAX_SESSION_ID_SIZE];
106 /* we only want to get here once - only in client hello */
107 session->internals.v2_hello = 0;
109 DECR_LEN (len, 2);
111 _gnutls_handshake_log
112 ("HSK[%x]: SSL 2.0 Hello: Client's version: %d.%d\n", session,
113 data[pos], data[pos + 1]);
115 set_adv_version (session, data[pos], data[pos + 1]);
117 adv_version = _gnutls_version_get (data[pos], data[pos + 1]);
119 ret = _gnutls_negotiate_version( session, adv_version);
120 if (ret < 0)
122 gnutls_assert ();
123 return ret;
126 pos += 2;
128 /* Read uint16_t cipher_spec_length */
129 DECR_LEN (len, 2);
130 sizeOfSuites = _gnutls_read_uint16 (&data[pos]);
131 pos += 2;
133 /* read session id length */
134 DECR_LEN (len, 2);
135 session_id_len = _gnutls_read_uint16 (&data[pos]);
136 pos += 2;
138 if (session_id_len > TLS_MAX_SESSION_ID_SIZE)
140 gnutls_assert ();
141 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
144 /* read challenge length */
145 DECR_LEN (len, 2);
146 challenge = _gnutls_read_uint16 (&data[pos]);
147 pos += 2;
149 if (challenge < 16 || challenge > TLS_RANDOM_SIZE)
151 gnutls_assert ();
152 return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
155 /* call the user hello callback
157 ret = _gnutls_user_hello_func( session, adv_version);
158 if (ret < 0)
160 gnutls_assert();
161 return ret;
164 /* find an appropriate cipher suite */
166 DECR_LEN (len, sizeOfSuites);
167 ret = _gnutls_handshake_select_v2_suite (session, &data[pos], sizeOfSuites);
169 pos += sizeOfSuites;
170 if (ret < 0)
172 gnutls_assert ();
173 return ret;
176 /* check if the credentials (username, public key etc.) are ok
178 if (_gnutls_get_kx_cred
179 (session,
180 _gnutls_cipher_suite_get_kx_algo (&session->security_parameters.
181 current_cipher_suite),
182 &err) == NULL && err != 0)
184 gnutls_assert ();
185 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
188 /* set the mod_auth_st to the appropriate struct
189 * according to the KX algorithm. This is needed since all the
190 * handshake functions are read from there;
192 session->internals.auth_struct =
193 _gnutls_kx_auth_struct (_gnutls_cipher_suite_get_kx_algo
194 (&session->security_parameters.
195 current_cipher_suite));
196 if (session->internals.auth_struct == NULL)
199 _gnutls_handshake_log
200 ("HSK[%x]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n",
201 session);
203 gnutls_assert ();
204 return GNUTLS_E_INTERNAL_ERROR;
209 /* read random new values -skip session id for now */
210 DECR_LEN (len, session_id_len); /* skip session id for now */
211 memcpy (session_id, &data[pos], session_id_len);
212 pos += session_id_len;
214 DECR_LEN (len, challenge);
215 memset (rnd, 0, TLS_RANDOM_SIZE);
217 memcpy (&rnd[TLS_RANDOM_SIZE - challenge], &data[pos], challenge);
219 _gnutls_set_client_random (session, rnd);
221 /* generate server random value */
223 _gnutls_tls_create_random (rnd);
224 _gnutls_set_server_random (session, rnd);
226 session->security_parameters.timestamp = time (NULL);
229 /* RESUME SESSION */
231 DECR_LEN (len, session_id_len);
232 ret = _gnutls_server_restore_session (session, session_id, session_id_len);
234 if (ret == 0)
235 { /* resumed! */
236 /* get the new random values */
237 memcpy (session->internals.resumed_security_parameters.
238 server_random, session->security_parameters.server_random,
239 TLS_RANDOM_SIZE);
240 memcpy (session->internals.resumed_security_parameters.
241 client_random, session->security_parameters.client_random,
242 TLS_RANDOM_SIZE);
244 session->internals.resumed = RESUME_TRUE;
245 return 0;
247 else
249 _gnutls_generate_session_id (session->security_parameters.
250 session_id,
251 &session->security_parameters.
252 session_id_size);
253 session->internals.resumed = RESUME_FALSE;
256 session->internals.compression_method = GNUTLS_COMP_NULL;
258 return 0;