forked from quic-go/quic-go
rename crypto.Signer to crypto.CertChain
This commit is contained in:
82
crypto/cert_chain.go
Normal file
82
crypto/cert_chain.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A CertChain holds a certificate and a private key
|
||||
type CertChain interface {
|
||||
SignServerProof(sni string, chlo []byte, serverConfigData []byte) ([]byte, error)
|
||||
GetCertsCompressed(sni string, commonSetHashes, cachedHashes []byte) ([]byte, error)
|
||||
GetLeafCert(sni string) ([]byte, error)
|
||||
}
|
||||
|
||||
// proofSource stores a key and a certificate for the server proof
|
||||
type certChain struct {
|
||||
config *tls.Config
|
||||
}
|
||||
|
||||
var _ CertChain = &certChain{}
|
||||
|
||||
// NewCertChain loads the key and cert from files
|
||||
func NewCertChain(tlsConfig *tls.Config) (CertChain, error) {
|
||||
return &certChain{config: tlsConfig}, nil
|
||||
}
|
||||
|
||||
// SignServerProof signs CHLO and server config for use in the server proof
|
||||
func (c *certChain) SignServerProof(sni string, chlo []byte, serverConfigData []byte) ([]byte, error) {
|
||||
cert, err := c.getCertForSNI(sni)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return signServerProof(cert, chlo, serverConfigData)
|
||||
}
|
||||
|
||||
// GetCertsCompressed gets the certificate in the format described by the QUIC crypto doc
|
||||
func (c *certChain) GetCertsCompressed(sni string, pCommonSetHashes, pCachedHashes []byte) ([]byte, error) {
|
||||
cert, err := c.getCertForSNI(sni)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getCompressedCert(cert.Certificate, pCommonSetHashes, pCachedHashes)
|
||||
}
|
||||
|
||||
// GetLeafCert gets the leaf certificate
|
||||
func (c *certChain) GetLeafCert(sni string) ([]byte, error) {
|
||||
cert, err := c.getCertForSNI(sni)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cert.Certificate[0], nil
|
||||
}
|
||||
|
||||
func (c *certChain) getCertForSNI(sni string) (*tls.Certificate, error) {
|
||||
if c.config.GetCertificate != nil {
|
||||
cert, err := c.config.GetCertificate(&tls.ClientHelloInfo{ServerName: sni})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cert != nil {
|
||||
return cert, nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.config.NameToCertificate) != 0 {
|
||||
if cert, ok := c.config.NameToCertificate[sni]; ok {
|
||||
return cert, nil
|
||||
}
|
||||
wildcardSNI := "*" + strings.TrimLeftFunc(sni, func(r rune) bool { return r != '.' })
|
||||
if cert, ok := c.config.NameToCertificate[wildcardSNI]; ok {
|
||||
return cert, nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.config.Certificates) != 0 {
|
||||
return &c.config.Certificates[0], nil
|
||||
}
|
||||
|
||||
return nil, errors.New("no matching certificate found")
|
||||
}
|
||||
102
crypto/cert_chain_test.go
Normal file
102
crypto/cert_chain_test.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
"compress/zlib"
|
||||
"crypto/tls"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Proof", 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()...)))
|
||||
})
|
||||
|
||||
// Context("retrieving certificate", func() {
|
||||
// var (
|
||||
// signer *proofSource
|
||||
// config *tls.Config
|
||||
// cert tls.Certificate
|
||||
// )
|
||||
//
|
||||
// BeforeEach(func() {
|
||||
// cert = testdata.GetCertificate()
|
||||
// config = &tls.Config{}
|
||||
// signer = &proofSource{config: config}
|
||||
// })
|
||||
//
|
||||
// It("errors without certificates", func() {
|
||||
// _, err := signer.getCertForSNI("")
|
||||
// Expect(err).To(MatchError("no matching certificate found"))
|
||||
// })
|
||||
//
|
||||
// It("uses first certificate in config.Certificates", func() {
|
||||
// config.Certificates = []tls.Certificate{cert}
|
||||
// cert, err := signer.getCertForSNI("")
|
||||
// Expect(err).ToNot(HaveOccurred())
|
||||
// Expect(cert.PrivateKey).ToNot(BeNil())
|
||||
// Expect(cert.Certificate[0]).ToNot(BeNil())
|
||||
// })
|
||||
//
|
||||
// It("uses NameToCertificate entries", func() {
|
||||
// config.NameToCertificate = map[string]*tls.Certificate{
|
||||
// "quic.clemente.io": &cert,
|
||||
// }
|
||||
// cert, err := signer.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.NameToCertificate = map[string]*tls.Certificate{
|
||||
// "*.clemente.io": &cert,
|
||||
// }
|
||||
// cert, err := signer.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 := signer.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 := signer.GetLeafCert("")
|
||||
// Expect(err).ToNot(HaveOccurred())
|
||||
// Expect(cert2).To(Equal(cert.Certificate[0]))
|
||||
// })
|
||||
// })
|
||||
})
|
||||
@@ -1,92 +0,0 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// proofSource stores a key and a certificate for the server proof
|
||||
type proofSource struct {
|
||||
config *tls.Config
|
||||
}
|
||||
|
||||
// NewProofSource loads the key and cert from files
|
||||
func NewProofSource(tlsConfig *tls.Config) (Signer, error) {
|
||||
return &proofSource{config: tlsConfig}, nil
|
||||
}
|
||||
|
||||
// SignServerProof signs CHLO and server config for use in the server proof
|
||||
func (ps *proofSource) SignServerProof(sni string, chlo []byte, serverConfigData []byte) ([]byte, error) {
|
||||
cert, err := ps.getCertForSNI(sni)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte("QUIC CHLO and server config signature\x00"))
|
||||
chloHash := sha256.Sum256(chlo)
|
||||
hash.Write([]byte{32, 0, 0, 0})
|
||||
hash.Write(chloHash[:])
|
||||
hash.Write(serverConfigData)
|
||||
|
||||
key, ok := cert.PrivateKey.(crypto.Signer)
|
||||
if !ok {
|
||||
return nil, errors.New("expected PrivateKey to implement crypto.Signer")
|
||||
}
|
||||
|
||||
opts := crypto.SignerOpts(crypto.SHA256)
|
||||
|
||||
if _, ok = key.(*rsa.PrivateKey); ok {
|
||||
opts = &rsa.PSSOptions{SaltLength: 32, Hash: crypto.SHA256}
|
||||
}
|
||||
|
||||
return key.Sign(rand.Reader, hash.Sum(nil), opts)
|
||||
}
|
||||
|
||||
// GetCertsCompressed gets the certificate in the format described by the QUIC crypto doc
|
||||
func (ps *proofSource) GetCertsCompressed(sni string, pCommonSetHashes, pCachedHashes []byte) ([]byte, error) {
|
||||
cert, err := ps.getCertForSNI(sni)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return getCompressedCert(cert.Certificate, pCommonSetHashes, pCachedHashes)
|
||||
}
|
||||
|
||||
// GetLeafCert gets the leaf certificate
|
||||
func (ps *proofSource) GetLeafCert(sni string) ([]byte, error) {
|
||||
cert, err := ps.getCertForSNI(sni)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cert.Certificate[0], nil
|
||||
}
|
||||
|
||||
func (ps *proofSource) getCertForSNI(sni string) (*tls.Certificate, error) {
|
||||
if ps.config.GetCertificate != nil {
|
||||
cert, err := ps.config.GetCertificate(&tls.ClientHelloInfo{ServerName: sni})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cert != nil {
|
||||
return cert, nil
|
||||
}
|
||||
}
|
||||
if len(ps.config.NameToCertificate) != 0 {
|
||||
if cert, ok := ps.config.NameToCertificate[sni]; ok {
|
||||
return cert, nil
|
||||
}
|
||||
wildcardSNI := "*" + strings.TrimLeftFunc(sni, func(r rune) bool { return r != '.' })
|
||||
if cert, ok := ps.config.NameToCertificate[wildcardSNI]; ok {
|
||||
return cert, nil
|
||||
}
|
||||
}
|
||||
if len(ps.config.Certificates) != 0 {
|
||||
return &ps.config.Certificates[0], nil
|
||||
}
|
||||
return nil, errors.New("no matching certificate found")
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
"compress/zlib"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"encoding/asn1"
|
||||
"math/big"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/testdata"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
type ecdsaSignature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
var _ = Describe("ProofRsa", 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 := &proofSource{
|
||||
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()...)))
|
||||
})
|
||||
|
||||
Context("when using RSA", func() {
|
||||
It("gives valid signatures", func() {
|
||||
key := testdata.GetTLSConfig().Certificates[0].PrivateKey.(*rsa.PrivateKey).Public().(*rsa.PublicKey)
|
||||
kd, err := NewProofSource(testdata.GetTLSConfig())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
signature, err := kd.SignServerProof("", []byte{'C', 'H', 'L', 'O'}, []byte{'S', 'C', 'F', 'G'})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// Generated with:
|
||||
// ruby -e 'require "digest"; p Digest::SHA256.digest("QUIC CHLO and server config signature\x00" + "\x20\x00\x00\x00" + Digest::SHA256.digest("CHLO") + "SCFG")'
|
||||
data := []byte("W\xA6\xFC\xDE\xC7\xD2>c\xE6\xB5\xF6\tq\x9E|<~1\xA33\x01\xCA=\x19\xBD\xC1\xE4\xB0\xBA\x9B\x16%")
|
||||
err = rsa.VerifyPSS(key, crypto.SHA256, data, signature, &rsa.PSSOptions{SaltLength: 32})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("when using ECDSA", func() {
|
||||
var (
|
||||
key crypto.Signer
|
||||
config *tls.Config
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
config = &tls.Config{
|
||||
Certificates: []tls.Certificate{
|
||||
{PrivateKey: key},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
It("gives valid signatures", func() {
|
||||
kd, err := NewProofSource(config)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
signature, err := kd.SignServerProof("", []byte{'C', 'H', 'L', 'O'}, []byte{'S', 'C', 'F', 'G'})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// Generated with:
|
||||
// ruby -e 'require "digest"; p Digest::SHA256.digest("QUIC CHLO and server config signature\x00" + "\x20\x00\x00\x00" + Digest::SHA256.digest("CHLO") + "SCFG")'
|
||||
data := []byte("W\xA6\xFC\xDE\xC7\xD2>c\xE6\xB5\xF6\tq\x9E|<~1\xA33\x01\xCA=\x19\xBD\xC1\xE4\xB0\xBA\x9B\x16%")
|
||||
s := &ecdsaSignature{}
|
||||
_, err = asn1.Unmarshal(signature, s)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
b := ecdsa.Verify(key.Public().(*ecdsa.PublicKey), data, s.R, s.S)
|
||||
Expect(b).To(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
Context("retrieving certificate", func() {
|
||||
var (
|
||||
signer *proofSource
|
||||
config *tls.Config
|
||||
cert tls.Certificate
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cert = testdata.GetCertificate()
|
||||
config = &tls.Config{}
|
||||
signer = &proofSource{config: config}
|
||||
})
|
||||
|
||||
It("errors without certificates", func() {
|
||||
_, err := signer.getCertForSNI("")
|
||||
Expect(err).To(MatchError("no matching certificate found"))
|
||||
})
|
||||
|
||||
It("uses first certificate in config.Certificates", func() {
|
||||
config.Certificates = []tls.Certificate{cert}
|
||||
cert, err := signer.getCertForSNI("")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cert.PrivateKey).ToNot(BeNil())
|
||||
Expect(cert.Certificate[0]).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("uses NameToCertificate entries", func() {
|
||||
config.NameToCertificate = map[string]*tls.Certificate{
|
||||
"quic.clemente.io": &cert,
|
||||
}
|
||||
cert, err := signer.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.NameToCertificate = map[string]*tls.Certificate{
|
||||
"*.clemente.io": &cert,
|
||||
}
|
||||
cert, err := signer.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 := signer.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 := signer.GetLeafCert("")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cert2).To(Equal(cert.Certificate[0]))
|
||||
})
|
||||
})
|
||||
})
|
||||
38
crypto/server_proof.go
Normal file
38
crypto/server_proof.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type ecdsaSignature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
// signServerProof signs CHLO and server config for use in the server proof
|
||||
func signServerProof(cert *tls.Certificate, chlo []byte, serverConfigData []byte) ([]byte, error) {
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte("QUIC CHLO and server config signature\x00"))
|
||||
chloHash := sha256.Sum256(chlo)
|
||||
hash.Write([]byte{32, 0, 0, 0})
|
||||
hash.Write(chloHash[:])
|
||||
hash.Write(serverConfigData)
|
||||
|
||||
key, ok := cert.PrivateKey.(crypto.Signer)
|
||||
if !ok {
|
||||
return nil, errors.New("expected PrivateKey to implement crypto.Signer")
|
||||
}
|
||||
|
||||
opts := crypto.SignerOpts(crypto.SHA256)
|
||||
|
||||
if _, ok = key.(*rsa.PrivateKey); ok {
|
||||
opts = &rsa.PSSOptions{SaltLength: 32, Hash: crypto.SHA256}
|
||||
}
|
||||
|
||||
return key.Sign(rand.Reader, hash.Sum(nil), opts)
|
||||
}
|
||||
58
crypto/server_proof_test.go
Normal file
58
crypto/server_proof_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"encoding/asn1"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/testdata"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Proof", func() {
|
||||
Context("when using RSA", func() {
|
||||
It("gives valid signatures", func() {
|
||||
key := &testdata.GetTLSConfig().Certificates[0]
|
||||
signature, err := signServerProof(key, []byte{'C', 'H', 'L', 'O'}, []byte{'S', 'C', 'F', 'G'})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// Generated with:
|
||||
// ruby -e 'require "digest"; p Digest::SHA256.digest("QUIC CHLO and server config signature\x00" + "\x20\x00\x00\x00" + Digest::SHA256.digest("CHLO") + "SCFG")'
|
||||
data := []byte("W\xA6\xFC\xDE\xC7\xD2>c\xE6\xB5\xF6\tq\x9E|<~1\xA33\x01\xCA=\x19\xBD\xC1\xE4\xB0\xBA\x9B\x16%")
|
||||
err = rsa.VerifyPSS(key.PrivateKey.(*rsa.PrivateKey).Public().(*rsa.PublicKey), crypto.SHA256, data, signature, &rsa.PSSOptions{SaltLength: 32})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("when using ECDSA", func() {
|
||||
var (
|
||||
key crypto.Signer
|
||||
cert *tls.Certificate
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
cert = &tls.Certificate{PrivateKey: key}
|
||||
})
|
||||
|
||||
It("gives valid signatures", func() {
|
||||
signature, err := signServerProof(cert, []byte{'C', 'H', 'L', 'O'}, []byte{'S', 'C', 'F', 'G'})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// Generated with:
|
||||
// ruby -e 'require "digest"; p Digest::SHA256.digest("QUIC CHLO and server config signature\x00" + "\x20\x00\x00\x00" + Digest::SHA256.digest("CHLO") + "SCFG")'
|
||||
data := []byte("W\xA6\xFC\xDE\xC7\xD2>c\xE6\xB5\xF6\tq\x9E|<~1\xA33\x01\xCA=\x19\xBD\xC1\xE4\xB0\xBA\x9B\x16%")
|
||||
s := &ecdsaSignature{}
|
||||
_, err = asn1.Unmarshal(signature, s)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
b := ecdsa.Verify(key.Public().(*ecdsa.PublicKey), data, s.R, s.S)
|
||||
Expect(b).To(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,8 +0,0 @@
|
||||
package crypto
|
||||
|
||||
// A Signer holds a certificate and a private key
|
||||
type Signer interface {
|
||||
SignServerProof(sni string, chlo []byte, serverConfigData []byte) ([]byte, error)
|
||||
GetCertsCompressed(sni string, commonSetHashes, cachedHashes []byte) ([]byte, error)
|
||||
GetLeafCert(sni string) ([]byte, error)
|
||||
}
|
||||
@@ -185,9 +185,9 @@ var _ = Describe("Crypto setup", func() {
|
||||
cs.serverConfig = &serverConfigClient{raw: serverConfigData}
|
||||
certManager.leafCert = leafCert.Raw
|
||||
|
||||
ps, err := crypto.NewProofSource(tlsConfig)
|
||||
cc, err := crypto.NewCertChain(tlsConfig)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
signature, err := ps.SignServerProof("", cs.chloForSignature, serverConfigData)
|
||||
signature, err := cc.SignServerProof("", cs.chloForSignature, serverConfigData)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
cs.proof = signature
|
||||
|
||||
@@ -228,9 +228,9 @@ var _ = Describe("Crypto setup", func() {
|
||||
cs.serverConfig = &serverConfigClient{raw: serverConfigData}
|
||||
certManager.leafCert = leafCert.Raw
|
||||
|
||||
ps, err := crypto.NewProofSource(tlsConfig)
|
||||
cc, err := crypto.NewCertChain(tlsConfig)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
signature, err := ps.SignServerProof("", cs.chloForSignature, serverConfigData)
|
||||
signature, err := cc.SignServerProof("", cs.chloForSignature, serverConfigData)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
cs.proof = signature
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ func (h *cryptoSetupServer) handleMessage(chloData []byte, cryptoData map[Tag][]
|
||||
var reply []byte
|
||||
var err error
|
||||
|
||||
certUncompressed, err := h.scfg.signer.GetLeafCert(sni)
|
||||
certUncompressed, err := h.scfg.certChain.GetLeafCert(sni)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -264,7 +264,7 @@ func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[T
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
certUncompressed, err := h.scfg.signer.GetLeafCert(sni)
|
||||
certUncompressed, err := h.scfg.certChain.GetLeafCert(sni)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ var _ = Describe("Crypto setup", func() {
|
||||
BeforeEach(func() {
|
||||
xlct = make([]byte, 8)
|
||||
var err error
|
||||
cert, err = cs.scfg.signer.GetLeafCert("")
|
||||
cert, err = cs.scfg.certChain.GetLeafCert("")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
binary.LittleEndian.PutUint64(xlct, crypto.HashCert(cert))
|
||||
})
|
||||
|
||||
@@ -9,15 +9,15 @@ import (
|
||||
|
||||
// ServerConfig is a server config
|
||||
type ServerConfig struct {
|
||||
kex crypto.KeyExchange
|
||||
certChain crypto.CertChain
|
||||
ID []byte
|
||||
obit []byte
|
||||
kex crypto.KeyExchange
|
||||
signer crypto.Signer
|
||||
stkSource crypto.StkSource
|
||||
}
|
||||
|
||||
// NewServerConfig creates a new server config
|
||||
func NewServerConfig(kex crypto.KeyExchange, signer crypto.Signer) (*ServerConfig, error) {
|
||||
func NewServerConfig(kex crypto.KeyExchange, certChain crypto.CertChain) (*ServerConfig, error) {
|
||||
id := make([]byte, 16)
|
||||
_, err := rand.Read(id)
|
||||
if err != nil {
|
||||
@@ -40,10 +40,10 @@ func NewServerConfig(kex crypto.KeyExchange, signer crypto.Signer) (*ServerConfi
|
||||
}
|
||||
|
||||
return &ServerConfig{
|
||||
kex: kex,
|
||||
certChain: certChain,
|
||||
ID: id,
|
||||
obit: obit,
|
||||
kex: kex,
|
||||
signer: signer,
|
||||
stkSource: stkSource,
|
||||
}, nil
|
||||
}
|
||||
@@ -64,10 +64,10 @@ func (s *ServerConfig) Get() []byte {
|
||||
|
||||
// Sign the server config and CHLO with the server's keyData
|
||||
func (s *ServerConfig) Sign(sni string, chlo []byte) ([]byte, error) {
|
||||
return s.signer.SignServerProof(sni, chlo, s.Get())
|
||||
return s.certChain.SignServerProof(sni, chlo, s.Get())
|
||||
}
|
||||
|
||||
// GetCertsCompressed returns the certificate data
|
||||
func (s *ServerConfig) GetCertsCompressed(sni string, commonSetHashes, compressedHashes []byte) ([]byte, error) {
|
||||
return s.signer.GetCertsCompressed(sni, commonSetHashes, compressedHashes)
|
||||
return s.certChain.GetCertsCompressed(sni, commonSetHashes, compressedHashes)
|
||||
}
|
||||
|
||||
10
server.go
10
server.go
@@ -30,8 +30,8 @@ type Server struct {
|
||||
conn *net.UDPConn
|
||||
connMutex sync.Mutex
|
||||
|
||||
signer crypto.Signer
|
||||
scfg *handshake.ServerConfig
|
||||
certChain crypto.CertChain
|
||||
scfg *handshake.ServerConfig
|
||||
|
||||
sessions map[protocol.ConnectionID]packetHandler
|
||||
sessionsMutex sync.RWMutex
|
||||
@@ -44,7 +44,7 @@ type Server struct {
|
||||
|
||||
// NewServer makes a new server
|
||||
func NewServer(addr string, tlsConfig *tls.Config, cb StreamCallback) (*Server, error) {
|
||||
signer, err := crypto.NewProofSource(tlsConfig)
|
||||
certChain, err := crypto.NewCertChain(tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func NewServer(addr string, tlsConfig *tls.Config, cb StreamCallback) (*Server,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scfg, err := handshake.NewServerConfig(kex, signer)
|
||||
scfg, err := handshake.NewServerConfig(kex, certChain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func NewServer(addr string, tlsConfig *tls.Config, cb StreamCallback) (*Server,
|
||||
|
||||
return &Server{
|
||||
addr: udpAddr,
|
||||
signer: signer,
|
||||
certChain: certChain,
|
||||
scfg: scfg,
|
||||
streamCallback: cb,
|
||||
sessions: map[protocol.ConnectionID]packetHandler{},
|
||||
|
||||
@@ -129,11 +129,11 @@ var _ = Describe("Session", func() {
|
||||
streamCallbackCalled = false
|
||||
closeCallbackCalled = false
|
||||
|
||||
signer, err := crypto.NewProofSource(testdata.GetTLSConfig())
|
||||
certChain, err := crypto.NewCertChain(testdata.GetTLSConfig())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
kex, err := crypto.NewCurve25519KEX()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
scfg, err := handshake.NewServerConfig(kex, signer)
|
||||
scfg, err := handshake.NewServerConfig(kex, certChain)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
pSession, err := newSession(
|
||||
conn,
|
||||
|
||||
Reference in New Issue
Block a user