forked from quic-go/quic-go
implement certificate compression using common certificate sets
fixes #47
This commit is contained in:
@@ -33,19 +33,27 @@ func compressChain(chain [][]byte, pCommonSetHashes, pCachedHashes []byte) ([]by
|
||||
return nil, err
|
||||
}
|
||||
|
||||
setHashes, err := splitHashes(pCommonSetHashes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chainHashes := make([]uint64, len(chain))
|
||||
for i := range chain {
|
||||
chainHashes[i] = hashCert(chain[i])
|
||||
}
|
||||
|
||||
entries := buildEntries(chain, chainHashes, cachedHashes)
|
||||
entries := buildEntries(chain, chainHashes, cachedHashes, setHashes)
|
||||
|
||||
totalUncompressedLen := 0
|
||||
for i, e := range entries {
|
||||
res.WriteByte(uint8(e.t))
|
||||
switch e.t {
|
||||
case entryCached:
|
||||
utils.WriteUint64(res, chainHashes[i])
|
||||
utils.WriteUint64(res, e.h)
|
||||
case entryCommon:
|
||||
utils.WriteUint64(res, e.h)
|
||||
utils.WriteUint32(res, e.i)
|
||||
case entryCompressed:
|
||||
totalUncompressedLen += 4 + len(chain[i])
|
||||
}
|
||||
@@ -80,7 +88,7 @@ func compressChain(chain [][]byte, pCommonSetHashes, pCachedHashes []byte) ([]by
|
||||
return res.Bytes(), nil
|
||||
}
|
||||
|
||||
func buildEntries(chain [][]byte, chainHashes, cachedHashes []uint64) []entry {
|
||||
func buildEntries(chain [][]byte, chainHashes, cachedHashes, setHashes []uint64) []entry {
|
||||
res := make([]entry, len(chain))
|
||||
chainLoop:
|
||||
for i := range chain {
|
||||
@@ -92,6 +100,22 @@ chainLoop:
|
||||
}
|
||||
}
|
||||
|
||||
// Go through common sets and check if it's in there
|
||||
for _, setHash := range setHashes {
|
||||
set, ok := certSets[setHash]
|
||||
if !ok {
|
||||
// We don't have this set
|
||||
continue
|
||||
}
|
||||
// We have this set, check if chain[i] is in the set
|
||||
pos := set.findCertInSet(chain[i])
|
||||
if pos >= 0 {
|
||||
// Found
|
||||
res[i] = entry{t: entryCommon, h: setHash, i: uint32(pos)}
|
||||
continue chainLoop
|
||||
}
|
||||
}
|
||||
|
||||
res[i] = entry{t: entryCompressed}
|
||||
}
|
||||
return res
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/binary"
|
||||
"hash/fnv"
|
||||
|
||||
"github.com/lucas-clemente/quic-go-certificates"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
@@ -95,4 +96,41 @@ var _ = Describe("Cert compression", func() {
|
||||
expected = append(expected, certZlib.Bytes()...)
|
||||
Expect(compressed).To(Equal(expected))
|
||||
})
|
||||
|
||||
It("uses common certificates", func() {
|
||||
cert := certsets.CertSet1[42]
|
||||
setHash := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(setHash, certsets.CertSet1Hash)
|
||||
chain := [][]byte{cert}
|
||||
compressed, err := compressChain(chain, setHash, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expected := []byte{0x03}
|
||||
expected = append(expected, setHash...)
|
||||
expected = append(expected, []byte{42, 0, 0, 0}...)
|
||||
expected = append(expected, 0x00)
|
||||
Expect(compressed).To(Equal(expected))
|
||||
})
|
||||
|
||||
It("uses common certificates and compressed combined", func() {
|
||||
cert1 := []byte{0xde, 0xca, 0xfb, 0xad}
|
||||
cert2 := certsets.CertSet1[42]
|
||||
setHash := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(setHash, certsets.CertSet1Hash)
|
||||
certZlib := &bytes.Buffer{}
|
||||
z, err := zlib.NewWriterLevelDict(certZlib, flate.BestCompression, append(cert2, certDictZlib...))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
z.Write([]byte{0x04, 0x00, 0x00, 0x00})
|
||||
z.Write(cert1)
|
||||
z.Close()
|
||||
chain := [][]byte{cert1, cert2}
|
||||
compressed, err := compressChain(chain, setHash, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expected := []byte{0x01, 0x03}
|
||||
expected = append(expected, setHash...)
|
||||
expected = append(expected, []byte{42, 0, 0, 0}...)
|
||||
expected = append(expected, 0x00)
|
||||
expected = append(expected, []byte{0x08, 0, 0, 0}...)
|
||||
expected = append(expected, certZlib.Bytes()...)
|
||||
Expect(compressed).To(Equal(expected))
|
||||
})
|
||||
})
|
||||
|
||||
24
crypto/cert_sets.go
Normal file
24
crypto/cert_sets.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/lucas-clemente/quic-go-certificates"
|
||||
)
|
||||
|
||||
type certSet [][]byte
|
||||
|
||||
var certSets = map[uint64]certSet{
|
||||
certsets.CertSet1Hash: certsets.CertSet1,
|
||||
certsets.CertSet2Hash: certsets.CertSet2,
|
||||
}
|
||||
|
||||
// findCertInSet searches for the cert in the set. Negative return value means not found.
|
||||
func (s *certSet) findCertInSet(cert []byte) int {
|
||||
for i, c := range *s {
|
||||
if bytes.Equal(c, cert) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
Reference in New Issue
Block a user