-
Notifications
You must be signed in to change notification settings - Fork 191
/
signerbuilder.go
154 lines (129 loc) · 4.55 KB
/
signerbuilder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package certchains
import (
"fmt"
"k8s.io/apimachinery/pkg/util/sets"
"github.com/openshift/library-go/pkg/crypto"
"github.com/openshift/microshift/pkg/util/cryptomaterial"
)
type SignerInfo interface {
Name() string
Directory() string
ValidityDays() int
}
type CertificateSignerBuilder interface {
SignerInfo
WithSignerConfig(config *crypto.CA) CertificateSignerBuilder
WithSubCAs(subCAsInfo ...CertificateSignerBuilder) CertificateSignerBuilder
WithClientCertificates(signInfos ...*ClientCertificateSigningRequestInfo) CertificateSignerBuilder
WithServingCertificates(signInfos ...*ServingCertificateSigningRequestInfo) CertificateSignerBuilder
WithPeerCertificiates(signInfos ...*PeerCertificateSigningRequestInfo) CertificateSignerBuilder
WithCABundlePaths(bundlePath ...string) CertificateSignerBuilder
Complete() (*CertificateSigner, error)
}
type certificateSigner struct {
signerName string
signerDir string
signerValidityDays int
// signerConfig should only be used in case this is a sub-ca signer
// It should be populated during CertificateSigner.SignSubCA()
signerConfig *crypto.CA
subCAs []CertificateSignerBuilder
certificatesToSign []CSRInfo
// locations of bundles where this signer appears
caBundlePaths []string
}
// NewCertificateSigner returns a builder object for a certificate chain for the given signer
//
//nolint:ireturn
func NewCertificateSigner(signerName, signerDir string, validityDays int) CertificateSignerBuilder {
return &certificateSigner{
signerName: signerName,
signerDir: signerDir,
signerValidityDays: validityDays,
}
}
func (s *certificateSigner) Name() string { return s.signerName }
func (s *certificateSigner) Directory() string { return s.signerDir }
func (s *certificateSigner) ValidityDays() int { return s.signerValidityDays }
// WithSignerConfig uses the provided configuration in `config` to sign its
// direct certificates.
// This is useful when creating intermediate signers.
//
//nolint:ireturn
func (s *certificateSigner) WithSignerConfig(config *crypto.CA) CertificateSignerBuilder {
s.signerConfig = config
return s
}
//nolint:ireturn
func (s *certificateSigner) WithCABundlePaths(bundlePaths ...string) CertificateSignerBuilder {
s.caBundlePaths = append(s.caBundlePaths, bundlePaths...)
return s
}
//nolint:ireturn
func (s *certificateSigner) WithClientCertificates(signInfos ...*ClientCertificateSigningRequestInfo) CertificateSignerBuilder {
for _, signInfo := range signInfos {
s.certificatesToSign = append(s.certificatesToSign, signInfo)
}
return s
}
//nolint:ireturn
func (s *certificateSigner) WithServingCertificates(signInfos ...*ServingCertificateSigningRequestInfo) CertificateSignerBuilder {
for _, signInfo := range signInfos {
s.certificatesToSign = append(s.certificatesToSign, signInfo)
}
return s
}
//nolint:ireturn
func (s *certificateSigner) WithPeerCertificiates(signInfos ...*PeerCertificateSigningRequestInfo) CertificateSignerBuilder {
for _, signInfo := range signInfos {
s.certificatesToSign = append(s.certificatesToSign, signInfo)
}
return s
}
//nolint:ireturn
func (s *certificateSigner) WithSubCAs(subCAsInfo ...CertificateSignerBuilder) CertificateSignerBuilder {
s.subCAs = append(s.subCAs, subCAsInfo...)
return s
}
func (s *certificateSigner) Complete() (*CertificateSigner, error) {
// in case this is a sub-ca, it's already going to have the signer-config populated
signerConfig := s.signerConfig
if signerConfig == nil {
var err error
signerConfig, _, err = crypto.EnsureCA(
cryptomaterial.CACertPath(s.signerDir),
cryptomaterial.CAKeyPath(s.signerDir),
cryptomaterial.CASerialsPath(s.signerDir),
s.signerName,
s.signerValidityDays,
)
if err != nil {
return nil, fmt.Errorf("failed to generate %s CA certificate: %w", s.signerName, err)
}
}
signerCompleted := &CertificateSigner{
signerName: s.signerName,
signerDir: s.signerDir,
signerValidityDays: s.signerValidityDays,
signerConfig: signerConfig,
subCAs: make(map[string]*CertificateSigner),
signedCertificates: make(map[string]*signedCertificateInfo),
caBundlePaths: sets.New[string](),
}
for _, subCA := range s.subCAs {
subCA := subCA
if err := signerCompleted.SignSubCA(subCA); err != nil {
return nil, err
}
}
for _, si := range s.certificatesToSign {
si := si
if err := signerCompleted.SignCertificate(si); err != nil {
return nil, err
}
}
if err := signerCompleted.AddToBundles(s.caBundlePaths...); err != nil {
return nil, err
}
return signerCompleted, nil
}