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