forked from quic-go/quic-go
Merge pull request #610 from lucas-clemente/fix-609
fix a race condition in the client crypto setup
This commit is contained in:
@@ -29,14 +29,16 @@ type cryptoSetupClient struct {
|
||||
|
||||
serverConfig *serverConfigClient
|
||||
|
||||
stk []byte
|
||||
sno []byte
|
||||
nonc []byte
|
||||
proof []byte
|
||||
stk []byte
|
||||
sno []byte
|
||||
nonc []byte
|
||||
proof []byte
|
||||
chloForSignature []byte
|
||||
lastSentCHLO []byte
|
||||
certManager crypto.CertManager
|
||||
|
||||
divNonceChan chan []byte
|
||||
diversificationNonce []byte
|
||||
chloForSignature []byte
|
||||
lastSentCHLO []byte
|
||||
certManager crypto.CertManager
|
||||
|
||||
clientHelloCounter int
|
||||
serverVerified bool // has the certificate chain and the proof already been verified
|
||||
@@ -83,20 +85,35 @@ func NewCryptoSetupClient(
|
||||
nullAEAD: crypto.NewNullAEAD(protocol.PerspectiveClient, version),
|
||||
aeadChanged: aeadChanged,
|
||||
negotiatedVersions: negotiatedVersions,
|
||||
divNonceChan: make(chan []byte),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *cryptoSetupClient) HandleCryptoStream() error {
|
||||
messageChan := make(chan HandshakeMessage)
|
||||
errorChan := make(chan error)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
message, err := ParseHandshakeMessage(h.cryptoStream)
|
||||
if err != nil {
|
||||
errorChan <- qerr.Error(qerr.HandshakeFailed, err.Error())
|
||||
return
|
||||
}
|
||||
messageChan <- message
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
err := h.maybeUpgradeCrypto()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// send CHLOs until the forward secure encryption is established
|
||||
h.mutex.RLock()
|
||||
sendCHLO := h.forwardSecureAEAD == nil
|
||||
sendCHLO := h.secureAEAD == nil
|
||||
h.mutex.RUnlock()
|
||||
|
||||
if sendCHLO {
|
||||
err = h.sendCHLO()
|
||||
if err != nil {
|
||||
@@ -104,37 +121,36 @@ func (h *cryptoSetupClient) HandleCryptoStream() error {
|
||||
}
|
||||
}
|
||||
|
||||
var shloData bytes.Buffer
|
||||
|
||||
messageTag, cryptoData, err := ParseHandshakeMessage(io.TeeReader(h.cryptoStream, &shloData))
|
||||
if err != nil {
|
||||
return qerr.HandshakeFailed
|
||||
var message HandshakeMessage
|
||||
select {
|
||||
case divNonce := <-h.divNonceChan:
|
||||
if len(h.diversificationNonce) != 0 && !bytes.Equal(h.diversificationNonce, divNonce) {
|
||||
return errConflictingDiversificationNonces
|
||||
}
|
||||
h.diversificationNonce = divNonce
|
||||
// there's no message to process, but we should try upgrading the crypto again
|
||||
continue
|
||||
case message = <-messageChan:
|
||||
case err = <-errorChan:
|
||||
return err
|
||||
}
|
||||
|
||||
if messageTag != TagSHLO && messageTag != TagREJ {
|
||||
utils.Debugf("Got %s", message)
|
||||
switch message.Tag {
|
||||
case TagREJ:
|
||||
err = h.handleREJMessage(message.Data)
|
||||
case TagSHLO:
|
||||
err = h.handleSHLOMessage(message.Data)
|
||||
default:
|
||||
return qerr.InvalidCryptoMessageType
|
||||
}
|
||||
|
||||
if messageTag == TagSHLO {
|
||||
utils.Debugf("Got SHLO:\n%s", printHandshakeMessage(cryptoData))
|
||||
err = h.handleSHLOMessage(cryptoData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if messageTag == TagREJ {
|
||||
err = h.handleREJMessage(cryptoData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetupClient) handleREJMessage(cryptoData map[Tag][]byte) error {
|
||||
utils.Debugf("Got REJ:\n%s", printHandshakeMessage(cryptoData))
|
||||
|
||||
var err error
|
||||
|
||||
if stk, ok := cryptoData[TagSTK]; ok {
|
||||
@@ -360,15 +376,8 @@ func (h *cryptoSetupClient) DiversificationNonce() []byte {
|
||||
panic("not needed for cryptoSetupClient")
|
||||
}
|
||||
|
||||
func (h *cryptoSetupClient) SetDiversificationNonce(data []byte) error {
|
||||
if len(h.diversificationNonce) == 0 {
|
||||
h.diversificationNonce = data
|
||||
return h.maybeUpgradeCrypto()
|
||||
}
|
||||
if !bytes.Equal(h.diversificationNonce, data) {
|
||||
return errConflictingDiversificationNonces
|
||||
}
|
||||
return nil
|
||||
func (h *cryptoSetupClient) SetDiversificationNonce(data []byte) {
|
||||
h.divNonceChan <- data
|
||||
}
|
||||
|
||||
func (h *cryptoSetupClient) sendCHLO() error {
|
||||
@@ -384,9 +393,13 @@ func (h *cryptoSetupClient) sendCHLO() error {
|
||||
return err
|
||||
}
|
||||
h.addPadding(tags)
|
||||
message := HandshakeMessage{
|
||||
Tag: TagCHLO,
|
||||
Data: tags,
|
||||
}
|
||||
|
||||
utils.Debugf("Sending CHLO:\n%s", printHandshakeMessage(tags))
|
||||
WriteHandshakeMessage(b, TagCHLO, tags)
|
||||
utils.Debugf("Sending %s", message)
|
||||
message.Write(b)
|
||||
|
||||
_, err = h.cryptoStream.Write(b.Bytes())
|
||||
if err != nil {
|
||||
@@ -464,7 +477,6 @@ func (h *cryptoSetupClient) maybeUpgradeCrypto() error {
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
leafCert := h.certManager.GetLeafCert()
|
||||
|
||||
if h.secureAEAD == nil && (h.serverConfig != nil && len(h.serverConfig.sharedSecret) > 0 && len(h.nonc) > 0 && len(leafCert) > 0 && len(h.diversificationNonce) > 0 && len(h.lastSentCHLO) > 0) {
|
||||
var err error
|
||||
var nonce []byte
|
||||
|
||||
@@ -101,7 +101,7 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
return &mockAEAD{forwardSecure: forwardSecure, sharedSecret: sharedSecret}, nil
|
||||
}
|
||||
|
||||
stream = &mockStream{}
|
||||
stream = newMockStream()
|
||||
certManager = &mockCertManager{}
|
||||
version := protocol.Version36
|
||||
aeadChanged = make(chan protocol.EncryptionLevel, 2)
|
||||
@@ -113,6 +113,10 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
cs.keyExchange = func() crypto.KeyExchange { return &mockKEX{ephermal: true} }
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
close(stream.unblockRead)
|
||||
})
|
||||
|
||||
Context("Reading REJ", func() {
|
||||
var tagMap map[Tag][]byte
|
||||
|
||||
@@ -121,29 +125,24 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
})
|
||||
|
||||
It("rejects handshake messages with the wrong message tag", func() {
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, tagMap)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: tagMap}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.InvalidCryptoMessageType))
|
||||
})
|
||||
|
||||
It("errors on invalid handshake messages", func() {
|
||||
b := &bytes.Buffer{}
|
||||
WriteHandshakeMessage(b, TagCHLO, tagMap)
|
||||
stream.dataToRead.Write(b.Bytes()[:b.Len()-2]) // cut the handshake message
|
||||
stream.dataToRead.Write([]byte("invalid message"))
|
||||
err := cs.HandleCryptoStream()
|
||||
// note that if this was a complete handshake message, HandleCryptoStream would fail with a qerr.InvalidCryptoMessageType
|
||||
Expect(err).To(MatchError(qerr.HandshakeFailed))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.HandshakeFailed))
|
||||
})
|
||||
|
||||
It("passes the message on for parsing, and reads the source address token", func() {
|
||||
stk := []byte("foobar")
|
||||
tagMap[TagSTK] = stk
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagREJ, tagMap)
|
||||
// this will throw a qerr.HandshakeFailed due to an EOF in WriteHandshakeMessage
|
||||
// this is because the mockStream doesn't block if there's no data to read
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.HandshakeFailed))
|
||||
Expect(cs.stk).Should(Equal(stk))
|
||||
HandshakeMessage{Tag: TagREJ, Data: tagMap}.Write(&stream.dataToRead)
|
||||
go cs.HandleCryptoStream()
|
||||
Eventually(func() []byte { return cs.stk }).Should(Equal(stk))
|
||||
})
|
||||
|
||||
It("saves the proof", func() {
|
||||
@@ -301,7 +300,7 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
It("reads a server config", func() {
|
||||
b := &bytes.Buffer{}
|
||||
scfg := getDefaultServerConfigClient()
|
||||
WriteHandshakeMessage(b, TagSCFG, scfg)
|
||||
HandshakeMessage{Tag: TagSCFG, Data: scfg}.Write(b)
|
||||
tagMap[TagSCFG] = b.Bytes()
|
||||
err := cs.handleREJMessage(tagMap)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -313,7 +312,7 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
b := &bytes.Buffer{}
|
||||
scfg := getDefaultServerConfigClient()
|
||||
scfg[TagEXPY] = []byte{0x80, 0x54, 0x72, 0x4F, 0, 0, 0, 0} // 2012-03-28
|
||||
WriteHandshakeMessage(b, TagSCFG, scfg)
|
||||
HandshakeMessage{Tag: TagSCFG, Data: scfg}.Write(b)
|
||||
tagMap[TagSCFG] = b.Bytes()
|
||||
// make sure we actually set TagEXPY correct
|
||||
serverConfig, err := parseServerConfig(b.Bytes())
|
||||
@@ -326,7 +325,7 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
|
||||
It("generates a client nonce after reading a server config", func() {
|
||||
b := &bytes.Buffer{}
|
||||
WriteHandshakeMessage(b, TagSCFG, getDefaultServerConfigClient())
|
||||
HandshakeMessage{Tag: TagSCFG, Data: getDefaultServerConfigClient()}.Write(b)
|
||||
tagMap[TagSCFG] = b.Bytes()
|
||||
err := cs.handleREJMessage(tagMap)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -335,7 +334,7 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
|
||||
It("only generates a client nonce once, when reading multiple server configs", func() {
|
||||
b := &bytes.Buffer{}
|
||||
WriteHandshakeMessage(b, TagSCFG, getDefaultServerConfigClient())
|
||||
HandshakeMessage{Tag: TagSCFG, Data: getDefaultServerConfigClient()}.Write(b)
|
||||
tagMap[TagSCFG] = b.Bytes()
|
||||
err := cs.handleREJMessage(tagMap)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -348,7 +347,7 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
|
||||
It("passes on errors from reading the server config", func() {
|
||||
b := &bytes.Buffer{}
|
||||
WriteHandshakeMessage(b, TagSHLO, make(map[Tag][]byte))
|
||||
HandshakeMessage{Tag: TagSHLO, Data: make(map[Tag][]byte)}.Write(b)
|
||||
tagMap[TagSCFG] = b.Bytes()
|
||||
_, origErr := parseServerConfig(b.Bytes())
|
||||
err := cs.handleREJMessage(tagMap)
|
||||
@@ -637,26 +636,28 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
It("tries to escalate before reading a handshake message", func() {
|
||||
Expect(cs.secureAEAD).To(BeNil())
|
||||
cs.serverVerified = true
|
||||
err := cs.HandleCryptoStream()
|
||||
// this will throw a qerr.HandshakeFailed due to an EOF in WriteHandshakeMessage
|
||||
// this is because the mockStream doesn't block if there's no data to read
|
||||
Expect(err).To(MatchError(qerr.HandshakeFailed))
|
||||
go cs.HandleCryptoStream()
|
||||
Eventually(aeadChanged).Should(Receive(Equal(protocol.EncryptionSecure)))
|
||||
Expect(cs.secureAEAD).ToNot(BeNil())
|
||||
Expect(aeadChanged).To(Receive(Equal(protocol.EncryptionSecure)))
|
||||
Expect(aeadChanged).ToNot(Receive())
|
||||
Expect(aeadChanged).ToNot(BeClosed())
|
||||
})
|
||||
|
||||
It("tries to escalate the crypto after receiving a diversification nonce", func() {
|
||||
It("tries to escalate the crypto after receiving a diversification nonce", func(done Done) {
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
cs.HandleCryptoStream()
|
||||
Fail("HandleCryptoStream should not have returned")
|
||||
}()
|
||||
cs.diversificationNonce = nil
|
||||
cs.serverVerified = true
|
||||
Expect(cs.secureAEAD).To(BeNil())
|
||||
err := cs.SetDiversificationNonce([]byte("div"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
cs.SetDiversificationNonce([]byte("div"))
|
||||
Eventually(aeadChanged).Should(Receive(Equal(protocol.EncryptionSecure)))
|
||||
Expect(cs.secureAEAD).ToNot(BeNil())
|
||||
Expect(aeadChanged).To(Receive(Equal(protocol.EncryptionSecure)))
|
||||
Expect(aeadChanged).ToNot(Receive())
|
||||
Expect(aeadChanged).ToNot(BeClosed())
|
||||
close(done)
|
||||
})
|
||||
|
||||
Context("null encryption", func() {
|
||||
@@ -786,28 +787,32 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
|
||||
Context("Diversification Nonces", func() {
|
||||
It("sets a diversification nonce", func() {
|
||||
go cs.HandleCryptoStream()
|
||||
nonce := []byte("foobar")
|
||||
err := cs.SetDiversificationNonce(nonce)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cs.diversificationNonce).To(Equal(nonce))
|
||||
cs.SetDiversificationNonce(nonce)
|
||||
Eventually(func() []byte { return cs.diversificationNonce }).Should(Equal(nonce))
|
||||
})
|
||||
|
||||
It("doesn't do anything when called multiple times with the same nonce", func() {
|
||||
It("doesn't do anything when called multiple times with the same nonce", func(done Done) {
|
||||
go cs.HandleCryptoStream()
|
||||
nonce := []byte("foobar")
|
||||
err := cs.SetDiversificationNonce(nonce)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = cs.SetDiversificationNonce(nonce)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cs.diversificationNonce).To(Equal(nonce))
|
||||
cs.SetDiversificationNonce(nonce)
|
||||
cs.SetDiversificationNonce(nonce)
|
||||
Eventually(func() []byte { return cs.diversificationNonce }).Should(Equal(nonce))
|
||||
close(done)
|
||||
})
|
||||
|
||||
It("rejects a different diversification nonce", func() {
|
||||
var err error
|
||||
go func() {
|
||||
err = cs.HandleCryptoStream()
|
||||
}()
|
||||
|
||||
nonce1 := []byte("foobar")
|
||||
nonce2 := []byte("raboof")
|
||||
err := cs.SetDiversificationNonce(nonce1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = cs.SetDiversificationNonce(nonce2)
|
||||
Expect(err).To(MatchError(errConflictingDiversificationNonces))
|
||||
cs.SetDiversificationNonce(nonce1)
|
||||
cs.SetDiversificationNonce(nonce2)
|
||||
Eventually(func() error { return err }).Should(MatchError(errConflictingDiversificationNonces))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -85,17 +85,16 @@ func NewCryptoSetup(
|
||||
func (h *cryptoSetupServer) HandleCryptoStream() error {
|
||||
for {
|
||||
var chloData bytes.Buffer
|
||||
messageTag, cryptoData, err := ParseHandshakeMessage(io.TeeReader(h.cryptoStream, &chloData))
|
||||
message, err := ParseHandshakeMessage(io.TeeReader(h.cryptoStream, &chloData))
|
||||
if err != nil {
|
||||
return qerr.HandshakeFailed
|
||||
}
|
||||
if messageTag != TagCHLO {
|
||||
if message.Tag != TagCHLO {
|
||||
return qerr.InvalidCryptoMessageType
|
||||
}
|
||||
|
||||
utils.Debugf("Got CHLO:\n%s", printHandshakeMessage(cryptoData))
|
||||
|
||||
done, err := h.handleMessage(chloData.Bytes(), cryptoData)
|
||||
utils.Debugf("Got %s", message)
|
||||
done, err := h.handleMessage(chloData.Bytes(), message.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -305,9 +304,14 @@ func (h *cryptoSetupServer) handleInchoateCHLO(sni string, chlo []byte, cryptoDa
|
||||
replyMap[TagCERT] = certCompressed
|
||||
}
|
||||
|
||||
message := HandshakeMessage{
|
||||
Tag: TagREJ,
|
||||
Data: replyMap,
|
||||
}
|
||||
|
||||
var serverReply bytes.Buffer
|
||||
WriteHandshakeMessage(&serverReply, TagREJ, replyMap)
|
||||
utils.Debugf("Sending REJ:\n%s", printHandshakeMessage(replyMap))
|
||||
message.Write(&serverReply)
|
||||
utils.Debugf("Sending %s", message)
|
||||
return serverReply.Bytes(), nil
|
||||
}
|
||||
|
||||
@@ -413,9 +417,13 @@ func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[T
|
||||
replyMap[TagVER] = verTag.Bytes()
|
||||
|
||||
// note that the SHLO *has* to fit into one packet
|
||||
message := HandshakeMessage{
|
||||
Tag: TagSHLO,
|
||||
Data: replyMap,
|
||||
}
|
||||
var reply bytes.Buffer
|
||||
WriteHandshakeMessage(&reply, TagSHLO, replyMap)
|
||||
utils.Debugf("Sending SHLO:\n%s", printHandshakeMessage(replyMap))
|
||||
message.Write(&reply)
|
||||
utils.Debugf("Sending %s", message)
|
||||
|
||||
h.aeadChanged <- protocol.EncryptionForwardSecure
|
||||
|
||||
@@ -427,7 +435,7 @@ func (h *cryptoSetupServer) DiversificationNonce() []byte {
|
||||
return h.diversificationNonce
|
||||
}
|
||||
|
||||
func (h *cryptoSetupServer) SetDiversificationNonce(data []byte) error {
|
||||
func (h *cryptoSetupServer) SetDiversificationNonce(data []byte) {
|
||||
panic("not needed for cryptoSetupServer")
|
||||
}
|
||||
|
||||
|
||||
@@ -95,12 +95,21 @@ func mockKeyDerivation(forwardSecure bool, sharedSecret, nonces []byte, connID p
|
||||
}
|
||||
|
||||
type mockStream struct {
|
||||
unblockRead chan struct{} // close this chan to unblock Read
|
||||
dataToRead bytes.Buffer
|
||||
dataWritten bytes.Buffer
|
||||
}
|
||||
|
||||
func newMockStream() *mockStream {
|
||||
return &mockStream{unblockRead: make(chan struct{})}
|
||||
}
|
||||
|
||||
func (s *mockStream) Read(p []byte) (int, error) {
|
||||
return s.dataToRead.Read(p)
|
||||
n, _ := s.dataToRead.Read(p)
|
||||
if n == 0 { // block if there's no data
|
||||
<-s.unblockRead
|
||||
}
|
||||
return n, nil // never return an EOF
|
||||
}
|
||||
|
||||
func (s *mockStream) ReadByte() (byte, error) {
|
||||
@@ -168,7 +177,7 @@ var _ = Describe("Server Crypto Setup", func() {
|
||||
expectedInitialNonceLen = 32
|
||||
expectedFSNonceLen = 64
|
||||
aeadChanged = make(chan protocol.EncryptionLevel, 2)
|
||||
stream = &mockStream{}
|
||||
stream = newMockStream()
|
||||
kex = &mockKEX{}
|
||||
signer = &mockSigner{}
|
||||
scfg, err = NewServerConfig(kex, signer)
|
||||
@@ -190,6 +199,10 @@ var _ = Describe("Server Crypto Setup", func() {
|
||||
cs.keyExchange = func() crypto.KeyExchange { return &mockKEX{ephermal: true} }
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
close(stream.unblockRead)
|
||||
})
|
||||
|
||||
Context("diversification nonce", func() {
|
||||
BeforeEach(func() {
|
||||
cs.version = protocol.Version35
|
||||
@@ -231,9 +244,12 @@ var _ = Describe("Server Crypto Setup", func() {
|
||||
})
|
||||
|
||||
It("doesn't support Chrome's head-of-line blocking experiment", func() {
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, map[Tag][]byte{
|
||||
TagFHL2: []byte("foobar"),
|
||||
})
|
||||
HandshakeMessage{
|
||||
Tag: TagCHLO,
|
||||
Data: map[Tag][]byte{
|
||||
TagFHL2: []byte("foobar"),
|
||||
},
|
||||
}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(ErrHOLExperiment))
|
||||
})
|
||||
@@ -292,13 +308,16 @@ var _ = Describe("Server Crypto Setup", func() {
|
||||
})
|
||||
|
||||
It("handles long handshake", func() {
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, map[Tag][]byte{
|
||||
TagSNI: []byte("quic.clemente.io"),
|
||||
TagSTK: validSTK,
|
||||
TagPAD: bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize),
|
||||
TagVER: versionTag,
|
||||
})
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{
|
||||
Tag: TagCHLO,
|
||||
Data: map[Tag][]byte{
|
||||
TagSNI: []byte("quic.clemente.io"),
|
||||
TagSTK: validSTK,
|
||||
TagPAD: bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize),
|
||||
TagVER: versionTag,
|
||||
},
|
||||
}.Write(&stream.dataToRead)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(stream.dataWritten.Bytes()).To(HavePrefix("REJ"))
|
||||
@@ -311,14 +330,14 @@ var _ = Describe("Server Crypto Setup", func() {
|
||||
|
||||
It("rejects client nonces that have the wrong length", func() {
|
||||
fullCHLO[TagNONC] = []byte("too short client nonce")
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "invalid client nonce length")))
|
||||
})
|
||||
|
||||
It("rejects client nonces that have the wrong OBIT value", func() {
|
||||
fullCHLO[TagNONC] = make([]byte, 32) // the OBIT value is nonce[4:12] and here just initialized to 0
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "OBIT not matching")))
|
||||
})
|
||||
@@ -326,13 +345,13 @@ var _ = Describe("Server Crypto Setup", func() {
|
||||
It("errors if it can't calculate a shared key", func() {
|
||||
testErr := errors.New("test error")
|
||||
kex.sharedKeyError = testErr
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(testErr))
|
||||
})
|
||||
|
||||
It("handles 0-RTT handshake", func() {
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(stream.dataWritten.Bytes()).To(HavePrefix("SHLO"))
|
||||
@@ -382,17 +401,20 @@ var _ = Describe("Server Crypto Setup", func() {
|
||||
})
|
||||
|
||||
It("rejects CHLOs without the version tag", func() {
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, map[Tag][]byte{
|
||||
TagSCID: scfg.ID,
|
||||
TagSNI: []byte("quic.clemente.io"),
|
||||
})
|
||||
HandshakeMessage{
|
||||
Tag: TagCHLO,
|
||||
Data: map[Tag][]byte{
|
||||
TagSCID: scfg.ID,
|
||||
TagSNI: []byte("quic.clemente.io"),
|
||||
},
|
||||
}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "client hello missing version tag")))
|
||||
})
|
||||
|
||||
It("rejects CHLOs with a version tag that has the wrong length", func() {
|
||||
fullCHLO[TagVER] = []byte{0x13, 0x37} // should be 4 bytes
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "incorrect version tag")))
|
||||
})
|
||||
@@ -405,7 +427,7 @@ var _ = Describe("Server Crypto Setup", func() {
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, protocol.VersionNumberToTag(lowestSupportedVersion))
|
||||
fullCHLO[TagVER] = b
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.VersionNegotiationMismatch, "Downgrade attack detected")))
|
||||
})
|
||||
@@ -418,64 +440,71 @@ var _ = Describe("Server Crypto Setup", func() {
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, protocol.VersionNumberToTag(unsupportedVersion))
|
||||
fullCHLO[TagVER] = b
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("errors if the AEAD tag is missing", func() {
|
||||
delete(fullCHLO, TagAEAD)
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.CryptoNoSupport, "Unsupported AEAD or KEXS")))
|
||||
})
|
||||
|
||||
It("errors if the AEAD tag has the wrong value", func() {
|
||||
fullCHLO[TagAEAD] = []byte("wrong")
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.CryptoNoSupport, "Unsupported AEAD or KEXS")))
|
||||
})
|
||||
|
||||
It("errors if the KEXS tag is missing", func() {
|
||||
delete(fullCHLO, TagKEXS)
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.CryptoNoSupport, "Unsupported AEAD or KEXS")))
|
||||
})
|
||||
|
||||
It("errors if the KEXS tag has the wrong value", func() {
|
||||
fullCHLO[TagKEXS] = []byte("wrong")
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, fullCHLO)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: fullCHLO}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.CryptoNoSupport, "Unsupported AEAD or KEXS")))
|
||||
})
|
||||
})
|
||||
|
||||
It("errors without SNI", func() {
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, map[Tag][]byte{
|
||||
TagSTK: validSTK,
|
||||
})
|
||||
HandshakeMessage{
|
||||
Tag: TagCHLO,
|
||||
Data: map[Tag][]byte{
|
||||
TagSTK: validSTK,
|
||||
},
|
||||
}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError("CryptoMessageParameterNotFound: SNI required"))
|
||||
})
|
||||
|
||||
It("errors with empty SNI", func() {
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagCHLO, map[Tag][]byte{
|
||||
TagSTK: validSTK,
|
||||
TagSNI: nil,
|
||||
})
|
||||
HandshakeMessage{
|
||||
Tag: TagCHLO,
|
||||
Data: map[Tag][]byte{
|
||||
TagSTK: validSTK,
|
||||
TagSNI: nil,
|
||||
},
|
||||
}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError("CryptoMessageParameterNotFound: SNI required"))
|
||||
})
|
||||
|
||||
It("errors with invalid message", func() {
|
||||
stream.dataToRead.Write([]byte("invalid message"))
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.HandshakeFailed))
|
||||
})
|
||||
|
||||
It("errors with non-CHLO message", func() {
|
||||
WriteHandshakeMessage(&stream.dataToRead, TagPAD, nil)
|
||||
HandshakeMessage{Tag: TagPAD, Data: nil}.Write(&stream.dataToRead)
|
||||
err := cs.HandleCryptoStream()
|
||||
Expect(err).To(MatchError(qerr.InvalidCryptoMessageType))
|
||||
})
|
||||
|
||||
@@ -12,27 +12,35 @@ import (
|
||||
"github.com/lucas-clemente/quic-go/utils"
|
||||
)
|
||||
|
||||
// A HandshakeMessage is a handshake message
|
||||
type HandshakeMessage struct {
|
||||
Tag Tag
|
||||
Data map[Tag][]byte
|
||||
}
|
||||
|
||||
var _ fmt.Stringer = &HandshakeMessage{}
|
||||
|
||||
// ParseHandshakeMessage reads a crypto message
|
||||
func ParseHandshakeMessage(r io.Reader) (Tag, map[Tag][]byte, error) {
|
||||
func ParseHandshakeMessage(r io.Reader) (HandshakeMessage, error) {
|
||||
slice4 := make([]byte, 4)
|
||||
|
||||
if _, err := io.ReadFull(r, slice4); err != nil {
|
||||
return 0, nil, err
|
||||
return HandshakeMessage{}, err
|
||||
}
|
||||
messageTag := Tag(binary.LittleEndian.Uint32(slice4))
|
||||
|
||||
if _, err := io.ReadFull(r, slice4); err != nil {
|
||||
return 0, nil, err
|
||||
return HandshakeMessage{}, err
|
||||
}
|
||||
nPairs := binary.LittleEndian.Uint32(slice4)
|
||||
|
||||
if nPairs > protocol.CryptoMaxParams {
|
||||
return 0, nil, qerr.CryptoTooManyEntries
|
||||
return HandshakeMessage{}, qerr.CryptoTooManyEntries
|
||||
}
|
||||
|
||||
index := make([]byte, nPairs*8)
|
||||
if _, err := io.ReadFull(r, index); err != nil {
|
||||
return 0, nil, err
|
||||
return HandshakeMessage{}, err
|
||||
}
|
||||
|
||||
resultMap := map[Tag][]byte{}
|
||||
@@ -44,24 +52,27 @@ func ParseHandshakeMessage(r io.Reader) (Tag, map[Tag][]byte, error) {
|
||||
|
||||
dataLen := dataEnd - dataStart
|
||||
if dataLen > protocol.CryptoParameterMaxLength {
|
||||
return 0, nil, qerr.Error(qerr.CryptoInvalidValueLength, "value too long")
|
||||
return HandshakeMessage{}, qerr.Error(qerr.CryptoInvalidValueLength, "value too long")
|
||||
}
|
||||
|
||||
data := make([]byte, dataLen)
|
||||
if _, err := io.ReadFull(r, data); err != nil {
|
||||
return 0, nil, err
|
||||
return HandshakeMessage{}, err
|
||||
}
|
||||
|
||||
resultMap[tag] = data
|
||||
dataStart = dataEnd
|
||||
}
|
||||
|
||||
return messageTag, resultMap, nil
|
||||
return HandshakeMessage{
|
||||
Tag: messageTag,
|
||||
Data: resultMap}, nil
|
||||
}
|
||||
|
||||
// WriteHandshakeMessage writes a crypto message
|
||||
func WriteHandshakeMessage(b *bytes.Buffer, messageTag Tag, data map[Tag][]byte) {
|
||||
utils.WriteUint32(b, uint32(messageTag))
|
||||
// Write writes a crypto message
|
||||
func (h HandshakeMessage) Write(b *bytes.Buffer) {
|
||||
data := h.Data
|
||||
utils.WriteUint32(b, uint32(h.Tag))
|
||||
utils.WriteUint16(b, uint16(len(data)))
|
||||
utils.WriteUint16(b, 0)
|
||||
|
||||
@@ -71,17 +82,8 @@ func WriteHandshakeMessage(b *bytes.Buffer, messageTag Tag, data map[Tag][]byte)
|
||||
indexData := make([]byte, 8*len(data))
|
||||
b.Write(indexData) // Will be updated later
|
||||
|
||||
// Sort the tags
|
||||
tags := make([]uint32, len(data))
|
||||
i := 0
|
||||
for t := range data {
|
||||
tags[i] = uint32(t)
|
||||
i++
|
||||
}
|
||||
sort.Sort(utils.Uint32Slice(tags))
|
||||
|
||||
offset := uint32(0)
|
||||
for i, t := range tags {
|
||||
for i, t := range h.getTagsSorted() {
|
||||
v := data[Tag(t)]
|
||||
b.Write(v)
|
||||
offset += uint32(len(v))
|
||||
@@ -93,21 +95,32 @@ func WriteHandshakeMessage(b *bytes.Buffer, messageTag Tag, data map[Tag][]byte)
|
||||
copy(b.Bytes()[indexStart:], indexData)
|
||||
}
|
||||
|
||||
func printHandshakeMessage(data map[Tag][]byte) string {
|
||||
var res string
|
||||
func (h *HandshakeMessage) getTagsSorted() []uint32 {
|
||||
tags := make([]uint32, len(h.Data))
|
||||
i := 0
|
||||
for t := range h.Data {
|
||||
tags[i] = uint32(t)
|
||||
i++
|
||||
}
|
||||
sort.Sort(utils.Uint32Slice(tags))
|
||||
return tags
|
||||
}
|
||||
|
||||
func (h HandshakeMessage) String() string {
|
||||
var pad string
|
||||
for k, v := range data {
|
||||
if k == TagPAD {
|
||||
pad = fmt.Sprintf("\t%s: (%d bytes)\n", tagToString(k), len(v))
|
||||
res := tagToString(h.Tag) + ":\n"
|
||||
for _, t := range h.getTagsSorted() {
|
||||
tag := Tag(t)
|
||||
if tag == TagPAD {
|
||||
pad = fmt.Sprintf("\t%s: (%d bytes)\n", tagToString(tag), len(h.Data[tag]))
|
||||
} else {
|
||||
res += fmt.Sprintf("\t%s: %#v\n", tagToString(k), string(v))
|
||||
res += fmt.Sprintf("\t%s: %#v\n", tagToString(tag), string(h.Data[tag]))
|
||||
}
|
||||
}
|
||||
|
||||
if len(pad) > 0 {
|
||||
res += pad
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
@@ -11,15 +11,15 @@ import (
|
||||
var _ = Describe("Handshake Message", func() {
|
||||
Context("when parsing", func() {
|
||||
It("parses sample CHLO message", func() {
|
||||
tag, msg, err := ParseHandshakeMessage(bytes.NewReader(sampleCHLO))
|
||||
msg, err := ParseHandshakeMessage(bytes.NewReader(sampleCHLO))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(tag).To(Equal(TagCHLO))
|
||||
Expect(msg).To(Equal(sampleCHLOMap))
|
||||
Expect(msg.Tag).To(Equal(TagCHLO))
|
||||
Expect(msg.Data).To(Equal(sampleCHLOMap))
|
||||
})
|
||||
|
||||
It("rejects large numbers of pairs", func() {
|
||||
r := bytes.NewReader([]byte("CHLO\xff\xff\xff\xff"))
|
||||
_, _, err := ParseHandshakeMessage(r)
|
||||
_, err := ParseHandshakeMessage(r)
|
||||
Expect(err).To(MatchError(qerr.CryptoTooManyEntries))
|
||||
})
|
||||
|
||||
@@ -30,7 +30,7 @@ var _ = Describe("Handshake Message", func() {
|
||||
0, 0, 0, 0,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
})
|
||||
_, _, err := ParseHandshakeMessage(r)
|
||||
_, err := ParseHandshakeMessage(r)
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.CryptoInvalidValueLength, "value too long")))
|
||||
})
|
||||
})
|
||||
@@ -38,8 +38,34 @@ var _ = Describe("Handshake Message", func() {
|
||||
Context("when writing", func() {
|
||||
It("writes sample message", func() {
|
||||
b := &bytes.Buffer{}
|
||||
WriteHandshakeMessage(b, TagCHLO, sampleCHLOMap)
|
||||
HandshakeMessage{Tag: TagCHLO, Data: sampleCHLOMap}.Write(b)
|
||||
Expect(b.Bytes()).To(Equal(sampleCHLO))
|
||||
})
|
||||
})
|
||||
|
||||
Context("string representation", func() {
|
||||
It("has a string representation", func() {
|
||||
str := HandshakeMessage{
|
||||
Tag: TagSHLO,
|
||||
Data: map[Tag][]byte{
|
||||
TagAEAD: []byte("foobar"),
|
||||
TagEXPY: []byte("raboof"),
|
||||
},
|
||||
}.String()
|
||||
Expect(str[:4]).To(Equal("SHLO"))
|
||||
Expect(str).To(ContainSubstring("AEAD: \"foobar\""))
|
||||
Expect(str).To(ContainSubstring("EXPY: \"raboof\""))
|
||||
})
|
||||
|
||||
It("lists padding separately", func() {
|
||||
str := HandshakeMessage{
|
||||
Tag: TagSHLO,
|
||||
Data: map[Tag][]byte{
|
||||
TagPAD: bytes.Repeat([]byte{0}, 1337),
|
||||
},
|
||||
}.String()
|
||||
Expect(str).To(ContainSubstring("PAD"))
|
||||
Expect(str).To(ContainSubstring("1337 bytes"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -10,8 +10,8 @@ type CryptoSetup interface {
|
||||
Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error)
|
||||
HandleCryptoStream() error
|
||||
// TODO: clean up this interface
|
||||
DiversificationNonce() []byte // only needed for cryptoSetupServer
|
||||
SetDiversificationNonce([]byte) error // only needed for cryptoSetupClient
|
||||
DiversificationNonce() []byte // only needed for cryptoSetupServer
|
||||
SetDiversificationNonce([]byte) // only needed for cryptoSetupClient
|
||||
|
||||
GetSealer() (protocol.EncryptionLevel, Sealer)
|
||||
GetSealerWithEncryptionLevel(protocol.EncryptionLevel) (Sealer, error)
|
||||
|
||||
@@ -51,14 +51,18 @@ func NewServerConfig(kex crypto.KeyExchange, certChain crypto.CertChain) (*Serve
|
||||
// Get the server config binary representation
|
||||
func (s *ServerConfig) Get() []byte {
|
||||
var serverConfig bytes.Buffer
|
||||
WriteHandshakeMessage(&serverConfig, TagSCFG, map[Tag][]byte{
|
||||
TagSCID: s.ID,
|
||||
TagKEXS: []byte("C255"),
|
||||
TagAEAD: []byte("AESG"),
|
||||
TagPUBS: append([]byte{0x20, 0x00, 0x00}, s.kex.PublicKey()...),
|
||||
TagOBIT: s.obit,
|
||||
TagEXPY: {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
})
|
||||
msg := HandshakeMessage{
|
||||
Tag: TagSCFG,
|
||||
Data: map[Tag][]byte{
|
||||
TagSCID: s.ID,
|
||||
TagKEXS: []byte("C255"),
|
||||
TagAEAD: []byte("AESG"),
|
||||
TagPUBS: append([]byte{0x20, 0x00, 0x00}, s.kex.PublicKey()...),
|
||||
TagOBIT: s.obit,
|
||||
TagEXPY: {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
}
|
||||
msg.Write(&serverConfig)
|
||||
return serverConfig.Bytes()
|
||||
}
|
||||
|
||||
|
||||
@@ -28,16 +28,16 @@ var (
|
||||
|
||||
// parseServerConfig parses a server config
|
||||
func parseServerConfig(data []byte) (*serverConfigClient, error) {
|
||||
tag, tagMap, err := ParseHandshakeMessage(bytes.NewReader(data))
|
||||
message, err := ParseHandshakeMessage(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tag != TagSCFG {
|
||||
if message.Tag != TagSCFG {
|
||||
return nil, errMessageNotServerConfig
|
||||
}
|
||||
|
||||
scfg := &serverConfigClient{raw: data}
|
||||
err = scfg.parseValues(tagMap)
|
||||
err = scfg.parseValues(message.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ var _ = Describe("Server Config", func() {
|
||||
It("returns the parsed server config", func() {
|
||||
tagMap[TagSCID] = []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}
|
||||
b := &bytes.Buffer{}
|
||||
WriteHandshakeMessage(b, TagSCFG, tagMap)
|
||||
HandshakeMessage{Tag: TagSCFG, Data: tagMap}.Write(b)
|
||||
scfg, err := parseServerConfig(b.Bytes())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(scfg.ID).To(Equal(tagMap[TagSCID]))
|
||||
@@ -39,7 +39,7 @@ var _ = Describe("Server Config", func() {
|
||||
|
||||
It("saves the raw server config", func() {
|
||||
b := &bytes.Buffer{}
|
||||
WriteHandshakeMessage(b, TagSCFG, tagMap)
|
||||
HandshakeMessage{Tag: TagSCFG, Data: tagMap}.Write(b)
|
||||
scfg, err := parseServerConfig(b.Bytes())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(scfg.raw).To(Equal(b.Bytes()))
|
||||
@@ -56,28 +56,28 @@ var _ = Describe("Server Config", func() {
|
||||
Context("parsing the server config", func() {
|
||||
It("rejects a handshake message with the wrong message tag", func() {
|
||||
var serverConfig bytes.Buffer
|
||||
WriteHandshakeMessage(&serverConfig, TagCHLO, make(map[Tag][]byte))
|
||||
HandshakeMessage{Tag: TagCHLO, Data: make(map[Tag][]byte)}.Write(&serverConfig)
|
||||
_, err := parseServerConfig(serverConfig.Bytes())
|
||||
Expect(err).To(MatchError(errMessageNotServerConfig))
|
||||
})
|
||||
|
||||
It("errors on invalid handshake messages", func() {
|
||||
var serverConfig bytes.Buffer
|
||||
WriteHandshakeMessage(&serverConfig, TagSCFG, make(map[Tag][]byte))
|
||||
HandshakeMessage{Tag: TagSCFG, Data: make(map[Tag][]byte)}.Write(&serverConfig)
|
||||
_, err := parseServerConfig(serverConfig.Bytes()[:serverConfig.Len()-2])
|
||||
Expect(err).To(MatchError("unexpected EOF"))
|
||||
})
|
||||
|
||||
It("passes on errors encountered when reading the TagMap", func() {
|
||||
var serverConfig bytes.Buffer
|
||||
WriteHandshakeMessage(&serverConfig, TagSCFG, make(map[Tag][]byte))
|
||||
HandshakeMessage{Tag: TagSCFG, Data: make(map[Tag][]byte)}.Write(&serverConfig)
|
||||
_, err := parseServerConfig(serverConfig.Bytes())
|
||||
Expect(err).To(MatchError("CryptoMessageParameterNotFound: SCID"))
|
||||
})
|
||||
|
||||
It("reads an example Handshake Message", func() {
|
||||
var serverConfig bytes.Buffer
|
||||
WriteHandshakeMessage(&serverConfig, TagSCFG, tagMap)
|
||||
HandshakeMessage{Tag: TagSCFG, Data: tagMap}.Write(&serverConfig)
|
||||
scfg, err := parseServerConfig(serverConfig.Bytes())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(scfg.ID).To(Equal(tagMap[TagSCID]))
|
||||
|
||||
@@ -35,7 +35,7 @@ func (m *mockCryptoSetup) GetSealerWithEncryptionLevel(protocol.EncryptionLevel)
|
||||
func (m *mockCryptoSetup) DiversificationNonce() []byte {
|
||||
return m.divNonce
|
||||
}
|
||||
func (m *mockCryptoSetup) SetDiversificationNonce([]byte) error { panic("not implemented") }
|
||||
func (m *mockCryptoSetup) SetDiversificationNonce([]byte) { panic("not implemented") }
|
||||
|
||||
var _ handshake.CryptoSetup = &mockCryptoSetup{}
|
||||
|
||||
|
||||
@@ -32,15 +32,15 @@ func writePublicReset(connectionID protocol.ConnectionID, rejectedPacketNumber p
|
||||
|
||||
func parsePublicReset(r *bytes.Reader) (*publicReset, error) {
|
||||
pr := publicReset{}
|
||||
tag, tagMap, err := handshake.ParseHandshakeMessage(r)
|
||||
msg, err := handshake.ParseHandshakeMessage(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tag != handshake.TagPRST {
|
||||
if msg.Tag != handshake.TagPRST {
|
||||
return nil, errors.New("wrong public reset tag")
|
||||
}
|
||||
|
||||
rseq, ok := tagMap[handshake.TagRSEQ]
|
||||
rseq, ok := msg.Data[handshake.TagRSEQ]
|
||||
if !ok {
|
||||
return nil, errors.New("RSEQ missing")
|
||||
}
|
||||
@@ -49,7 +49,7 @@ func parsePublicReset(r *bytes.Reader) (*publicReset, error) {
|
||||
}
|
||||
pr.rejectedPacketNumber = protocol.PacketNumber(binary.LittleEndian.Uint64(rseq))
|
||||
|
||||
rnon, ok := tagMap[handshake.TagRNON]
|
||||
rnon, ok := msg.Data[handshake.TagRNON]
|
||||
if !ok {
|
||||
return nil, errors.New("RNON missing")
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ var _ = Describe("public reset", func() {
|
||||
})
|
||||
|
||||
It("rejects packets with the wrong tag", func() {
|
||||
handshake.WriteHandshakeMessage(b, handshake.TagREJ, nil)
|
||||
handshake.HandshakeMessage{Tag: handshake.TagREJ, Data: nil}.Write(b)
|
||||
_, err := parsePublicReset(bytes.NewReader(b.Bytes()))
|
||||
Expect(err).To(MatchError("wrong public reset tag"))
|
||||
})
|
||||
@@ -58,7 +58,7 @@ var _ = Describe("public reset", func() {
|
||||
data := map[handshake.Tag][]byte{
|
||||
handshake.TagRSEQ: []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37},
|
||||
}
|
||||
handshake.WriteHandshakeMessage(b, handshake.TagPRST, data)
|
||||
handshake.HandshakeMessage{Tag: handshake.TagPRST, Data: data}.Write(b)
|
||||
_, err := parsePublicReset(bytes.NewReader(b.Bytes()))
|
||||
Expect(err).To(MatchError("RNON missing"))
|
||||
})
|
||||
@@ -68,7 +68,7 @@ var _ = Describe("public reset", func() {
|
||||
handshake.TagRSEQ: []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37},
|
||||
handshake.TagRNON: []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13},
|
||||
}
|
||||
handshake.WriteHandshakeMessage(b, handshake.TagPRST, data)
|
||||
handshake.HandshakeMessage{Tag: handshake.TagPRST, Data: data}.Write(b)
|
||||
_, err := parsePublicReset(bytes.NewReader(b.Bytes()))
|
||||
Expect(err).To(MatchError("invalid RNON tag"))
|
||||
})
|
||||
@@ -77,7 +77,7 @@ var _ = Describe("public reset", func() {
|
||||
data := map[handshake.Tag][]byte{
|
||||
handshake.TagRNON: []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37},
|
||||
}
|
||||
handshake.WriteHandshakeMessage(b, handshake.TagPRST, data)
|
||||
handshake.HandshakeMessage{Tag: handshake.TagPRST, Data: data}.Write(b)
|
||||
_, err := parsePublicReset(bytes.NewReader(b.Bytes()))
|
||||
Expect(err).To(MatchError("RSEQ missing"))
|
||||
})
|
||||
@@ -87,7 +87,7 @@ var _ = Describe("public reset", func() {
|
||||
handshake.TagRSEQ: []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13},
|
||||
handshake.TagRNON: []byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37},
|
||||
}
|
||||
handshake.WriteHandshakeMessage(b, handshake.TagPRST, data)
|
||||
handshake.HandshakeMessage{Tag: handshake.TagPRST, Data: data}.Write(b)
|
||||
_, err := parsePublicReset(bytes.NewReader(b.Bytes()))
|
||||
Expect(err).To(MatchError("invalid RSEQ tag"))
|
||||
})
|
||||
|
||||
@@ -163,7 +163,7 @@ var _ = Describe("Session", func() {
|
||||
sess.connectionParameters = cpm
|
||||
|
||||
clientSess, err = newClientSession(
|
||||
nil,
|
||||
mconn,
|
||||
"hostname",
|
||||
protocol.Version35,
|
||||
0,
|
||||
@@ -738,11 +738,15 @@ var _ = Describe("Session", func() {
|
||||
})
|
||||
|
||||
It("passes the diversification nonce to the cryptoSetup, if it is a client", func() {
|
||||
go clientSess.run()
|
||||
hdr.PacketNumber = 5
|
||||
hdr.DiversificationNonce = []byte("foobar")
|
||||
err := clientSess.handlePacketImpl(&receivedPacket{publicHeader: hdr})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect((*[]byte)(unsafe.Pointer(reflect.ValueOf(clientSess.cryptoSetup).Elem().FieldByName("diversificationNonce").UnsafeAddr()))).To(Equal(&hdr.DiversificationNonce))
|
||||
Eventually(func() []byte {
|
||||
return *(*[]byte)(unsafe.Pointer(reflect.ValueOf(clientSess.cryptoSetup).Elem().FieldByName("diversificationNonce").UnsafeAddr()))
|
||||
}).Should(Equal(hdr.DiversificationNonce))
|
||||
Expect(clientSess.Close(nil)).To(Succeed())
|
||||
})
|
||||
|
||||
Context("updating the remote address", func() {
|
||||
|
||||
Reference in New Issue
Block a user