forked from TrueCloudLab/lego
Remove embedded issuer certificates from issued certificate if bundle is false (#1655)
Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
This commit is contained in:
parent
e96d2c08fe
commit
e7ffbe77f8
2 changed files with 35 additions and 12 deletions
|
@ -1,6 +1,7 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -87,6 +88,11 @@ func (c *CertificateService) getCertificateChain(cert []byte, headers http.Heade
|
||||||
// See https://community.letsencrypt.org/t/acme-v2-no-up-link-in-response/64962
|
// See https://community.letsencrypt.org/t/acme-v2-no-up-link-in-response/64962
|
||||||
_, issuer := pem.Decode(cert)
|
_, issuer := pem.Decode(cert)
|
||||||
if issuer != nil {
|
if issuer != nil {
|
||||||
|
// If bundle is false, we want to return a single certificate.
|
||||||
|
// To do this, we remove the issuer cert(s) from the issued cert.
|
||||||
|
if !bundle {
|
||||||
|
cert = bytes.TrimSuffix(cert, issuer)
|
||||||
|
}
|
||||||
return &acme.RawCertificate{Cert: cert, Issuer: issuer}
|
return &acme.RawCertificate{Cert: cert, Issuer: issuer}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,27 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const certResponseNoBundleMock = `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDEDCCAfigAwIBAgIHPhckqW5fPDANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQD
|
||||||
|
Ex1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDM5NWU2MTAeFw0xODExMDcxNzQ2NTZa
|
||||||
|
Fw0yMzExMDcxNzQ2NTZaMBMxETAPBgNVBAMTCGFjbWUud3RmMIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwtLNKvZXD20XPUQCWYSK9rUSKxD9Eb0c9fag
|
||||||
|
bxOxOkLRTgL8LH6yln+bxc3MrHDou4PpDUdeo2CyOQu3CKsTS5mrH3NXYHu0H7p5
|
||||||
|
y3riOJTHnfkGKLT9LciGz7GkXd62nvNP57bOf5Sk4P2M+Qbxd0hPTSfu52740LSy
|
||||||
|
144cnxe2P1aDYehrEp6nYCESuyD/CtUHTo0qwJmzIy163Sp3rSs15BuCPyhySnE3
|
||||||
|
BJ8Ggv+qC6D5I1932DfSqyQJ79iq/HRm0Fn84am3KwvRlUfWxabmsUGARXoqCgnE
|
||||||
|
zcbJVOZKewv0zlQJpfac+b+Imj6Lvt1TGjIz2mVyefYgLx8gwwIDAQABo1QwUjAO
|
||||||
|
BgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG
|
||||||
|
A1UdEwEB/wQCMAAwEwYDVR0RBAwwCoIIYWNtZS53dGYwDQYJKoZIhvcNAQELBQAD
|
||||||
|
ggEBABB/0iYhmfPSQot5RaeeovQnsqYjI5ryQK2cwzW6qcTJfv8N6+p6XkqF1+W4
|
||||||
|
jXZjrQP8MvgO9KNWlvx12vhINE6wubk88L+2piAi5uS2QejmZbXpyYB9s+oPqlk9
|
||||||
|
IDvfdlVYOqvYAhSx7ggGi+j73mjZVtjAavP6dKuu475ZCeq+NIC15RpbbikWKtYE
|
||||||
|
HBJ7BW8XQKx67iHGx8ygHTDLbREL80Bck3oUm7wIYGMoNijD6RBl25p4gYl9dzOd
|
||||||
|
TqGl5hW/1P5hMbgEzHbr4O3BfWqU2g7tV36TASy3jbC3ONFRNNYrpEZ1AL3+cUri
|
||||||
|
OPPkKtAKAbQkKbUIfsHpBZjKZMU=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
`
|
||||||
|
|
||||||
const certResponseMock = `-----BEGIN CERTIFICATE-----
|
const certResponseMock = `-----BEGIN CERTIFICATE-----
|
||||||
MIIDEDCCAfigAwIBAgIHPhckqW5fPDANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQD
|
MIIDEDCCAfigAwIBAgIHPhckqW5fPDANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQD
|
||||||
Ex1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDM5NWU2MTAeFw0xODExMDcxNzQ2NTZa
|
Ex1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDM5NWU2MTAeFw0xODExMDcxNzQ2NTZa
|
||||||
|
@ -179,9 +200,8 @@ func Test_checkResponse(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
certRes := &Resource{}
|
certRes := &Resource{}
|
||||||
bundle := false
|
|
||||||
|
|
||||||
valid, err := certifier.checkResponse(order, certRes, bundle, "")
|
valid, err := certifier.checkResponse(order, certRes, true, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.True(t, valid)
|
assert.True(t, valid)
|
||||||
assert.NotNil(t, certRes)
|
assert.NotNil(t, certRes)
|
||||||
|
@ -230,9 +250,8 @@ func Test_checkResponse_issuerRelUp(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
certRes := &Resource{}
|
certRes := &Resource{}
|
||||||
bundle := false
|
|
||||||
|
|
||||||
valid, err := certifier.checkResponse(order, certRes, bundle, "")
|
valid, err := certifier.checkResponse(order, certRes, true, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.True(t, valid)
|
assert.True(t, valid)
|
||||||
assert.NotNil(t, certRes)
|
assert.NotNil(t, certRes)
|
||||||
|
@ -245,7 +264,7 @@ func Test_checkResponse_issuerRelUp(t *testing.T) {
|
||||||
assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate")
|
assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_checkResponse_embeddedIssuer(t *testing.T) {
|
func Test_checkResponse_no_bundle(t *testing.T) {
|
||||||
mux, apiURL := tester.SetupFakeAPI(t)
|
mux, apiURL := tester.SetupFakeAPI(t)
|
||||||
|
|
||||||
mux.HandleFunc("/certificate", func(w http.ResponseWriter, _ *http.Request) {
|
mux.HandleFunc("/certificate", func(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
@ -271,9 +290,8 @@ func Test_checkResponse_embeddedIssuer(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
certRes := &Resource{}
|
certRes := &Resource{}
|
||||||
bundle := false
|
|
||||||
|
|
||||||
valid, err := certifier.checkResponse(order, certRes, bundle, "")
|
valid, err := certifier.checkResponse(order, certRes, false, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.True(t, valid)
|
assert.True(t, valid)
|
||||||
assert.NotNil(t, certRes)
|
assert.NotNil(t, certRes)
|
||||||
|
@ -282,7 +300,7 @@ func Test_checkResponse_embeddedIssuer(t *testing.T) {
|
||||||
assert.Contains(t, certRes.CertURL, "/certificate")
|
assert.Contains(t, certRes.CertURL, "/certificate")
|
||||||
assert.Nil(t, certRes.CSR)
|
assert.Nil(t, certRes.CSR)
|
||||||
assert.Nil(t, certRes.PrivateKey)
|
assert.Nil(t, certRes.PrivateKey)
|
||||||
assert.Equal(t, certResponseMock, string(certRes.Certificate), "Certificate")
|
assert.Equal(t, certResponseNoBundleMock, string(certRes.Certificate), "Certificate")
|
||||||
assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate")
|
assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,9 +342,8 @@ func Test_checkResponse_alternate(t *testing.T) {
|
||||||
certRes := &Resource{
|
certRes := &Resource{
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
}
|
}
|
||||||
bundle := false
|
|
||||||
|
|
||||||
valid, err := certifier.checkResponse(order, certRes, bundle, "DST Root CA X3")
|
valid, err := certifier.checkResponse(order, certRes, true, "DST Root CA X3")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.True(t, valid)
|
assert.True(t, valid)
|
||||||
|
@ -359,7 +376,7 @@ func Test_Get(t *testing.T) {
|
||||||
|
|
||||||
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
|
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
|
||||||
|
|
||||||
certRes, err := certifier.Get(apiURL+"/acme/cert/test-cert", false)
|
certRes, err := certifier.Get(apiURL+"/acme/cert/test-cert", true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.NotNil(t, certRes)
|
assert.NotNil(t, certRes)
|
||||||
|
@ -376,6 +393,6 @@ type resolverMock struct {
|
||||||
error error
|
error error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resolverMock) Solve(authorizations []acme.Authorization) error {
|
func (r *resolverMock) Solve(_ []acme.Authorization) error {
|
||||||
return r.error
|
return r.error
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue