@@ -3,8 +3,10 @@ package util
33import (
44 cryptorand "crypto/rand"
55 "crypto/rsa"
6+ "crypto/sha1"
67 "crypto/x509"
78 "crypto/x509/pkix"
9+ "encoding/asn1"
810 "encoding/json"
911 "encoding/pem"
1012 "errors"
@@ -13,6 +15,7 @@ import (
1315 "math/big"
1416 "net"
1517 "reflect"
18+ "slices"
1619 "strings"
1720 "time"
1821
@@ -76,6 +79,10 @@ type AltNames struct {
7679 IPs []net.IP
7780}
7881
82+ type authorityKeyId struct {
83+ KeyIdentifier []byte `asn1:"optional,tag:0"`
84+ }
85+
7986func (ca Bundle ) Sign (config Config ) (* Bundle , error ) {
8087 if ! ca .Certificate .IsCA {
8188 return nil , errors .New ("You can't use this certificate for signing. It's not a CA..." )
@@ -95,6 +102,17 @@ func (ca Bundle) Sign(config Config) (*Bundle, error) {
95102 notBefore = ca .Certificate .NotBefore
96103 }
97104
105+ var authorityKeyIdent []byte
106+ if ca .Certificate .SubjectKeyId != nil {
107+ var err error
108+ authorityKeyIdent , err = asn1 .Marshal (authorityKeyId {
109+ KeyIdentifier : ca .Certificate .SubjectKeyId ,
110+ })
111+ if err != nil {
112+ return nil , fmt .Errorf ("Failed to marshal authority key id: %s" , err )
113+ }
114+ }
115+
98116 certTmpl := x509.Certificate {
99117 Subject : pkix.Name {
100118 CommonName : config .Sign ,
@@ -103,13 +121,14 @@ func (ca Bundle) Sign(config Config) (*Bundle, error) {
103121 Province : config .Province ,
104122 Locality : config .Locality ,
105123 },
106- DNSNames : config .AltNames .DNSNames ,
107- IPAddresses : config .AltNames .IPs ,
108- SerialNumber : serial ,
109- NotBefore : notBefore ,
110- NotAfter : time .Now ().Add (config .ValidFor ).UTC (),
111- KeyUsage : x509 .KeyUsageKeyEncipherment | x509 .KeyUsageDigitalSignature ,
112- ExtKeyUsage : config .Usages ,
124+ DNSNames : config .AltNames .DNSNames ,
125+ IPAddresses : config .AltNames .IPs ,
126+ SerialNumber : serial ,
127+ NotBefore : notBefore ,
128+ NotAfter : time .Now ().Add (config .ValidFor ).UTC (),
129+ KeyUsage : x509 .KeyUsageKeyEncipherment | x509 .KeyUsageDigitalSignature ,
130+ ExtKeyUsage : config .Usages ,
131+ AuthorityKeyId : authorityKeyIdent ,
113132 }
114133
115134 certDERBytes , _ := x509 .CreateCertificate (cryptorand .Reader , & certTmpl , ca .Certificate , key .Public (), ca .PrivateKey )
@@ -375,7 +394,17 @@ func (cf *CertificateFactory) UserCert(principal *models.Principal, apiURL strin
375394}
376395
377396func loadOrCreateCA (kluster * v1.Kluster , name string , cert , key * string , certUpdates * []CertUpdates ) (* Bundle , error ) {
378- if * cert != "" && * key != "" {
397+ regenerate := false
398+ if name == "TLS" && * cert != "" {
399+ caCert , err := x509 .ParseCertificate ([]byte (* cert ))
400+ if err != nil {
401+ return nil , fmt .Errorf ("Failed to parse TLS CA certificate: %s" , err )
402+ }
403+ if caCert .SubjectKeyId == nil {
404+ regenerate = true
405+ }
406+ }
407+ if * cert != "" && * key != "" && ! regenerate {
379408 return NewBundle ([]byte (* key ), []byte (* cert ))
380409 }
381410 caBundle , err := createCA (kluster .Name , name )
@@ -489,6 +518,9 @@ func createCA(klusterName, name string) (*Bundle, error) {
489518 return nil , fmt .Errorf ("Failed to generate private key for %s ca: %s" , name , err )
490519 }
491520
521+ keyBytes := x509 .MarshalPKCS1PublicKey (& privateKey .PublicKey )
522+ keyHash := sha1 .Sum (keyBytes )
523+
492524 now := time .Now ()
493525 tmpl := x509.Certificate {
494526 SerialNumber : new (big.Int ).SetInt64 (0 ),
@@ -501,6 +533,7 @@ func createCA(klusterName, name string) (*Bundle, error) {
501533 KeyUsage : x509 .KeyUsageKeyEncipherment | x509 .KeyUsageDigitalSignature | x509 .KeyUsageCertSign ,
502534 BasicConstraintsValid : true ,
503535 IsCA : true ,
536+ SubjectKeyId : keyHash [:],
504537 }
505538
506539 certDERBytes , err := x509 .CreateCertificate (cryptorand .Reader , & tmpl , & tmpl , privateKey .Public (), privateKey )
@@ -523,6 +556,10 @@ func isCertChangedOrExpires(origCert, newCert, caCert *x509.Certificate, duratio
523556 return "SAN IP changes: " + strings .Join (IPSliceDiff (origCert .IPAddresses , newCert .IPAddresses ), " " ), true
524557 }
525558
559+ if ! slices .Equal (origCert .AuthorityKeyId , newCert .AuthorityKeyId ) {
560+ return "AuthorityKeyId changed" , true
561+ }
562+
526563 expire := time .Now ().Add (duration )
527564 if expire .After (origCert .NotAfter ) {
528565 return fmt .Sprintf ("Certificate expires at %s" , origCert .NotAfter ), true
0 commit comments