blob: 68cac5b1a1e79d371fce4c178e2746a3fa33bcae [file] [log] [blame]
Robert Sloan8542c082018-02-05 09:07:34 -08001/* Copyright (c) 2018, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#include <openssl/ssl.h>
16
17#include <openssl/bytestring.h>
18
19#include "internal.h"
20
21
22namespace bssl {
23
24constexpr int kHandoffVersion = 0;
25constexpr int kHandbackVersion = 0;
26
27bool SSL_serialize_handoff(const SSL *ssl, CBB *out) {
28 const SSL3_STATE *const s3 = ssl->s3;
29 if (!ssl->server ||
30 s3->hs == nullptr ||
31 s3->rwstate != SSL_HANDOFF) {
32 return false;
33 }
34
35 CBB seq;
36 Span<const uint8_t> transcript = s3->hs->transcript.buffer();
37 if (!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE) ||
38 !CBB_add_asn1_uint64(&seq, kHandoffVersion) ||
39 !CBB_add_asn1_octet_string(&seq, transcript.data(), transcript.size()) ||
40 !CBB_add_asn1_octet_string(&seq,
41 reinterpret_cast<uint8_t *>(s3->hs_buf->data),
42 s3->hs_buf->length) ||
43 !CBB_flush(out)) {
44 return false;
45 }
46
47 return true;
48}
49
50bool SSL_decline_handoff(SSL *ssl) {
51 const SSL3_STATE *const s3 = ssl->s3;
52 if (!ssl->server ||
53 s3->hs == nullptr ||
54 s3->rwstate != SSL_HANDOFF) {
55 return false;
56 }
57
Adam Vartanianbfcf3a72018-08-10 14:55:24 +010058 s3->hs->config->handoff = false;
Robert Sloan8542c082018-02-05 09:07:34 -080059 return true;
60}
61
62bool SSL_apply_handoff(SSL *ssl, Span<const uint8_t> handoff) {
63 if (ssl->method->is_dtls) {
64 return false;
65 }
66
67 CBS seq, handoff_cbs(handoff);
68 uint64_t handoff_version;
69 if (!CBS_get_asn1(&handoff_cbs, &seq, CBS_ASN1_SEQUENCE) ||
70 !CBS_get_asn1_uint64(&seq, &handoff_version) ||
71 handoff_version != kHandoffVersion) {
72 return false;
73 }
74
75 CBS transcript, hs_buf;
76 if (!CBS_get_asn1(&seq, &transcript, CBS_ASN1_OCTETSTRING) ||
77 !CBS_get_asn1(&seq, &hs_buf, CBS_ASN1_OCTETSTRING)) {
78 return false;
79 }
80
81 SSL_set_accept_state(ssl);
82
83 SSL3_STATE *const s3 = ssl->s3;
84 s3->v2_hello_done = true;
85 s3->has_message = true;
86
87 s3->hs_buf.reset(BUF_MEM_new());
88 if (!s3->hs_buf ||
89 !BUF_MEM_append(s3->hs_buf.get(), CBS_data(&hs_buf), CBS_len(&hs_buf))) {
90 return false;
91 }
92
93 if (CBS_len(&transcript) != 0) {
94 s3->hs->transcript.Update(transcript);
95 s3->is_v2_hello = true;
Robert Sloan8542c082018-02-05 09:07:34 -080096 }
Adam Vartanianbfcf3a72018-08-10 14:55:24 +010097 s3->hs->handback = true;
Robert Sloan8542c082018-02-05 09:07:34 -080098
99 return true;
100}
101
102bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100103 if (!ssl->server || ssl->method->is_dtls) {
Robert Sloan8542c082018-02-05 09:07:34 -0800104 return false;
105 }
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100106 handback_t type;
107 switch (ssl->s3->hs->state) {
108 case state12_read_change_cipher_spec:
109 type = handback_after_session_resumption;
110 break;
111 case state12_read_client_certificate:
112 type = handback_after_ecdhe;
113 break;
114 case state12_finish_server_handshake:
115 type = handback_after_handshake;
116 break;
117 default:
118 return false;
119 }
Robert Sloan8542c082018-02-05 09:07:34 -0800120
121 const SSL3_STATE *const s3 = ssl->s3;
122 size_t hostname_len = 0;
123 if (s3->hostname) {
124 hostname_len = strlen(s3->hostname.get());
125 }
126
Robert Sloandc2f6092018-04-10 10:22:33 -0700127 Span<const uint8_t> transcript;
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100128 if (type == handback_after_ecdhe ||
129 type == handback_after_session_resumption) {
Robert Sloandc2f6092018-04-10 10:22:33 -0700130 transcript = s3->hs->transcript.buffer();
Robert Sloan8542c082018-02-05 09:07:34 -0800131 }
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100132 size_t write_iv_len = 0;
133 const uint8_t *write_iv = nullptr;
134 if ((type == handback_after_session_resumption ||
135 type == handback_after_handshake) &&
136 ssl->version == TLS1_VERSION &&
137 SSL_CIPHER_is_block_cipher(s3->aead_write_ctx->cipher()) &&
138 !s3->aead_write_ctx->GetIV(&write_iv, &write_iv_len)) {
139 return false;
140 }
141 size_t read_iv_len = 0;
142 const uint8_t *read_iv = nullptr;
143 if (type == handback_after_handshake &&
144 ssl->version == TLS1_VERSION &&
145 SSL_CIPHER_is_block_cipher(s3->aead_read_ctx->cipher()) &&
146 !s3->aead_read_ctx->GetIV(&read_iv, &read_iv_len)) {
147 return false;
148 }
Robert Sloan8542c082018-02-05 09:07:34 -0800149
Robert Sloandc2f6092018-04-10 10:22:33 -0700150 // TODO(mab): make sure everything is serialized.
151 CBB seq, key_share;
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100152 const SSL_SESSION *session =
153 s3->session_reused ? ssl->session.get() : s3->hs->new_session.get();
Robert Sloan8542c082018-02-05 09:07:34 -0800154 if (!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE) ||
155 !CBB_add_asn1_uint64(&seq, kHandbackVersion) ||
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100156 !CBB_add_asn1_uint64(&seq, type) ||
Robert Sloan8542c082018-02-05 09:07:34 -0800157 !CBB_add_asn1_octet_string(&seq, s3->read_sequence,
158 sizeof(s3->read_sequence)) ||
159 !CBB_add_asn1_octet_string(&seq, s3->write_sequence,
160 sizeof(s3->write_sequence)) ||
161 !CBB_add_asn1_octet_string(&seq, s3->server_random,
162 sizeof(s3->server_random)) ||
163 !CBB_add_asn1_octet_string(&seq, s3->client_random,
164 sizeof(s3->client_random)) ||
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100165 !CBB_add_asn1_octet_string(&seq, read_iv, read_iv_len) ||
166 !CBB_add_asn1_octet_string(&seq, write_iv, write_iv_len) ||
Robert Sloan8542c082018-02-05 09:07:34 -0800167 !CBB_add_asn1_bool(&seq, s3->session_reused) ||
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100168 !CBB_add_asn1_bool(&seq, s3->channel_id_valid) ||
Robert Sloandc2f6092018-04-10 10:22:33 -0700169 !ssl_session_serialize(session, &seq) ||
Robert Sloan8542c082018-02-05 09:07:34 -0800170 !CBB_add_asn1_octet_string(&seq, s3->next_proto_negotiated.data(),
171 s3->next_proto_negotiated.size()) ||
172 !CBB_add_asn1_octet_string(&seq, s3->alpn_selected.data(),
173 s3->alpn_selected.size()) ||
174 !CBB_add_asn1_octet_string(
175 &seq, reinterpret_cast<uint8_t *>(s3->hostname.get()),
176 hostname_len) ||
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100177 !CBB_add_asn1_octet_string(&seq, s3->channel_id,
178 sizeof(s3->channel_id)) ||
Robert Sloan15c0b352018-04-16 08:36:46 -0700179 !CBB_add_asn1_bool(&seq, ssl->s3->token_binding_negotiated) ||
180 !CBB_add_asn1_uint64(&seq, ssl->s3->negotiated_token_binding_param) ||
Robert Sloandc2f6092018-04-10 10:22:33 -0700181 !CBB_add_asn1_bool(&seq, s3->hs->next_proto_neg_seen) ||
182 !CBB_add_asn1_bool(&seq, s3->hs->cert_request) ||
183 !CBB_add_asn1_bool(&seq, s3->hs->extended_master_secret) ||
184 !CBB_add_asn1_bool(&seq, s3->hs->ticket_expected) ||
185 !CBB_add_asn1_uint64(&seq, SSL_CIPHER_get_id(s3->hs->new_cipher)) ||
186 !CBB_add_asn1_octet_string(&seq, transcript.data(), transcript.size()) ||
187 !CBB_add_asn1(&seq, &key_share, CBS_ASN1_SEQUENCE)) {
Robert Sloan8542c082018-02-05 09:07:34 -0800188 return false;
189 }
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100190 if (type == handback_after_ecdhe &&
Robert Sloandc2f6092018-04-10 10:22:33 -0700191 !s3->hs->key_share->Serialize(&key_share)) {
192 return false;
193 }
194 return CBB_flush(out);
Robert Sloan8542c082018-02-05 09:07:34 -0800195}
196
197bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
198 if (ssl->do_handshake != nullptr ||
199 ssl->method->is_dtls) {
200 return false;
201 }
202
203 SSL3_STATE *const s3 = ssl->s3;
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100204 uint64_t handback_version, negotiated_token_binding_param, cipher, type;
Robert Sloandc2f6092018-04-10 10:22:33 -0700205
Robert Sloan8542c082018-02-05 09:07:34 -0800206 CBS seq, read_seq, write_seq, server_rand, client_rand, read_iv, write_iv,
Robert Sloandc2f6092018-04-10 10:22:33 -0700207 next_proto, alpn, hostname, channel_id, transcript, key_share;
Robert Sloan15c0b352018-04-16 08:36:46 -0700208 int session_reused, channel_id_valid, cert_request, extended_master_secret,
209 ticket_expected, token_binding_negotiated, next_proto_neg_seen;
Robert Sloandc2f6092018-04-10 10:22:33 -0700210 SSL_SESSION *session = nullptr;
Robert Sloan8542c082018-02-05 09:07:34 -0800211
212 CBS handback_cbs(handback);
213 if (!CBS_get_asn1(&handback_cbs, &seq, CBS_ASN1_SEQUENCE) ||
214 !CBS_get_asn1_uint64(&seq, &handback_version) ||
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100215 handback_version != kHandbackVersion ||
216 !CBS_get_asn1_uint64(&seq, &type)) {
Robert Sloan8542c082018-02-05 09:07:34 -0800217 return false;
218 }
219
Robert Sloan15c0b352018-04-16 08:36:46 -0700220 if (!CBS_get_asn1(&seq, &read_seq, CBS_ASN1_OCTETSTRING) ||
Robert Sloan8542c082018-02-05 09:07:34 -0800221 CBS_len(&read_seq) != sizeof(s3->read_sequence) ||
222 !CBS_get_asn1(&seq, &write_seq, CBS_ASN1_OCTETSTRING) ||
223 CBS_len(&write_seq) != sizeof(s3->write_sequence) ||
224 !CBS_get_asn1(&seq, &server_rand, CBS_ASN1_OCTETSTRING) ||
225 CBS_len(&server_rand) != sizeof(s3->server_random) ||
226 !CBS_copy_bytes(&server_rand, s3->server_random,
227 sizeof(s3->server_random)) ||
228 !CBS_get_asn1(&seq, &client_rand, CBS_ASN1_OCTETSTRING) ||
229 CBS_len(&client_rand) != sizeof(s3->client_random) ||
230 !CBS_copy_bytes(&client_rand, s3->client_random,
231 sizeof(s3->client_random)) ||
232 !CBS_get_asn1(&seq, &read_iv, CBS_ASN1_OCTETSTRING) ||
233 !CBS_get_asn1(&seq, &write_iv, CBS_ASN1_OCTETSTRING) ||
234 !CBS_get_asn1_bool(&seq, &session_reused) ||
Robert Sloan8542c082018-02-05 09:07:34 -0800235 !CBS_get_asn1_bool(&seq, &channel_id_valid)) {
236 return false;
237 }
238
Robert Sloandc2f6092018-04-10 10:22:33 -0700239 s3->hs = ssl_handshake_new(ssl);
240 if (session_reused) {
241 ssl->session =
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100242 SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool);
243 session = ssl->session.get();
Robert Sloandc2f6092018-04-10 10:22:33 -0700244 } else {
245 s3->hs->new_session =
246 SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool);
247 session = s3->hs->new_session.get();
248 }
Robert Sloan8542c082018-02-05 09:07:34 -0800249
Robert Sloandc2f6092018-04-10 10:22:33 -0700250 if (!session || !CBS_get_asn1(&seq, &next_proto, CBS_ASN1_OCTETSTRING) ||
Robert Sloan8542c082018-02-05 09:07:34 -0800251 !CBS_get_asn1(&seq, &alpn, CBS_ASN1_OCTETSTRING) ||
252 !CBS_get_asn1(&seq, &hostname, CBS_ASN1_OCTETSTRING) ||
253 !CBS_get_asn1(&seq, &channel_id, CBS_ASN1_OCTETSTRING) ||
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100254 CBS_len(&channel_id) != sizeof(s3->channel_id) ||
255 !CBS_copy_bytes(&channel_id, s3->channel_id,
256 sizeof(s3->channel_id)) ||
Robert Sloandc2f6092018-04-10 10:22:33 -0700257 !CBS_get_asn1_bool(&seq, &token_binding_negotiated) ||
258 !CBS_get_asn1_uint64(&seq, &negotiated_token_binding_param) ||
259 !CBS_get_asn1_bool(&seq, &next_proto_neg_seen) ||
260 !CBS_get_asn1_bool(&seq, &cert_request) ||
261 !CBS_get_asn1_bool(&seq, &extended_master_secret) ||
262 !CBS_get_asn1_bool(&seq, &ticket_expected) ||
263 !CBS_get_asn1_uint64(&seq, &cipher)) {
264 return false;
265 }
266 if ((s3->hs->new_cipher =
267 SSL_get_cipher_by_value(static_cast<uint16_t>(cipher))) == nullptr) {
268 return false;
269 }
270 if (!CBS_get_asn1(&seq, &transcript, CBS_ASN1_OCTETSTRING) ||
271 !CBS_get_asn1(&seq, &key_share, CBS_ASN1_SEQUENCE)) {
Robert Sloan8542c082018-02-05 09:07:34 -0800272 return false;
273 }
274
Robert Sloan15c0b352018-04-16 08:36:46 -0700275 ssl->version = session->ssl_version;
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100276 s3->have_version = true;
277 if (!ssl_method_supports_version(ssl->method, ssl->version) ||
278 session->cipher != s3->hs->new_cipher ||
279 ssl_protocol_version(ssl) < SSL_CIPHER_get_min_version(session->cipher) ||
280 SSL_CIPHER_get_max_version(session->cipher) < ssl_protocol_version(ssl)) {
281 return false;
282 }
Robert Sloan8542c082018-02-05 09:07:34 -0800283 ssl->do_handshake = ssl_server_handshake;
284 ssl->server = true;
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100285 switch (type) {
286 case handback_after_session_resumption:
287 ssl->s3->hs->state = state12_read_change_cipher_spec;
288 if (!session_reused) {
289 return false;
290 }
291 break;
292 case handback_after_ecdhe:
293 ssl->s3->hs->state = state12_read_client_certificate;
294 if (session_reused) {
295 return false;
296 }
297 break;
298 case handback_after_handshake:
299 ssl->s3->hs->state = state12_finish_server_handshake;
300 break;
301 default:
302 return false;
303 }
Robert Sloan8542c082018-02-05 09:07:34 -0800304 s3->session_reused = session_reused;
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100305 s3->channel_id_valid = channel_id_valid;
Robert Sloan8542c082018-02-05 09:07:34 -0800306 s3->next_proto_negotiated.CopyFrom(next_proto);
307 s3->alpn_selected.CopyFrom(alpn);
308
309 const size_t hostname_len = CBS_len(&hostname);
310 if (hostname_len == 0) {
311 s3->hostname.reset();
312 } else {
313 char *hostname_str = nullptr;
314 if (!CBS_strdup(&hostname, &hostname_str)) {
315 return false;
316 }
317 s3->hostname.reset(hostname_str);
318 }
319
Robert Sloan15c0b352018-04-16 08:36:46 -0700320 s3->token_binding_negotiated = token_binding_negotiated;
321 s3->negotiated_token_binding_param =
Robert Sloandc2f6092018-04-10 10:22:33 -0700322 static_cast<uint8_t>(negotiated_token_binding_param);
323 s3->hs->next_proto_neg_seen = next_proto_neg_seen;
324 s3->hs->wait = ssl_hs_flush;
325 s3->hs->extended_master_secret = extended_master_secret;
326 s3->hs->ticket_expected = ticket_expected;
327 s3->aead_write_ctx->SetVersionIfNullCipher(ssl->version);
328 s3->hs->cert_request = cert_request;
Robert Sloan8542c082018-02-05 09:07:34 -0800329
Adam Vartanianbfcf3a72018-08-10 14:55:24 +0100330 Array<uint8_t> key_block;
331 if ((type == handback_after_session_resumption ||
332 type == handback_after_handshake) &&
333 (!tls1_configure_aead(ssl, evp_aead_seal, &key_block, session->cipher,
334 write_iv) ||
335 !CBS_copy_bytes(&write_seq, s3->write_sequence,
336 sizeof(s3->write_sequence)))) {
337 return false;
338 }
339 if (type == handback_after_handshake &&
340 (!tls1_configure_aead(ssl, evp_aead_open, &key_block, session->cipher,
341 read_iv) ||
342 !CBS_copy_bytes(&read_seq, s3->read_sequence,
343 sizeof(s3->read_sequence)))) {
344 return false;
345 }
346 if ((type == handback_after_ecdhe ||
347 type == handback_after_session_resumption) &&
348 (!s3->hs->transcript.Init() ||
349 !s3->hs->transcript.InitHash(ssl_protocol_version(ssl),
350 s3->hs->new_cipher) ||
351 !s3->hs->transcript.Update(transcript))) {
352 return false;
353 }
354 if (type == handback_after_ecdhe &&
355 (s3->hs->key_share = SSLKeyShare::Create(&key_share)) == nullptr) {
356 return false;
Robert Sloan8542c082018-02-05 09:07:34 -0800357 }
358
Robert Sloandc2f6092018-04-10 10:22:33 -0700359 return CBS_len(&seq) == 0;
Robert Sloan8542c082018-02-05 09:07:34 -0800360}
361
362} // namespace bssl