1 /** @file
2  *
3  *  A brief file description
4  *
5  *  @section license License
6  *
7  *  Licensed to the Apache Software Foundation (ASF) under one
8  *  or more contributor license agreements.  See the NOTICE file
9  *  distributed with this work for additional information
10  *  regarding copyright ownership.  The ASF licenses this file
11  *  to you under the Apache License, Version 2.0 (the
12  *  "License"); you may not use this file except in compliance
13  *  with the License.  You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  *  Unless required by applicable law or agreed to in writing, software
18  *  distributed under the License is distributed on an "AS IS" BASIS,
19  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  *  See the License for the specific language governing permissions and
21  *  limitations under the License.
22  */
23 
24 #include "QUICHandshake.h"
25 
26 #include <utility>
27 
28 #include "QUICEvents.h"
29 #include "QUICGlobals.h"
30 #include "QUICHandshakeProtocol.h"
31 #include "QUICPacketFactory.h"
32 #include "QUICVersionNegotiator.h"
33 #include "QUICConfig.h"
34 
35 #define QUICHSDebug(fmt, ...) Debug("quic_handshake", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__)
36 
37 #define QUICVHSDebug(fmt, ...) Debug("v_quic_handshake", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__)
38 
39 #define I_WANNA_DUMP_THIS_BUF(buf, len)                                                                                            \
40   {                                                                                                                                \
41     static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt";                                                                \
42     int i;                                                                                                                         \
43     Debug(dump_tag, "len=%" PRId64 "\n", len);                                                                                     \
44     for (i = 0; i < len / 8; i++) {                                                                                                \
45       Debug(dump_tag, "%02x %02x %02x %02x %02x %02x %02x %02x ", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3],  \
46             buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6], buf[i * 8 + 7]);                                                       \
47     }                                                                                                                              \
48     switch (len % 8) {                                                                                                             \
49     case 1:                                                                                                                        \
50       Debug(dump_tag, "%02x", buf[i * 8 + 0]);                                                                                     \
51       break;                                                                                                                       \
52     case 2:                                                                                                                        \
53       Debug(dump_tag, "%02x %02x", buf[i * 8 + 0], buf[i * 8 + 1]);                                                                \
54                                                                                                                                    \
55       break;                                                                                                                       \
56     case 3:                                                                                                                        \
57       Debug(dump_tag, "%02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2]);                                           \
58                                                                                                                                    \
59       break;                                                                                                                       \
60     case 4:                                                                                                                        \
61       Debug(dump_tag, "%02x %02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3]);                      \
62                                                                                                                                    \
63       break;                                                                                                                       \
64     case 5:                                                                                                                        \
65       Debug(dump_tag, "%02x %02x %02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3], buf[i * 8 + 4]); \
66                                                                                                                                    \
67       break;                                                                                                                       \
68     case 6:                                                                                                                        \
69       Debug(dump_tag, "%02x %02x %02x %02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3],             \
70             buf[i * 8 + 4], buf[i * 8 + 5]);                                                                                       \
71                                                                                                                                    \
72       break;                                                                                                                       \
73     case 7:                                                                                                                        \
74       Debug(dump_tag, "%02x %02x %02x %02x %02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3],        \
75             buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6]);                                                                       \
76                                                                                                                                    \
77       break;                                                                                                                       \
78     default:                                                                                                                       \
79       break;                                                                                                                       \
80     }                                                                                                                              \
81   }
82 
83 static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527;
84 
QUICHandshake(QUICVersion version,QUICConnection * qc,QUICHandshakeProtocol * hsp)85 QUICHandshake::QUICHandshake(QUICVersion version, QUICConnection *qc, QUICHandshakeProtocol *hsp)
86   : QUICHandshake(version, qc, hsp, {}, false)
87 {
88 }
89 
QUICHandshake(QUICVersion version,QUICConnection * qc,QUICHandshakeProtocol * hsp,QUICStatelessResetToken token,bool stateless_retry)90 QUICHandshake::QUICHandshake(QUICVersion version, QUICConnection *qc, QUICHandshakeProtocol *hsp, QUICStatelessResetToken token,
91                              bool stateless_retry)
92   : _qc(qc),
93     _hs_protocol(hsp),
94     _version_negotiator(new QUICVersionNegotiator()),
95     _reset_token(token),
96     _stateless_retry(stateless_retry)
97 {
98   this->_hs_protocol->initialize_key_materials(this->_qc->original_connection_id(), version);
99 
100   if (this->_qc->direction() == NET_VCONNECTION_OUT) {
101     this->_client_initial = true;
102   }
103 }
104 
~QUICHandshake()105 QUICHandshake::~QUICHandshake()
106 {
107   delete this->_hs_protocol;
108 }
109 
110 QUICConnectionErrorUPtr
start(const QUICTPConfig & tp_config,QUICPacketFactory * packet_factory,bool vn_exercise_enabled)111 QUICHandshake::start(const QUICTPConfig &tp_config, QUICPacketFactory *packet_factory, bool vn_exercise_enabled)
112 {
113   QUICVersion initial_version = QUIC_SUPPORTED_VERSIONS[0];
114   if (vn_exercise_enabled) {
115     initial_version = QUIC_EXERCISE_VERSION1;
116   }
117 
118   this->_load_local_client_transport_parameters(tp_config);
119   packet_factory->set_version(initial_version);
120 
121   return nullptr;
122 }
123 
124 QUICConnectionErrorUPtr
start(const QUICTPConfig & tp_config,const QUICInitialPacketR & initial_packet,QUICPacketFactory * packet_factory,const QUICPreferredAddress * pref_addr)125 QUICHandshake::start(const QUICTPConfig &tp_config, const QUICInitialPacketR &initial_packet, QUICPacketFactory *packet_factory,
126                      const QUICPreferredAddress *pref_addr)
127 {
128   // Negotiate version
129   if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) {
130     if (initial_packet.type() != QUICPacketType::INITIAL) {
131       return std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
132     }
133     if (initial_packet.version()) {
134       if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) {
135         QUICHSDebug("Version negotiation succeeded: %x", initial_packet.version());
136         this->_load_local_server_transport_parameters(tp_config, pref_addr);
137         packet_factory->set_version(this->_version_negotiator->negotiated_version());
138       } else {
139         ink_assert(!"Unsupported version initial packet should be dropped QUICPacketHandler");
140       }
141     } else {
142       return std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
143     }
144     this->_initial_source_cid_received = initial_packet.source_cid();
145   }
146   return nullptr;
147 }
148 
149 QUICConnectionErrorUPtr
negotiate_version(const QUICVersionNegotiationPacketR & vn,QUICPacketFactory * packet_factory)150 QUICHandshake::negotiate_version(const QUICVersionNegotiationPacketR &vn, QUICPacketFactory *packet_factory)
151 {
152   // Client side only
153   ink_assert(this->_qc->direction() == NET_VCONNECTION_OUT);
154 
155   // If already negotiated, just ignore it
156   if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED ||
157       this->_version_negotiator->status() == QUICVersionNegotiationStatus::VALIDATED) {
158     QUICHSDebug("Ignore Version Negotiation packet");
159     return nullptr;
160   }
161 
162   if (vn.version() != 0x00) {
163     QUICHSDebug("Version field must be 0x00000000");
164     return std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
165   }
166 
167   if (this->_version_negotiator->negotiate(vn) == QUICVersionNegotiationStatus::NEGOTIATED) {
168     QUICVersion version = this->_version_negotiator->negotiated_version();
169     QUICHSDebug("Version negotiation succeeded: 0x%x", version);
170     packet_factory->set_version(version);
171   } else {
172     QUICHSDebug("Version negotiation failed");
173     return std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
174   }
175 
176   return nullptr;
177 }
178 
179 bool
is_version_negotiated() const180 QUICHandshake::is_version_negotiated() const
181 {
182   return (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED ||
183           this->_version_negotiator->status() == QUICVersionNegotiationStatus::VALIDATED);
184 }
185 
186 bool
is_completed() const187 QUICHandshake::is_completed() const
188 {
189   return this->_hs_protocol->is_handshake_finished();
190 }
191 
192 bool
is_confirmed() const193 QUICHandshake::is_confirmed() const
194 {
195   if (this->_qc->direction() == NET_VCONNECTION_IN) {
196     return this->is_completed();
197   } else {
198     return this->_is_handshake_done_received;
199   }
200 }
201 
202 bool
is_stateless_retry_enabled() const203 QUICHandshake::is_stateless_retry_enabled() const
204 {
205   return this->_stateless_retry;
206 }
207 
208 bool
has_remote_tp() const209 QUICHandshake::has_remote_tp() const
210 {
211   return this->_remote_transport_parameters != nullptr;
212 }
213 
214 QUICVersion
negotiated_version() const215 QUICHandshake::negotiated_version() const
216 {
217   return this->_version_negotiator->negotiated_version();
218 }
219 
220 // Similar to SSLNetVConnection::getSSLCipherSuite()
221 const char *
negotiated_cipher_suite() const222 QUICHandshake::negotiated_cipher_suite() const
223 {
224   return this->_hs_protocol->negotiated_cipher_suite();
225 }
226 
227 void
negotiated_application_name(const uint8_t ** name,unsigned int * len) const228 QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *len) const
229 {
230   this->_hs_protocol->negotiated_application_name(name, len);
231 }
232 
233 bool
check_remote_transport_parameters()234 QUICHandshake::check_remote_transport_parameters()
235 {
236   auto tp = this->_hs_protocol->remote_transport_parameters();
237 
238   if (tp == nullptr) {
239     // nothing to check
240     return true;
241   }
242 
243   if (std::dynamic_pointer_cast<const QUICTransportParametersInClientHello>(tp)) {
244     return this->_check_remote_transport_parameters(std::static_pointer_cast<const QUICTransportParametersInClientHello>(tp));
245   } else {
246     return this->_check_remote_transport_parameters(
247       std::static_pointer_cast<const QUICTransportParametersInEncryptedExtensions>(tp));
248   }
249 }
250 
251 bool
_check_remote_transport_parameters(std::shared_ptr<const QUICTransportParametersInClientHello> tp)252 QUICHandshake::_check_remote_transport_parameters(std::shared_ptr<const QUICTransportParametersInClientHello> tp)
253 {
254   // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR.
255   if (!tp->is_valid()) {
256     QUICHSDebug("Transport parameter is not valid");
257     this->_abort_handshake(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR);
258     return false;
259   }
260 
261   // Check if CIDs in TP match with the ones in packets
262   if (this->negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]) { // draft-28
263     uint16_t cid_buf_len;
264     const uint8_t *cid_buf = tp->getAsBytes(QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID, cid_buf_len);
265     QUICConnectionId cid_in_tp(cid_buf, cid_buf_len);
266     if (cid_in_tp != this->_initial_source_cid_received) {
267       this->_abort_handshake(QUICTransErrorCode::PROTOCOL_VIOLATION);
268       return false;
269     }
270   }
271 
272   this->_remote_transport_parameters = tp;
273 
274   return true;
275 }
276 
277 bool
_check_remote_transport_parameters(std::shared_ptr<const QUICTransportParametersInEncryptedExtensions> tp)278 QUICHandshake::_check_remote_transport_parameters(std::shared_ptr<const QUICTransportParametersInEncryptedExtensions> tp)
279 {
280   // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR.
281   if (!tp->is_valid()) {
282     QUICHSDebug("Transport parameter is not valid");
283     this->_abort_handshake(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR);
284     return false;
285   }
286 
287   // Check if CIDs in TP match with the ones in packets
288   if (this->negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]) { // draft-28
289     uint16_t cid_buf_len;
290     const uint8_t *cid_buf = tp->getAsBytes(QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID, cid_buf_len);
291     QUICConnectionId cid_in_tp(cid_buf, cid_buf_len);
292     if (cid_in_tp != this->_initial_source_cid_received) {
293       this->_abort_handshake(QUICTransErrorCode::PROTOCOL_VIOLATION);
294       return false;
295     }
296 
297     if (!this->_retry_source_cid_received.is_zero()) {
298       cid_buf = tp->getAsBytes(QUICTransportParameterId::RETRY_SOURCE_CONNECTION_ID, cid_buf_len);
299       QUICConnectionId cid_in_tp(cid_buf, cid_buf_len);
300       if (cid_in_tp != this->_retry_source_cid_received) {
301         this->_abort_handshake(QUICTransErrorCode::PROTOCOL_VIOLATION);
302         return false;
303       }
304     }
305   }
306 
307   this->_remote_transport_parameters = tp;
308 
309   return true;
310 }
311 
312 std::shared_ptr<const QUICTransportParameters>
local_transport_parameters()313 QUICHandshake::local_transport_parameters()
314 {
315   return this->_local_transport_parameters;
316 }
317 
318 std::shared_ptr<const QUICTransportParameters>
remote_transport_parameters()319 QUICHandshake::remote_transport_parameters()
320 {
321   return this->_remote_transport_parameters;
322 }
323 
324 /**
325  * reset states for starting over
326  */
327 void
reset()328 QUICHandshake::reset()
329 {
330   this->_client_initial = true;
331   this->_hs_protocol->reset();
332 
333   for (auto level : QUIC_ENCRYPTION_LEVELS) {
334     int index                = static_cast<int>(level);
335     QUICCryptoStream *stream = &this->_crypto_streams[index];
336     stream->reset_send_offset();
337     stream->reset_recv_offset();
338   }
339 }
340 
341 void
update(const QUICInitialPacketR & packet)342 QUICHandshake::update(const QUICInitialPacketR &packet)
343 {
344   this->_initial_source_cid_received = packet.source_cid();
345 }
346 
347 void
update(const QUICRetryPacketR & packet)348 QUICHandshake::update(const QUICRetryPacketR &packet)
349 {
350   this->_retry_source_cid_received = packet.source_cid();
351 }
352 
353 std::vector<QUICFrameType>
interests()354 QUICHandshake::interests()
355 {
356   return {
357     QUICFrameType::CRYPTO,
358     QUICFrameType::HANDSHAKE_DONE,
359   };
360 }
361 
362 QUICConnectionErrorUPtr
handle_frame(QUICEncryptionLevel level,const QUICFrame & frame)363 QUICHandshake::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame)
364 {
365   QUICConnectionErrorUPtr error = nullptr;
366   switch (frame.type()) {
367   case QUICFrameType::CRYPTO:
368     error = this->_crypto_streams[static_cast<int>(level)].recv(static_cast<const QUICCryptoFrame &>(frame));
369     if (error == nullptr) {
370       error = this->do_handshake();
371     }
372     break;
373   case QUICFrameType::HANDSHAKE_DONE:
374     if (this->_qc->direction() == NET_VCONNECTION_IN) {
375       error = std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
376     } else {
377       this->_is_handshake_done_received = true;
378     }
379     break;
380   default:
381     QUICHSDebug("Unexpected frame type: %02x", static_cast<unsigned int>(frame.type()));
382     ink_assert(false);
383     break;
384   }
385 
386   return error;
387 }
388 
389 bool
will_generate_frame(QUICEncryptionLevel level,size_t current_packet_size,bool ack_eliciting,uint32_t seq_num)390 QUICHandshake::will_generate_frame(QUICEncryptionLevel level, size_t current_packet_size, bool ack_eliciting, uint32_t seq_num)
391 {
392   if (!this->_is_level_matched(level)) {
393     return false;
394   }
395 
396   return (this->_qc->direction() == NET_VCONNECTION_IN && !this->_is_handshake_done_sent) ||
397          this->_crypto_streams[static_cast<int>(level)].will_generate_frame(level, current_packet_size, ack_eliciting, seq_num);
398 }
399 
400 QUICFrame *
generate_frame(uint8_t * buf,QUICEncryptionLevel level,uint64_t connection_credit,uint16_t maximum_frame_size,size_t current_packet_size,uint32_t seq_num)401 QUICHandshake::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size,
402                               size_t current_packet_size, uint32_t seq_num)
403 {
404   QUICFrame *frame = nullptr;
405 
406   if (this->_is_level_matched(level)) {
407     // CRYPTO
408     frame = this->_crypto_streams[static_cast<int>(level)].generate_frame(buf, level, connection_credit, maximum_frame_size,
409                                                                           current_packet_size, seq_num);
410     if (frame) {
411       return frame;
412     }
413   }
414 
415   if (level == QUICEncryptionLevel::ONE_RTT) {
416     // HANDSHAKE_DONE
417     if (!this->_is_handshake_done_sent && this->is_completed()) {
418       frame = QUICFrameFactory::create_handshake_done_frame(buf, this->_issue_frame_id(), this);
419     }
420     if (frame) {
421       this->_is_handshake_done_sent = true;
422       return frame;
423     }
424   }
425 
426   return frame;
427 }
428 
429 void
_load_local_server_transport_parameters(const QUICTPConfig & tp_config,const QUICPreferredAddress * pref_addr)430 QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_config, const QUICPreferredAddress *pref_addr)
431 {
432   QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions();
433 
434   // MUSTs
435   tp->set(QUICTransportParameterId::MAX_IDLE_TIMEOUT, static_cast<uint16_t>(tp_config.no_activity_timeout()));
436   if (this->_stateless_retry) {
437     tp->set(QUICTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID, this->_qc->first_connection_id(),
438             this->_qc->first_connection_id().length());
439     tp->set(QUICTransportParameterId::RETRY_SOURCE_CONNECTION_ID, this->_qc->retry_source_connection_id(),
440             this->_qc->retry_source_connection_id().length());
441   } else {
442     if (this->negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]) { // draft-28
443       tp->set(QUICTransportParameterId::ORIGINAL_DESTINATION_CONNECTION_ID, this->_qc->original_connection_id(),
444               this->_qc->original_connection_id().length());
445     }
446   }
447   if (this->negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]) { // draft-28
448     tp->set(QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID, this->_qc->initial_source_connection_id(),
449             this->_qc->initial_source_connection_id().length());
450   }
451 
452   // MAYs
453   if (tp_config.initial_max_data() != 0) {
454     tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, tp_config.initial_max_data());
455   }
456   if (tp_config.initial_max_streams_bidi() != 0) {
457     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, tp_config.initial_max_streams_bidi());
458   }
459   if (tp_config.initial_max_streams_uni() != 0) {
460     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, tp_config.initial_max_streams_uni());
461   }
462   if (tp_config.initial_max_stream_data_bidi_local() != 0) {
463     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, tp_config.initial_max_stream_data_bidi_local());
464   }
465   if (tp_config.initial_max_stream_data_bidi_remote() != 0) {
466     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, tp_config.initial_max_stream_data_bidi_remote());
467   }
468   if (tp_config.initial_max_stream_data_uni() != 0) {
469     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, tp_config.initial_max_stream_data_uni());
470   }
471   if (tp_config.disable_active_migration()) {
472     tp->set(QUICTransportParameterId::DISABLE_ACTIVE_MIGRATION, nullptr, 0);
473   }
474   if (pref_addr != nullptr) {
475     uint8_t pref_addr_buf[QUICPreferredAddress::MAX_LEN];
476     uint16_t len;
477     pref_addr->store(pref_addr_buf, len);
478     tp->set(QUICTransportParameterId::PREFERRED_ADDRESS, pref_addr_buf, len);
479   }
480   if (tp_config.active_cid_limit() != 0) {
481     tp->set(QUICTransportParameterId::ACTIVE_CONNECTION_ID_LIMIT, tp_config.active_cid_limit());
482   }
483 
484   // MAYs (server)
485   tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN);
486   tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, tp_config.ack_delay_exponent());
487 
488   // Additional parameters
489   for (auto &&param : tp_config.additional_tp()) {
490     tp->set(param.first, param.second.first, param.second.second);
491   }
492 
493   // Additional parameters
494   for (auto &&param : tp_config.additional_tp()) {
495     tp->set(param.first, param.second.first, param.second.second);
496   }
497 
498   this->_local_transport_parameters = std::shared_ptr<QUICTransportParameters>(tp);
499   this->_hs_protocol->set_local_transport_parameters(this->_local_transport_parameters);
500 }
501 
502 void
_load_local_client_transport_parameters(const QUICTPConfig & tp_config)503 QUICHandshake::_load_local_client_transport_parameters(const QUICTPConfig &tp_config)
504 {
505   QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello();
506 
507   // MUSTs
508   tp->set(QUICTransportParameterId::MAX_IDLE_TIMEOUT, static_cast<uint16_t>(tp_config.no_activity_timeout()));
509   tp->set(QUICTransportParameterId::INITIAL_SOURCE_CONNECTION_ID, this->_qc->initial_source_connection_id(),
510           this->_qc->initial_source_connection_id().length());
511 
512   // MAYs
513   if (tp_config.initial_max_data() != 0) {
514     tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, tp_config.initial_max_data());
515   }
516   if (tp_config.initial_max_streams_bidi() != 0) {
517     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, tp_config.initial_max_streams_bidi());
518   }
519   if (tp_config.initial_max_streams_uni() != 0) {
520     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, tp_config.initial_max_streams_uni());
521   }
522   if (tp_config.initial_max_stream_data_bidi_local() != 0) {
523     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, tp_config.initial_max_stream_data_bidi_local());
524   }
525   if (tp_config.initial_max_stream_data_bidi_remote() != 0) {
526     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, tp_config.initial_max_stream_data_bidi_remote());
527   }
528   if (tp_config.initial_max_stream_data_uni() != 0) {
529     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, tp_config.initial_max_stream_data_uni());
530   }
531   tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, tp_config.ack_delay_exponent());
532   if (tp_config.active_cid_limit() != 0) {
533     tp->set(QUICTransportParameterId::ACTIVE_CONNECTION_ID_LIMIT, tp_config.active_cid_limit());
534   }
535 
536   // Additional parameters
537   for (auto &&param : tp_config.additional_tp()) {
538     tp->set(param.first, param.second.first, param.second.second);
539   }
540 
541   this->_local_transport_parameters = std::shared_ptr<QUICTransportParameters>(tp);
542   this->_hs_protocol->set_local_transport_parameters(std::unique_ptr<QUICTransportParameters>(tp));
543 }
544 
545 QUICConnectionErrorUPtr
do_handshake()546 QUICHandshake::do_handshake()
547 {
548   QUICConnectionErrorUPtr error = nullptr;
549 
550   QUICHandshakeMsgs in;
551   uint8_t in_buf[UDP_MAXIMUM_PAYLOAD_SIZE] = {0};
552   in.buf                                   = in_buf;
553   in.max_buf_len                           = UDP_MAXIMUM_PAYLOAD_SIZE;
554 
555   if (this->_client_initial) {
556     this->_client_initial = false;
557   } else {
558     for (auto level : QUIC_ENCRYPTION_LEVELS) {
559       int index                = static_cast<int>(level);
560       QUICCryptoStream *stream = &this->_crypto_streams[index];
561       int64_t bytes_avail      = stream->read_avail();
562       // TODO: check size
563       if (bytes_avail > 0) {
564         stream->read(in.buf + in.offsets[index], bytes_avail);
565       }
566       in.offsets[index + 1] = in.offsets[index] + bytes_avail;
567     }
568   }
569 
570   QUICHandshakeMsgs *out = nullptr;
571   int result             = this->_hs_protocol->handshake(&out, &in);
572   if (this->_remote_transport_parameters == nullptr) {
573     if (!this->check_remote_transport_parameters()) {
574       result = 0;
575     }
576   }
577 
578   if (result == 1) {
579     if (out) {
580       for (auto level : QUIC_ENCRYPTION_LEVELS) {
581         int index                = static_cast<int>(level);
582         QUICCryptoStream *stream = &this->_crypto_streams[index];
583         size_t len               = out->offsets[index + 1] - out->offsets[index];
584         // TODO: check size
585         if (len > 0) {
586           stream->write(out->buf + out->offsets[index], len);
587         }
588       }
589     }
590   } else {
591     this->_hs_protocol->abort_handshake();
592     if (this->_hs_protocol->has_crypto_error()) {
593       error = std::make_unique<QUICConnectionError>(QUICErrorClass::TRANSPORT, this->_hs_protocol->crypto_error());
594     } else {
595       error = std::make_unique<QUICConnectionError>(QUICErrorClass::TRANSPORT,
596                                                     static_cast<uint16_t>(QUICTransErrorCode::PROTOCOL_VIOLATION));
597     }
598   }
599 
600   return error;
601 }
602 
603 void
_abort_handshake(QUICTransErrorCode code)604 QUICHandshake::_abort_handshake(QUICTransErrorCode code)
605 {
606   QUICHSDebug("Abort Handshake");
607 
608   this->_hs_protocol->abort_handshake();
609 
610   this->_qc->close_quic_connection(QUICConnectionErrorUPtr(new QUICConnectionError(code)));
611 }
612 
613 /*
614    No limit of encryption level.
615    ```
616    std::array<QUICEncryptionLevel, 4> _encryption_level_filter = {
617      QUICEncryptionLevel::INITIAL,
618      QUICEncryptionLevel::ZERO_RTT,
619      QUICEncryptionLevel::HANDSHAKE,
620      QUICEncryptionLevel::ONE_RTT,
621    };
622    ```
623 */
624 bool
_is_level_matched(QUICEncryptionLevel level)625 QUICHandshake::_is_level_matched(QUICEncryptionLevel level)
626 {
627   return true;
628 }
629 
630 void
_on_frame_lost(QUICFrameInformationUPtr & info)631 QUICHandshake::_on_frame_lost(QUICFrameInformationUPtr &info)
632 {
633   ink_assert(info->type == QUICFrameType::HANDSHAKE_DONE);
634   this->_is_handshake_done_sent = false;
635 }
636