forked from quic-go/quic-go
validate server config signature, for ECDSA certificates
This commit is contained in:
@@ -3,13 +3,16 @@ package handshake
|
||||
import (
|
||||
"bytes"
|
||||
gocrypto "crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/crypto"
|
||||
@@ -18,6 +21,10 @@ import (
|
||||
"github.com/lucas-clemente/quic-go/utils"
|
||||
)
|
||||
|
||||
type ecdsaSignature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
type cryptoSetupClient struct {
|
||||
connID protocol.ConnectionID
|
||||
version protocol.VersionNumber
|
||||
@@ -180,7 +187,14 @@ func (h *cryptoSetupClient) verifyServerConfigSignature() error {
|
||||
return qerr.ProofInvalid
|
||||
}
|
||||
} else {
|
||||
panic("Not a RSA.")
|
||||
signature := &ecdsaSignature{}
|
||||
rest, err := asn1.Unmarshal(h.proof, signature)
|
||||
if err != nil || len(rest) != 0 {
|
||||
return qerr.ProofInvalid
|
||||
}
|
||||
if !ecdsa.Verify(cert.PublicKey.(*ecdsa.PublicKey), hash.Sum(nil), signature.R, signature.S) {
|
||||
return qerr.ProofInvalid
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: verify certificate chain
|
||||
|
||||
@@ -3,6 +3,7 @@ package handshake
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
@@ -38,6 +39,10 @@ func pemBlockForKey(priv interface{}) *pem.Block {
|
||||
}
|
||||
}
|
||||
|
||||
func pemBlockForCert(certDER []byte) *pem.Block {
|
||||
return &pem.Block{Type: "CERTIFICATE", Bytes: certDER}
|
||||
}
|
||||
|
||||
type mockCertManager struct {
|
||||
setDataCalledWith []byte
|
||||
leafCert []byte
|
||||
@@ -128,21 +133,11 @@ var _ = Describe("Crypto setup", func() {
|
||||
})
|
||||
|
||||
Context("Certificates", func() {
|
||||
var leafCert *x509.Certificate
|
||||
var tlsConfig *tls.Config
|
||||
|
||||
BeforeEach(func() {
|
||||
// generate a RSA key pair and a certificate
|
||||
key, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
template := x509.Certificate{SerialNumber: big.NewInt(1)}
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
leafCert, err = x509.ParseCertificate(certDER)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
certTemplate := x509.Certificate{SerialNumber: big.NewInt(1)}
|
||||
|
||||
getTlsConfig := func(key interface{}, certDER []byte) *tls.Config {
|
||||
// export certificate and key in PEM format
|
||||
b := &pem.Block{Type: "CERTIFICATE", Bytes: certDER}
|
||||
b := pemBlockForCert(certDER)
|
||||
certPEM := pem.EncodeToMemory(b)
|
||||
b = pemBlockForKey(key)
|
||||
keyPEM := pem.EncodeToMemory(b)
|
||||
@@ -150,10 +145,8 @@ var _ = Describe("Crypto setup", func() {
|
||||
// create a tls.Config
|
||||
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
tlsConfig = &tls.Config{
|
||||
Certificates: []tls.Certificate{tlsCert},
|
||||
}
|
||||
})
|
||||
return &tls.Config{Certificates: []tls.Certificate{tlsCert}}
|
||||
}
|
||||
|
||||
It("passes the certificates to the CertManager", func() {
|
||||
tagMap[TagCERT] = []byte("cert")
|
||||
@@ -170,35 +163,96 @@ var _ = Describe("Crypto setup", func() {
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "Certificate data invalid")))
|
||||
})
|
||||
|
||||
It("verifies the signature of the server config", func() {
|
||||
cs.chloForSignature = []byte("CHLO for signature")
|
||||
serverConfigData := []byte("Server Config Data")
|
||||
cs.serverConfig = &serverConfigClient{raw: serverConfigData}
|
||||
certManager.leafCert = leafCert.Raw
|
||||
|
||||
ps, err := crypto.NewProofSource(tlsConfig)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
signature, err := ps.SignServerProof("", cs.chloForSignature, serverConfigData)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
cs.proof = signature
|
||||
|
||||
err = cs.verifyServerConfigSignature()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("errors if it can't read the leaf certificate", func() {
|
||||
certManager.leafCert = []byte("invalid leaf cert")
|
||||
err := cs.verifyServerConfigSignature()
|
||||
Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "Certificate data invalid")))
|
||||
})
|
||||
|
||||
It("rejects invalid signatures of the server config", func() {
|
||||
cs.serverConfig = &serverConfigClient{raw: []byte("Server Config Data")}
|
||||
cs.proof = []byte("invalid signature")
|
||||
certManager.leafCert = leafCert.Raw
|
||||
Context("RSA keys", func() {
|
||||
It("verifies the signature of the server config, for an RSA key", func() {
|
||||
// generate a RSA key pair and a certificate
|
||||
key, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, &key.PublicKey, key)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
leafCert, err := x509.ParseCertificate(certDER)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
tlsConfig := getTlsConfig(key, certDER)
|
||||
|
||||
err := cs.verifyServerConfigSignature()
|
||||
Expect(err).To(MatchError(qerr.ProofInvalid))
|
||||
cs.chloForSignature = []byte("CHLO for signature")
|
||||
serverConfigData := []byte("Server Config Data")
|
||||
cs.serverConfig = &serverConfigClient{raw: serverConfigData}
|
||||
certManager.leafCert = leafCert.Raw
|
||||
|
||||
ps, err := crypto.NewProofSource(tlsConfig)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
signature, err := ps.SignServerProof("", cs.chloForSignature, serverConfigData)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
cs.proof = signature
|
||||
|
||||
err = cs.verifyServerConfigSignature()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("rejects invalid signatures of the server config, for an RSA key", func() {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, &key.PublicKey, key)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
leafCert, err := x509.ParseCertificate(certDER)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
cs.serverConfig = &serverConfigClient{raw: []byte("Server Config Data")}
|
||||
cs.proof = []byte("invalid signature")
|
||||
certManager.leafCert = leafCert.Raw
|
||||
|
||||
err = cs.verifyServerConfigSignature()
|
||||
Expect(err).To(MatchError(qerr.ProofInvalid))
|
||||
})
|
||||
})
|
||||
|
||||
Context("ECDSA keys", func() {
|
||||
It("verifies the signature of the server config, for ECDSA keys", func() {
|
||||
// generate a ECDSA key pair and a certificate
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, &key.PublicKey, key)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
leafCert, err := x509.ParseCertificate(certDER)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
tlsConfig := getTlsConfig(key, certDER)
|
||||
|
||||
cs.chloForSignature = []byte("CHLO for signature")
|
||||
serverConfigData := []byte("Server Config Data")
|
||||
cs.serverConfig = &serverConfigClient{raw: serverConfigData}
|
||||
certManager.leafCert = leafCert.Raw
|
||||
|
||||
ps, err := crypto.NewProofSource(tlsConfig)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
signature, err := ps.SignServerProof("", cs.chloForSignature, serverConfigData)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
cs.proof = signature
|
||||
|
||||
err = cs.verifyServerConfigSignature()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("rejects invalid signatures of the server config, for an RSA key", func() {
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, &key.PublicKey, key)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
leafCert, err := x509.ParseCertificate(certDER)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
cs.serverConfig = &serverConfigClient{raw: []byte("Server Config Data")}
|
||||
cs.proof = []byte("invalid signature")
|
||||
certManager.leafCert = leafCert.Raw
|
||||
|
||||
err = cs.verifyServerConfigSignature()
|
||||
Expect(err).To(MatchError(qerr.ProofInvalid))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user