Tizen 2.0 Release
[external/libgnutls26.git] / lib / gnutls_v2_compat.c
1 /*
2  * Copyright (C) 2001, 2004, 2005, 2006, 2008, 2010 Free Software
3  * Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
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.
13  *
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.
18  *
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
23  *
24  */
25
26 /* Functions to parse the SSLv2.0 hello message.
27  */
28
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"
46
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)
51 {
52   int i, j, ret;
53   opaque *_data;
54   int _datalen;
55
56   _gnutls_handshake_log ("HSK[%p]: Parsing a version 2.0 client hello.\n",
57                          session);
58
59   _data = gnutls_malloc (datalen);
60   if (_data == NULL)
61     {
62       gnutls_assert ();
63       return GNUTLS_E_MEMORY_ERROR;
64     }
65
66   if (datalen % 3 != 0)
67     {
68       gnutls_assert ();
69       return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
70     }
71
72   i = _datalen = 0;
73   for (j = 0; j < datalen; j += 3)
74     {
75       if (data[j] == 0)
76         {
77           memcpy (&_data[i], &data[j + 1], 2);
78           i += 2;
79           _datalen += 2;
80         }
81     }
82
83   ret = _gnutls_server_select_suite (session, _data, _datalen);
84   gnutls_free (_data);
85
86   return ret;
87
88 }
89
90
91 /* Read a v2 client hello. Some browsers still use that beast!
92  * However they set their version to 3.0 or 3.1.
93  */
94 int
95 _gnutls_read_client_hello_v2 (gnutls_session_t session, opaque * data,
96                               int datalen)
97 {
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];
108
109   /* we only want to get here once - only in client hello */
110   session->internals.v2_hello = 0;
111
112   DECR_LEN (len, 2);
113
114   _gnutls_handshake_log
115     ("HSK[%p]: SSL 2.0 Hello: Client's version: %d.%d\n", session,
116      data[pos], data[pos + 1]);
117
118   set_adv_version (session, data[pos], data[pos + 1]);
119
120   adv_version = _gnutls_version_get (data[pos], data[pos + 1]);
121
122   ret = _gnutls_negotiate_version (session, adv_version);
123   if (ret < 0)
124     {
125       gnutls_assert ();
126       return ret;
127     }
128
129   pos += 2;
130
131   /* Read uint16_t cipher_spec_length */
132   DECR_LEN (len, 2);
133   sizeOfSuites = _gnutls_read_uint16 (&data[pos]);
134   pos += 2;
135
136   /* read session id length */
137   DECR_LEN (len, 2);
138   session_id_len = _gnutls_read_uint16 (&data[pos]);
139   pos += 2;
140
141   if (session_id_len > TLS_MAX_SESSION_ID_SIZE)
142     {
143       gnutls_assert ();
144       return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
145     }
146
147   /* read challenge length */
148   DECR_LEN (len, 2);
149   challenge = _gnutls_read_uint16 (&data[pos]);
150   pos += 2;
151
152   if (challenge < 16 || challenge > GNUTLS_RANDOM_SIZE)
153     {
154       gnutls_assert ();
155       return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
156     }
157
158   /* call the user hello callback
159    */
160   ret = _gnutls_user_hello_func (session, adv_version);
161   if (ret < 0)
162     {
163       gnutls_assert ();
164       return ret;
165     }
166
167   /* find an appropriate cipher suite */
168
169   DECR_LEN (len, sizeOfSuites);
170   ret = _gnutls_handshake_select_v2_suite (session, &data[pos], sizeOfSuites);
171
172   pos += sizeOfSuites;
173   if (ret < 0)
174     {
175       gnutls_assert ();
176       return ret;
177     }
178
179   /* check if the credentials (username, public key etc.) are ok
180    */
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)
186     {
187       gnutls_assert ();
188       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
189     }
190
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;
194    */
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)
200     {
201
202       _gnutls_handshake_log
203         ("HSK[%p]: SSL 2.0 Hello: Cannot find the appropriate handler for the KX algorithm\n",
204          session);
205
206       gnutls_assert ();
207       return GNUTLS_E_INTERNAL_ERROR;
208     }
209
210
211
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;
216
217   DECR_LEN (len, challenge);
218   memset (rnd, 0, GNUTLS_RANDOM_SIZE);
219
220   memcpy (&rnd[GNUTLS_RANDOM_SIZE - challenge], &data[pos], challenge);
221
222   _gnutls_set_client_random (session, rnd);
223
224   /* generate server random value */
225
226   _gnutls_tls_create_random (rnd);
227   _gnutls_set_server_random (session, rnd);
228
229   session->security_parameters.timestamp = gnutls_time (NULL);
230
231
232   /* RESUME SESSION */
233
234   DECR_LEN (len, session_id_len);
235   ret = _gnutls_server_restore_session (session, session_id, session_id_len);
236
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);
244
245       session->internals.resumed = RESUME_TRUE;
246       return 0;
247     }
248   else
249     {
250       _gnutls_generate_session_id (session->security_parameters.session_id,
251                                    &session->
252                                    security_parameters.session_id_size);
253       session->internals.resumed = RESUME_FALSE;
254     }
255
256   session->internals.compression_method = GNUTLS_COMP_NULL;
257   _gnutls_epoch_set_compression (session, EPOCH_NEXT, session->internals.compression_method);
258
259   return 0;
260 }