149 lines
4.5 KiB
Go
149 lines
4.5 KiB
Go
package crypto
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/flate"
|
|
"compress/zlib"
|
|
"crypto/tls"
|
|
"reflect"
|
|
|
|
"github.com/lucas-clemente/quic-go/testdata"
|
|
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Proof", func() {
|
|
var (
|
|
cc *certChain
|
|
config *tls.Config
|
|
cert tls.Certificate
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
cert = testdata.GetCertificate()
|
|
config = &tls.Config{}
|
|
cc = NewCertChain(config).(*certChain)
|
|
})
|
|
|
|
Context("certificate compression", func() {
|
|
It("compresses certs", func() {
|
|
cert := []byte{0xde, 0xca, 0xfb, 0xad}
|
|
certZlib := &bytes.Buffer{}
|
|
z, err := zlib.NewWriterLevelDict(certZlib, flate.BestCompression, certDictZlib)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
z.Write([]byte{0x04, 0x00, 0x00, 0x00})
|
|
z.Write(cert)
|
|
z.Close()
|
|
kd := &certChain{
|
|
config: &tls.Config{
|
|
Certificates: []tls.Certificate{
|
|
{Certificate: [][]byte{cert}},
|
|
},
|
|
},
|
|
}
|
|
certCompressed, err := kd.GetCertsCompressed("", nil, nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(certCompressed).To(Equal(append([]byte{
|
|
0x01, 0x00,
|
|
0x08, 0x00, 0x00, 0x00,
|
|
}, certZlib.Bytes()...)))
|
|
})
|
|
|
|
It("errors when it can't retrieve a certificate", func() {
|
|
_, err := cc.GetCertsCompressed("invalid domain", nil, nil)
|
|
Expect(err).To(MatchError(errNoMatchingCertificate))
|
|
})
|
|
})
|
|
|
|
Context("signing server configs", func() {
|
|
It("errors when it can't retrieve a certificate for the requested SNI", func() {
|
|
_, err := cc.SignServerProof("invalid", []byte("chlo"), []byte("scfg"))
|
|
Expect(err).To(MatchError(errNoMatchingCertificate))
|
|
})
|
|
|
|
It("signs the server config", func() {
|
|
config.Certificates = []tls.Certificate{cert}
|
|
proof, err := cc.SignServerProof("", []byte("chlo"), []byte("scfg"))
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(proof).ToNot(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Context("retrieving certificates", func() {
|
|
It("errors without certificates", func() {
|
|
_, err := cc.getCertForSNI("")
|
|
Expect(err).To(MatchError(errNoMatchingCertificate))
|
|
})
|
|
|
|
It("uses first certificate in config.Certificates", func() {
|
|
config.Certificates = []tls.Certificate{cert}
|
|
cert, err := cc.getCertForSNI("")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(cert.PrivateKey).ToNot(BeNil())
|
|
Expect(cert.Certificate[0]).ToNot(BeNil())
|
|
})
|
|
|
|
It("uses NameToCertificate entries", func() {
|
|
config.Certificates = []tls.Certificate{cert, cert} // two entries so the long path is used
|
|
config.NameToCertificate = map[string]*tls.Certificate{
|
|
"quic.clemente.io": &cert,
|
|
}
|
|
cert, err := cc.getCertForSNI("quic.clemente.io")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(cert.PrivateKey).ToNot(BeNil())
|
|
Expect(cert.Certificate[0]).ToNot(BeNil())
|
|
})
|
|
|
|
It("uses NameToCertificate entries with wildcard", func() {
|
|
config.Certificates = []tls.Certificate{cert, cert} // two entries so the long path is used
|
|
config.NameToCertificate = map[string]*tls.Certificate{
|
|
"*.clemente.io": &cert,
|
|
}
|
|
cert, err := cc.getCertForSNI("quic.clemente.io")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(cert.PrivateKey).ToNot(BeNil())
|
|
Expect(cert.Certificate[0]).ToNot(BeNil())
|
|
})
|
|
|
|
It("uses GetCertificate", func() {
|
|
config.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
|
Expect(clientHello.ServerName).To(Equal("quic.clemente.io"))
|
|
return &cert, nil
|
|
}
|
|
cert, err := cc.getCertForSNI("quic.clemente.io")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(cert.PrivateKey).ToNot(BeNil())
|
|
Expect(cert.Certificate[0]).ToNot(BeNil())
|
|
})
|
|
|
|
It("gets leaf certificates", func() {
|
|
config.Certificates = []tls.Certificate{cert}
|
|
cert2, err := cc.GetLeafCert("")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(cert2).To(Equal(cert.Certificate[0]))
|
|
})
|
|
|
|
It("errors when it can't retrieve a leaf certificate", func() {
|
|
_, err := cc.GetLeafCert("invalid domain")
|
|
Expect(err).To(MatchError(errNoMatchingCertificate))
|
|
})
|
|
|
|
It("respects GetConfigForClient", func() {
|
|
if !reflect.ValueOf(tls.Config{}).FieldByName("GetConfigForClient").IsValid() {
|
|
// Pre 1.8, we don't have to do anything
|
|
return
|
|
}
|
|
nestedConfig := &tls.Config{Certificates: []tls.Certificate{cert}}
|
|
l := func(chi *tls.ClientHelloInfo) (*tls.Config, error) {
|
|
Expect(chi.ServerName).To(Equal("quic.clemente.io"))
|
|
return nestedConfig, nil
|
|
}
|
|
reflect.ValueOf(config).Elem().FieldByName("GetConfigForClient").Set(reflect.ValueOf(l))
|
|
resultCert, err := cc.getCertForSNI("quic.clemente.io")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(*resultCert).To(Equal(cert))
|
|
})
|
|
})
|
|
})
|