1 |
|
|
/* $OpenBSD: ssl_packet.c,v 1.6 2017/05/06 16:18:36 jsing Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> |
4 |
|
|
* |
5 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
6 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
7 |
|
|
* copyright notice and this permission notice appear in all copies. |
8 |
|
|
* |
9 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 |
|
|
*/ |
17 |
|
|
|
18 |
|
|
#include "ssl_locl.h" |
19 |
|
|
|
20 |
|
|
#include "bytestring.h" |
21 |
|
|
|
22 |
|
|
static int |
23 |
|
|
ssl_is_sslv2_client_hello(CBS *header) |
24 |
|
|
{ |
25 |
|
12 |
uint16_t record_length; |
26 |
|
6 |
uint8_t message_type; |
27 |
|
6 |
CBS cbs; |
28 |
|
|
|
29 |
|
6 |
CBS_dup(header, &cbs); |
30 |
|
|
|
31 |
✓✗✗✓
|
12 |
if (!CBS_get_u16(&cbs, &record_length) || |
32 |
|
6 |
!CBS_get_u8(&cbs, &message_type)) |
33 |
|
|
return 0; |
34 |
|
|
|
35 |
|
|
/* |
36 |
|
|
* The SSLv2 record length field uses variable length (2 or 3 byte) |
37 |
|
|
* encoding. Given the size of a client hello, we expect/require the |
38 |
|
|
* 2-byte form which is indicated by a one in the most significant bit. |
39 |
|
|
*/ |
40 |
✗✓ |
6 |
if ((record_length & 0x8000) == 0) |
41 |
|
|
return 0; |
42 |
✗✓ |
6 |
if ((record_length & ~0x8000) < 3) |
43 |
|
|
return 0; |
44 |
✗✓ |
6 |
if (message_type != SSL2_MT_CLIENT_HELLO) |
45 |
|
|
return 0; |
46 |
|
|
|
47 |
|
6 |
return 1; |
48 |
|
6 |
} |
49 |
|
|
|
50 |
|
|
static int |
51 |
|
|
ssl_is_sslv3_handshake(CBS *header) |
52 |
|
|
{ |
53 |
|
324 |
uint16_t record_version; |
54 |
|
162 |
uint8_t record_type; |
55 |
|
162 |
CBS cbs; |
56 |
|
|
|
57 |
|
162 |
CBS_dup(header, &cbs); |
58 |
|
|
|
59 |
✓✗✗✓
|
324 |
if (!CBS_get_u8(&cbs, &record_type) || |
60 |
|
162 |
!CBS_get_u16(&cbs, &record_version)) |
61 |
|
|
return 0; |
62 |
|
|
|
63 |
✓✓ |
162 |
if (record_type != SSL3_RT_HANDSHAKE) |
64 |
|
6 |
return 0; |
65 |
✗✓ |
156 |
if ((record_version >> 8) != SSL3_VERSION_MAJOR) |
66 |
|
|
return 0; |
67 |
|
|
|
68 |
|
156 |
return 1; |
69 |
|
162 |
} |
70 |
|
|
|
71 |
|
|
static int |
72 |
|
|
ssl_convert_sslv2_client_hello(SSL *s) |
73 |
|
|
{ |
74 |
|
12 |
CBB cbb, handshake, client_hello, cipher_suites, compression, session_id; |
75 |
|
6 |
CBS cbs, challenge, cipher_specs, session; |
76 |
|
6 |
uint16_t record_length, client_version, cipher_specs_length; |
77 |
|
6 |
uint16_t session_id_length, challenge_length; |
78 |
|
6 |
unsigned char *client_random = NULL, *data = NULL; |
79 |
|
6 |
size_t data_len, pad_len, len; |
80 |
|
6 |
uint32_t cipher_spec; |
81 |
|
6 |
uint8_t message_type; |
82 |
|
6 |
unsigned char *pad; |
83 |
|
|
int ret = -1; |
84 |
|
|
int n; |
85 |
|
|
|
86 |
|
6 |
memset(&cbb, 0, sizeof(cbb)); |
87 |
|
|
|
88 |
|
6 |
CBS_init(&cbs, s->internal->packet, SSL3_RT_HEADER_LENGTH); |
89 |
|
|
|
90 |
✓✗✗✓
|
12 |
if (!CBS_get_u16(&cbs, &record_length) || |
91 |
✓✗ |
6 |
!CBS_get_u8(&cbs, &message_type) || |
92 |
|
6 |
!CBS_get_u16(&cbs, &client_version)) |
93 |
|
|
return -1; |
94 |
|
|
|
95 |
|
|
/* |
96 |
|
|
* The SSLv2 record length field uses variable length (2 or 3 byte) |
97 |
|
|
* encoding. Given the size of a client hello, we expect/require the |
98 |
|
|
* 2-byte form which is indicated by a one in the most significant bit. |
99 |
|
|
* Also note that the record length value does not include the bytes |
100 |
|
|
* used for the record length field. |
101 |
|
|
*/ |
102 |
✗✓ |
6 |
if ((record_length & 0x8000) == 0) |
103 |
|
|
return -1; |
104 |
|
6 |
record_length &= ~0x8000; |
105 |
✗✓ |
6 |
if (record_length < SSL3_RT_HEADER_LENGTH - 2) |
106 |
|
|
return -1; |
107 |
✗✓ |
6 |
if (message_type != SSL2_MT_CLIENT_HELLO) |
108 |
|
|
return -1; |
109 |
|
|
|
110 |
✗✓ |
6 |
if (record_length < 9) { |
111 |
|
|
SSLerror(s, SSL_R_RECORD_LENGTH_MISMATCH); |
112 |
|
|
return -1; |
113 |
|
|
} |
114 |
✗✓ |
6 |
if (record_length > 4096) { |
115 |
|
|
SSLerror(s, SSL_R_RECORD_TOO_LARGE); |
116 |
|
|
return -1; |
117 |
|
|
} |
118 |
|
|
|
119 |
|
6 |
n = ssl3_packet_extend(s, record_length + 2); |
120 |
✗✓ |
6 |
if (n != record_length + 2) |
121 |
|
|
return n; |
122 |
|
|
|
123 |
|
12 |
tls1_finish_mac(s, s->internal->packet + 2, |
124 |
|
6 |
s->internal->packet_length - 2); |
125 |
|
6 |
s->internal->mac_packet = 0; |
126 |
|
|
|
127 |
✗✓ |
6 |
if (s->internal->msg_callback) |
128 |
|
|
s->internal->msg_callback(0, SSL2_VERSION, 0, |
129 |
|
|
s->internal->packet + 2, s->internal->packet_length - 2, s, |
130 |
|
|
s->internal->msg_callback_arg); |
131 |
|
|
|
132 |
|
|
/* Decode the SSLv2 record containing the client hello. */ |
133 |
|
6 |
CBS_init(&cbs, s->internal->packet, s->internal->packet_length); |
134 |
|
|
|
135 |
✗✓ |
6 |
if (!CBS_get_u16(&cbs, &record_length)) |
136 |
|
|
return -1; |
137 |
✗✓ |
6 |
if (!CBS_get_u8(&cbs, &message_type)) |
138 |
|
|
return -1; |
139 |
✗✓ |
6 |
if (!CBS_get_u16(&cbs, &client_version)) |
140 |
|
|
return -1; |
141 |
✗✓ |
6 |
if (!CBS_get_u16(&cbs, &cipher_specs_length)) |
142 |
|
|
return -1; |
143 |
✗✓ |
6 |
if (!CBS_get_u16(&cbs, &session_id_length)) |
144 |
|
|
return -1; |
145 |
✗✓ |
6 |
if (!CBS_get_u16(&cbs, &challenge_length)) |
146 |
|
|
return -1; |
147 |
✗✓ |
6 |
if (!CBS_get_bytes(&cbs, &cipher_specs, cipher_specs_length)) |
148 |
|
|
return -1; |
149 |
✗✓ |
6 |
if (!CBS_get_bytes(&cbs, &session, session_id_length)) |
150 |
|
|
return -1; |
151 |
✗✓ |
6 |
if (!CBS_get_bytes(&cbs, &challenge, challenge_length)) |
152 |
|
|
return -1; |
153 |
✗✓ |
6 |
if (CBS_len(&cbs) != 0) { |
154 |
|
|
SSLerror(s, SSL_R_RECORD_LENGTH_MISMATCH); |
155 |
|
|
return -1; |
156 |
|
|
} |
157 |
|
|
|
158 |
|
|
/* |
159 |
|
|
* Convert SSLv2 challenge to SSLv3/TLS client random, by truncating or |
160 |
|
|
* left-padding with zero bytes. |
161 |
|
|
*/ |
162 |
✓✗ |
6 |
if ((client_random = malloc(SSL3_RANDOM_SIZE)) == NULL) |
163 |
|
|
goto err; |
164 |
✓✗ |
6 |
if (!CBB_init_fixed(&cbb, client_random, SSL3_RANDOM_SIZE)) |
165 |
|
|
goto err; |
166 |
|
6 |
if ((len = CBS_len(&challenge)) > SSL3_RANDOM_SIZE) |
167 |
|
|
len = SSL3_RANDOM_SIZE; |
168 |
|
6 |
pad_len = SSL3_RANDOM_SIZE - len; |
169 |
✓✗ |
6 |
if (!CBB_add_space(&cbb, &pad, pad_len)) |
170 |
|
|
goto err; |
171 |
|
6 |
memset(pad, 0, pad_len); |
172 |
✓✗ |
6 |
if (!CBB_add_bytes(&cbb, CBS_data(&challenge), len)) |
173 |
|
|
goto err; |
174 |
✓✗ |
6 |
if (!CBB_finish(&cbb, NULL, NULL)) |
175 |
|
|
goto err; |
176 |
|
|
|
177 |
|
|
/* Build SSLv3/TLS record with client hello. */ |
178 |
✓✗ |
6 |
if (!CBB_init(&cbb, SSL3_RT_MAX_PLAIN_LENGTH)) |
179 |
|
|
goto err; |
180 |
✓✗ |
6 |
if (!CBB_add_u8(&cbb, SSL3_RT_HANDSHAKE)) |
181 |
|
|
goto err; |
182 |
✓✗ |
6 |
if (!CBB_add_u16(&cbb, 0x0301)) |
183 |
|
|
goto err; |
184 |
✓✗ |
6 |
if (!CBB_add_u16_length_prefixed(&cbb, &handshake)) |
185 |
|
|
goto err; |
186 |
✓✗ |
6 |
if (!CBB_add_u8(&handshake, SSL3_MT_CLIENT_HELLO)) |
187 |
|
|
goto err; |
188 |
✓✗ |
6 |
if (!CBB_add_u24_length_prefixed(&handshake, &client_hello)) |
189 |
|
|
goto err; |
190 |
✓✗ |
6 |
if (!CBB_add_u16(&client_hello, client_version)) |
191 |
|
|
goto err; |
192 |
✓✗ |
6 |
if (!CBB_add_bytes(&client_hello, client_random, SSL3_RANDOM_SIZE)) |
193 |
|
|
goto err; |
194 |
✓✗ |
6 |
if (!CBB_add_u8_length_prefixed(&client_hello, &session_id)) |
195 |
|
|
goto err; |
196 |
✓✗ |
6 |
if (!CBB_add_u16_length_prefixed(&client_hello, &cipher_suites)) |
197 |
|
|
goto err; |
198 |
✓✓ |
498 |
while (CBS_len(&cipher_specs) > 0) { |
199 |
✓✗ |
243 |
if (!CBS_get_u24(&cipher_specs, &cipher_spec)) |
200 |
|
|
goto err; |
201 |
✗✓ |
243 |
if ((cipher_spec & 0xff0000) != 0) |
202 |
|
|
continue; |
203 |
✓✗ |
243 |
if (!CBB_add_u16(&cipher_suites, cipher_spec & 0xffff)) |
204 |
|
|
goto err; |
205 |
|
|
} |
206 |
✓✗ |
6 |
if (!CBB_add_u8_length_prefixed(&client_hello, &compression)) |
207 |
|
|
goto err; |
208 |
✓✗ |
6 |
if (!CBB_add_u8(&compression, 0)) |
209 |
|
|
goto err; |
210 |
✓✗ |
6 |
if (!CBB_finish(&cbb, &data, &data_len)) |
211 |
|
|
goto err; |
212 |
|
|
|
213 |
✓✗ |
6 |
if (data_len > s->s3->rbuf.len) |
214 |
|
|
goto err; |
215 |
|
|
|
216 |
|
6 |
s->internal->packet = s->s3->rbuf.buf; |
217 |
|
6 |
s->internal->packet_length = data_len; |
218 |
|
6 |
memcpy(s->internal->packet, data, data_len); |
219 |
|
6 |
ret = 1; |
220 |
|
|
|
221 |
|
|
err: |
222 |
|
6 |
CBB_cleanup(&cbb); |
223 |
|
6 |
free(client_random); |
224 |
|
6 |
free(data); |
225 |
|
|
|
226 |
|
6 |
return (ret); |
227 |
|
6 |
} |
228 |
|
|
|
229 |
|
|
/* |
230 |
|
|
* Potentially do legacy processing on the first packet received by a TLS |
231 |
|
|
* server. We return 1 if we want SSLv3/TLS record processing to continue |
232 |
|
|
* normally, otherwise we must set an SSLerr and return -1. |
233 |
|
|
*/ |
234 |
|
|
int |
235 |
|
|
ssl_server_legacy_first_packet(SSL *s) |
236 |
|
|
{ |
237 |
|
324 |
uint16_t min_version; |
238 |
|
|
const char *data; |
239 |
|
162 |
CBS header; |
240 |
|
|
|
241 |
✗✓ |
162 |
if (SSL_IS_DTLS(s)) |
242 |
|
|
return 1; |
243 |
|
|
|
244 |
|
162 |
CBS_init(&header, s->internal->packet, SSL3_RT_HEADER_LENGTH); |
245 |
|
|
|
246 |
✓✓ |
162 |
if (ssl_is_sslv3_handshake(&header) == 1) |
247 |
|
156 |
return 1; |
248 |
|
|
|
249 |
|
|
/* Only continue if this is not a version locked method. */ |
250 |
✗✓ |
6 |
if (s->method->internal->min_version == s->method->internal->max_version) |
251 |
|
|
return 1; |
252 |
|
|
|
253 |
✓✗ |
6 |
if (ssl_is_sslv2_client_hello(&header) == 1) { |
254 |
|
|
/* Only permit SSLv2 client hellos if TLSv1.0 is enabled. */ |
255 |
✗✓ |
6 |
if (ssl_enabled_version_range(s, &min_version, NULL) != 1) { |
256 |
|
|
SSLerror(s, SSL_R_NO_PROTOCOLS_AVAILABLE); |
257 |
|
|
return -1; |
258 |
|
|
} |
259 |
✗✓ |
6 |
if (min_version > TLS1_VERSION) |
260 |
|
|
return 1; |
261 |
|
|
|
262 |
✗✓ |
6 |
if (ssl_convert_sslv2_client_hello(s) != 1) { |
263 |
|
|
SSLerror(s, SSL_R_BAD_PACKET_LENGTH); |
264 |
|
|
return -1; |
265 |
|
|
} |
266 |
|
|
|
267 |
|
6 |
return 1; |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
/* Ensure that we have SSL3_RT_HEADER_LENGTH (5 bytes) of the packet. */ |
271 |
|
|
if (CBS_len(&header) != SSL3_RT_HEADER_LENGTH) { |
272 |
|
|
SSLerror(s, ERR_R_INTERNAL_ERROR); |
273 |
|
|
return -1; |
274 |
|
|
} |
275 |
|
|
data = (const char *)CBS_data(&header); |
276 |
|
|
|
277 |
|
|
/* Is this a cleartext protocol? */ |
278 |
|
|
if (strncmp("GET ", data, 4) == 0 || |
279 |
|
|
strncmp("POST ", data, 5) == 0 || |
280 |
|
|
strncmp("HEAD ", data, 5) == 0 || |
281 |
|
|
strncmp("PUT ", data, 4) == 0) { |
282 |
|
|
SSLerror(s, SSL_R_HTTP_REQUEST); |
283 |
|
|
return -1; |
284 |
|
|
} |
285 |
|
|
if (strncmp("CONNE", data, 5) == 0) { |
286 |
|
|
SSLerror(s, SSL_R_HTTPS_PROXY_REQUEST); |
287 |
|
|
return -1; |
288 |
|
|
} |
289 |
|
|
|
290 |
|
|
SSLerror(s, SSL_R_UNKNOWN_PROTOCOL); |
291 |
|
|
|
292 |
|
|
return -1; |
293 |
|
162 |
} |