Merge pull request #6755 from import-shiburin/master
bugfix: wrong certificate chain is used if preferredChain is configured
This commit is contained in:
commit
f643eef2b2
@ -107,7 +107,7 @@ spec:
|
||||
description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
|
||||
type: string
|
||||
preferredChain:
|
||||
description: 'PreferredChain is the chain to use if the ACME server outputs multiple. PreferredChain is no guarantee that this one gets delivered by the ACME endpoint. For example, for Let''s Encrypt''s DST crosssign you would use: "DST Root CA X3" or "ISRG Root X1" for the newer Let''s Encrypt root CA. This value picks the first certificate bundle in the ACME alternative chains that has a certificate with this value as its issuer''s CN'
|
||||
description: 'PreferredChain is the chain to use if the ACME server outputs multiple. PreferredChain is no guarantee that this one gets delivered by the ACME endpoint. For example, for Let''s Encrypt''s DST crosssign you would use: "DST Root CA X3" or "ISRG Root X1" for the newer Let''s Encrypt root CA. This value picks the first certificate bundle in the combined set of ACME default and alternative chains that has a root-most certificate with this value as its issuer''s commonname.'
|
||||
type: string
|
||||
maxLength: 64
|
||||
privateKeySecretRef:
|
||||
|
||||
@ -108,7 +108,7 @@ spec:
|
||||
description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
|
||||
type: string
|
||||
preferredChain:
|
||||
description: 'PreferredChain is the chain to use if the ACME server outputs multiple. PreferredChain is no guarantee that this one gets delivered by the ACME endpoint. For example, for Let''s Encrypt''s DST crosssign you would use: "DST Root CA X3" or "ISRG Root X1" for the newer Let''s Encrypt root CA. This value picks the first certificate bundle in the ACME alternative chains that has a certificate with this value as its issuer''s CN'
|
||||
description: 'PreferredChain is the chain to use if the ACME server outputs multiple. PreferredChain is no guarantee that this one gets delivered by the ACME endpoint. For example, for Let''s Encrypt''s DST crosssign you would use: "DST Root CA X3" or "ISRG Root X1" for the newer Let''s Encrypt root CA. This value picks the first certificate bundle in the combined set of ACME default and alternative chains that has a root-most certificate with this value as its issuer''s commonname.'
|
||||
type: string
|
||||
maxLength: 64
|
||||
privateKeySecretRef:
|
||||
|
||||
@ -48,8 +48,9 @@ type ACMEIssuer struct {
|
||||
// endpoint.
|
||||
// For example, for Let's Encrypt's DST crosssign you would use:
|
||||
// "DST Root CA X3" or "ISRG Root X1" for the newer Let's Encrypt root CA.
|
||||
// This value picks the first certificate bundle in the ACME alternative
|
||||
// chains that has a certificate with this value as its issuer's CN
|
||||
// This value picks the first certificate bundle in the combined set of
|
||||
// ACME default and alternative chains that has a root-most certificate with
|
||||
// this value as its issuer's commonname.
|
||||
// +optional
|
||||
// +kubebuilder:validation:MaxLength=64
|
||||
PreferredChain string `json:"preferredChain,omitempty"`
|
||||
|
||||
@ -585,17 +585,17 @@ func (c *controller) finalizeOrder(ctx context.Context, cl acmecl.Interface, o *
|
||||
}
|
||||
|
||||
if issuer.GetSpec().ACME != nil && issuer.GetSpec().ACME.PreferredChain != "" {
|
||||
preferredChain := issuer.GetSpec().ACME.PreferredChain
|
||||
found, altChain, err := getAltCertChain(ctx, cl, certURL, preferredChain)
|
||||
preferredChainName := issuer.GetSpec().ACME.PreferredChain
|
||||
found, preferredCertChain, err := getPreferredCertChain(ctx, cl, certURL, certSlice, preferredChainName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving alternate chain: %w", err)
|
||||
return fmt.Errorf("error retrieving preferred chain: %w", err)
|
||||
}
|
||||
if found {
|
||||
return c.storeCertificateOnStatus(ctx, o, altChain)
|
||||
return c.storeCertificateOnStatus(ctx, o, preferredCertChain)
|
||||
}
|
||||
// if no match is found we return to the actual cert
|
||||
// it is a *preferred* chain after all
|
||||
log.V(logf.DebugLevel).Info(fmt.Sprintf("Preferred chain %s not found, fall back to the default cert", preferredChain))
|
||||
log.V(logf.DebugLevel).Info(fmt.Sprintf("Preferred chain %s not found, fall back to the default cert", preferredChainName))
|
||||
}
|
||||
|
||||
return c.storeCertificateOnStatus(ctx, o, certSlice)
|
||||
@ -652,16 +652,6 @@ func (c *controller) syncCertificateDataWithOrder(ctx context.Context, cl acmecl
|
||||
return nil
|
||||
}
|
||||
|
||||
if issuer.GetSpec().ACME != nil && issuer.GetSpec().ACME.PreferredChain != "" {
|
||||
found, altCerts, err := getAltCertChain(ctx, cl, acmeOrder.CertURL, issuer.GetSpec().ACME.PreferredChain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if found {
|
||||
return c.storeCertificateOnStatus(ctx, o, altCerts)
|
||||
}
|
||||
|
||||
}
|
||||
certs, err := cl.FetchCert(ctx, acmeOrder.CertURL, true)
|
||||
if acmeErr, ok := err.(*acmeapi.Error); ok {
|
||||
if acmeErr.StatusCode >= 400 && acmeErr.StatusCode < 500 {
|
||||
@ -675,6 +665,16 @@ func (c *controller) syncCertificateDataWithOrder(ctx context.Context, cl acmecl
|
||||
return err
|
||||
}
|
||||
|
||||
if issuer.GetSpec().ACME != nil && issuer.GetSpec().ACME.PreferredChain != "" {
|
||||
found, preferredCertChain, err := getPreferredCertChain(ctx, cl, acmeOrder.CertURL, certs, issuer.GetSpec().ACME.PreferredChain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if found {
|
||||
return c.storeCertificateOnStatus(ctx, o, preferredCertChain)
|
||||
}
|
||||
}
|
||||
|
||||
err = c.storeCertificateOnStatus(ctx, o, certs)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -700,35 +700,73 @@ func getACMEOrder(ctx context.Context, cl acmecl.Interface, o *cmacme.Order) (*a
|
||||
return acmeOrder, nil
|
||||
}
|
||||
|
||||
func getAltCertChain(ctx context.Context, cl acmecl.Interface, certURL string, preferredChain string) (bool, [][]byte, error) {
|
||||
func getPreferredCertChain(
|
||||
ctx context.Context,
|
||||
cl acmecl.Interface,
|
||||
certURL string,
|
||||
certBundle [][]byte,
|
||||
preferredChain string,
|
||||
) (bool, [][]byte, error) {
|
||||
log := logf.FromContext(ctx)
|
||||
altURLs, err := cl.ListCertAlternates(ctx, certURL)
|
||||
if err != nil {
|
||||
return false, nil, fmt.Errorf("error listing alternate certificate URLs: %w", err)
|
||||
}
|
||||
// Loop over all alternative chains
|
||||
for _, altURL := range altURLs {
|
||||
altChain, err := cl.FetchCert(ctx, altURL, true)
|
||||
if err != nil {
|
||||
return false, nil, fmt.Errorf("error fetching alternate certificate chain from %s: %w", altURL, err)
|
||||
}
|
||||
// Loop over each cert in this alternative chain
|
||||
for _, altCert := range altChain {
|
||||
cert, err := x509.ParseCertificate(altCert)
|
||||
if err != nil {
|
||||
return false, nil, fmt.Errorf("error parsing alternate certificate chain: %w", err)
|
||||
}
|
||||
log.V(logf.DebugLevel).WithValues("Issuer CN", cert.Issuer.CommonName).Info("Found alternative ACME bundle")
|
||||
if cert.Issuer.CommonName == preferredChain {
|
||||
// if the issuer's CN matched the preferred chain it means this bundle is
|
||||
// signed by the requested chain
|
||||
log.V(logf.DebugLevel).WithValues("Issuer CN", cert.Issuer.CommonName).Info("Selecting alternative ACME bundle with a matching Common Name from %s", altURL)
|
||||
return true, altChain, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil, nil
|
||||
|
||||
isMatch := func(name string, chain [][]byte) (bool, error) {
|
||||
if len(chain) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Check topmost certificate
|
||||
cert, err := x509.ParseCertificate(chain[len(chain)-1])
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error parsing certificate chain: %w", err)
|
||||
}
|
||||
|
||||
log.V(logf.DebugLevel).WithValues("Issuer CN", cert.Issuer.CommonName).Info("Found ACME bundle")
|
||||
if cert.Issuer.CommonName == preferredChain {
|
||||
// if the issuer's CN matched the preferred chain it means this bundle is
|
||||
// signed by the requested chain
|
||||
log.V(logf.DebugLevel).WithValues("Issuer CN", cert.Issuer.CommonName).Info("Selecting preferred ACME bundle with a matching Common Name from %s", name)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Check if the default chain matches the preferred chain
|
||||
{
|
||||
match, err := isMatch("default", certBundle)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
if match {
|
||||
return true, certBundle, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any alternate chain matches the preferred chain
|
||||
{
|
||||
altURLs, err := cl.ListCertAlternates(ctx, certURL)
|
||||
if err != nil {
|
||||
return false, nil, fmt.Errorf("error listing alternate certificate URLs: %w", err)
|
||||
}
|
||||
|
||||
for _, chainURL := range altURLs {
|
||||
certChain, err := cl.FetchCert(ctx, chainURL, true)
|
||||
if err != nil {
|
||||
return false, nil, fmt.Errorf("error fetching certificate chain from %s: %w", chainURL, err)
|
||||
}
|
||||
|
||||
match, err := isMatch(chainURL, certChain)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if match {
|
||||
return true, certChain, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
// updateOrApplyStatus will update the order status.
|
||||
|
||||
@ -36,6 +36,7 @@ import (
|
||||
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
|
||||
testpkg "github.com/cert-manager/cert-manager/pkg/controller/test"
|
||||
schedulertest "github.com/cert-manager/cert-manager/pkg/scheduler/test"
|
||||
"github.com/cert-manager/cert-manager/pkg/util/pki"
|
||||
"github.com/cert-manager/cert-manager/test/unit/gen"
|
||||
)
|
||||
|
||||
@ -68,7 +69,7 @@ func TestSync(t *testing.T) {
|
||||
}))
|
||||
|
||||
testIssuerHTTP01TestComPreferredChain := gen.Issuer("testissuer", gen.SetIssuerACME(cmacme.ACMEIssuer{
|
||||
PreferredChain: "ISRG Root X1",
|
||||
PreferredChain: "DST Root CA X3", // This is the common name of the root certificate in the testAltCert
|
||||
Solvers: []cmacme.ACMEChallengeSolver{
|
||||
{
|
||||
Selector: &cmacme.CertificateDNSNameSelector{
|
||||
@ -144,6 +145,124 @@ func TestSync(t *testing.T) {
|
||||
Detail: "some error",
|
||||
}
|
||||
|
||||
// testCert is using the following Let's Encrypt chain (X1 is not included):
|
||||
// leaf -> R3 -> ISRG Root X1
|
||||
testCert := `-----BEGIN CERTIFICATE-----
|
||||
MIIEZjCCA06gAwIBAgISAx0TG3o1EufZi/OTOnR9vqt/MA0GCSqGSIb3DQEBCwUA
|
||||
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
|
||||
EwJSMzAeFw0yMzEyMTkxNjIwMjFaFw0yNDAzMTgxNjIwMjBaMBoxGDAWBgNVBAMT
|
||||
D2NlcnQtbWFuYWdlci5pbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCRoMZW8
|
||||
FQpb9R2fNhLps2Jms1e058hkiz9PzfyVZT4n0ONmV2OlnNXg7Y3F8v47yc5tq5W6
|
||||
8oum8TN+Y2v3u2CjggJXMIICUzAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYI
|
||||
KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFBljJ3oq
|
||||
zwwTlkvYYFNit4ol03klMB8GA1UdIwQYMBaAFBQusxe3WFbLrlAJQOYfr52LFMLG
|
||||
MFUGCCsGAQUFBwEBBEkwRzAhBggrBgEFBQcwAYYVaHR0cDovL3IzLm8ubGVuY3Iu
|
||||
b3JnMCIGCCsGAQUFBzAChhZodHRwOi8vcjMuaS5sZW5jci5vcmcvMF4GA1UdEQRX
|
||||
MFWCD2NlcnQtbWFuYWdlci5pb4IUZG9jcy5jZXJ0LW1hbmFnZXIuaW+CF25ldGxp
|
||||
ZnkuY2VydC1tYW5hZ2VyLmlvghN3d3cuY2VydC1tYW5hZ2VyLmlvMBMGA1UdIAQM
|
||||
MAowCAYGZ4EMAQIBMIIBBgYKKwYBBAHWeQIEAgSB9wSB9ADyAHcASLDja9qmRzQP
|
||||
5WoC+p0w6xxSActW3SyB2bu/qznYhHMAAAGMgxfC6wAABAMASDBGAiEA1Ac3K8oT
|
||||
EGY509sNj0/hZ4x5Td6aA3HsElojcF0DOMwCIQDxXgjEDmg0vS4u5BHEndIecmHe
|
||||
2cMTnTIRM8c9IW0ZTgB3AKLiv9Ye3i8vB6DWTm03p9xlQ7DGtS6i2reK+Jpt9RfY
|
||||
AAABjIMXwyAAAAQDAEgwRgIhAI9E0vDiqkNXYqtVmQBxM1Nk6eOmeMtZSGoojfBW
|
||||
IsHBAiEA4S+mvJMqrVQ78UtAT+SGJ9Mr6fb/T45rDmID0PDhuXEwDQYJKoZIhvcN
|
||||
AQELBQADggEBAJuZ66ArEUG/98Aaz+xYPbpRAfNmllyk9o6exmmZWrAvTBgzCF+D
|
||||
T+UN8XtOwVW4lTJGHBsXmY9mGtP4lPehGwSD26fJsHTGZYTUGHFwStHrhbu1tyKc
|
||||
hQg/wgviBN0oRsPWcBqMp0jZkHDNUZPq6fmVGXWeX+sx6Cu+iC8BrdQiEzD8DtrJ
|
||||
11n6zDjy3mW64D/8MNCGzESbJ9F9N5162Yd3JWHO2eA9FXvcDg6lY2lBitQECqz1
|
||||
m8/A7QoPnC9uk/LvEnaqmLbZy7+yK/5+wDbW1y6AbIeo7On1UAXymn5zBTKlEkVm
|
||||
Q+Rh9actCRTGKaeLO4ar2i59xZ9OnqZhx9c=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
|
||||
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
|
||||
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
|
||||
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
|
||||
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
|
||||
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
|
||||
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
|
||||
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
|
||||
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
|
||||
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
|
||||
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
|
||||
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
|
||||
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
|
||||
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
|
||||
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
|
||||
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
|
||||
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
|
||||
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
|
||||
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
|
||||
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
|
||||
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
|
||||
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
|
||||
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
|
||||
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
|
||||
nLRbwHOoq7hHwg==
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
|
||||
// testCert is using the following Let's Encrypt chain (DST Root CA X3 is not included):
|
||||
// leaf -> R3 -> ISRG Root X1 -> DST Root CA X3
|
||||
testAltCert := testCert + `-----BEGIN CERTIFICATE-----
|
||||
MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB
|
||||
AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC
|
||||
ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL
|
||||
wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D
|
||||
LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK
|
||||
4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5
|
||||
bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y
|
||||
sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ
|
||||
Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4
|
||||
FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc
|
||||
SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql
|
||||
PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND
|
||||
TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
|
||||
SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1
|
||||
c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx
|
||||
+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB
|
||||
ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu
|
||||
b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E
|
||||
U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu
|
||||
MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC
|
||||
5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW
|
||||
9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG
|
||||
WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O
|
||||
he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC
|
||||
Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5
|
||||
-----END CERTIFICATE-----
|
||||
`
|
||||
|
||||
decodeAll := func(pemBytes []byte) [][]byte {
|
||||
var blocks [][]byte
|
||||
for {
|
||||
block, rest := pem.Decode(pemBytes)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
blocks = append(blocks, block.Bytes)
|
||||
pemBytes = rest
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
|
||||
rawTestCert := decodeAll([]byte(testCert))
|
||||
if _, err := pki.ParseSingleCertificateChainPEM([]byte(testCert)); err != nil {
|
||||
t.Fatalf("error parsing test certificate: %v", err)
|
||||
}
|
||||
|
||||
rawTestAltCert := decodeAll([]byte(testAltCert))
|
||||
if _, err := pki.ParseSingleCertificateChainPEM([]byte(testAltCert)); err != nil {
|
||||
t.Fatalf("error parsing test certificate: %v", err)
|
||||
}
|
||||
|
||||
testOrderPending := gen.OrderFrom(testOrder, gen.SetOrderStatus(pendingStatus))
|
||||
testOrderInvalid := testOrderPending.DeepCopy()
|
||||
testOrderInvalid.Status.State = cmacme.Invalid
|
||||
@ -154,51 +273,13 @@ func TestSync(t *testing.T) {
|
||||
testOrderValid := testOrderPending.DeepCopy()
|
||||
testOrderValid.Status.State = cmacme.Valid
|
||||
// pem encoded word 'test'
|
||||
testOrderValid.Status.Certificate = []byte(`-----BEGIN CERTIFICATE-----
|
||||
dGVzdA==
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
testOrderValid.Status.Certificate = []byte(testCert)
|
||||
testOrderReady := testOrderPending.DeepCopy()
|
||||
testOrderReady.Status.State = cmacme.Ready
|
||||
|
||||
testCert := []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1
|
||||
WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
|
||||
RW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEi
|
||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrX
|
||||
NSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf
|
||||
89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHl
|
||||
Npi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7Dc
|
||||
Gu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgz
|
||||
uEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMB
|
||||
AAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBU
|
||||
BgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIB
|
||||
FiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSo
|
||||
SmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js
|
||||
LnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEF
|
||||
BQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsG
|
||||
AQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYD
|
||||
VR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIB
|
||||
ABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGx
|
||||
A/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRM
|
||||
UM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2
|
||||
DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1
|
||||
eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOu
|
||||
OsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vw
|
||||
p7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY
|
||||
2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0
|
||||
ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKR
|
||||
PB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5b
|
||||
rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
rawTestCert, _ := pem.Decode(testCert)
|
||||
|
||||
testOrderValidAltCert := gen.OrderFrom(testOrder, gen.SetOrderStatus(pendingStatus))
|
||||
testOrderValidAltCert.Status.State = cmacme.Valid
|
||||
testOrderValidAltCert.Status.Certificate = testCert
|
||||
testOrderValidAltCert.Status.Certificate = []byte(testAltCert)
|
||||
|
||||
fakeHTTP01ACMECl := &acmecl.FakeACME{
|
||||
FakeHTTP01ChallengeResponse: func(s string) (string, error) {
|
||||
@ -251,6 +332,7 @@ rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt
|
||||
testACMEOrderValid := &acmeapi.Order{}
|
||||
*testACMEOrderValid = *testACMEOrderPending
|
||||
testACMEOrderValid.Status = acmeapi.StatusValid
|
||||
testACMEOrderValid.CertURL = "http://testurl"
|
||||
// shallow copy
|
||||
testACMEOrderReady := &acmeapi.Order{}
|
||||
*testACMEOrderReady = *testACMEOrderPending
|
||||
@ -540,8 +622,7 @@ rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt
|
||||
return testACMEOrderValid, nil
|
||||
},
|
||||
FakeCreateOrderCert: func(_ context.Context, url string, csr []byte, bundle bool) ([][]byte, string, error) {
|
||||
testData := []byte("test")
|
||||
return [][]byte{testData}, "http://testurl", nil
|
||||
return rawTestCert, testACMEOrderValid.CertURL, nil
|
||||
},
|
||||
FakeHTTP01ChallengeResponse: func(s string) (string, error) {
|
||||
// TODO: assert s = "token"
|
||||
@ -617,7 +698,13 @@ rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt
|
||||
return "key", nil
|
||||
},
|
||||
FakeFetchCert: func(_ context.Context, url string, bundle bool) ([][]byte, error) {
|
||||
return [][]byte{[]byte("test")}, nil
|
||||
if url != testACMEOrderValid.CertURL {
|
||||
return nil, errors.New("Cert URL is incorrect")
|
||||
}
|
||||
if !bundle {
|
||||
return nil, errors.New("Expecting to be called with bundle=true")
|
||||
}
|
||||
return rawTestCert, nil
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
@ -647,24 +734,22 @@ rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt
|
||||
return "key", nil
|
||||
},
|
||||
FakeListCertAlternates: func(_ context.Context, url string) ([]string, error) {
|
||||
if url != testACMEOrderValid.CertURL {
|
||||
return nil, errors.New("Cert URL is incorrect")
|
||||
}
|
||||
return []string{"http://alturl"}, nil
|
||||
|
||||
},
|
||||
FakeFetchCert: func(_ context.Context, url string, bundle bool) ([][]byte, error) {
|
||||
if url != "http://alturl" {
|
||||
// This bit just ensures that we
|
||||
// call it from the correct
|
||||
// place. This is the same URL
|
||||
// that is returned from
|
||||
// FakeCertAlternates that
|
||||
// should have been called
|
||||
// before this.
|
||||
if url != testACMEOrderValid.CertURL && url != "http://alturl" {
|
||||
return nil, errors.New("Cert URL is incorrect")
|
||||
}
|
||||
if !bundle {
|
||||
return nil, errors.New("Expecting to be called with bundle=true")
|
||||
}
|
||||
return [][]byte{rawTestCert.Bytes}, nil
|
||||
if url == testACMEOrderValid.CertURL {
|
||||
return rawTestCert, nil
|
||||
}
|
||||
return rawTestAltCert, nil
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
@ -687,11 +772,10 @@ rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt
|
||||
return testACMEOrderValid, nil
|
||||
},
|
||||
FakeCreateOrderCert: func(_ context.Context, url string, csr []byte, bundle bool) ([][]byte, string, error) {
|
||||
testData := []byte("test")
|
||||
return [][]byte{testData}, "http://testurl", nil
|
||||
return rawTestCert, testACMEOrderValid.CertURL, nil
|
||||
},
|
||||
FakeListCertAlternates: func(_ context.Context, url string) ([]string, error) {
|
||||
if url != "http://testurl" {
|
||||
if url != testACMEOrderValid.CertURL {
|
||||
return nil, errors.New("Cert URL is incorrect")
|
||||
}
|
||||
return []string{"http://alturl"}, nil
|
||||
@ -699,19 +783,47 @@ rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt
|
||||
},
|
||||
FakeFetchCert: func(_ context.Context, url string, bundle bool) ([][]byte, error) {
|
||||
if url != "http://alturl" {
|
||||
// This bit just ensures that we
|
||||
// call it from the correct
|
||||
// place. This is the same URL
|
||||
// that is returned from
|
||||
// FakeCertAlternates that
|
||||
// should have been called
|
||||
// before this.
|
||||
return nil, errors.New("Cert URL is incorrect")
|
||||
return nil, errors.New("Cert URL is incorrect: expected http://alturl got " + url)
|
||||
}
|
||||
if !bundle {
|
||||
return nil, errors.New("Expecting to be called with bundle=true")
|
||||
}
|
||||
return [][]byte{rawTestCert.Bytes}, nil
|
||||
return rawTestAltCert, nil
|
||||
},
|
||||
FakeHTTP01ChallengeResponse: func(s string) (string, error) {
|
||||
// TODO: assert s = "token"
|
||||
return "key", nil
|
||||
},
|
||||
},
|
||||
},
|
||||
"preferred chain is default cert chain": {
|
||||
order: testOrderReady.DeepCopy(),
|
||||
builder: &testpkg.Builder{
|
||||
CertManagerObjects: []runtime.Object{
|
||||
gen.IssuerFrom(testIssuerHTTP01TestComPreferredChain, gen.SetIssuerACMEPreferredChain("ISRG Root X1")),
|
||||
testOrderReady, testAuthorizationChallengeValid,
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateSubresourceAction(cmacme.SchemeGroupVersion.WithResource("orders"),
|
||||
"status",
|
||||
testOrderValid.Namespace, testOrderValid)),
|
||||
},
|
||||
ExpectedEvents: []string{
|
||||
"Normal Complete Order completed successfully",
|
||||
},
|
||||
},
|
||||
acmeClient: &acmecl.FakeACME{
|
||||
FakeGetOrder: func(_ context.Context, url string) (*acmeapi.Order, error) {
|
||||
return testACMEOrderValid, nil
|
||||
},
|
||||
FakeCreateOrderCert: func(_ context.Context, url string, csr []byte, bundle bool) ([][]byte, string, error) {
|
||||
return rawTestCert, testACMEOrderValid.CertURL, nil
|
||||
},
|
||||
FakeListCertAlternates: func(_ context.Context, url string) ([]string, error) {
|
||||
return nil, errors.New("should not be called")
|
||||
},
|
||||
FakeFetchCert: func(_ context.Context, url string, bundle bool) ([][]byte, error) {
|
||||
return nil, errors.New("should not be called")
|
||||
},
|
||||
FakeHTTP01ChallengeResponse: func(s string) (string, error) {
|
||||
// TODO: assert s = "token"
|
||||
|
||||
@ -95,6 +95,16 @@ func SetIssuerACME(a cmacme.ACMEIssuer) IssuerModifier {
|
||||
}
|
||||
}
|
||||
|
||||
func SetIssuerACMEPreferredChain(chain string) IssuerModifier {
|
||||
return func(iss v1.GenericIssuer) {
|
||||
spec := iss.GetSpec()
|
||||
if spec.ACME == nil {
|
||||
spec.ACME = &cmacme.ACMEIssuer{}
|
||||
}
|
||||
spec.ACME.PreferredChain = chain
|
||||
}
|
||||
}
|
||||
|
||||
func SetIssuerACMEURL(url string) IssuerModifier {
|
||||
return func(iss v1.GenericIssuer) {
|
||||
spec := iss.GetSpec()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user