validate XLCT tag in client hello

fixes #363
This commit is contained in:
Marten Seemann
2017-01-04 11:41:43 +07:00
parent 98ff7ccb50
commit 863467f344
4 changed files with 79 additions and 9 deletions

View File

@@ -41,7 +41,7 @@ func compressChain(chain [][]byte, pCommonSetHashes, pCachedHashes []byte) ([]by
chainHashes := make([]uint64, len(chain))
for i := range chain {
chainHashes[i] = hashCert(chain[i])
chainHashes[i] = HashCert(chain[i])
}
entries := buildEntries(chain, chainHashes, cachedHashes, setHashes)
@@ -149,7 +149,8 @@ func splitHashes(hashes []byte) ([]uint64, error) {
return res, nil
}
func hashCert(cert []byte) uint64 {
// HashCert calculates the FNV1a hash of a certificate
func HashCert(cert []byte) uint64 {
h := fnv.New64a()
h.Write(cert)
return h.Sum64()

View File

@@ -121,7 +121,13 @@ func (h *CryptoSetup) handleMessage(chloData []byte, cryptoData map[Tag][]byte)
var reply []byte
var err error
if !h.isInchoateCHLO(cryptoData) {
certUncompressed, err := h.scfg.signer.GetLeafCert(sni)
if err != nil {
return false, err
}
if !h.isInchoateCHLO(cryptoData, certUncompressed) {
// We have a CHLO with a proper server config ID, do a 0-RTT handshake
reply, err = h.handleCHLO(sni, chloData, cryptoData)
if err != nil {
@@ -185,12 +191,20 @@ func (h *CryptoSetup) Seal(dst, src []byte, packetNumber protocol.PacketNumber,
}
}
func (h *CryptoSetup) isInchoateCHLO(cryptoData map[Tag][]byte) bool {
func (h *CryptoSetup) isInchoateCHLO(cryptoData map[Tag][]byte, cert []byte) bool {
if _, ok := cryptoData[TagPUBS]; !ok {
return true
}
scid, ok := cryptoData[TagSCID]
if !ok || !bytes.Equal(h.scfg.ID, scid) {
return true
}
if _, ok := cryptoData[TagPUBS]; !ok {
xlctTag, ok := cryptoData[TagXLCT]
if !ok || len(xlctTag) != 8 {
return true
}
xlct := binary.LittleEndian.Uint64(xlctTag)
if crypto.HashCert(cert) != xlct {
return true
}
if err := h.scfg.stkSource.VerifyToken(h.ip, cryptoData[TagSTK]); err != nil {

View File

@@ -204,6 +204,17 @@ var _ = Describe("Crypto setup", func() {
})
Context("when responding to client messages", func() {
var cert []byte
var xlct []byte
BeforeEach(func() {
xlct = make([]byte, 8)
var err error
cert, err = cs.scfg.signer.GetLeafCert("")
Expect(err).ToNot(HaveOccurred())
binary.LittleEndian.PutUint64(xlct, crypto.HashCert(cert))
})
It("generates REJ messages", func() {
response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize), nil)
Expect(err).ToNot(HaveOccurred())
@@ -265,6 +276,7 @@ var _ = Describe("Crypto setup", func() {
TagSNI: []byte("quic.clemente.io"),
TagNONC: nonce32,
TagSTK: validSTK,
TagXLCT: xlct,
TagAEAD: aead,
TagKEXS: kexs,
TagPUBS: nil,
@@ -283,6 +295,7 @@ var _ = Describe("Crypto setup", func() {
TagSNI: []byte("quic.clemente.io"),
TagNONC: []byte("too short client nonce"),
TagSTK: validSTK,
TagXLCT: xlct,
TagPUBS: nil,
TagVER: versionTag,
})
@@ -297,6 +310,7 @@ var _ = Describe("Crypto setup", func() {
TagSNI: []byte("quic.clemente.io"),
TagNONC: nonce,
TagSTK: validSTK,
TagXLCT: xlct,
TagPUBS: nil,
TagVER: versionTag,
})
@@ -310,6 +324,7 @@ var _ = Describe("Crypto setup", func() {
TagSNI: []byte("quic.clemente.io"),
TagNONC: nonce32,
TagSTK: validSTK,
TagXLCT: xlct,
TagAEAD: aead,
TagKEXS: kexs,
TagPUBS: nil,
@@ -323,18 +338,50 @@ var _ = Describe("Crypto setup", func() {
})
It("recognizes inchoate CHLOs missing SCID", func() {
Expect(cs.isInchoateCHLO(map[Tag][]byte{TagPUBS: nil, TagSTK: validSTK})).To(BeTrue())
Expect(cs.isInchoateCHLO(map[Tag][]byte{
TagPUBS: nil,
TagSTK: validSTK,
}, cert)).To(BeTrue())
})
It("recognizes inchoate CHLOs missing PUBS", func() {
Expect(cs.isInchoateCHLO(map[Tag][]byte{TagSCID: scfg.ID, TagSTK: validSTK})).To(BeTrue())
Expect(cs.isInchoateCHLO(map[Tag][]byte{
TagSCID: scfg.ID,
TagSTK: validSTK,
}, cert)).To(BeTrue())
})
It("recognizes inchoate CHLOs with invalid tokens", func() {
Expect(cs.isInchoateCHLO(map[Tag][]byte{
TagSCID: scfg.ID,
TagPUBS: nil,
})).To(BeTrue())
}, cert)).To(BeTrue())
})
It("recognizes inchoate CHLOs with missing XLCT", func() {
Expect(cs.isInchoateCHLO(map[Tag][]byte{
TagSCID: scfg.ID,
TagPUBS: nil,
TagSTK: validSTK,
}, cert)).To(BeTrue())
})
It("recognizes inchoate CHLOs with wrong length XLCT", func() {
Expect(cs.isInchoateCHLO(map[Tag][]byte{
TagSCID: scfg.ID,
TagPUBS: nil,
TagSTK: validSTK,
TagXLCT: xlct[1:],
}, cert)).To(BeTrue())
})
It("recognizes inchoate CHLOs with wrong XLCT", func() {
Expect(cs.isInchoateCHLO(map[Tag][]byte{
TagSCID: scfg.ID,
TagPUBS: nil,
TagSTK: validSTK,
TagXLCT: bytes.Repeat([]byte{'f'}, 8),
}, cert)).To(BeTrue())
})
It("recognizes proper CHLOs", func() {
@@ -342,7 +389,8 @@ var _ = Describe("Crypto setup", func() {
TagSCID: scfg.ID,
TagPUBS: nil,
TagSTK: validSTK,
})).To(BeFalse())
TagXLCT: xlct,
}, cert)).To(BeFalse())
})
It("errors on too short inchoate CHLOs", func() {
@@ -408,6 +456,7 @@ var _ = Describe("Crypto setup", func() {
TagPUBS: []byte("pubs"),
TagNONC: nonce32,
TagSTK: validSTK,
TagXLCT: xlct,
TagKEXS: kexs,
TagAEAD: aead,
TagVER: b,
@@ -423,6 +472,7 @@ var _ = Describe("Crypto setup", func() {
TagPUBS: []byte("pubs"),
TagNONC: nonce32,
TagSTK: validSTK,
TagXLCT: xlct,
TagKEXS: kexs,
TagVER: versionTag,
})
@@ -437,6 +487,7 @@ var _ = Describe("Crypto setup", func() {
TagPUBS: []byte("pubs"),
TagNONC: nonce32,
TagSTK: validSTK,
TagXLCT: xlct,
TagAEAD: []byte("wrong"),
TagKEXS: kexs,
TagVER: versionTag,
@@ -452,6 +503,7 @@ var _ = Describe("Crypto setup", func() {
TagPUBS: []byte("pubs"),
TagNONC: nonce32,
TagSTK: validSTK,
TagXLCT: xlct,
TagAEAD: aead,
TagVER: versionTag,
})
@@ -466,6 +518,7 @@ var _ = Describe("Crypto setup", func() {
TagPUBS: []byte("pubs"),
TagNONC: nonce32,
TagSTK: validSTK,
TagXLCT: xlct,
TagAEAD: aead,
TagKEXS: []byte("wrong"),
TagVER: versionTag,

View File

@@ -59,6 +59,8 @@ const (
// TagNONC is the client nonce
TagNONC Tag = 'N' + 'O'<<8 + 'N'<<16 + 'C'<<24
// TagXLCT is the expected leaf certificate
TagXLCT Tag = 'X' + 'L'<<8 + 'C'<<16 + 'T'<<24
// TagSCID is the server config ID
TagSCID Tag = 'S' + 'C'<<8 + 'I'<<16 + 'D'<<24