mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-04 04:37:36 +03:00
When QUIC abandoned the "stream 0" design, it introduced separate packet number spaces for packets with different encryption levels. Packet number compression now also works per packet number space. The current code doesn't lead to any problems if the peer starts sending with packet number 0, as we only exchange a few packets in the Initial and the Handshake packet number space and there's nothing to compress. It might lead to problems if the peer starts with a large packet number in one space (which is allowed by the spec), and then starts with a small packet number in another packet number space.
202 lines
6.3 KiB
Go
202 lines
6.3 KiB
Go
package quic
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/lucas-clemente/quic-go/internal/handshake"
|
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
|
"github.com/lucas-clemente/quic-go/internal/wire"
|
|
)
|
|
|
|
type headerDecryptor interface {
|
|
DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte)
|
|
}
|
|
|
|
type headerParseError struct {
|
|
err error
|
|
}
|
|
|
|
func (e *headerParseError) Is(err error) bool {
|
|
_, ok := err.(*headerParseError)
|
|
return ok
|
|
}
|
|
|
|
func (e *headerParseError) Unwrap() error {
|
|
fmt.Println("unwrap")
|
|
return e.err
|
|
}
|
|
|
|
func (e *headerParseError) Error() string {
|
|
return e.err.Error()
|
|
}
|
|
|
|
type unpackedPacket struct {
|
|
packetNumber protocol.PacketNumber // the decoded packet number
|
|
hdr *wire.ExtendedHeader
|
|
encryptionLevel protocol.EncryptionLevel
|
|
data []byte
|
|
}
|
|
|
|
// The packetUnpacker unpacks QUIC packets.
|
|
type packetUnpacker struct {
|
|
cs handshake.CryptoSetup
|
|
|
|
version protocol.VersionNumber
|
|
}
|
|
|
|
var _ unpacker = &packetUnpacker{}
|
|
|
|
func newPacketUnpacker(cs handshake.CryptoSetup, version protocol.VersionNumber) unpacker {
|
|
return &packetUnpacker{
|
|
cs: cs,
|
|
version: version,
|
|
}
|
|
}
|
|
|
|
// 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) Unpack(hdr *wire.Header, rcvTime time.Time, data []byte) (*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)
|
|
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)
|
|
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)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
default:
|
|
if hdr.IsLongHeader {
|
|
return nil, fmt.Errorf("unknown packet type: %s", hdr.Type)
|
|
}
|
|
encLevel = protocol.Encryption1RTT
|
|
opener, err := u.cs.Get1RTTOpener()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
extHdr, decrypted, err = u.unpackShortHeaderPacket(opener, hdr, rcvTime, data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return &unpackedPacket{
|
|
hdr: extHdr,
|
|
packetNumber: extHdr.PacketNumber,
|
|
encryptionLevel: encLevel,
|
|
data: decrypted,
|
|
}, nil
|
|
}
|
|
|
|
func (u *packetUnpacker) unpackLongHeaderPacket(opener handshake.LongHeaderOpener, hdr *wire.Header, data []byte) (*wire.ExtendedHeader, []byte, error) {
|
|
extHdr, parseErr := u.unpackHeader(opener, hdr, 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 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,
|
|
hdr *wire.Header,
|
|
rcvTime time.Time,
|
|
data []byte,
|
|
) (*wire.ExtendedHeader, []byte, error) {
|
|
extHdr, parseErr := u.unpackHeader(opener, hdr, 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 nil, nil, parseErr
|
|
}
|
|
extHdr.PacketNumber = opener.DecodePacketNumber(extHdr.PacketNumber, extHdr.PacketNumberLen)
|
|
extHdrLen := extHdr.ParsedLen()
|
|
decrypted, err := opener.Open(data[extHdrLen:extHdrLen], data[extHdrLen:], rcvTime, extHdr.PacketNumber, extHdr.KeyPhase, data[:extHdrLen])
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if parseErr != nil {
|
|
return nil, nil, parseErr
|
|
}
|
|
return extHdr, decrypted, nil
|
|
}
|
|
|
|
// The error is either nil, a wire.ErrInvalidReservedBits or of type headerParseError.
|
|
func (u *packetUnpacker) unpackHeader(hd headerDecryptor, hdr *wire.Header, data []byte) (*wire.ExtendedHeader, error) {
|
|
extHdr, err := unpackHeader(hd, hdr, data, u.version)
|
|
if err != nil && err != wire.ErrInvalidReservedBits {
|
|
return nil, &headerParseError{err: err}
|
|
}
|
|
return extHdr, err
|
|
}
|
|
|
|
func unpackHeader(hd headerDecryptor, hdr *wire.Header, data []byte, version 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, version)
|
|
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
|
|
}
|