package quic
import (
"fmt"
"time"
"github.com/quic-go/quic-go/internal/handshake"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/qerr"
"github.com/quic-go/quic-go/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
}
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 ,
}
}
func (u *packetUnpacker ) UnpackLongHeader (hdr *wire .Header , data []byte ) (*unpackedPacket , error ) {
var encLevel protocol .EncryptionLevel
var extHdr *wire .ExtendedHeader
var decrypted []byte
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 :
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 ) (*wire .ExtendedHeader , []byte , error ) {
extHdr , parseErr := u .unpackLongHeader (opener , hdr , data )
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 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 + 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 ])
hd .DecryptHeader (
data [hdrLen +4 :hdrLen +4 +16 ],
&data [0 ],
data [hdrLen :hdrLen +4 ],
)
l , pn , pnLen , kp , parseErr := wire .ParseShortHeader (data , u .shortHdrConnIDLen )
if parseErr != nil && parseErr != wire .ErrInvalidReservedBits {
return l , pn , pnLen , kp , parseErr
}
if pnLen != protocol .PacketNumberLen4 {
copy (data [hdrLen +int (pnLen ):hdrLen +4 ], origPNBytes [int (pnLen ):])
}
return l , pn , pnLen , kp , parseErr
}
func (u *packetUnpacker ) unpackLongHeader (hd headerDecryptor , hdr *wire .Header , data []byte ) (*wire .ExtendedHeader , error ) {
extHdr , err := unpackLongHeader (hd , hdr , data )
if err != nil && err != wire .ErrInvalidReservedBits {
return nil , &headerParseError {err : err }
}
return extHdr , err
}
func unpackLongHeader(hd headerDecryptor , hdr *wire .Header , data []byte ) (*wire .ExtendedHeader , error ) {
hdrLen := hdr .ParsedLen ()
if protocol .ByteCount (len (data )) < hdrLen +4 +16 {
return nil , fmt .Errorf ("packet too small, expected at least 20 bytes after the header, got %d" , protocol .ByteCount (len (data ))-hdrLen )
}
origPNBytes := make ([]byte , 4 )
copy (origPNBytes , data [hdrLen :hdrLen +4 ])
hd .DecryptHeader (
data [hdrLen +4 :hdrLen +4 +16 ],
&data [0 ],
data [hdrLen :hdrLen +4 ],
)
extHdr , parseErr := hdr .ParseExtended (data )
if parseErr != nil && parseErr != wire .ErrInvalidReservedBits {
return nil , parseErr
}
if extHdr .PacketNumberLen != protocol .PacketNumberLen4 {
copy (data [extHdr .ParsedLen ():hdrLen +4 ], origPNBytes [int (extHdr .PacketNumberLen ):])
}
return extHdr , parseErr
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .