diff --git a/pkg/crypto/crypto.go b/pkg/crypto/crypto.go index 5a593d2b12..a6cffed0dc 100644 --- a/pkg/crypto/crypto.go +++ b/pkg/crypto/crypto.go @@ -6,6 +6,7 @@ import ( "crypto/ecdsa" "crypto/rand" "crypto/rsa" + "crypto/sha1" "crypto/tls" "crypto/x509" "crypto/x509/pkix" @@ -542,27 +543,39 @@ func MakeSelfSignedCA(certFile, keyFile, serialFile, name string, expireDays int } func MakeSelfSignedCAConfig(name string, expireDays int) (*TLSCertificateConfig, error) { + subject := pkix.Name{CommonName: name} + return MakeSelfSignedCAConfigForSubject(subject, expireDays) +} + +func MakeSelfSignedCAConfigForSubject(subject pkix.Name, expireDays int) (*TLSCertificateConfig, error) { var caLifetimeInDays = DefaultCACertificateLifetimeInDays if expireDays > 0 { caLifetimeInDays = expireDays } if caLifetimeInDays > DefaultCACertificateLifetimeInDays { - warnAboutCertificateLifeTime(name, DefaultCACertificateLifetimeInDays) + warnAboutCertificateLifeTime(subject.CommonName, DefaultCACertificateLifetimeInDays) } caLifetime := time.Duration(caLifetimeInDays) * 24 * time.Hour - - return MakeSelfSignedCAConfigForDuration(name, caLifetime) + return makeSelfSignedCAConfigForSubjectAndDuration(subject, caLifetime) } func MakeSelfSignedCAConfigForDuration(name string, caLifetime time.Duration) (*TLSCertificateConfig, error) { + subject := pkix.Name{CommonName: name} + return makeSelfSignedCAConfigForSubjectAndDuration(subject, caLifetime) +} + +func makeSelfSignedCAConfigForSubjectAndDuration(subject pkix.Name, caLifetime time.Duration) (*TLSCertificateConfig, error) { // Create CA cert - rootcaPublicKey, rootcaPrivateKey, err := NewKeyPair() + rootcaPublicKey, rootcaPrivateKey, publicKeyHash, err := newKeyPairWithHash() if err != nil { return nil, err } - rootcaTemplate := newSigningCertificateTemplateForDuration(pkix.Name{CommonName: name}, caLifetime, time.Now) + // AuthorityKeyId and SubjectKeyId should match for a self-signed CA + authorityKeyId := publicKeyHash + subjectKeyId := publicKeyHash + rootcaTemplate := newSigningCertificateTemplateForDuration(subject, caLifetime, time.Now, authorityKeyId, subjectKeyId) rootcaCert, err := signCertificate(rootcaTemplate, rootcaPublicKey, rootcaTemplate, rootcaPrivateKey) if err != nil { return nil, err @@ -576,11 +589,13 @@ func MakeSelfSignedCAConfigForDuration(name string, caLifetime time.Duration) (* func MakeCAConfigForDuration(name string, caLifetime time.Duration, issuer *CA) (*TLSCertificateConfig, error) { // Create CA cert - signerPublicKey, signerPrivateKey, err := NewKeyPair() + signerPublicKey, signerPrivateKey, publicKeyHash, err := newKeyPairWithHash() if err != nil { return nil, err } - signerTemplate := newSigningCertificateTemplateForDuration(pkix.Name{CommonName: name}, caLifetime, time.Now) + authorityKeyId := issuer.Config.Certs[0].SubjectKeyId + subjectKeyId := publicKeyHash + signerTemplate := newSigningCertificateTemplateForDuration(pkix.Name{CommonName: name}, caLifetime, time.Now, authorityKeyId, subjectKeyId) signerCert, err := issuer.signCertificate(signerTemplate, signerPublicKey) if err != nil { return nil, err @@ -638,8 +653,10 @@ func (ca *CA) MakeAndWriteServerCert(certFile, keyFile string, hostnames sets.St type CertificateExtensionFunc func(*x509.Certificate) error func (ca *CA) MakeServerCert(hostnames sets.String, expireDays int, fns ...CertificateExtensionFunc) (*TLSCertificateConfig, error) { - serverPublicKey, serverPrivateKey, _ := NewKeyPair() - serverTemplate := newServerCertificateTemplate(pkix.Name{CommonName: hostnames.List()[0]}, hostnames.List(), expireDays, time.Now) + serverPublicKey, serverPrivateKey, publicKeyHash, _ := newKeyPairWithHash() + authorityKeyId := ca.Config.Certs[0].SubjectKeyId + subjectKeyId := publicKeyHash + serverTemplate := newServerCertificateTemplate(pkix.Name{CommonName: hostnames.List()[0]}, hostnames.List(), expireDays, time.Now, authorityKeyId, subjectKeyId) for _, fn := range fns { if err := fn(serverTemplate); err != nil { return nil, err @@ -657,8 +674,10 @@ func (ca *CA) MakeServerCert(hostnames sets.String, expireDays int, fns ...Certi } func (ca *CA) MakeServerCertForDuration(hostnames sets.String, lifetime time.Duration, fns ...CertificateExtensionFunc) (*TLSCertificateConfig, error) { - serverPublicKey, serverPrivateKey, _ := NewKeyPair() - serverTemplate := newServerCertificateTemplateForDuration(pkix.Name{CommonName: hostnames.List()[0]}, hostnames.List(), lifetime, time.Now) + serverPublicKey, serverPrivateKey, publicKeyHash, _ := newKeyPairWithHash() + authorityKeyId := ca.Config.Certs[0].SubjectKeyId + subjectKeyId := publicKeyHash + serverTemplate := newServerCertificateTemplateForDuration(pkix.Name{CommonName: hostnames.List()[0]}, hostnames.List(), lifetime, time.Now, authorityKeyId, subjectKeyId) for _, fn := range fns { if err := fn(serverTemplate); err != nil { return nil, err @@ -795,6 +814,21 @@ func (ca *CA) signCertificate(template *x509.Certificate, requestKey crypto.Publ } func NewKeyPair() (crypto.PublicKey, crypto.PrivateKey, error) { + return newRSAKeyPair() +} + +func newKeyPairWithHash() (crypto.PublicKey, crypto.PrivateKey, []byte, error) { + publicKey, privateKey, err := newRSAKeyPair() + var publicKeyHash []byte + if err == nil { + hash := sha1.New() + hash.Write(publicKey.N.Bytes()) + publicKeyHash = hash.Sum(nil) + } + return publicKey, privateKey, publicKeyHash, err +} + +func newRSAKeyPair() (*rsa.PublicKey, *rsa.PrivateKey, error) { privateKey, err := rsa.GenerateKey(rand.Reader, keyBits) if err != nil { return nil, nil, err @@ -803,7 +837,7 @@ func NewKeyPair() (crypto.PublicKey, crypto.PrivateKey, error) { } // Can be used for CA or intermediate signing certs -func newSigningCertificateTemplateForDuration(subject pkix.Name, caLifetime time.Duration, currentTime func() time.Time) *x509.Certificate { +func newSigningCertificateTemplateForDuration(subject pkix.Name, caLifetime time.Duration, currentTime func() time.Time, authorityKeyId, subjectKeyId []byte) *x509.Certificate { return &x509.Certificate{ Subject: subject, @@ -816,11 +850,14 @@ func newSigningCertificateTemplateForDuration(subject pkix.Name, caLifetime time KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, BasicConstraintsValid: true, IsCA: true, + + AuthorityKeyId: authorityKeyId, + SubjectKeyId: subjectKeyId, } } // Can be used for ListenAndServeTLS -func newServerCertificateTemplate(subject pkix.Name, hosts []string, expireDays int, currentTime func() time.Time) *x509.Certificate { +func newServerCertificateTemplate(subject pkix.Name, hosts []string, expireDays int, currentTime func() time.Time, authorityKeyId, subjectKeyId []byte) *x509.Certificate { var lifetimeInDays = DefaultCertificateLifetimeInDays if expireDays > 0 { lifetimeInDays = expireDays @@ -832,11 +869,11 @@ func newServerCertificateTemplate(subject pkix.Name, hosts []string, expireDays lifetime := time.Duration(lifetimeInDays) * 24 * time.Hour - return newServerCertificateTemplateForDuration(subject, hosts, lifetime, currentTime) + return newServerCertificateTemplateForDuration(subject, hosts, lifetime, currentTime, authorityKeyId, subjectKeyId) } // Can be used for ListenAndServeTLS -func newServerCertificateTemplateForDuration(subject pkix.Name, hosts []string, lifetime time.Duration, currentTime func() time.Time) *x509.Certificate { +func newServerCertificateTemplateForDuration(subject pkix.Name, hosts []string, lifetime time.Duration, currentTime func() time.Time, authorityKeyId, subjectKeyId []byte) *x509.Certificate { template := &x509.Certificate{ Subject: subject, @@ -849,6 +886,9 @@ func newServerCertificateTemplateForDuration(subject pkix.Name, hosts []string, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, + + AuthorityKeyId: authorityKeyId, + SubjectKeyId: subjectKeyId, } template.IPAddresses, template.DNSNames = IPAddressesDNSNames(hosts) diff --git a/pkg/crypto/crypto_test.go b/pkg/crypto/crypto_test.go index 8ccd02d58c..adb6a72b96 100644 --- a/pkg/crypto/crypto_test.go +++ b/pkg/crypto/crypto_test.go @@ -138,7 +138,7 @@ func newSigningCertificateTemplate(subject pkix.Name, expireDays int, currentTim caLifetime := time.Duration(caLifetimeInDays) * 24 * time.Hour - return newSigningCertificateTemplateForDuration(subject, caLifetime, currentTime) + return newSigningCertificateTemplateForDuration(subject, caLifetime, currentTime, nil, nil) } func buildCA(t *testing.T) (crypto.PrivateKey, *x509.Certificate) { @@ -176,7 +176,7 @@ func buildServer(t *testing.T, signingKey crypto.PrivateKey, signingCrt *x509.Ce t.Fatalf("Unexpected error: %#v", err) } hosts := []string{"127.0.0.1", "localhost", "www.example.com"} - serverTemplate := newServerCertificateTemplate(pkix.Name{CommonName: "Server"}, hosts, certificateLifetime, time.Now) + serverTemplate := newServerCertificateTemplate(pkix.Name{CommonName: "Server"}, hosts, certificateLifetime, time.Now, nil, nil) serverCrt, err := signCertificate(serverTemplate, serverPublicKey, signingCrt, signingKey) if err != nil { t.Fatalf("Unexpected error: %#v", err) @@ -224,7 +224,7 @@ func TestRandomSerialGenerator(t *testing.T) { generator := &RandomSerialGenerator{} hostnames := []string{"foo", "bar"} - template := newServerCertificateTemplate(pkix.Name{CommonName: hostnames[0]}, hostnames, certificateLifetime, time.Now) + template := newServerCertificateTemplate(pkix.Name{CommonName: hostnames[0]}, hostnames, certificateLifetime, time.Now, nil, nil) if _, err := generator.Next(template); err != nil { t.Fatalf("unexpected error: %v", err) } @@ -296,6 +296,8 @@ func TestValidityPeriodOfServerCertificate(t *testing.T) { []string{"www.example.com"}, test.passedExpireDays, currentFakeTime, + nil, + nil, ) expirationDate := cert.NotAfter expectedExpirationDate := currentTime.Add(time.Duration(test.realExpireDays) * 24 * time.Hour)