Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/tls13/hello_retry.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2017 Red Hat, 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
#include "gnutls_int.h"
24
#include "errors.h"
25
#include "hello_ext.h"
26
#include "handshake.h"
27
#include "tls13/hello_retry.h"
28
#include "auth/cert.h"
29
#include "mbuffers.h"
30
#include "state.h"
31
32
int _gnutls13_send_hello_retry_request(gnutls_session_t session, unsigned again)
33
0
{
34
0
  int ret;
35
0
  mbuffer_st *bufel = NULL;
36
0
  gnutls_buffer_st buf;
37
0
  const version_entry_st *ver;
38
0
  const uint8_t vbuf[2] = { 0x03, 0x03 };
39
40
0
  if (again == 0) {
41
0
    ver = get_version(session);
42
0
    if (unlikely(ver == NULL ||
43
0
           session->security_parameters.cs == NULL))
44
0
      return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
45
46
0
    ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
47
0
    if (ret < 0)
48
0
      return gnutls_assert_val(ret);
49
50
0
    ret = _gnutls_buffer_append_data(&buf, vbuf, 2);
51
0
    if (ret < 0)
52
0
      return gnutls_assert_val(ret);
53
54
0
    ret = _gnutls_buffer_append_data(&buf, HRR_RANDOM,
55
0
             GNUTLS_RANDOM_SIZE);
56
0
    if (ret < 0) {
57
0
      gnutls_assert();
58
0
      goto cleanup;
59
0
    }
60
61
0
    ret = _gnutls_buffer_append_data_prefix(
62
0
      &buf, 8, session->security_parameters.session_id,
63
0
      session->security_parameters.session_id_size);
64
0
    if (ret < 0) {
65
0
      gnutls_assert();
66
0
      goto cleanup;
67
0
    }
68
69
0
    ret = _gnutls_buffer_append_data(
70
0
      &buf, session->security_parameters.cs->id, 2);
71
0
    if (ret < 0) {
72
0
      gnutls_assert();
73
0
      goto cleanup;
74
0
    }
75
76
    /* compression */
77
0
    ret = _gnutls_buffer_append_prefix(&buf, 8, 0);
78
0
    if (ret < 0) {
79
0
      gnutls_assert();
80
0
      goto cleanup;
81
0
    }
82
83
0
    ret = _gnutls_gen_hello_extensions(
84
0
      session, &buf, GNUTLS_EXT_FLAG_HRR, GNUTLS_EXT_ANY);
85
0
    if (ret < 0) {
86
0
      gnutls_assert();
87
0
      goto cleanup;
88
0
    }
89
90
    /* reset extensions sent by this session to allow re-sending them */
91
0
    session->internals.used_exts = 0;
92
93
0
    reset_binders(session);
94
95
0
    bufel = _gnutls_buffer_to_mbuffer(&buf);
96
0
  }
97
98
0
  return _gnutls_send_handshake(session, bufel,
99
0
              GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST);
100
101
0
cleanup:
102
0
  _gnutls_buffer_clear(&buf);
103
0
  return ret;
104
0
}
105
106
int _gnutls13_recv_hello_retry_request(gnutls_session_t session,
107
               gnutls_buffer_st *buf)
108
0
{
109
0
  int ret;
110
0
  uint8_t tmp[2];
111
0
  const gnutls_cipher_suite_entry_st *cs;
112
0
  const mac_entry_st *prf;
113
0
  gnutls_datum_t session_id;
114
0
  uint8_t random[GNUTLS_RANDOM_SIZE];
115
116
  /* only under TLS 1.3 */
117
0
  if (IS_DTLS(session))
118
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
119
120
0
  if (session->internals.hsk_flags & HSK_HRR_RECEIVED)
121
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
122
123
0
  session->internals.hsk_flags |= HSK_HRR_RECEIVED;
124
125
  /* version */
126
0
  ret = _gnutls_buffer_pop_data(buf, tmp, 2);
127
0
  if (ret < 0)
128
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
129
130
0
  if (unlikely(tmp[0] != 0x03 || tmp[1] != 0x03))
131
0
    return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
132
133
0
  ret = _gnutls_buffer_pop_data(buf, random, GNUTLS_RANDOM_SIZE);
134
0
  if (ret < 0)
135
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
136
137
0
  if (memcmp(random, HRR_RANDOM, GNUTLS_RANDOM_SIZE) != 0) {
138
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
139
0
  }
140
141
0
  ret = _gnutls_buffer_pop_datum_prefix8(buf, &session_id);
142
0
  if (ret < 0)
143
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
144
145
  /* read ciphersuites */
146
0
  ret = _gnutls_buffer_pop_data(buf, tmp, 2);
147
0
  if (ret < 0)
148
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
149
150
0
  cs = ciphersuite_to_entry(tmp);
151
0
  if (unlikely(cs == NULL))
152
0
    return gnutls_assert_val(GNUTLS_E_UNKNOWN_CIPHER_SUITE);
153
154
0
  _gnutls_handshake_log("EXT[%p]: Hello Retry Request with %s\n", session,
155
0
            cs->name);
156
0
  memcpy(session->internals.hrr_cs, cs->id, 2);
157
158
0
  prf = mac_to_entry(cs->prf);
159
0
  if (unlikely(prf == NULL))
160
0
    return gnutls_assert_val(GNUTLS_E_UNKNOWN_CIPHER_SUITE);
161
162
  /* compression */
163
0
  ret = _gnutls_buffer_pop_data(buf, tmp, 1);
164
0
  if (ret < 0)
165
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
166
167
0
  if (unlikely(tmp[0] != 0))
168
0
    return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
169
170
0
  ret = _gnutls13_handshake_hash_buffers_synth(session, prf, 1);
171
0
  if (ret < 0)
172
0
    return gnutls_assert_val(ret);
173
174
0
  if (buf->length <= 2) {
175
    /* no extensions present */
176
0
    return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
177
0
  }
178
179
  /* figure version first */
180
0
  ret = _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_HRR,
181
0
               GNUTLS_EXT_VERSION_NEG, buf->data,
182
0
               buf->length);
183
0
  if (ret < 0)
184
0
    return gnutls_assert_val(ret);
185
186
  /* parse the rest of extensions */
187
0
  ret = _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_HRR,
188
0
               GNUTLS_EXT_ANY, buf->data,
189
0
               buf->length);
190
0
  if (ret < 0)
191
0
    return gnutls_assert_val(ret);
192
193
0
  session->internals.used_exts = 0;
194
195
0
  return 0;
196
0
}