mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 04:07:35 +03:00
uTLS is not yet bumped to the new version, so this commit breaks the dependencies relationship by getting rid of the local replace.
226 lines
7.7 KiB
Go
226 lines
7.7 KiB
Go
package quic
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/refraction-networking/uquic/internal/handshake"
|
|
"github.com/refraction-networking/uquic/internal/protocol"
|
|
"github.com/refraction-networking/uquic/internal/qerr"
|
|
"github.com/refraction-networking/uquic/internal/wire"
|
|
)
|
|
|
|
type headerDecryptor interface {
|
|
DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte)
|
|
}
|
|
|
|
type headerParseError struct {
|
|
err error
|
|
}
|
|
|
|
func (e *headerParseError) Unwrap() error {
|
|
return e.err
|
|
}
|
|
|
|
func (e *headerParseError) Error() string {
|
|
return e.err.Error()
|
|
}
|
|
|
|
type unpackedPacket struct {
|
|
hdr *wire.ExtendedHeader
|
|
encryptionLevel protocol.EncryptionLevel
|
|
data []byte
|
|
}
|
|
|
|
// The packetUnpacker unpacks QUIC packets.
|
|
type packetUnpacker struct {
|
|
cs handshake.CryptoSetup
|
|
|
|
shortHdrConnIDLen int
|
|
}
|
|
|
|
var _ unpacker = &packetUnpacker{}
|
|
|
|
func newPacketUnpacker(cs handshake.CryptoSetup, shortHdrConnIDLen int) *packetUnpacker {
|
|
return &packetUnpacker{
|
|
cs: cs,
|
|
shortHdrConnIDLen: shortHdrConnIDLen,
|
|
}
|
|
}
|
|
|
|
// UnpackLongHeader unpacks a Long Header packet.
|
|
// If the reserved bits are invalid, the error is wire.ErrInvalidReservedBits.
|
|
// If any other error occurred when parsing the header, the error is of type headerParseError.
|
|
// If decrypting the payload fails for any reason, the error is the error returned by the AEAD.
|
|
func (u *packetUnpacker) UnpackLongHeader(hdr *wire.Header, rcvTime time.Time, data []byte, v protocol.VersionNumber) (*unpackedPacket, error) {
|
|
var encLevel protocol.EncryptionLevel
|
|
var extHdr *wire.ExtendedHeader
|
|
var decrypted []byte
|
|
//nolint:exhaustive // Retry packets can't be unpacked.
|
|
switch hdr.Type {
|
|
case protocol.PacketTypeInitial:
|
|
encLevel = protocol.EncryptionInitial
|
|
opener, err := u.cs.GetInitialOpener()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
extHdr, decrypted, err = u.unpackLongHeaderPacket(opener, hdr, data, v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case protocol.PacketTypeHandshake:
|
|
encLevel = protocol.EncryptionHandshake
|
|
opener, err := u.cs.GetHandshakeOpener()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
extHdr, decrypted, err = u.unpackLongHeaderPacket(opener, hdr, data, v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case protocol.PacketType0RTT:
|
|
encLevel = protocol.Encryption0RTT
|
|
opener, err := u.cs.Get0RTTOpener()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
extHdr, decrypted, err = u.unpackLongHeaderPacket(opener, hdr, data, v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("unknown packet type: %s", hdr.Type)
|
|
}
|
|
|
|
if len(decrypted) == 0 {
|
|
return nil, &qerr.TransportError{
|
|
ErrorCode: qerr.ProtocolViolation,
|
|
ErrorMessage: "empty packet",
|
|
}
|
|
}
|
|
|
|
return &unpackedPacket{
|
|
hdr: extHdr,
|
|
encryptionLevel: encLevel,
|
|
data: decrypted,
|
|
}, nil
|
|
}
|
|
|
|
func (u *packetUnpacker) UnpackShortHeader(rcvTime time.Time, data []byte) (protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, []byte, error) {
|
|
opener, err := u.cs.Get1RTTOpener()
|
|
if err != nil {
|
|
return 0, 0, 0, nil, err
|
|
}
|
|
pn, pnLen, kp, decrypted, err := u.unpackShortHeaderPacket(opener, rcvTime, data)
|
|
if err != nil {
|
|
return 0, 0, 0, nil, err
|
|
}
|
|
if len(decrypted) == 0 {
|
|
return 0, 0, 0, nil, &qerr.TransportError{
|
|
ErrorCode: qerr.ProtocolViolation,
|
|
ErrorMessage: "empty packet",
|
|
}
|
|
}
|
|
return pn, pnLen, kp, decrypted, nil
|
|
}
|
|
|
|
func (u *packetUnpacker) unpackLongHeaderPacket(opener handshake.LongHeaderOpener, hdr *wire.Header, data []byte, v protocol.VersionNumber) (*wire.ExtendedHeader, []byte, error) {
|
|
extHdr, parseErr := u.unpackLongHeader(opener, hdr, data, v)
|
|
// If the reserved bits are set incorrectly, we still need to continue unpacking.
|
|
// This avoids a timing side-channel, which otherwise might allow an attacker
|
|
// to gain information about the header encryption.
|
|
if parseErr != nil && parseErr != wire.ErrInvalidReservedBits {
|
|
return nil, nil, parseErr
|
|
}
|
|
extHdrLen := extHdr.ParsedLen()
|
|
extHdr.PacketNumber = opener.DecodePacketNumber(extHdr.PacketNumber, extHdr.PacketNumberLen)
|
|
decrypted, err := opener.Open(data[extHdrLen:extHdrLen], data[extHdrLen:], extHdr.PacketNumber, data[:extHdrLen])
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if parseErr != nil {
|
|
return nil, nil, parseErr
|
|
}
|
|
return extHdr, decrypted, nil
|
|
}
|
|
|
|
func (u *packetUnpacker) unpackShortHeaderPacket(opener handshake.ShortHeaderOpener, rcvTime time.Time, data []byte) (protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, []byte, error) {
|
|
l, pn, pnLen, kp, parseErr := u.unpackShortHeader(opener, data)
|
|
// If the reserved bits are set incorrectly, we still need to continue unpacking.
|
|
// This avoids a timing side-channel, which otherwise might allow an attacker
|
|
// to gain information about the header encryption.
|
|
if parseErr != nil && parseErr != wire.ErrInvalidReservedBits {
|
|
return 0, 0, 0, nil, &headerParseError{parseErr}
|
|
}
|
|
pn = opener.DecodePacketNumber(pn, pnLen)
|
|
decrypted, err := opener.Open(data[l:l], data[l:], rcvTime, pn, kp, data[:l])
|
|
if err != nil {
|
|
return 0, 0, 0, nil, err
|
|
}
|
|
return pn, pnLen, kp, decrypted, parseErr
|
|
}
|
|
|
|
func (u *packetUnpacker) unpackShortHeader(hd headerDecryptor, data []byte) (int, protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, error) {
|
|
hdrLen := 1 /* first header byte */ + u.shortHdrConnIDLen
|
|
if len(data) < hdrLen+4+16 {
|
|
return 0, 0, 0, 0, fmt.Errorf("packet too small, expected at least 20 bytes after the header, got %d", len(data)-hdrLen)
|
|
}
|
|
origPNBytes := make([]byte, 4)
|
|
copy(origPNBytes, data[hdrLen:hdrLen+4])
|
|
// 2. decrypt the header, assuming a 4 byte packet number
|
|
hd.DecryptHeader(
|
|
data[hdrLen+4:hdrLen+4+16],
|
|
&data[0],
|
|
data[hdrLen:hdrLen+4],
|
|
)
|
|
// 3. parse the header (and learn the actual length of the packet number)
|
|
l, pn, pnLen, kp, parseErr := wire.ParseShortHeader(data, u.shortHdrConnIDLen)
|
|
if parseErr != nil && parseErr != wire.ErrInvalidReservedBits {
|
|
return l, pn, pnLen, kp, parseErr
|
|
}
|
|
// 4. if the packet number is shorter than 4 bytes, replace the remaining bytes with the copy we saved earlier
|
|
if pnLen != protocol.PacketNumberLen4 {
|
|
copy(data[hdrLen+int(pnLen):hdrLen+4], origPNBytes[int(pnLen):])
|
|
}
|
|
return l, pn, pnLen, kp, parseErr
|
|
}
|
|
|
|
// The error is either nil, a wire.ErrInvalidReservedBits or of type headerParseError.
|
|
func (u *packetUnpacker) unpackLongHeader(hd headerDecryptor, hdr *wire.Header, data []byte, v protocol.VersionNumber) (*wire.ExtendedHeader, error) {
|
|
extHdr, err := unpackLongHeader(hd, hdr, data, v)
|
|
if err != nil && err != wire.ErrInvalidReservedBits {
|
|
return nil, &headerParseError{err: err}
|
|
}
|
|
return extHdr, err
|
|
}
|
|
|
|
func unpackLongHeader(hd headerDecryptor, hdr *wire.Header, data []byte, v protocol.VersionNumber) (*wire.ExtendedHeader, error) {
|
|
r := bytes.NewReader(data)
|
|
|
|
hdrLen := hdr.ParsedLen()
|
|
if protocol.ByteCount(len(data)) < hdrLen+4+16 {
|
|
//nolint:stylecheck
|
|
return nil, fmt.Errorf("Packet too small. Expected at least 20 bytes after the header, got %d", protocol.ByteCount(len(data))-hdrLen)
|
|
}
|
|
// The packet number can be up to 4 bytes long, but we won't know the length until we decrypt it.
|
|
// 1. save a copy of the 4 bytes
|
|
origPNBytes := make([]byte, 4)
|
|
copy(origPNBytes, data[hdrLen:hdrLen+4])
|
|
// 2. decrypt the header, assuming a 4 byte packet number
|
|
hd.DecryptHeader(
|
|
data[hdrLen+4:hdrLen+4+16],
|
|
&data[0],
|
|
data[hdrLen:hdrLen+4],
|
|
)
|
|
// 3. parse the header (and learn the actual length of the packet number)
|
|
extHdr, parseErr := hdr.ParseExtended(r, v)
|
|
if parseErr != nil && parseErr != wire.ErrInvalidReservedBits {
|
|
return nil, parseErr
|
|
}
|
|
// 4. if the packet number is shorter than 4 bytes, replace the remaining bytes with the copy we saved earlier
|
|
if extHdr.PacketNumberLen != protocol.PacketNumberLen4 {
|
|
copy(data[extHdr.ParsedLen():hdrLen+4], origPNBytes[int(extHdr.PacketNumberLen):])
|
|
}
|
|
return extHdr, parseErr
|
|
}
|