Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit bb176ae

Browse files
vanclueversaitho
authored andcommitted
r/certificate: do not require exactly 2 certificates in the bundle
Let's Encrypt, in part of the work in migrating to their own independent root CA certificate, has introduced an additional intermediate in the default chain to help compatibility with older systems, namely Android devices. The new chain is now being issued with new requests, which has caused issues with our current assertions where we look for two certificates. This assertion possibly could fail with other ACME CAs that are not Let's Encrypt that may eventually need to do something similar. For now, we are just removing the assertion that expects this. For PEM encoding we are just concatenating the entire collection of issuer certificates in issuer_pem. This will be migrated to a list at a later time. Since PFX encoding takes certificates un-encoded, this is a more natural, graceful change. Additionally, we should look to add a certificate chain preference at a later time, as Let's Encrypt will be eventually transitioning their default chain to one that does not include the cross-signed intermediate. Related to vancluever#154. (cherry picked from commit a8f59aa)
1 parent cd08e2b commit bb176ae

File tree

1 file changed

+15
-14
lines changed

1 file changed

+15
-14
lines changed

acme/acme_structure.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -208,28 +208,33 @@ func certDaysRemaining(cert *certificate.Resource) (int64, error) {
208208
return remaining / 86400, nil
209209
}
210210

211-
// splitPEMBundle gets a slice of x509 certificates from parsePEMBundle,
212-
// and always returns 2 certificates - the issued cert first, and the issuer
213-
// certificate second.
211+
// splitPEMBundle gets a slice of x509 certificates from
212+
// parsePEMBundle.
214213
//
215-
// if the certificate count in a bundle is != 2 then this function will fail.
214+
// The first certificate split is returned as the issued certificate,
215+
// with the rest returned as the issuer (intermediate) chain.
216+
//
217+
// Technically, it will be possible for issuer to be empty, if there
218+
// are zero certificates in the intermediate chain. This is highly
219+
// unlikely, however.
216220
func splitPEMBundle(bundle []byte) (cert, issuer []byte, err error) {
217221
cb, err := parsePEMBundle(bundle)
218222
if err != nil {
219223
return
220224
}
221-
if len(cb) != 2 {
222-
err = fmt.Errorf("Certificate bundle does not contain exactly 2 certificates")
223-
return
224-
}
225+
225226
// lego always returns the issued cert first, if the CA is first there is a problem
226227
if cb[0].IsCA {
227228
err = fmt.Errorf("First certificate is a CA certificate")
228229
return
229230
}
230231

231232
cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cb[0].Raw})
232-
issuer = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cb[1].Raw})
233+
issuer = make([]byte, 0)
234+
for _, ic := range cb[1:] {
235+
issuer = append(issuer, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: ic.Raw})...)
236+
}
237+
233238
return
234239
}
235240

@@ -244,10 +249,6 @@ func bundleToPKCS12(bundle, key []byte, password string) ([]byte, error) {
244249
return nil, err
245250
}
246251

247-
if len(cb) != 2 {
248-
return nil, fmt.Errorf("Certificate bundle does not contain exactly 2 certificates")
249-
}
250-
251252
// lego always returns the issued cert first, if the CA is first there is a problem
252253
if cb[0].IsCA {
253254
return nil, fmt.Errorf("First certificate is a CA certificate")
@@ -258,7 +259,7 @@ func bundleToPKCS12(bundle, key []byte, password string) ([]byte, error) {
258259
return nil, err
259260
}
260261

261-
pfxData, err := pkcs12.Encode(rand.Reader, pk, cb[0], cb[1:2], password)
262+
pfxData, err := pkcs12.Encode(rand.Reader, pk, cb[0], cb[1:], password)
262263
if err != nil {
263264
return nil, err
264265
}

0 commit comments

Comments
 (0)