@@ -14,6 +14,7 @@ import (
1414 "fmt"
1515 "math/big"
1616 mrand "math/rand/v2"
17+ "slices"
1718
1819 ct "github.com/google/certificate-transparency-go"
1920 cttls "github.com/google/certificate-transparency-go/tls"
@@ -63,15 +64,6 @@ type issuanceEvent struct {
6364 Certificate string `json:",omitempty"`
6465}
6566
66- // Two maps of keys to Issuers. Lookup by PublicKeyAlgorithm is useful for
67- // determining the set of issuers which can sign a given (pre)cert, based on its
68- // PublicKeyAlgorithm. Lookup by NameID is useful for looking up a specific
69- // issuer based on the issuer of a given (pre)certificate.
70- type issuerMaps struct {
71- byAlg map [x509.PublicKeyAlgorithm ][]* issuance.Issuer
72- byNameID map [issuance.NameID ]* issuance.Issuer
73- }
74-
7567// caMetrics holds various metrics which are shared between caImpl and crlImpl.
7668type caMetrics struct {
7769 signatureCount * prometheus.CounterVec
@@ -123,11 +115,11 @@ func (m *caMetrics) noteSignError(err error) {
123115// certificateAuthorityImpl represents a CA that signs certificates.
124116type certificateAuthorityImpl struct {
125117 capb.UnsafeCertificateAuthorityServer
126- sa sapb.StorageAuthorityCertificateClient
127- sctClient rapb.SCTProviderClient
128- pa core.PolicyAuthority
129- issuers issuerMaps
130- certProfiles map [string ]* issuance.Profile
118+ sa sapb.StorageAuthorityCertificateClient
119+ sctClient rapb.SCTProviderClient
120+ pa core.PolicyAuthority
121+ issuers [] * issuance. Issuer
122+ profiles map [string ]* issuance.Profile
131123
132124 // The prefix is prepended to the serial number.
133125 prefix byte
@@ -141,60 +133,14 @@ type certificateAuthorityImpl struct {
141133
142134var _ capb.CertificateAuthorityServer = (* certificateAuthorityImpl )(nil )
143135
144- // makeIssuerMaps processes a list of issuers into a set of maps for easy
145- // lookup either by key algorithm (useful for picking an issuer for a precert)
146- // or by unique ID (useful for final certs and CRLs). If two issuers with
147- // the same unique ID are encountered, an error is returned.
148- func makeIssuerMaps (issuers []* issuance.Issuer ) (issuerMaps , error ) {
149- issuersByAlg := make (map [x509.PublicKeyAlgorithm ][]* issuance.Issuer , 2 )
150- issuersByNameID := make (map [issuance.NameID ]* issuance.Issuer , len (issuers ))
151- for _ , issuer := range issuers {
152- if _ , found := issuersByNameID [issuer .NameID ()]; found {
153- return issuerMaps {}, fmt .Errorf ("two issuers with same NameID %d (%s) configured" , issuer .NameID (), issuer .Name ())
154- }
155- issuersByNameID [issuer .NameID ()] = issuer
156- if issuer .IsActive () {
157- issuersByAlg [issuer .KeyType ()] = append (issuersByAlg [issuer .KeyType ()], issuer )
158- }
159- }
160- if i , ok := issuersByAlg [x509 .ECDSA ]; ! ok || len (i ) == 0 {
161- return issuerMaps {}, errors .New ("no ECDSA issuers configured" )
162- }
163- if i , ok := issuersByAlg [x509 .RSA ]; ! ok || len (i ) == 0 {
164- return issuerMaps {}, errors .New ("no RSA issuers configured" )
165- }
166- return issuerMaps {issuersByAlg , issuersByNameID }, nil
167- }
168-
169- // makeCertificateProfilesMap processes a set of named certificate issuance
170- // profile configs into a map from name to profile.
171- func makeCertificateProfilesMap (profiles map [string ]* issuance.ProfileConfig ) (map [string ]* issuance.Profile , error ) {
172- if len (profiles ) <= 0 {
173- return nil , fmt .Errorf ("must pass at least one certificate profile" )
174- }
175-
176- profilesByName := make (map [string ]* issuance.Profile , len (profiles ))
177-
178- for name , profileConfig := range profiles {
179- profile , err := issuance .NewProfile (profileConfig )
180- if err != nil {
181- return nil , err
182- }
183-
184- profilesByName [name ] = profile
185- }
186-
187- return profilesByName , nil
188- }
189-
190136// NewCertificateAuthorityImpl creates a CA instance that can sign certificates
191137// from any number of issuance.Issuers and for any number of profiles.
192138func NewCertificateAuthorityImpl (
193139 sa sapb.StorageAuthorityCertificateClient ,
194140 sctService rapb.SCTProviderClient ,
195141 pa core.PolicyAuthority ,
196- boulderIssuers []* issuance.Issuer ,
197- certificateProfiles map [string ]* issuance.ProfileConfig ,
142+ issuers []* issuance.Issuer ,
143+ profiles map [string ]* issuance.Profile ,
198144 serialPrefix byte ,
199145 maxNames int ,
200146 keyPolicy goodkey.KeyPolicy ,
@@ -206,33 +152,27 @@ func NewCertificateAuthorityImpl(
206152 return nil , errors .New ("serial prefix must be between 0x01 (1) and 0x7f (127)" )
207153 }
208154
209- if len (boulderIssuers ) == 0 {
155+ if len (issuers ) == 0 {
210156 return nil , errors .New ("must have at least one issuer" )
211157 }
212158
213- certProfiles , err := makeCertificateProfilesMap (certificateProfiles )
214- if err != nil {
215- return nil , err
216- }
217-
218- issuers , err := makeIssuerMaps (boulderIssuers )
219- if err != nil {
220- return nil , err
159+ if len (profiles ) == 0 {
160+ return nil , errors .New ("must have at least one profile" )
221161 }
222162
223163 return & certificateAuthorityImpl {
224- sa : sa ,
225- sctClient : sctService ,
226- pa : pa ,
227- issuers : issuers ,
228- certProfiles : certProfiles ,
229- prefix : serialPrefix ,
230- maxNames : maxNames ,
231- keyPolicy : keyPolicy ,
232- log : logger ,
233- metrics : metrics ,
234- tracer : otel .GetTracerProvider ().Tracer ("github.com/letsencrypt/boulder/ca" ),
235- clk : clk ,
164+ sa : sa ,
165+ sctClient : sctService ,
166+ pa : pa ,
167+ issuers : issuers ,
168+ profiles : profiles ,
169+ prefix : serialPrefix ,
170+ maxNames : maxNames ,
171+ keyPolicy : keyPolicy ,
172+ log : logger ,
173+ metrics : metrics ,
174+ tracer : otel .GetTracerProvider ().Tracer ("github.com/letsencrypt/boulder/ca" ),
175+ clk : clk ,
236176 }, nil
237177}
238178
@@ -259,7 +199,7 @@ func (ca *certificateAuthorityImpl) IssueCertificate(ctx context.Context, req *c
259199 return nil , errors .New ("IssueCertificate called with a nil SCT service" )
260200 }
261201
262- profile , ok := ca .certProfiles [req .CertProfileName ]
202+ profile , ok := ca .profiles [req .CertProfileName ]
263203 if ! ok {
264204 return nil , fmt .Errorf ("incapable of using a profile named %q" , req .CertProfileName )
265205 }
@@ -276,7 +216,7 @@ func (ca *certificateAuthorityImpl) IssueCertificate(ctx context.Context, req *c
276216 return nil , err
277217 }
278218
279- issuer , err := ca .pickIssuer (csr .PublicKeyAlgorithm )
219+ issuer , err := ca .pickIssuer (req . CertProfileName , csr .PublicKeyAlgorithm )
280220 if err != nil {
281221 return nil , err
282222 }
@@ -495,13 +435,22 @@ func (ca *certificateAuthorityImpl) IssueCertificate(ctx context.Context, req *c
495435}
496436
497437// pickIssuer returns an issuer which is willing to issue certificates for the
498- // given public key algorithm. If no such issuer exists, it returns
438+ // given profile and public key algorithm. If no such issuer exists, it returns
499439// an error. If multiple such issuers exist, it selects one at random.
500- func (ca * certificateAuthorityImpl ) pickIssuer (keyAlg x509.PublicKeyAlgorithm ) (* issuance.Issuer , error ) {
501- pool , ok := ca .issuers .byAlg [keyAlg ]
440+ func (ca * certificateAuthorityImpl ) pickIssuer (profileName string , keyAlg x509.PublicKeyAlgorithm ) (* issuance.Issuer , error ) {
441+ var pool []* issuance.Issuer
442+ for _ , issuer := range ca .issuers {
443+ if issuer .KeyType () != keyAlg {
444+ continue
445+ }
446+ if ! slices .Contains (issuer .Profiles (), profileName ) {
447+ continue
448+ }
449+ pool = append (pool , issuer )
450+ }
502451
503- if ! ok || len (pool ) == 0 {
504- return nil , fmt .Errorf ("no issuer found for key algorithm %s" , keyAlg )
452+ if len (pool ) == 0 {
453+ return nil , fmt .Errorf ("no issuer found for profile %q and key algorithm %s" , profileName , keyAlg )
505454 }
506455
507456 return pool [mrand .IntN (len (pool ))], nil
0 commit comments