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 "QUICPacketFactory.h"
31 #include "QUICVersionNegotiator.h"
32 #include "QUICConfig.h"
33 
34 #define QUICHSDebug(fmt, ...) Debug("quic_handshake", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__)
35 
36 #define QUICVHSDebug(fmt, ...) Debug("v_quic_handshake", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__)
37 
38 #define I_WANNA_DUMP_THIS_BUF(buf, len)                                                                                            \
39   {                                                                                                                                \
40     static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt";                                                                \
41     int i;                                                                                                                         \
42     Debug(dump_tag, "len=%" PRId64 "\n", len);                                                                                     \
43     for (i = 0; i < len / 8; i++) {                                                                                                \
44       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],  \
45             buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6], buf[i * 8 + 7]);                                                       \
46     }                                                                                                                              \
47     switch (len % 8) {                                                                                                             \
48     case 1:                                                                                                                        \
49       Debug(dump_tag, "%02x", buf[i * 8 + 0]);                                                                                     \
50       break;                                                                                                                       \
51     case 2:                                                                                                                        \
52       Debug(dump_tag, "%02x %02x", buf[i * 8 + 0], buf[i * 8 + 1]);                                                                \
53                                                                                                                                    \
54       break;                                                                                                                       \
55     case 3:                                                                                                                        \
56       Debug(dump_tag, "%02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2]);                                           \
57                                                                                                                                    \
58       break;                                                                                                                       \
59     case 4:                                                                                                                        \
60       Debug(dump_tag, "%02x %02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3]);                      \
61                                                                                                                                    \
62       break;                                                                                                                       \
63     case 5:                                                                                                                        \
64       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]); \
65                                                                                                                                    \
66       break;                                                                                                                       \
67     case 6:                                                                                                                        \
68       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],             \
69             buf[i * 8 + 4], buf[i * 8 + 5]);                                                                                       \
70                                                                                                                                    \
71       break;                                                                                                                       \
72     case 7:                                                                                                                        \
73       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],        \
74             buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6]);                                                                       \
75                                                                                                                                    \
76       break;                                                                                                                       \
77     default:                                                                                                                       \
78       break;                                                                                                                       \
79     }                                                                                                                              \
80   }
81 
82 static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527;
83 // TODO: fix size
84 static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527;
85 
QUICHandshake(QUICConnection * qc,QUICHandshakeProtocol * hsp)86 QUICHandshake::QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp) : QUICHandshake(qc, hsp, {}, false) {}
87 
QUICHandshake(QUICConnection * qc,QUICHandshakeProtocol * hsp,QUICStatelessResetToken token,bool stateless_retry)88 QUICHandshake::QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp, QUICStatelessResetToken token, bool stateless_retry)
89   : _qc(qc),
90     _hs_protocol(hsp),
91     _version_negotiator(new QUICVersionNegotiator()),
92     _reset_token(token),
93     _stateless_retry(stateless_retry)
94 {
95   this->_hs_protocol->initialize_key_materials(this->_qc->original_connection_id());
96 
97   if (this->_qc->direction() == NET_VCONNECTION_OUT) {
98     this->_client_initial = true;
99   }
100 }
101 
~QUICHandshake()102 QUICHandshake::~QUICHandshake()
103 {
104   delete this->_hs_protocol;
105 }
106 
107 QUICConnectionErrorUPtr
start(const QUICTPConfig & tp_config,QUICPacketFactory * packet_factory,bool vn_exercise_enabled)108 QUICHandshake::start(const QUICTPConfig &tp_config, QUICPacketFactory *packet_factory, bool vn_exercise_enabled)
109 {
110   QUICVersion initital_version = QUIC_SUPPORTED_VERSIONS[0];
111   if (vn_exercise_enabled) {
112     initital_version = QUIC_EXERCISE_VERSION;
113   }
114 
115   this->_load_local_client_transport_parameters(tp_config);
116   packet_factory->set_version(initital_version);
117 
118   return nullptr;
119 }
120 
121 QUICConnectionErrorUPtr
start(const QUICTPConfig & tp_config,const QUICPacket & initial_packet,QUICPacketFactory * packet_factory,const QUICPreferredAddress * pref_addr)122 QUICHandshake::start(const QUICTPConfig &tp_config, const QUICPacket &initial_packet, QUICPacketFactory *packet_factory,
123                      const QUICPreferredAddress *pref_addr)
124 {
125   // Negotiate version
126   if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) {
127     if (initial_packet.type() != QUICPacketType::INITIAL) {
128       return std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
129     }
130     if (initial_packet.version()) {
131       if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) {
132         QUICHSDebug("Version negotiation succeeded: %x", initial_packet.version());
133         this->_load_local_server_transport_parameters(tp_config, pref_addr);
134         packet_factory->set_version(this->_version_negotiator->negotiated_version());
135       } else {
136         ink_assert(!"Unsupported version initial packet should be droped QUICPakcetHandler");
137       }
138     } else {
139       return std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
140     }
141   }
142   return nullptr;
143 }
144 
145 QUICConnectionErrorUPtr
negotiate_version(const QUICPacket & vn,QUICPacketFactory * packet_factory)146 QUICHandshake::negotiate_version(const QUICPacket &vn, QUICPacketFactory *packet_factory)
147 {
148   // Client side only
149   ink_assert(this->_qc->direction() == NET_VCONNECTION_OUT);
150 
151   // If already negotiated, just ignore it
152   if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED ||
153       this->_version_negotiator->status() == QUICVersionNegotiationStatus::VALIDATED) {
154     QUICHSDebug("Ignore Version Negotiation packet");
155     return nullptr;
156   }
157 
158   if (vn.version() != 0x00) {
159     QUICHSDebug("Version field must be 0x00000000");
160     return std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
161   }
162 
163   if (this->_version_negotiator->negotiate(vn) == QUICVersionNegotiationStatus::NEGOTIATED) {
164     QUICVersion version = this->_version_negotiator->negotiated_version();
165     QUICHSDebug("Version negotiation succeeded: 0x%x", version);
166     packet_factory->set_version(version);
167   } else {
168     QUICHSDebug("Version negotiation failed");
169     return std::make_unique<QUICConnectionError>(QUICTransErrorCode::PROTOCOL_VIOLATION);
170   }
171 
172   return nullptr;
173 }
174 
175 bool
is_version_negotiated() const176 QUICHandshake::is_version_negotiated() const
177 {
178   return (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED ||
179           this->_version_negotiator->status() == QUICVersionNegotiationStatus::VALIDATED);
180 }
181 
182 bool
is_completed() const183 QUICHandshake::is_completed() const
184 {
185   return this->_hs_protocol->is_handshake_finished();
186 }
187 
188 bool
is_stateless_retry_enabled() const189 QUICHandshake::is_stateless_retry_enabled() const
190 {
191   return this->_stateless_retry;
192 }
193 
194 bool
has_remote_tp() const195 QUICHandshake::has_remote_tp() const
196 {
197   return this->_remote_transport_parameters != nullptr;
198 }
199 
200 QUICVersion
negotiated_version()201 QUICHandshake::negotiated_version()
202 {
203   return this->_version_negotiator->negotiated_version();
204 }
205 
206 // Similar to SSLNetVConnection::getSSLCipherSuite()
207 const char *
negotiated_cipher_suite()208 QUICHandshake::negotiated_cipher_suite()
209 {
210   return this->_hs_protocol->negotiated_cipher_suite();
211 }
212 
213 void
negotiated_application_name(const uint8_t ** name,unsigned int * len)214 QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *len)
215 {
216   this->_hs_protocol->negotiated_application_name(name, len);
217 }
218 
219 bool
check_remote_transport_parameters()220 QUICHandshake::check_remote_transport_parameters()
221 {
222   auto tp = this->_hs_protocol->remote_transport_parameters();
223 
224   if (tp == nullptr) {
225     // nothing to check
226     return true;
227   }
228 
229   if (std::dynamic_pointer_cast<const QUICTransportParametersInClientHello>(tp)) {
230     return this->_check_remote_transport_parameters(std::static_pointer_cast<const QUICTransportParametersInClientHello>(tp));
231   } else {
232     return this->_check_remote_transport_parameters(
233       std::static_pointer_cast<const QUICTransportParametersInEncryptedExtensions>(tp));
234   }
235 }
236 
237 bool
_check_remote_transport_parameters(std::shared_ptr<const QUICTransportParametersInClientHello> tp)238 QUICHandshake::_check_remote_transport_parameters(std::shared_ptr<const QUICTransportParametersInClientHello> tp)
239 {
240   // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR.
241   if (!tp->is_valid()) {
242     QUICHSDebug("Transport parameter is not valid");
243     this->_abort_handshake(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR);
244     return false;
245   }
246 
247   this->_remote_transport_parameters = tp;
248 
249   return true;
250 }
251 
252 bool
_check_remote_transport_parameters(std::shared_ptr<const QUICTransportParametersInEncryptedExtensions> tp)253 QUICHandshake::_check_remote_transport_parameters(std::shared_ptr<const QUICTransportParametersInEncryptedExtensions> tp)
254 {
255   // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR.
256   if (!tp->is_valid()) {
257     QUICHSDebug("Transport parameter is not valid");
258     this->_abort_handshake(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR);
259     return false;
260   }
261 
262   this->_remote_transport_parameters = tp;
263 
264   return true;
265 }
266 
267 std::shared_ptr<const QUICTransportParameters>
local_transport_parameters()268 QUICHandshake::local_transport_parameters()
269 {
270   return this->_local_transport_parameters;
271 }
272 
273 std::shared_ptr<const QUICTransportParameters>
remote_transport_parameters()274 QUICHandshake::remote_transport_parameters()
275 {
276   return this->_remote_transport_parameters;
277 }
278 
279 /**
280  * reset states for starting over
281  */
282 void
reset()283 QUICHandshake::reset()
284 {
285   this->_client_initial = true;
286   this->_hs_protocol->reset();
287 
288   for (auto level : QUIC_ENCRYPTION_LEVELS) {
289     int index                = static_cast<int>(level);
290     QUICCryptoStream *stream = &this->_crypto_streams[index];
291     stream->reset_send_offset();
292     stream->reset_recv_offset();
293   }
294 }
295 
296 std::vector<QUICFrameType>
interests()297 QUICHandshake::interests()
298 {
299   return {
300     QUICFrameType::CRYPTO,
301   };
302 }
303 
304 QUICConnectionErrorUPtr
handle_frame(QUICEncryptionLevel level,const QUICFrame & frame)305 QUICHandshake::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame)
306 {
307   QUICConnectionErrorUPtr error = nullptr;
308   switch (frame.type()) {
309   case QUICFrameType::CRYPTO:
310     error = this->_crypto_streams[static_cast<int>(level)].recv(static_cast<const QUICCryptoFrame &>(frame));
311     if (error != nullptr) {
312       return error;
313     }
314     break;
315   default:
316     QUICHSDebug("Unexpected frame type: %02x", static_cast<unsigned int>(frame.type()));
317     ink_assert(false);
318     break;
319   }
320 
321   return this->do_handshake();
322 }
323 
324 bool
will_generate_frame(QUICEncryptionLevel level,size_t current_packet_size,bool ack_eliciting,uint32_t seq_num)325 QUICHandshake::will_generate_frame(QUICEncryptionLevel level, size_t current_packet_size, bool ack_eliciting, uint32_t seq_num)
326 {
327   if (!this->_is_level_matched(level)) {
328     return false;
329   }
330 
331   return this->_crypto_streams[static_cast<int>(level)].will_generate_frame(level, current_packet_size, ack_eliciting, seq_num);
332 }
333 
334 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)335 QUICHandshake::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size,
336                               size_t current_packet_size, uint32_t seq_num)
337 {
338   QUICFrame *frame = nullptr;
339 
340   if (this->_is_level_matched(level)) {
341     frame = this->_crypto_streams[static_cast<int>(level)].generate_frame(buf, level, connection_credit, maximum_frame_size,
342                                                                           current_packet_size, seq_num);
343   }
344 
345   return frame;
346 }
347 
348 void
_load_local_server_transport_parameters(const QUICTPConfig & tp_config,const QUICPreferredAddress * pref_addr)349 QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_config, const QUICPreferredAddress *pref_addr)
350 {
351   QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions();
352 
353   // MUSTs
354   tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast<uint16_t>(tp_config.no_activity_timeout()));
355   if (this->_stateless_retry) {
356     tp->set(QUICTransportParameterId::ORIGINAL_CONNECTION_ID, this->_qc->first_connection_id(),
357             this->_qc->first_connection_id().length());
358   }
359 
360   // MAYs
361   if (tp_config.initial_max_data() != 0) {
362     tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, tp_config.initial_max_data());
363   }
364   if (tp_config.initial_max_streams_bidi() != 0) {
365     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, tp_config.initial_max_streams_bidi());
366   }
367   if (tp_config.initial_max_streams_uni() != 0) {
368     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, tp_config.initial_max_streams_uni());
369   }
370   if (tp_config.initial_max_stream_data_bidi_local() != 0) {
371     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, tp_config.initial_max_stream_data_bidi_local());
372   }
373   if (tp_config.initial_max_stream_data_bidi_remote() != 0) {
374     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, tp_config.initial_max_stream_data_bidi_remote());
375   }
376   if (tp_config.initial_max_stream_data_uni() != 0) {
377     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, tp_config.initial_max_stream_data_uni());
378   }
379   if (pref_addr != nullptr) {
380     uint8_t pref_addr_buf[QUICPreferredAddress::MAX_LEN];
381     uint16_t len;
382     pref_addr->store(pref_addr_buf, len);
383     tp->set(QUICTransportParameterId::PREFERRED_ADDRESS, pref_addr_buf, len);
384   }
385   if (tp_config.active_cid_limit() != 0) {
386     tp->set(QUICTransportParameterId::ACTIVE_CONNECTION_ID_LIMIT, tp_config.active_cid_limit());
387   }
388 
389   // MAYs (server)
390   tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN);
391   tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, tp_config.ack_delay_exponent());
392 
393   tp->add_version(QUIC_SUPPORTED_VERSIONS[0]);
394 
395   this->_local_transport_parameters = std::shared_ptr<QUICTransportParameters>(tp);
396   this->_hs_protocol->set_local_transport_parameters(this->_local_transport_parameters);
397 }
398 
399 void
_load_local_client_transport_parameters(const QUICTPConfig & tp_config)400 QUICHandshake::_load_local_client_transport_parameters(const QUICTPConfig &tp_config)
401 {
402   QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello();
403 
404   // MUSTs
405   tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast<uint16_t>(tp_config.no_activity_timeout()));
406 
407   // MAYs
408   if (tp_config.initial_max_data() != 0) {
409     tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, tp_config.initial_max_data());
410   }
411   if (tp_config.initial_max_streams_bidi() != 0) {
412     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, tp_config.initial_max_streams_bidi());
413   }
414   if (tp_config.initial_max_streams_uni() != 0) {
415     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, tp_config.initial_max_streams_uni());
416   }
417   if (tp_config.initial_max_stream_data_bidi_local() != 0) {
418     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, tp_config.initial_max_stream_data_bidi_local());
419   }
420   if (tp_config.initial_max_stream_data_bidi_remote() != 0) {
421     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, tp_config.initial_max_stream_data_bidi_remote());
422   }
423   if (tp_config.initial_max_stream_data_uni() != 0) {
424     tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, tp_config.initial_max_stream_data_uni());
425   }
426   tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, tp_config.ack_delay_exponent());
427   if (tp_config.active_cid_limit() != 0) {
428     tp->set(QUICTransportParameterId::ACTIVE_CONNECTION_ID_LIMIT, tp_config.active_cid_limit());
429   }
430 
431   this->_local_transport_parameters = std::shared_ptr<QUICTransportParameters>(tp);
432   this->_hs_protocol->set_local_transport_parameters(std::unique_ptr<QUICTransportParameters>(tp));
433 }
434 
435 QUICConnectionErrorUPtr
do_handshake()436 QUICHandshake::do_handshake()
437 {
438   QUICConnectionErrorUPtr error = nullptr;
439 
440   QUICHandshakeMsgs in;
441   uint8_t in_buf[UDP_MAXIMUM_PAYLOAD_SIZE] = {0};
442   in.buf                                   = in_buf;
443   in.max_buf_len                           = UDP_MAXIMUM_PAYLOAD_SIZE;
444 
445   if (this->_client_initial) {
446     this->_client_initial = false;
447   } else {
448     for (auto level : QUIC_ENCRYPTION_LEVELS) {
449       int index                = static_cast<int>(level);
450       QUICCryptoStream *stream = &this->_crypto_streams[index];
451       int64_t bytes_avail      = stream->read_avail();
452       // TODO: check size
453       if (bytes_avail > 0) {
454         stream->read(in.buf + in.offsets[index], bytes_avail);
455         in.offsets[index] = bytes_avail;
456         in.offsets[4] += bytes_avail;
457       }
458     }
459   }
460 
461   QUICHandshakeMsgs out;
462   uint8_t out_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
463   out.buf                                = out_buf;
464   out.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
465 
466   int result = this->_hs_protocol->handshake(&out, &in);
467   if (this->_remote_transport_parameters == nullptr) {
468     if (!this->check_remote_transport_parameters()) {
469       result = 0;
470     }
471   }
472 
473   if (result == 1) {
474     for (auto level : QUIC_ENCRYPTION_LEVELS) {
475       int index                = static_cast<int>(level);
476       QUICCryptoStream *stream = &this->_crypto_streams[index];
477       size_t len               = out.offsets[index + 1] - out.offsets[index];
478       // TODO: check size
479       if (len > 0) {
480         stream->write(out.buf + out.offsets[index], len);
481       }
482     }
483   } else if (out.error_code != 0) {
484     this->_hs_protocol->abort_handshake();
485     error = std::make_unique<QUICConnectionError>(QUICErrorClass::TRANSPORT, out.error_code);
486   }
487 
488   return error;
489 }
490 
491 void
_abort_handshake(QUICTransErrorCode code)492 QUICHandshake::_abort_handshake(QUICTransErrorCode code)
493 {
494   QUICHSDebug("Abort Handshake");
495 
496   this->_hs_protocol->abort_handshake();
497 
498   this->_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(code)));
499 }
500 
501 /*
502    No limit of encryption level.
503    ```
504    std::array<QUICEncryptionLevel, 4> _encryption_level_filter = {
505      QUICEncryptionLevel::INITIAL,
506      QUICEncryptionLevel::ZERO_RTT,
507      QUICEncryptionLevel::HANDSHAKE,
508      QUICEncryptionLevel::ONE_RTT,
509    };
510    ```
511 */
512 bool
_is_level_matched(QUICEncryptionLevel level)513 QUICHandshake::_is_level_matched(QUICEncryptionLevel level)
514 {
515   return true;
516 }
517