Coverage Report

Created: 2025-03-18 06:55

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