This is an automated email from the ASF dual-hosted git repository. maskit pushed a commit to branch quic-latest in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit c753466bb394ea4b25b91b8792020e8fc07c8d6c Author: Masakazu Kitajo <mas...@apache.org> AuthorDate: Tue Jun 19 17:30:17 2018 +0900 Add QUICPacketNumberProtector --- iocore/net/P_QUICNetVConnection.h | 3 +- iocore/net/QUICNetVConnection.cc | 1 + iocore/net/quic/QUICHandshakeProtocol.cc | 26 +++++++++ iocore/net/quic/QUICHandshakeProtocol.h | 17 ++++++ iocore/net/quic/QUICPacketReceiveQueue.cc | 90 +++++++++++++++++++++++-------- iocore/net/quic/QUICPacketReceiveQueue.h | 5 +- 6 files changed, 119 insertions(+), 23 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e3ba582..543b330 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -246,6 +246,7 @@ private: QUICFrameFactory _frame_factory; QUICAckFrameCreator _ack_frame_creator; QUICPacketRetransmitter _packet_retransmitter; + QUICPacketNumberProtector _pn_protector; QUICApplicationMap *_application_map = nullptr; uint32_t _pmtu = 1280; @@ -266,7 +267,7 @@ private: QUICAltConnectionManager *_alt_con_manager = nullptr; QUICPathValidator *_path_validator = nullptr; - QUICPacketReceiveQueue _packet_recv_queue = {this->_packet_factory}; + QUICPacketReceiveQueue _packet_recv_queue = {this->_packet_factory, this->_pn_protector}; CountQueue<QUICPacket> _packet_send_queue; QUICConnectionErrorUPtr _connection_error = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b17d93c..8e39676 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -211,6 +211,7 @@ QUICNetVConnection::start() this->_hs_protocol = this->_handshake_handler->protocol(); this->_frame_dispatcher = new QUICFrameDispatcher(this); this->_packet_factory.set_hs_protocol(this->_hs_protocol); + this->_pn_protector.set_hs_protocol(this->_hs_protocol); // Create frame handlers this->_congestion_controller = new QUICCongestionController(this); diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 8d46370..94bf852 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -78,6 +78,32 @@ QUICPacketProtection::key_phase() const } // +// QUICPacketNumberProtector +// + +bool +QUICPacketNumberProtector::protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, + uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const +{ + // FIXME HandshakeProtocol shouldn't do this. The logic should be moved from there to here. + return this->_hs_protocol->encrypt_pn(protected_pn, protected_pn_len, unprotected_pn, unprotected_pn_len, sample, phase); +} + +bool +QUICPacketNumberProtector::unprotect(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, + uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const +{ + // FIXME HandshakeProtocol shouldn't do this. The logic should be moved from there to here. + return this->_hs_protocol->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, phase); +} + +void +QUICPacketNumberProtector::set_hs_protocol(QUICHandshakeProtocol *hs_protocol) +{ + this->_hs_protocol = hs_protocol; +} + +// // QUICHandshakeProtocol // QUICHandshakeMsgType diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 0701c4d..aec814c 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -26,6 +26,8 @@ #include "QUICKeyGenerator.h" #include "QUICTypes.h" +class QUICHandshakeProtocol; + class QUICPacketProtection { public: @@ -43,6 +45,21 @@ private: QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; }; +class QUICPacketNumberProtector +{ +public: + bool protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const; + bool unprotect(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const; + + // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICPacketProtection instead. + void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); + +private: + QUICHandshakeProtocol *_hs_protocol = nullptr; +}; + class QUICHandshakeProtocol { public: diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 3a7f435..4fd2ad3 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -24,11 +24,10 @@ #include "QUICPacketReceiveQueue.h" #include "QUICIntUtil.h" +#include "QUICConfig.h" // FIXME: workaround for coalescing packets -static constexpr int LONG_HDR_OFFSET_VERSION = 1; static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; -static constexpr int LONG_HDR_PKT_NUM_LEN = 4; static bool is_vn(QUICVersion v) @@ -39,27 +38,22 @@ is_vn(QUICVersion v) static size_t long_hdr_pkt_len(uint8_t *buf) { - uint8_t dcil = (buf[5] >> 4); - if (dcil) { - dcil += 3; - } - uint8_t scil = (buf[5] & 0x0F); - if (scil) { - scil += 3; - } - size_t offset = LONG_HDR_OFFSET_CONNECTION_ID; - offset += dcil; - offset += scil; + uint8_t dcil, scil; + QUICPacketLongHeader::dcil(dcil, buf, 6); + QUICPacketLongHeader::scil(scil, buf, 6); - size_t payload_len = QUICIntUtil::read_QUICVariableInt(buf + offset); - offset += QUICVariableInt::size(buf + offset); - offset += LONG_HDR_PKT_NUM_LEN; - offset += payload_len; + size_t payload_len_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; - return offset; + size_t payload_len; + uint8_t payload_len_field_len; + QUICPacketLongHeader::payload_length(payload_len, &payload_len_field_len, buf, payload_len_offset + 4); + return payload_len_offset + payload_len_field_len + QUICTypeUtil::read_QUICPacketNumberLen(buf) + payload_len; } -QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory) : _packet_factory(packet_factory) {} +QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketNumberProtector &pn_protector) + : _packet_factory(packet_factory), _pn_protector(pn_protector) +{ +} void QUICPacketReceiveQueue::enqueue(UDPPacket *packet) @@ -103,7 +97,8 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) size_t remaining_len = this->_payload_len - this->_offset; if (QUICInvariants::is_long_header(buf)) { - QUICVersion version = QUICTypeUtil::read_QUICVersion(buf + LONG_HDR_OFFSET_VERSION); + QUICVersion version; + QUICPacketLongHeader::version(version, buf, remaining_len); if (is_vn(version)) { pkt_len = remaining_len; } else if (!QUICTypeUtil::is_supported_version(version)) { @@ -142,7 +137,11 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) this->_offset = 0; } - quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->_largest_received_packet_number, result); + if (this->_unprotect_packet_number(pkt.get(), pkt_len)) { + quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->_largest_received_packet_number, result); + } else { + result = QUICPacketCreationResult::FAILED; + } if (udp_packet) { udp_packet->free(); @@ -179,3 +178,52 @@ QUICPacketReceiveQueue::reset() { this->_largest_received_packet_number = 0; } + +bool +QUICPacketReceiveQueue::_unprotect_packet_number(uint8_t *packet, size_t packet_len) +{ + size_t pn_offset = 0; + uint8_t pn_len = 4; + size_t sample_offset = 0; + uint8_t sample_len = 0; + constexpr int aead_expansion = 16; // Currently, AEAD expansion (which is probably AEAD tag) length is always 16 + int connection_id_len = QUICConfigParams::scid_len(); + QUICKeyPhase phase; + + if (QUICInvariants::is_long_header(packet)) { + QUICPacketType type; + QUICPacketLongHeader::type(type, packet, packet_len); + switch (type) { + case QUICPacketType::ZERO_RTT_PROTECTED: + phase = QUICKeyPhase::ZERORTT; + break; + default: + phase = QUICKeyPhase::CLEARTEXT; + break; + } + + uint8_t dcil, scil; + size_t payload_length; + uint8_t payload_length_field_len; + if (!QUICPacketLongHeader::dcil(dcil, packet, packet_len) || !QUICPacketLongHeader::scil(scil, packet, packet_len) || + !QUICPacketLongHeader::payload_length(payload_length, &payload_length_field_len, packet, packet_len)) { + return false; + } + pn_offset = 6 + dcil + scil + payload_length_field_len; + } else { + QUICPacketShortHeader::key_phase(phase, packet, packet_len); + pn_offset = 1 + connection_id_len; + } + sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); + sample_len = 16; // On draft-12, the length is always 16 (See 5.6.1 and 5.6.2) + + uint8_t unprotected_pn[4] = {0}; + uint8_t unprotected_pn_len = 0; + if (!this->_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, packet + pn_offset, pn_len, packet + sample_offset, + phase)) { + return false; + } + unprotected_pn_len = QUICTypeUtil::read_QUICPacketNumberLen(unprotected_pn); + memcpy(packet + pn_offset, unprotected_pn, unprotected_pn_len); + return true; +} diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h index 6349d26..230fc8a 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.h +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -31,7 +31,7 @@ class QUICPacketReceiveQueue { public: - QUICPacketReceiveQueue(QUICPacketFactory &packet_factory); + QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketNumberProtector &pn_protector); void enqueue(UDPPacket *packet); QUICPacketUPtr dequeue(QUICPacketCreationResult &result); @@ -41,10 +41,13 @@ public: private: CountQueue<UDPPacket> _queue; QUICPacketFactory &_packet_factory; + QUICPacketNumberProtector &_pn_protector; QUICPacketNumber _largest_received_packet_number = 0; // FIXME: workaround code for coalescing packets ats_unique_buf _payload = {nullptr, [](void *p) { ats_free(p); }}; size_t _payload_len = 0; size_t _offset = 0; IpEndpoint _from; + + bool _unprotect_packet_number(uint8_t *packet, size_t packet_len); };