validate server config signature, for ECDSA certificates

This commit is contained in:
Marten Seemann
2016-11-17 18:14:00 +07:00
parent 3063cab7cc
commit c8b3189caf
2 changed files with 108 additions and 40 deletions

View File

@@ -3,13 +3,16 @@ package handshake
import ( import (
"bytes" "bytes"
gocrypto "crypto" gocrypto "crypto"
"crypto/ecdsa"
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
"crypto/sha256" "crypto/sha256"
"crypto/x509" "crypto/x509"
"encoding/asn1"
"encoding/binary" "encoding/binary"
"errors" "errors"
"io" "io"
"math/big"
"time" "time"
"github.com/lucas-clemente/quic-go/crypto" "github.com/lucas-clemente/quic-go/crypto"
@@ -18,6 +21,10 @@ import (
"github.com/lucas-clemente/quic-go/utils" "github.com/lucas-clemente/quic-go/utils"
) )
type ecdsaSignature struct {
R, S *big.Int
}
type cryptoSetupClient struct { type cryptoSetupClient struct {
connID protocol.ConnectionID connID protocol.ConnectionID
version protocol.VersionNumber version protocol.VersionNumber
@@ -180,7 +187,14 @@ func (h *cryptoSetupClient) verifyServerConfigSignature() error {
return qerr.ProofInvalid return qerr.ProofInvalid
} }
} else { } 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 // TODO: verify certificate chain

View File

@@ -3,6 +3,7 @@ package handshake
import ( import (
"bytes" "bytes"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic"
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
"crypto/tls" "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 { type mockCertManager struct {
setDataCalledWith []byte setDataCalledWith []byte
leafCert []byte leafCert []byte
@@ -128,21 +133,11 @@ var _ = Describe("Crypto setup", func() {
}) })
Context("Certificates", func() { Context("Certificates", func() {
var leafCert *x509.Certificate certTemplate := x509.Certificate{SerialNumber: big.NewInt(1)}
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())
getTlsConfig := func(key interface{}, certDER []byte) *tls.Config {
// export certificate and key in PEM format // export certificate and key in PEM format
b := &pem.Block{Type: "CERTIFICATE", Bytes: certDER} b := pemBlockForCert(certDER)
certPEM := pem.EncodeToMemory(b) certPEM := pem.EncodeToMemory(b)
b = pemBlockForKey(key) b = pemBlockForKey(key)
keyPEM := pem.EncodeToMemory(b) keyPEM := pem.EncodeToMemory(b)
@@ -150,10 +145,8 @@ var _ = Describe("Crypto setup", func() {
// create a tls.Config // create a tls.Config
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
tlsConfig = &tls.Config{ return &tls.Config{Certificates: []tls.Certificate{tlsCert}}
Certificates: []tls.Certificate{tlsCert}, }
}
})
It("passes the certificates to the CertManager", func() { It("passes the certificates to the CertManager", func() {
tagMap[TagCERT] = []byte("cert") tagMap[TagCERT] = []byte("cert")
@@ -170,35 +163,96 @@ var _ = Describe("Crypto setup", func() {
Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "Certificate data invalid"))) 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() { It("errors if it can't read the leaf certificate", func() {
certManager.leafCert = []byte("invalid leaf cert") certManager.leafCert = []byte("invalid leaf cert")
err := cs.verifyServerConfigSignature() err := cs.verifyServerConfigSignature()
Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "Certificate data invalid"))) Expect(err).To(MatchError(qerr.Error(qerr.InvalidCryptoMessageParameter, "Certificate data invalid")))
}) })
It("rejects invalid signatures of the server config", func() { Context("RSA keys", func() {
cs.serverConfig = &serverConfigClient{raw: []byte("Server Config Data")} It("verifies the signature of the server config, for an RSA key", func() {
cs.proof = []byte("invalid signature") // generate a RSA key pair and a certificate
certManager.leafCert = leafCert.Raw 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() cs.chloForSignature = []byte("CHLO for signature")
Expect(err).To(MatchError(qerr.ProofInvalid)) 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))
})
}) })
}) })