don’t send more than 3 CHLOs

makes sure that the server allows the client to make progress in the handshake
This commit is contained in:
Marten Seemann
2016-12-01 14:40:04 +07:00
parent 7f2e706908
commit 2131e8fa6d
3 changed files with 34 additions and 7 deletions

View File

@@ -5,6 +5,7 @@ import (
"crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt"
"io" "io"
"time" "time"
@@ -32,10 +33,11 @@ type cryptoSetupClient struct {
lastSentCHLO []byte lastSentCHLO []byte
certManager crypto.CertManager certManager crypto.CertManager
serverVerified bool // has the certificate chain and the proof already been verified clientHelloCounter int
keyDerivation KeyDerivationFunction serverVerified bool // has the certificate chain and the proof already been verified
secureAEAD crypto.AEAD keyDerivation KeyDerivationFunction
forwardSecureAEAD crypto.AEAD secureAEAD crypto.AEAD
forwardSecureAEAD crypto.AEAD
} }
var _ crypto.AEAD = &cryptoSetupClient{} var _ crypto.AEAD = &cryptoSetupClient{}
@@ -72,9 +74,12 @@ func (h *cryptoSetupClient) HandleCryptoStream() error {
return err return err
} }
err = h.sendCHLO() // send CHLOs until the forward secure encryption is established
if err != nil { if h.forwardSecureAEAD == nil {
return err err = h.sendCHLO()
if err != nil {
return err
}
} }
var shloData bytes.Buffer var shloData bytes.Buffer
@@ -260,6 +265,11 @@ func (h *cryptoSetupClient) HandshakeComplete() bool {
} }
func (h *cryptoSetupClient) sendCHLO() error { func (h *cryptoSetupClient) sendCHLO() error {
h.clientHelloCounter++
if h.clientHelloCounter > protocol.MaxClientHellos {
return qerr.Error(qerr.CryptoTooManyRejects, fmt.Sprintf("More than %d rejects", protocol.MaxClientHellos))
}
b := &bytes.Buffer{} b := &bytes.Buffer{}
tags := h.getTags() tags := h.getTags()

View File

@@ -403,6 +403,17 @@ var _ = Describe("Crypto setup", func() {
Expect(tags[TagNONC]).To(Equal(cs.nonc)) Expect(tags[TagNONC]).To(Equal(cs.nonc))
Expect(tags[TagPUBS]).To(Equal(kex.PublicKey())) Expect(tags[TagPUBS]).To(Equal(kex.PublicKey()))
}) })
It("doesn't send more than MaxClientHellos CHLOs", func() {
Expect(cs.clientHelloCounter).To(BeZero())
for i := 1; i <= protocol.MaxClientHellos; i++ {
err := cs.sendCHLO()
Expect(err).ToNot(HaveOccurred())
Expect(cs.clientHelloCounter).To(Equal(i))
}
err := cs.sendCHLO()
Expect(err).To(MatchError(qerr.Error(qerr.CryptoTooManyRejects, fmt.Sprintf("More than %d rejects", protocol.MaxClientHellos))))
})
}) })
Context("escalating crypto", func() { Context("escalating crypto", func() {

View File

@@ -64,3 +64,9 @@ const MaxRetransmissionTime = 60 * time.Second
// ClientHelloMinimumSize is the minimum size the server expects an inchoate CHLO to have. // ClientHelloMinimumSize is the minimum size the server expects an inchoate CHLO to have.
const ClientHelloMinimumSize = 1024 const ClientHelloMinimumSize = 1024
// MaxClientHellos is the maximum number of times we'll send a client hello
// The value 3 accounts for:
// * one failure due to an incorrect or missing source-address token
// * one failure due the server's certificate chain being unavailible and the server being unwilling to send it without a valid source-address token
const MaxClientHellos = 3