name the quic.Cookie to quic.Token

This commit is contained in:
Marten Seemann 2019-05-30 22:13:06 +08:00
parent 06da72ae4e
commit 1d6707325f
12 changed files with 234 additions and 232 deletions

View file

@ -3,6 +3,7 @@
## v0.12.0 (unreleased) ## v0.12.0 (unreleased)
- Implement HTTP/3. - Implement HTTP/3.
- Rename `quic.Cookie` to `quic.Token` and `quic.Config.AcceptCookie` to `quic.Config.AcceptToken`.
## v0.11.0 (2019-04-05) ## v0.11.0 (2019-04-05)

View file

@ -113,8 +113,8 @@ var _ = Describe("Handshake RTT tests", func() {
expectDurationInRTTs(2) expectDurationInRTTs(2)
}) })
It("establishes a connection in 1 RTT when the server doesn't require a Cookie", func() { It("establishes a connection in 1 RTT when the server doesn't require a token", func() {
serverConfig.AcceptCookie = func(_ net.Addr, _ *quic.Cookie) bool { serverConfig.AcceptToken = func(_ net.Addr, _ *quic.Token) bool {
return true return true
} }
runServerAndProxy() runServerAndProxy()
@ -128,7 +128,7 @@ var _ = Describe("Handshake RTT tests", func() {
}) })
It("establishes a connection in 2 RTTs if a HelloRetryRequest is performed", func() { It("establishes a connection in 2 RTTs if a HelloRetryRequest is performed", func() {
serverConfig.AcceptCookie = func(_ net.Addr, _ *quic.Cookie) bool { serverConfig.AcceptToken = func(_ net.Addr, _ *quic.Token) bool {
return true return true
} }
serverTLSConfig.CurvePreferences = []tls.CurveID{tls.CurveP384} serverTLSConfig.CurvePreferences = []tls.CurveID{tls.CurveP384}
@ -142,8 +142,8 @@ var _ = Describe("Handshake RTT tests", func() {
expectDurationInRTTs(2) expectDurationInRTTs(2)
}) })
It("doesn't complete the handshake when the server never accepts the Cookie", func() { It("doesn't complete the handshake when the server never accepts the token", func() {
serverConfig.AcceptCookie = func(_ net.Addr, _ *quic.Cookie) bool { serverConfig.AcceptToken = func(_ net.Addr, _ *quic.Token) bool {
return false return false
} }
clientConfig.HandshakeTimeout = 500 * time.Millisecond clientConfig.HandshakeTimeout = 500 * time.Millisecond

View file

@ -196,7 +196,7 @@ var _ = Describe("Handshake tests", func() {
} }
BeforeEach(func() { BeforeEach(func() {
serverConfig.AcceptCookie = func(net.Addr, *quic.Cookie) bool { return true } serverConfig.AcceptToken = func(net.Addr, *quic.Token) bool { return true }
var err error var err error
// start the server, but don't call Accept // start the server, but don't call Accept
server, err = quic.ListenAddr("localhost:0", testdata.GetTLSConfig(), serverConfig) server, err = quic.ListenAddr("localhost:0", testdata.GetTLSConfig(), serverConfig)

View file

@ -16,8 +16,8 @@ type StreamID = protocol.StreamID
// A VersionNumber is a QUIC version number. // A VersionNumber is a QUIC version number.
type VersionNumber = protocol.VersionNumber type VersionNumber = protocol.VersionNumber
// A Cookie can be used to verify the ownership of the client address. // A Token can be used to verify the ownership of the client address.
type Cookie struct { type Token struct {
RemoteAddr string RemoteAddr string
SentTime time.Time SentTime time.Time
} }
@ -187,11 +187,11 @@ type Config struct {
// If the timeout is exceeded, the connection is closed. // If the timeout is exceeded, the connection is closed.
// If this value is zero, the timeout is set to 30 seconds. // If this value is zero, the timeout is set to 30 seconds.
IdleTimeout time.Duration IdleTimeout time.Duration
// AcceptCookie determines if a Cookie is accepted. // AcceptToken determines if a Token is accepted.
// It is called with cookie = nil if the client didn't send an Cookie. // It is called with token = nil if the client didn't send a token.
// If not set, it verifies that the address matches, and that the Cookie was issued within the last 24 hours. // If not set, it verifies that the address matches, and that the token was issued within the last 24 hours.
// This option is only valid for the server. // This option is only valid for the server.
AcceptCookie func(clientAddr net.Addr, cookie *Cookie) bool AcceptToken func(clientAddr net.Addr, token *Token) bool
// MaxReceiveStreamFlowControlWindow is the maximum stream-level flow control window for receiving data. // MaxReceiveStreamFlowControlWindow is the maximum stream-level flow control window for receiving data.
// If this value is zero, it will default to 1 MB for the server and 6 MB for the client. // If this value is zero, it will default to 1 MB for the server and 6 MB for the client.
MaxReceiveStreamFlowControlWindow uint64 MaxReceiveStreamFlowControlWindow uint64

View file

@ -1,109 +0,0 @@
package handshake
import (
"encoding/asn1"
"fmt"
"net"
"time"
"github.com/lucas-clemente/quic-go/internal/protocol"
)
const (
cookiePrefixIP byte = iota
cookiePrefixString
)
// A Cookie is derived from the client address and can be used to verify the ownership of this address.
type Cookie struct {
RemoteAddr string
OriginalDestConnectionID protocol.ConnectionID
// The time that the Cookie was issued (resolution 1 second)
SentTime time.Time
}
// token is the struct that is used for ASN1 serialization and deserialization
type token struct {
RemoteAddr []byte
OriginalDestConnectionID []byte
Timestamp int64
}
// A CookieGenerator generates Cookies
type CookieGenerator struct {
cookieProtector cookieProtector
}
// NewCookieGenerator initializes a new CookieGenerator
func NewCookieGenerator() (*CookieGenerator, error) {
cookieProtector, err := newCookieProtector()
if err != nil {
return nil, err
}
return &CookieGenerator{
cookieProtector: cookieProtector,
}, nil
}
// NewToken generates a new Cookie for a given source address
func (g *CookieGenerator) NewToken(raddr net.Addr, origConnID protocol.ConnectionID) ([]byte, error) {
data, err := asn1.Marshal(token{
RemoteAddr: encodeRemoteAddr(raddr),
OriginalDestConnectionID: origConnID,
Timestamp: time.Now().Unix(),
})
if err != nil {
return nil, err
}
return g.cookieProtector.NewToken(data)
}
// DecodeToken decodes a Cookie
func (g *CookieGenerator) DecodeToken(encrypted []byte) (*Cookie, error) {
// if the client didn't send any Cookie, DecodeToken will be called with a nil-slice
if len(encrypted) == 0 {
return nil, nil
}
data, err := g.cookieProtector.DecodeToken(encrypted)
if err != nil {
return nil, err
}
t := &token{}
rest, err := asn1.Unmarshal(data, t)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, fmt.Errorf("rest when unpacking token: %d", len(rest))
}
cookie := &Cookie{
RemoteAddr: decodeRemoteAddr(t.RemoteAddr),
SentTime: time.Unix(t.Timestamp, 0),
}
if len(t.OriginalDestConnectionID) > 0 {
cookie.OriginalDestConnectionID = protocol.ConnectionID(t.OriginalDestConnectionID)
}
return cookie, nil
}
// encodeRemoteAddr encodes a remote address such that it can be saved in the Cookie
func encodeRemoteAddr(remoteAddr net.Addr) []byte {
if udpAddr, ok := remoteAddr.(*net.UDPAddr); ok {
return append([]byte{cookiePrefixIP}, udpAddr.IP...)
}
return append([]byte{cookiePrefixString}, []byte(remoteAddr.String())...)
}
// decodeRemoteAddr decodes the remote address saved in the Cookie
func decodeRemoteAddr(data []byte) string {
// data will never be empty for a Cookie that we generated. Check it to be on the safe side
if len(data) == 0 {
return ""
}
if data[0] == cookiePrefixIP {
return net.IP(data[1:]).String()
}
return string(data[1:])
}

View file

@ -0,0 +1,110 @@
package handshake
import (
"encoding/asn1"
"fmt"
"net"
"time"
"github.com/lucas-clemente/quic-go/internal/protocol"
)
const (
tokenPrefixIP byte = iota
tokenPrefixString
)
// A Token is derived from the client address and can be used to verify the ownership of this address.
type Token struct {
RemoteAddr string
OriginalDestConnectionID protocol.ConnectionID
// The time that the Token was issued (resolution 1 second)
SentTime time.Time
}
// token is the struct that is used for ASN1 serialization and deserialization
type token struct {
RemoteAddr []byte
OriginalDestConnectionID []byte
Timestamp int64
}
// A TokenGenerator generates tokens
type TokenGenerator struct {
tokenProtector tokenProtector
}
// NewTokenGenerator initializes a new TookenGenerator
func NewTokenGenerator() (*TokenGenerator, error) {
tokenProtector, err := newTokenProtector()
if err != nil {
return nil, err
}
return &TokenGenerator{
tokenProtector: tokenProtector,
}, nil
}
// NewToken generates a new token for a given source address
func (g *TokenGenerator) NewToken(raddr net.Addr, origConnID protocol.ConnectionID) ([]byte, error) {
data, err := asn1.Marshal(token{
RemoteAddr: encodeRemoteAddr(raddr),
OriginalDestConnectionID: origConnID,
Timestamp: time.Now().Unix(),
})
if err != nil {
return nil, err
}
return g.tokenProtector.NewToken(data)
}
// DecodeToken decodes a token
func (g *TokenGenerator) DecodeToken(encrypted []byte) (*Token, error) {
// if the client didn't send any token, DecodeToken will be called with a nil-slice
if len(encrypted) == 0 {
return nil, nil
}
data, err := g.tokenProtector.DecodeToken(encrypted)
if err != nil {
return nil, err
}
t := &token{}
rest, err := asn1.Unmarshal(data, t)
if err != nil {
return nil, err
}
if len(rest) != 0 {
return nil, fmt.Errorf("rest when unpacking token: %d", len(rest))
}
token := &Token{
RemoteAddr: decodeRemoteAddr(t.RemoteAddr),
SentTime: time.Unix(t.Timestamp, 0),
}
if len(t.OriginalDestConnectionID) > 0 {
token.OriginalDestConnectionID = protocol.ConnectionID(t.OriginalDestConnectionID)
}
return token, nil
}
// encodeRemoteAddr encodes a remote address such that it can be saved in the token
func encodeRemoteAddr(remoteAddr net.Addr) []byte {
if udpAddr, ok := remoteAddr.(*net.UDPAddr); ok {
return append([]byte{tokenPrefixIP}, udpAddr.IP...)
}
return append([]byte{tokenPrefixString}, []byte(remoteAddr.String())...)
}
// decodeRemoteAddr decodes the remote address saved in the token
func decodeRemoteAddr(data []byte) string {
// data will never be empty for a token that we generated.
// Check it to be on the safe side
if len(data) == 0 {
return ""
}
if data[0] == tokenPrefixIP {
return net.IP(data[1:]).String()
}
return string(data[1:])
}

View file

@ -11,64 +11,64 @@ import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
var _ = Describe("Cookie Generator", func() { var _ = Describe("Token Generator", func() {
var cookieGen *CookieGenerator var tokenGen *TokenGenerator
BeforeEach(func() { BeforeEach(func() {
var err error var err error
cookieGen, err = NewCookieGenerator() tokenGen, err = NewTokenGenerator()
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
It("generates a Cookie", func() { It("generates a token", func() {
ip := net.IPv4(127, 0, 0, 1) ip := net.IPv4(127, 0, 0, 1)
token, err := cookieGen.NewToken(&net.UDPAddr{IP: ip, Port: 1337}, nil) token, err := tokenGen.NewToken(&net.UDPAddr{IP: ip, Port: 1337}, nil)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(token).ToNot(BeEmpty()) Expect(token).ToNot(BeEmpty())
}) })
It("works with nil tokens", func() { It("works with nil tokens", func() {
cookie, err := cookieGen.DecodeToken(nil) token, err := tokenGen.DecodeToken(nil)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(cookie).To(BeNil()) Expect(token).To(BeNil())
}) })
It("accepts a valid cookie", func() { It("accepts a valid token", func() {
ip := net.IPv4(192, 168, 0, 1) ip := net.IPv4(192, 168, 0, 1)
token, err := cookieGen.NewToken( tokenEnc, err := tokenGen.NewToken(
&net.UDPAddr{IP: ip, Port: 1337}, &net.UDPAddr{IP: ip, Port: 1337},
nil, nil,
) )
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
cookie, err := cookieGen.DecodeToken(token) token, err := tokenGen.DecodeToken(tokenEnc)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(cookie.RemoteAddr).To(Equal("192.168.0.1")) Expect(token.RemoteAddr).To(Equal("192.168.0.1"))
// the time resolution of the Cookie is just 1 second // the time resolution of the token is just 1 second
// if Cookie generation and this check happen in "different seconds", the difference will be between 1 and 2 seconds // if token generation and this check happen in "different seconds", the difference will be between 1 and 2 seconds
Expect(cookie.SentTime).To(BeTemporally("~", time.Now(), 2*time.Second)) Expect(token.SentTime).To(BeTemporally("~", time.Now(), 2*time.Second))
Expect(cookie.OriginalDestConnectionID).To(BeNil()) Expect(token.OriginalDestConnectionID).To(BeNil())
}) })
It("saves the connection ID", func() { It("saves the connection ID", func() {
token, err := cookieGen.NewToken( tokenEnc, err := tokenGen.NewToken(
&net.UDPAddr{}, &net.UDPAddr{},
protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef},
) )
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
cookie, err := cookieGen.DecodeToken(token) token, err := tokenGen.DecodeToken(tokenEnc)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(cookie.OriginalDestConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef})) Expect(token.OriginalDestConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}))
}) })
It("rejects invalid tokens", func() { It("rejects invalid tokens", func() {
_, err := cookieGen.DecodeToken([]byte("invalid token")) _, err := tokenGen.DecodeToken([]byte("invalid token"))
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
It("rejects tokens that cannot be decoded", func() { It("rejects tokens that cannot be decoded", func() {
token, err := cookieGen.cookieProtector.NewToken([]byte("foobar")) token, err := tokenGen.tokenProtector.NewToken([]byte("foobar"))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
_, err = cookieGen.DecodeToken(token) _, err = tokenGen.DecodeToken(token)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
@ -76,9 +76,9 @@ var _ = Describe("Cookie Generator", func() {
t, err := asn1.Marshal(token{RemoteAddr: []byte("foobar")}) t, err := asn1.Marshal(token{RemoteAddr: []byte("foobar")})
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
t = append(t, []byte("rest")...) t = append(t, []byte("rest")...)
enc, err := cookieGen.cookieProtector.NewToken(t) enc, err := tokenGen.tokenProtector.NewToken(t)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
_, err = cookieGen.DecodeToken(enc) _, err = tokenGen.DecodeToken(enc)
Expect(err).To(MatchError("rest when unpacking token: 4")) Expect(err).To(MatchError("rest when unpacking token: 4"))
}) })
@ -86,9 +86,9 @@ var _ = Describe("Cookie Generator", func() {
It("doesn't panic if a tokens has no data", func() { It("doesn't panic if a tokens has no data", func() {
t, err := asn1.Marshal(token{RemoteAddr: []byte("")}) t, err := asn1.Marshal(token{RemoteAddr: []byte("")})
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
enc, err := cookieGen.cookieProtector.NewToken(t) enc, err := tokenGen.tokenProtector.NewToken(t)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
_, err = cookieGen.DecodeToken(enc) _, err = tokenGen.DecodeToken(enc)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
@ -103,26 +103,26 @@ var _ = Describe("Cookie Generator", func() {
ip := net.ParseIP(addr) ip := net.ParseIP(addr)
Expect(ip).ToNot(BeNil()) Expect(ip).ToNot(BeNil())
raddr := &net.UDPAddr{IP: ip, Port: 1337} raddr := &net.UDPAddr{IP: ip, Port: 1337}
token, err := cookieGen.NewToken(raddr, nil) tokenEnc, err := tokenGen.NewToken(raddr, nil)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
cookie, err := cookieGen.DecodeToken(token) token, err := tokenGen.DecodeToken(tokenEnc)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(cookie.RemoteAddr).To(Equal(ip.String())) Expect(token.RemoteAddr).To(Equal(ip.String()))
// the time resolution of the Cookie is just 1 second // the time resolution of the token is just 1 second
// if Cookie generation and this check happen in "different seconds", the difference will be between 1 and 2 seconds // if token generation and this check happen in "different seconds", the difference will be between 1 and 2 seconds
Expect(cookie.SentTime).To(BeTemporally("~", time.Now(), 2*time.Second)) Expect(token.SentTime).To(BeTemporally("~", time.Now(), 2*time.Second))
} }
}) })
It("uses the string representation an address that is not a UDP address", func() { It("uses the string representation an address that is not a UDP address", func() {
raddr := &net.TCPAddr{IP: net.IPv4(192, 168, 13, 37), Port: 1337} raddr := &net.TCPAddr{IP: net.IPv4(192, 168, 13, 37), Port: 1337}
token, err := cookieGen.NewToken(raddr, nil) tokenEnc, err := tokenGen.NewToken(raddr, nil)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
cookie, err := cookieGen.DecodeToken(token) token, err := tokenGen.DecodeToken(tokenEnc)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(cookie.RemoteAddr).To(Equal("192.168.13.37:1337")) Expect(token.RemoteAddr).To(Equal("192.168.13.37:1337"))
// the time resolution of the Cookie is just 1 second // the time resolution of the token is just 1 second
// if Cookie generation and this check happen in "different seconds", the difference will be between 1 and 2 seconds // if token generation and this check happen in "different seconds", the difference will be between 1 and 2 seconds
Expect(cookie.SentTime).To(BeTemporally("~", time.Now(), 2*time.Second)) Expect(token.SentTime).To(BeTemporally("~", time.Now(), 2*time.Second))
}) })
}) })

View file

@ -11,8 +11,8 @@ import (
"golang.org/x/crypto/hkdf" "golang.org/x/crypto/hkdf"
) )
// CookieProtector is used to create and verify a cookie // TokenProtector is used to create and verify a token
type cookieProtector interface { type tokenProtector interface {
// NewToken creates a new token // NewToken creates a new token
NewToken([]byte) ([]byte, error) NewToken([]byte) ([]byte, error)
// DecodeToken decodes a token // DecodeToken decodes a token
@ -20,27 +20,27 @@ type cookieProtector interface {
} }
const ( const (
cookieSecretSize = 32 tokenSecretSize = 32
cookieNonceSize = 32 tokenNonceSize = 32
) )
// cookieProtector is used to create and verify a cookie // tokenProtector is used to create and verify a token
type cookieProtectorImpl struct { type tokenProtectorImpl struct {
secret []byte secret []byte
} }
// newCookieProtector creates a source for source address tokens // newTokenProtector creates a source for source address tokens
func newCookieProtector() (cookieProtector, error) { func newTokenProtector() (tokenProtector, error) {
secret := make([]byte, cookieSecretSize) secret := make([]byte, tokenSecretSize)
if _, err := rand.Read(secret); err != nil { if _, err := rand.Read(secret); err != nil {
return nil, err return nil, err
} }
return &cookieProtectorImpl{secret: secret}, nil return &tokenProtectorImpl{secret: secret}, nil
} }
// NewToken encodes data into a new token. // NewToken encodes data into a new token.
func (s *cookieProtectorImpl) NewToken(data []byte) ([]byte, error) { func (s *tokenProtectorImpl) NewToken(data []byte) ([]byte, error) {
nonce := make([]byte, cookieNonceSize) nonce := make([]byte, tokenNonceSize)
if _, err := rand.Read(nonce); err != nil { if _, err := rand.Read(nonce); err != nil {
return nil, err return nil, err
} }
@ -52,20 +52,20 @@ func (s *cookieProtectorImpl) NewToken(data []byte) ([]byte, error) {
} }
// DecodeToken decodes a token. // DecodeToken decodes a token.
func (s *cookieProtectorImpl) DecodeToken(p []byte) ([]byte, error) { func (s *tokenProtectorImpl) DecodeToken(p []byte) ([]byte, error) {
if len(p) < cookieNonceSize { if len(p) < tokenNonceSize {
return nil, fmt.Errorf("Token too short: %d", len(p)) return nil, fmt.Errorf("Token too short: %d", len(p))
} }
nonce := p[:cookieNonceSize] nonce := p[:tokenNonceSize]
aead, aeadNonce, err := s.createAEAD(nonce) aead, aeadNonce, err := s.createAEAD(nonce)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return aead.Open(nil, aeadNonce, p[cookieNonceSize:], nil) return aead.Open(nil, aeadNonce, p[tokenNonceSize:], nil)
} }
func (s *cookieProtectorImpl) createAEAD(nonce []byte) (cipher.AEAD, []byte, error) { func (s *tokenProtectorImpl) createAEAD(nonce []byte) (cipher.AEAD, []byte, error) {
h := hkdf.New(sha256.New, s.secret, nonce, []byte("quic-go cookie source")) h := hkdf.New(sha256.New, s.secret, nonce, []byte("quic-go token source"))
key := make([]byte, 32) // use a 32 byte key, in order to select AES-256 key := make([]byte, 32) // use a 32 byte key, in order to select AES-256
if _, err := io.ReadFull(h, key); err != nil { if _, err := io.ReadFull(h, key); err != nil {
return nil, nil, err return nil, nil, err

View file

@ -5,35 +5,35 @@ import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
var _ = Describe("Cookie Protector", func() { var _ = Describe("Token Protector", func() {
var cp cookieProtector var tp tokenProtector
BeforeEach(func() { BeforeEach(func() {
var err error var err error
cp, err = newCookieProtector() tp, err = newTokenProtector()
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
It("encodes and decodes tokens", func() { It("encodes and decodes tokens", func() {
token, err := cp.NewToken([]byte("foobar")) token, err := tp.NewToken([]byte("foobar"))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(token).ToNot(ContainSubstring("foobar")) Expect(token).ToNot(ContainSubstring("foobar"))
decoded, err := cp.DecodeToken(token) decoded, err := tp.DecodeToken(token)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(decoded).To(Equal([]byte("foobar"))) Expect(decoded).To(Equal([]byte("foobar")))
}) })
It("fails deconding invalid tokens", func() { It("fails deconding invalid tokens", func() {
token, err := cp.NewToken([]byte("foobar")) token, err := tp.NewToken([]byte("foobar"))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
token = token[1:] // remove the first byte token = token[1:] // remove the first byte
_, err = cp.DecodeToken(token) _, err = tp.DecodeToken(token)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("message authentication failed")) Expect(err.Error()).To(ContainSubstring("message authentication failed"))
}) })
It("errors when decoding too short tokens", func() { It("errors when decoding too short tokens", func() {
_, err := cp.DecodeToken([]byte("foobar")) _, err := tp.DecodeToken([]byte("foobar"))
Expect(err).To(MatchError("Token too short: 6")) Expect(err).To(MatchError("Token too short: 6"))
}) })
}) })

View file

@ -57,8 +57,8 @@ const MaxTrackedSkippedPackets = 10
// If the queue is full, new connection attempts will be rejected. // If the queue is full, new connection attempts will be rejected.
const MaxAcceptQueueSize = 32 const MaxAcceptQueueSize = 32
// CookieExpiryTime is the valid time of a cookie // TokenExpiryTime is the valid time of a token
const CookieExpiryTime = 24 * time.Hour const TokenExpiryTime = 24 * time.Hour
// MaxOutstandingSentPackets is maximum number of packets saved for retransmission. // MaxOutstandingSentPackets is maximum number of packets saved for retransmission.
// When reached, it imposes a soft limit on sending new packets: // When reached, it imposes a soft limit on sending new packets:

View file

@ -84,7 +84,7 @@ type server struct {
// If it is started with Listen, we take a packet conn as a parameter. // If it is started with Listen, we take a packet conn as a parameter.
createdPacketConn bool createdPacketConn bool
cookieGenerator *handshake.CookieGenerator tokenGenerator *handshake.TokenGenerator
sessionHandler packetHandlerManager sessionHandler packetHandlerManager
@ -186,19 +186,19 @@ func (s *server) setup() error {
}() }()
}, },
} }
cookieGenerator, err := handshake.NewCookieGenerator() tokenGenerator, err := handshake.NewTokenGenerator()
if err != nil { if err != nil {
return err return err
} }
s.cookieGenerator = cookieGenerator s.tokenGenerator = tokenGenerator
return nil return nil
} }
var defaultAcceptCookie = func(clientAddr net.Addr, cookie *Cookie) bool { var defaultAcceptToken = func(clientAddr net.Addr, token *Token) bool {
if cookie == nil { if token == nil {
return false return false
} }
if time.Now().After(cookie.SentTime.Add(protocol.CookieExpiryTime)) { if time.Now().After(token.SentTime.Add(protocol.TokenExpiryTime)) {
return false return false
} }
var sourceAddr string var sourceAddr string
@ -207,7 +207,7 @@ var defaultAcceptCookie = func(clientAddr net.Addr, cookie *Cookie) bool {
} else { } else {
sourceAddr = clientAddr.String() sourceAddr = clientAddr.String()
} }
return sourceAddr == cookie.RemoteAddr return sourceAddr == token.RemoteAddr
} }
// populateServerConfig populates fields in the quic.Config with their default values, if none are set // populateServerConfig populates fields in the quic.Config with their default values, if none are set
@ -221,9 +221,9 @@ func populateServerConfig(config *Config) *Config {
versions = protocol.SupportedVersions versions = protocol.SupportedVersions
} }
vsa := defaultAcceptCookie verifyToken := defaultAcceptToken
if config.AcceptCookie != nil { if config.AcceptToken != nil {
vsa = config.AcceptCookie verifyToken = config.AcceptToken
} }
handshakeTimeout := protocol.DefaultHandshakeTimeout handshakeTimeout := protocol.DefaultHandshakeTimeout
@ -264,7 +264,7 @@ func populateServerConfig(config *Config) *Config {
Versions: versions, Versions: versions,
HandshakeTimeout: handshakeTimeout, HandshakeTimeout: handshakeTimeout,
IdleTimeout: idleTimeout, IdleTimeout: idleTimeout,
AcceptCookie: vsa, AcceptToken: verifyToken,
KeepAlive: config.KeepAlive, KeepAlive: config.KeepAlive,
MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow, MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow,
MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow, MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow,
@ -381,19 +381,19 @@ func (s *server) handleInitialImpl(p *receivedPacket, hdr *wire.Header) (quicSes
return nil, nil, errors.New("too short connection ID") return nil, nil, errors.New("too short connection ID")
} }
var cookie *Cookie var token *Token
var origDestConnectionID protocol.ConnectionID var origDestConnectionID protocol.ConnectionID
if len(hdr.Token) > 0 { if len(hdr.Token) > 0 {
c, err := s.cookieGenerator.DecodeToken(hdr.Token) c, err := s.tokenGenerator.DecodeToken(hdr.Token)
if err == nil { if err == nil {
cookie = &Cookie{ token = &Token{
RemoteAddr: c.RemoteAddr, RemoteAddr: c.RemoteAddr,
SentTime: c.SentTime, SentTime: c.SentTime,
} }
origDestConnectionID = c.OriginalDestConnectionID origDestConnectionID = c.OriginalDestConnectionID
} }
} }
if !s.config.AcceptCookie(p.remoteAddr, cookie) { if !s.config.AcceptToken(p.remoteAddr, token) {
// Log the Initial packet now. // Log the Initial packet now.
// If no Retry is sent, the packet will be logged by the session. // If no Retry is sent, the packet will be logged by the session.
(&wire.ExtendedHeader{Header: *hdr}).Log(s.logger) (&wire.ExtendedHeader{Header: *hdr}).Log(s.logger)
@ -468,7 +468,7 @@ func (s *server) createNewSession(
} }
func (s *server) sendRetry(remoteAddr net.Addr, hdr *wire.Header) error { func (s *server) sendRetry(remoteAddr net.Addr, hdr *wire.Header) error {
token, err := s.cookieGenerator.NewToken(remoteAddr, hdr.DestConnectionID) token, err := s.tokenGenerator.NewToken(remoteAddr, hdr.DestConnectionID)
if err != nil { if err != nil {
return err return err
} }

View file

@ -69,7 +69,7 @@ var _ = Describe("Server", func() {
Expect(server.config.Versions).To(Equal(protocol.SupportedVersions)) Expect(server.config.Versions).To(Equal(protocol.SupportedVersions))
Expect(server.config.HandshakeTimeout).To(Equal(protocol.DefaultHandshakeTimeout)) Expect(server.config.HandshakeTimeout).To(Equal(protocol.DefaultHandshakeTimeout))
Expect(server.config.IdleTimeout).To(Equal(protocol.DefaultIdleTimeout)) Expect(server.config.IdleTimeout).To(Equal(protocol.DefaultIdleTimeout))
Expect(reflect.ValueOf(server.config.AcceptCookie)).To(Equal(reflect.ValueOf(defaultAcceptCookie))) Expect(reflect.ValueOf(server.config.AcceptToken)).To(Equal(reflect.ValueOf(defaultAcceptToken)))
Expect(server.config.KeepAlive).To(BeFalse()) Expect(server.config.KeepAlive).To(BeFalse())
// stop the listener // stop the listener
Expect(ln.Close()).To(Succeed()) Expect(ln.Close()).To(Succeed())
@ -77,10 +77,10 @@ var _ = Describe("Server", func() {
It("setups with the right values", func() { It("setups with the right values", func() {
supportedVersions := []protocol.VersionNumber{protocol.VersionTLS} supportedVersions := []protocol.VersionNumber{protocol.VersionTLS}
acceptCookie := func(_ net.Addr, _ *Cookie) bool { return true } acceptToken := func(_ net.Addr, _ *Token) bool { return true }
config := Config{ config := Config{
Versions: supportedVersions, Versions: supportedVersions,
AcceptCookie: acceptCookie, AcceptToken: acceptToken,
HandshakeTimeout: 1337 * time.Hour, HandshakeTimeout: 1337 * time.Hour,
IdleTimeout: 42 * time.Minute, IdleTimeout: 42 * time.Minute,
KeepAlive: true, KeepAlive: true,
@ -93,7 +93,7 @@ var _ = Describe("Server", func() {
Expect(server.config.Versions).To(Equal(supportedVersions)) Expect(server.config.Versions).To(Equal(supportedVersions))
Expect(server.config.HandshakeTimeout).To(Equal(1337 * time.Hour)) Expect(server.config.HandshakeTimeout).To(Equal(1337 * time.Hour))
Expect(server.config.IdleTimeout).To(Equal(42 * time.Minute)) Expect(server.config.IdleTimeout).To(Equal(42 * time.Minute))
Expect(reflect.ValueOf(server.config.AcceptCookie)).To(Equal(reflect.ValueOf(acceptCookie))) Expect(reflect.ValueOf(server.config.AcceptToken)).To(Equal(reflect.ValueOf(acceptToken)))
Expect(server.config.KeepAlive).To(BeTrue()) Expect(server.config.KeepAlive).To(BeTrue())
Expect(server.config.StatelessResetKey).To(Equal([]byte("foobar"))) Expect(server.config.StatelessResetKey).To(Equal([]byte("foobar")))
// stop the listener // stop the listener
@ -179,19 +179,19 @@ var _ = Describe("Server", func() {
)) ))
}) })
It("decodes the cookie from the Token field", func() { It("decodes the token from the Token field", func() {
raddr := &net.UDPAddr{ raddr := &net.UDPAddr{
IP: net.IPv4(192, 168, 13, 37), IP: net.IPv4(192, 168, 13, 37),
Port: 1337, Port: 1337,
} }
done := make(chan struct{}) done := make(chan struct{})
serv.config.AcceptCookie = func(addr net.Addr, cookie *Cookie) bool { serv.config.AcceptToken = func(addr net.Addr, token *Token) bool {
Expect(addr).To(Equal(raddr)) Expect(addr).To(Equal(raddr))
Expect(cookie).ToNot(BeNil()) Expect(token).ToNot(BeNil())
close(done) close(done)
return false return false
} }
token, err := serv.cookieGenerator.NewToken(raddr, nil) token, err := serv.tokenGenerator.NewToken(raddr, nil)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
packet := getPacket(&wire.Header{ packet := getPacket(&wire.Header{
IsLongHeader: true, IsLongHeader: true,
@ -204,15 +204,15 @@ var _ = Describe("Server", func() {
Eventually(done).Should(BeClosed()) Eventually(done).Should(BeClosed())
}) })
It("passes an empty cookie to the callback, if decoding fails", func() { It("passes an empty token to the callback, if decoding fails", func() {
raddr := &net.UDPAddr{ raddr := &net.UDPAddr{
IP: net.IPv4(192, 168, 13, 37), IP: net.IPv4(192, 168, 13, 37),
Port: 1337, Port: 1337,
} }
done := make(chan struct{}) done := make(chan struct{})
serv.config.AcceptCookie = func(addr net.Addr, cookie *Cookie) bool { serv.config.AcceptToken = func(addr net.Addr, token *Token) bool {
Expect(addr).To(Equal(raddr)) Expect(addr).To(Equal(raddr))
Expect(cookie).To(BeNil()) Expect(token).To(BeNil())
close(done) close(done)
return false return false
} }
@ -249,8 +249,8 @@ var _ = Describe("Server", func() {
Expect(hdr.SupportedVersions).ToNot(ContainElement(protocol.VersionNumber(0x42))) Expect(hdr.SupportedVersions).ToNot(ContainElement(protocol.VersionNumber(0x42)))
}) })
It("replies with a Retry packet, if a Cookie is required", func() { It("replies with a Retry packet, if a Token is required", func() {
serv.config.AcceptCookie = func(_ net.Addr, _ *Cookie) bool { return false } serv.config.AcceptToken = func(_ net.Addr, _ *Token) bool { return false }
hdr := &wire.Header{ hdr := &wire.Header{
IsLongHeader: true, IsLongHeader: true,
Type: protocol.PacketTypeInitial, Type: protocol.PacketTypeInitial,
@ -272,8 +272,8 @@ var _ = Describe("Server", func() {
Expect(replyHdr.Token).ToNot(BeEmpty()) Expect(replyHdr.Token).ToNot(BeEmpty())
}) })
It("creates a session, if no Cookie is required", func() { It("creates a session, if no Token is required", func() {
serv.config.AcceptCookie = func(_ net.Addr, _ *Cookie) bool { return true } serv.config.AcceptToken = func(_ net.Addr, _ *Token) bool { return true }
hdr := &wire.Header{ hdr := &wire.Header{
IsLongHeader: true, IsLongHeader: true,
Type: protocol.PacketTypeInitial, Type: protocol.PacketTypeInitial,
@ -320,7 +320,7 @@ var _ = Describe("Server", func() {
}) })
It("rejects new connection attempts if the accept queue is full", func() { It("rejects new connection attempts if the accept queue is full", func() {
serv.config.AcceptCookie = func(_ net.Addr, _ *Cookie) bool { return true } serv.config.AcceptToken = func(_ net.Addr, _ *Token) bool { return true }
senderAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 42} senderAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 42}
hdr := &wire.Header{ hdr := &wire.Header{
@ -375,7 +375,7 @@ var _ = Describe("Server", func() {
}) })
It("doesn't accept new sessions if they were closed in the mean time", func() { It("doesn't accept new sessions if they were closed in the mean time", func() {
serv.config.AcceptCookie = func(_ net.Addr, _ *Cookie) bool { return true } serv.config.AcceptToken = func(_ net.Addr, _ *Token) bool { return true }
senderAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 42} senderAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 42}
hdr := &wire.Header{ hdr := &wire.Header{
@ -543,51 +543,51 @@ var _ = Describe("Server", func() {
var _ = Describe("default source address verification", func() { var _ = Describe("default source address verification", func() {
It("accepts a token", func() { It("accepts a token", func() {
remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)} remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)}
cookie := &Cookie{ token := &Token{
RemoteAddr: "192.168.0.1", RemoteAddr: "192.168.0.1",
SentTime: time.Now().Add(-protocol.CookieExpiryTime).Add(time.Second), // will expire in 1 second SentTime: time.Now().Add(-protocol.TokenExpiryTime).Add(time.Second), // will expire in 1 second
} }
Expect(defaultAcceptCookie(remoteAddr, cookie)).To(BeTrue()) Expect(defaultAcceptToken(remoteAddr, token)).To(BeTrue())
}) })
It("requests verification if no token is provided", func() { It("requests verification if no token is provided", func() {
remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)} remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)}
Expect(defaultAcceptCookie(remoteAddr, nil)).To(BeFalse()) Expect(defaultAcceptToken(remoteAddr, nil)).To(BeFalse())
}) })
It("rejects a token if the address doesn't match", func() { It("rejects a token if the address doesn't match", func() {
remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)} remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)}
cookie := &Cookie{ token := &Token{
RemoteAddr: "127.0.0.1", RemoteAddr: "127.0.0.1",
SentTime: time.Now(), SentTime: time.Now(),
} }
Expect(defaultAcceptCookie(remoteAddr, cookie)).To(BeFalse()) Expect(defaultAcceptToken(remoteAddr, token)).To(BeFalse())
}) })
It("accepts a token for a remote address is not a UDP address", func() { It("accepts a token for a remote address is not a UDP address", func() {
remoteAddr := &net.TCPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1337} remoteAddr := &net.TCPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1337}
cookie := &Cookie{ token := &Token{
RemoteAddr: "192.168.0.1:1337", RemoteAddr: "192.168.0.1:1337",
SentTime: time.Now(), SentTime: time.Now(),
} }
Expect(defaultAcceptCookie(remoteAddr, cookie)).To(BeTrue()) Expect(defaultAcceptToken(remoteAddr, token)).To(BeTrue())
}) })
It("rejects an invalid token for a remote address is not a UDP address", func() { It("rejects an invalid token for a remote address is not a UDP address", func() {
remoteAddr := &net.TCPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1337} remoteAddr := &net.TCPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1337}
cookie := &Cookie{ token := &Token{
RemoteAddr: "192.168.0.1:7331", // mismatching port RemoteAddr: "192.168.0.1:7331", // mismatching port
SentTime: time.Now(), SentTime: time.Now(),
} }
Expect(defaultAcceptCookie(remoteAddr, cookie)).To(BeFalse()) Expect(defaultAcceptToken(remoteAddr, token)).To(BeFalse())
}) })
It("rejects an expired token", func() { It("rejects an expired token", func() {
remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)} remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)}
cookie := &Cookie{ token := &Token{
RemoteAddr: "192.168.0.1", RemoteAddr: "192.168.0.1",
SentTime: time.Now().Add(-protocol.CookieExpiryTime).Add(-time.Second), // expired 1 second ago SentTime: time.Now().Add(-protocol.TokenExpiryTime).Add(-time.Second), // expired 1 second ago
} }
Expect(defaultAcceptCookie(remoteAddr, cookie)).To(BeFalse()) Expect(defaultAcceptToken(remoteAddr, token)).To(BeFalse())
}) })
}) })