Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace certificate fixtures in etcdraft/consensus with certificates generated at runtime #2370

Merged
merged 2 commits into from
Feb 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions common/crypto/tlsgen/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ type CA interface {
// with a given custom SAN.
// The certificate is signed by the CA.
// Returns nil, error in case of failure
NewServerCertKeyPair(host string) (*CertKeyPair, error)
NewServerCertKeyPair(hosts ...string) (*CertKeyPair, error)
sykesm marked this conversation as resolved.
Show resolved Hide resolved

// Signer returns a crypto.Signer that signs with the CA's private key.
Signer() crypto.Signer
}

type ca struct {
Expand All @@ -50,7 +53,7 @@ type ca struct {
func NewCA() (CA, error) {
c := &ca{}
var err error
c.caCert, err = newCertKeyPair(true, false, "", nil, nil)
c.caCert, err = newCertKeyPair(true, false, nil, nil)
if err != nil {
return nil, err
}
Expand All @@ -60,7 +63,7 @@ func NewCA() (CA, error) {
func (c *ca) NewIntermediateCA() (CA, error) {
intermediateCA := &ca{}
var err error
intermediateCA.caCert, err = newCertKeyPair(true, false, "", c.caCert.Signer, c.caCert.TLSCert)
intermediateCA.caCert, err = newCertKeyPair(true, false, c.caCert.Signer, c.caCert.TLSCert)
if err != nil {
return nil, err
}
Expand All @@ -76,16 +79,21 @@ func (c *ca) CertBytes() []byte {
// or nil, error in case of failure
// The certificate is signed by the CA and is used as a client TLS certificate
func (c *ca) NewClientCertKeyPair() (*CertKeyPair, error) {
return newCertKeyPair(false, false, "", c.caCert.Signer, c.caCert.TLSCert)
return newCertKeyPair(false, false, c.caCert.Signer, c.caCert.TLSCert)
}

// newServerCertKeyPair returns a certificate and private key pair and nil,
// or nil, error in case of failure
// The certificate is signed by the CA and is used as a server TLS certificate
func (c *ca) NewServerCertKeyPair(host string) (*CertKeyPair, error) {
keypair, err := newCertKeyPair(false, true, host, c.caCert.Signer, c.caCert.TLSCert)
func (c *ca) NewServerCertKeyPair(hosts ...string) (*CertKeyPair, error) {
keypair, err := newCertKeyPair(false, true, c.caCert.Signer, c.caCert.TLSCert, hosts...)
if err != nil {
return nil, err
}
return keypair, nil
}

// Signer returns a crypto.Signer that signs with the CA's private key.
func (c *ca) Signer() crypto.Signer {
return c.caCert.Signer
}
6 changes: 6 additions & 0 deletions common/crypto/tlsgen/ca_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,9 @@ func TestTLSCA(t *testing.T) {
require.Error(t, err)
require.Contains(t, err.Error(), "context deadline exceeded")
}

func TestTLSCASigner(t *testing.T) {
tlsCA, err := NewCA()
require.NoError(t, err)
require.Equal(t, tlsCA.(*ca).caCert.Signer, tlsCA.Signer())
}
21 changes: 16 additions & 5 deletions common/crypto/tlsgen/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
Expand Down Expand Up @@ -47,7 +48,7 @@ func newCertTemplate() (x509.Certificate, error) {
}, nil
}

func newCertKeyPair(isCA bool, isServer bool, host string, certSigner crypto.Signer, parent *x509.Certificate) (*CertKeyPair, error) {
func newCertKeyPair(isCA bool, isServer bool, certSigner crypto.Signer, parent *x509.Certificate, hosts ...string) (*CertKeyPair, error) {
privateKey, privBytes, err := newPrivKey()
if err != nil {
return nil, err
Expand All @@ -74,12 +75,15 @@ func newCertKeyPair(isCA bool, isServer bool, host string, certSigner crypto.Sig
if isServer {
template.NotAfter = tenYearsFromNow
template.ExtKeyUsage = append(template.ExtKeyUsage, x509.ExtKeyUsageServerAuth)
if ip := net.ParseIP(host); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else {
template.DNSNames = append(template.DNSNames, host)
for _, host := range hosts {
if ip := net.ParseIP(host); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else {
template.DNSNames = append(template.DNSNames, host)
}
}
}
template.SubjectKeyId = computeSKI(&privateKey.PublicKey)
sykesm marked this conversation as resolved.
Show resolved Hide resolved
// If no parent cert, it's a self signed cert
if parent == nil || certSigner == nil {
parent = &template
Expand Down Expand Up @@ -111,3 +115,10 @@ func newCertKeyPair(isCA bool, isServer bool, host string, certSigner crypto.Sig
func encodePEM(keyType string, data []byte) []byte {
return pem.EncodeToMemory(&pem.Block{Type: keyType, Bytes: data})
}

// RFC 7093, Section 2, Method 4
func computeSKI(key *ecdsa.PublicKey) []byte {
raw := elliptic.Marshal(key.Curve, key.X, key.Y)
hash := sha256.Sum256(raw)
return hash[:]
}
2 changes: 1 addition & 1 deletion common/crypto/tlsgen/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
)

func TestLoadCert(t *testing.T) {
pair, err := newCertKeyPair(false, false, "", nil, nil)
pair, err := newCertKeyPair(false, false, nil, nil)
require.NoError(t, err)
require.NotNil(t, pair)
tlsCertPair, err := tls.X509KeyPair(pair.Cert, pair.Key)
Expand Down
2 changes: 1 addition & 1 deletion internal/cryptogen/ca/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func (ca *CA) SignCertificate(
return cert, nil
}

// compute Subject Key Identifier
// compute Subject Key Identifier using RFC 7093, Section 2, Method 4
func computeSKI(privKey *ecdsa.PrivateKey) []byte {
// Marshall the public key
raw := elliptic.Marshal(privKey.Curve, privKey.PublicKey.X, privKey.PublicKey.Y)
Expand Down
Loading