@@ -75,10 +75,11 @@ type CA struct {
75
75
// and module provisioning.
76
76
ID string `json:"-"`
77
77
78
- storage certmagic.Storage
79
- root , inter * x509.Certificate
80
- interKey any // TODO: should we just store these as crypto.Signer?
81
- mu * sync.RWMutex
78
+ storage certmagic.Storage
79
+ root * x509.Certificate
80
+ interChain []* x509.Certificate
81
+ interKey any // TODO: should we just store these as crypto.Signer?
82
+ mu * sync.RWMutex
82
83
83
84
rootCertPath string // mainly used for logging purposes if trusting
84
85
log * zap.Logger
@@ -129,14 +130,16 @@ func (ca *CA) Provision(ctx caddy.Context, id string, log *zap.Logger) error {
129
130
}
130
131
131
132
// load the certs and key that will be used for signing
132
- var rootCert , interCert * x509.Certificate
133
+ var rootCert * x509.Certificate
134
+ var rootCertChain , interCertChain []* x509.Certificate
133
135
var rootKey , interKey crypto.Signer
134
136
var err error
135
137
if ca .Root != nil {
136
138
if ca .Root .Format == "" || ca .Root .Format == "pem_file" {
137
139
ca .rootCertPath = ca .Root .Certificate
138
140
}
139
- rootCert , rootKey , err = ca .Root .Load ()
141
+ rootCertChain , rootKey , err = ca .Root .Load ()
142
+ rootCert = rootCertChain [0 ]
140
143
} else {
141
144
ca .rootCertPath = "storage:" + ca .storageKeyRootCert ()
142
145
rootCert , rootKey , err = ca .loadOrGenRoot ()
@@ -145,16 +148,16 @@ func (ca *CA) Provision(ctx caddy.Context, id string, log *zap.Logger) error {
145
148
return err
146
149
}
147
150
if ca .Intermediate != nil {
148
- interCert , interKey , err = ca .Intermediate .Load ()
151
+ interCertChain , interKey , err = ca .Intermediate .Load ()
149
152
} else {
150
- interCert , interKey , err = ca .loadOrGenIntermediate (rootCert , rootKey )
153
+ interCertChain , interKey , err = ca .loadOrGenIntermediate (rootCert , rootKey )
151
154
}
152
155
if err != nil {
153
156
return err
154
157
}
155
158
156
159
ca .mu .Lock ()
157
- ca .root , ca .inter , ca .interKey = rootCert , interCert , interKey
160
+ ca .root , ca .interChain , ca .interKey = rootCert , interCertChain , interKey
158
161
ca .mu .Unlock ()
159
162
160
163
return nil
@@ -180,7 +183,15 @@ func (ca CA) RootKey() (any, error) {
180
183
func (ca CA ) IntermediateCertificate () * x509.Certificate {
181
184
ca .mu .RLock ()
182
185
defer ca .mu .RUnlock ()
183
- return ca .inter
186
+ return ca .interChain [0 ]
187
+ }
188
+
189
+ // IntermediateCertificateChain returns the CA's intermediate
190
+ // certificate chain.
191
+ func (ca CA ) IntermediateCertificateChain () []* x509.Certificate {
192
+ ca .mu .RLock ()
193
+ defer ca .mu .RUnlock ()
194
+ return ca .interChain
184
195
}
185
196
186
197
// IntermediateKey returns the CA's intermediate private key.
@@ -218,13 +229,14 @@ func (ca *CA) NewAuthority(authorityConfig AuthorityConfig) (*authority.Authorit
218
229
// sure it's always fresh, because the intermediate may
219
230
// renew while Caddy is running (medium lifetime)
220
231
signerOption = authority .WithX509SignerFunc (func () ([]* x509.Certificate , crypto.Signer , error ) {
221
- issuerCert := ca .IntermediateCertificate ()
232
+ issuerChain := ca .IntermediateCertificateChain ()
233
+ issuerCert := issuerChain [0 ]
222
234
issuerKey := ca .IntermediateKey ().(crypto.Signer )
223
235
ca .log .Debug ("using intermediate signer" ,
224
236
zap .String ("serial" , issuerCert .SerialNumber .String ()),
225
237
zap .String ("not_before" , issuerCert .NotBefore .String ()),
226
238
zap .String ("not_after" , issuerCert .NotAfter .String ()))
227
- return [] * x509. Certificate { issuerCert } , issuerKey , nil
239
+ return issuerChain , issuerKey , nil
228
240
})
229
241
}
230
242
@@ -250,7 +262,11 @@ func (ca *CA) NewAuthority(authorityConfig AuthorityConfig) (*authority.Authorit
250
262
251
263
func (ca CA ) loadOrGenRoot () (rootCert * x509.Certificate , rootKey crypto.Signer , err error ) {
252
264
if ca .Root != nil {
253
- return ca .Root .Load ()
265
+ rootChain , rootSigner , err := ca .Root .Load ()
266
+ if err != nil {
267
+ return nil , nil , err
268
+ }
269
+ return rootChain [0 ], rootSigner , nil
254
270
}
255
271
rootCertPEM , err := ca .storage .Load (ca .ctx , ca .storageKeyRootCert ())
256
272
if err != nil {
@@ -312,7 +328,8 @@ func (ca CA) genRoot() (rootCert *x509.Certificate, rootKey crypto.Signer, err e
312
328
return rootCert , rootKey , nil
313
329
}
314
330
315
- func (ca CA ) loadOrGenIntermediate (rootCert * x509.Certificate , rootKey crypto.Signer ) (interCert * x509.Certificate , interKey crypto.Signer , err error ) {
331
+ func (ca CA ) loadOrGenIntermediate (rootCert * x509.Certificate , rootKey crypto.Signer ) (interCertChain []* x509.Certificate , interKey crypto.Signer , err error ) {
332
+ var interCert * x509.Certificate
316
333
interCertPEM , err := ca .storage .Load (ca .ctx , ca .storageKeyIntermediateCert ())
317
334
if err != nil {
318
335
if ! errors .Is (err , fs .ErrNotExist ) {
@@ -324,10 +341,12 @@ func (ca CA) loadOrGenIntermediate(rootCert *x509.Certificate, rootKey crypto.Si
324
341
if err != nil {
325
342
return nil , nil , fmt .Errorf ("generating new intermediate cert: %v" , err )
326
343
}
344
+
345
+ interCertChain = append (interCertChain , interCert )
327
346
}
328
347
329
- if interCert == nil {
330
- interCert , err = pemDecodeSingleCert (interCertPEM )
348
+ if len ( interCertChain ) == 0 {
349
+ interCertChain , err = pemDecodeCertificateChain (interCertPEM )
331
350
if err != nil {
332
351
return nil , nil , fmt .Errorf ("decoding intermediate certificate PEM: %v" , err )
333
352
}
@@ -344,7 +363,7 @@ func (ca CA) loadOrGenIntermediate(rootCert *x509.Certificate, rootKey crypto.Si
344
363
}
345
364
}
346
365
347
- return interCert , interKey , nil
366
+ return interCertChain , interKey , nil
348
367
}
349
368
350
369
func (ca CA ) genIntermediate (rootCert * x509.Certificate , rootKey crypto.Signer ) (interCert * x509.Certificate , interKey crypto.Signer , err error ) {
0 commit comments