Skip to content

Commit 8b72388

Browse files
authored
Add authority and subject key ids to generated certificates (#1005)
* Add authority and subject key ids to generated certificates * Check presence of subjectKeyId before creating authorityKeyId * Regenerate certs on key id changes
1 parent 9a41489 commit 8b72388

File tree

1 file changed

+45
-8
lines changed

1 file changed

+45
-8
lines changed

pkg/util/certificates.go

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ package util
33
import (
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+
7986
func (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

377396
func 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

Comments
 (0)