From 789be70516b782d3b09bfa04b4c49fcebb8cf621 Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 14:09:48 +0200 Subject: [PATCH 01/13] chore: added raw subject to certificate ObtainRequest --- certcrypto/crypto.go | 22 ++++++++++++++++------ certificate/certificates.go | 2 ++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/certcrypto/crypto.go b/certcrypto/crypto.go index 059c043e419..5301d72e34c 100644 --- a/certcrypto/crypto.go +++ b/certcrypto/crypto.go @@ -153,6 +153,7 @@ type CSROptions struct { MustStaple bool EmailAddresses []string Subject pkix.Name + RawSubject []byte } func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) { @@ -170,12 +171,21 @@ func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) { } opts.Subject.CommonName = opts.Domain - - template := x509.CertificateRequest{ - Subject: opts.Subject, - DNSNames: dnsNames, - EmailAddresses: opts.EmailAddresses, - IPAddresses: ipAddresses, + var template x509.CertificateRequest + if len(opts.RawSubject) > 0 { + template = x509.CertificateRequest{ + RawSubject: opts.RawSubject, + DNSNames: dnsNames, + EmailAddresses: opts.EmailAddresses, + IPAddresses: ipAddresses, + } + } else { + template = x509.CertificateRequest{ + Subject: opts.Subject, + DNSNames: dnsNames, + EmailAddresses: opts.EmailAddresses, + IPAddresses: ipAddresses, + } } if opts.MustStaple { diff --git a/certificate/certificates.go b/certificate/certificates.go index 299430b0a26..e298b8b2bca 100644 --- a/certificate/certificates.go +++ b/certificate/certificates.go @@ -69,6 +69,7 @@ type Resource struct { type ObtainRequest struct { Domains []string Subject pkix.Name + RawSubject []byte PrivateKey crypto.PrivateKey MustStaple bool EmailAddresses []string @@ -335,6 +336,7 @@ func (c *Certifier) getForOrder(domains []string, order acme.ExtendedOrder, requ MustStaple: request.MustStaple, EmailAddresses: request.EmailAddresses, Subject: request.Subject, + RawSubject: request.RawSubject, } csr, err := certcrypto.CreateCSR(privateKey, csrOptions) From 5dba1c55aae9db7866bd74b91527caa88498a3de Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 14:19:43 +0200 Subject: [PATCH 02/13] chore: add cn to raw subject for enrollment to succede --- certcrypto/crypto.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/certcrypto/crypto.go b/certcrypto/crypto.go index 5301d72e34c..1d36b37f491 100644 --- a/certcrypto/crypto.go +++ b/certcrypto/crypto.go @@ -169,10 +169,20 @@ func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) { dnsNames = append(dnsNames, altname) } } - opts.Subject.CommonName = opts.Domain var template x509.CertificateRequest if len(opts.RawSubject) > 0 { + // add the CommonName to the raw subject + if opts.Subject.CommonName != "" { + commonNameRDN := pkix.RelativeDistinguishedNameSET{ + {Type: asn1.ObjectIdentifier{2, 5, 4, 3}, Value: opts.Subject.CommonName}, + } + rawSubjectWithCN, err := asn1.Marshal([]pkix.RelativeDistinguishedNameSET{commonNameRDN}) + if err != nil { + return nil, fmt.Errorf("failed to marshal CommonName into raw subject: %w", err) + } + opts.RawSubject = append(opts.RawSubject, rawSubjectWithCN...) + } template = x509.CertificateRequest{ RawSubject: opts.RawSubject, DNSNames: dnsNames, From c0f21bee3300e258f86a7ef45cd5b46336c312c6 Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 14:22:25 +0200 Subject: [PATCH 03/13] chore: add cn to raw subject for enrollment to succede --- certcrypto/crypto.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/certcrypto/crypto.go b/certcrypto/crypto.go index 1d36b37f491..a716ffcaee4 100644 --- a/certcrypto/crypto.go +++ b/certcrypto/crypto.go @@ -169,21 +169,14 @@ func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) { dnsNames = append(dnsNames, altname) } } + opts.Subject.CommonName = opts.Domain var template x509.CertificateRequest if len(opts.RawSubject) > 0 { - // add the CommonName to the raw subject - if opts.Subject.CommonName != "" { - commonNameRDN := pkix.RelativeDistinguishedNameSET{ - {Type: asn1.ObjectIdentifier{2, 5, 4, 3}, Value: opts.Subject.CommonName}, - } - rawSubjectWithCN, err := asn1.Marshal([]pkix.RelativeDistinguishedNameSET{commonNameRDN}) - if err != nil { - return nil, fmt.Errorf("failed to marshal CommonName into raw subject: %w", err) - } - opts.RawSubject = append(opts.RawSubject, rawSubjectWithCN...) - } template = x509.CertificateRequest{ + Subject: pkix.Name{ + CommonName: opts.Domain, + }, RawSubject: opts.RawSubject, DNSNames: dnsNames, EmailAddresses: opts.EmailAddresses, From 3f6a0d706ac3620f07a1b57ac55ad8c78ba472cd Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 14:29:57 +0200 Subject: [PATCH 04/13] chore: new method to add cn to rawSubject --- certcrypto/crypto.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/certcrypto/crypto.go b/certcrypto/crypto.go index a716ffcaee4..c0a71dc6a67 100644 --- a/certcrypto/crypto.go +++ b/certcrypto/crypto.go @@ -170,19 +170,16 @@ func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) { } } - opts.Subject.CommonName = opts.Domain var template x509.CertificateRequest if len(opts.RawSubject) > 0 { template = x509.CertificateRequest{ - Subject: pkix.Name{ - CommonName: opts.Domain, - }, RawSubject: opts.RawSubject, DNSNames: dnsNames, EmailAddresses: opts.EmailAddresses, IPAddresses: ipAddresses, } } else { + opts.Subject.CommonName = opts.Domain template = x509.CertificateRequest{ Subject: opts.Subject, DNSNames: dnsNames, From 64e7765ef0c1fe9082570325da294dfaf696604d Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 14:30:03 +0200 Subject: [PATCH 05/13] chore: new method to add cn to rawSubject --- certcrypto/crypto.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/certcrypto/crypto.go b/certcrypto/crypto.go index c0a71dc6a67..c892e8bfb37 100644 --- a/certcrypto/crypto.go +++ b/certcrypto/crypto.go @@ -172,6 +172,21 @@ func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) { var template x509.CertificateRequest if len(opts.RawSubject) > 0 { + // unmarshal the raw subject into a rdn sequence, to ensure that the subject is still in order and add the cn + var rdnSequence pkix.RDNSequence + _, err := asn1.Unmarshal(opts.RawSubject, &rdnSequence) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal raw subject: %w", err) + } + // add the common name as the last rdn, to ensure that it is in the right order + if opts.Domain != "" { + opts.RawSubject, err = asn1.Marshal(append(rdnSequence, pkix.RelativeDistinguishedNameSET{ + {Type: []int{2, 5, 4, 3}, Value: opts.Domain}, + })) + if err != nil { + return nil, fmt.Errorf("failed to marshal raw subject with common name: %w", err) + } + } template = x509.CertificateRequest{ RawSubject: opts.RawSubject, DNSNames: dnsNames, From 880dca5c7e389680204f39f27a7662824319b833 Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 14:38:18 +0200 Subject: [PATCH 06/13] chore: prepend to avoid first CN to not be the domain --- certcrypto/crypto.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/certcrypto/crypto.go b/certcrypto/crypto.go index c892e8bfb37..001cf42b578 100644 --- a/certcrypto/crypto.go +++ b/certcrypto/crypto.go @@ -180,13 +180,17 @@ func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) { } // add the common name as the last rdn, to ensure that it is in the right order if opts.Domain != "" { - opts.RawSubject, err = asn1.Marshal(append(rdnSequence, pkix.RelativeDistinguishedNameSET{ - {Type: []int{2, 5, 4, 3}, Value: opts.Domain}, - })) + opts.RawSubject, err = asn1.Marshal(append( + pkix.RDNSequence{ + {{Type: []int{2, 5, 4, 3}, Value: opts.Domain}}, + }, + rdnSequence..., + )) if err != nil { return nil, fmt.Errorf("failed to marshal raw subject with common name: %w", err) } } + template = x509.CertificateRequest{ RawSubject: opts.RawSubject, DNSNames: dnsNames, From 8f1ac45d53f5ca8d912a1f40aa00363c69a757cd Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 14:46:06 +0200 Subject: [PATCH 07/13] chore: conform to linter --- certcrypto/crypto.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certcrypto/crypto.go b/certcrypto/crypto.go index 001cf42b578..3e7fe1fab18 100644 --- a/certcrypto/crypto.go +++ b/certcrypto/crypto.go @@ -171,9 +171,11 @@ func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) { } var template x509.CertificateRequest + if len(opts.RawSubject) > 0 { // unmarshal the raw subject into a rdn sequence, to ensure that the subject is still in order and add the cn var rdnSequence pkix.RDNSequence + _, err := asn1.Unmarshal(opts.RawSubject, &rdnSequence) if err != nil { return nil, fmt.Errorf("failed to unmarshal raw subject: %w", err) From d9baed6bf0c18255a0a72caffd60371977f3f900 Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 14:57:15 +0200 Subject: [PATCH 08/13] chore: revert to old behaviour without cn adding --- certcrypto/crypto.go | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/certcrypto/crypto.go b/certcrypto/crypto.go index 3e7fe1fab18..c0a71dc6a67 100644 --- a/certcrypto/crypto.go +++ b/certcrypto/crypto.go @@ -171,28 +171,7 @@ func CreateCSR(privateKey crypto.PrivateKey, opts CSROptions) ([]byte, error) { } var template x509.CertificateRequest - if len(opts.RawSubject) > 0 { - // unmarshal the raw subject into a rdn sequence, to ensure that the subject is still in order and add the cn - var rdnSequence pkix.RDNSequence - - _, err := asn1.Unmarshal(opts.RawSubject, &rdnSequence) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal raw subject: %w", err) - } - // add the common name as the last rdn, to ensure that it is in the right order - if opts.Domain != "" { - opts.RawSubject, err = asn1.Marshal(append( - pkix.RDNSequence{ - {{Type: []int{2, 5, 4, 3}, Value: opts.Domain}}, - }, - rdnSequence..., - )) - if err != nil { - return nil, fmt.Errorf("failed to marshal raw subject with common name: %w", err) - } - } - template = x509.CertificateRequest{ RawSubject: opts.RawSubject, DNSNames: dnsNames, From a61ebb8f759eb20edcec3b1a26e0dc556ab76db2 Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 15:06:13 +0200 Subject: [PATCH 09/13] chore: conform to linter --- acme/api/internal/sender/sender.go | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/acme/api/internal/sender/sender.go b/acme/api/internal/sender/sender.go index f8f7ef4815b..25051e402f3 100644 --- a/acme/api/internal/sender/sender.go +++ b/acme/api/internal/sender/sender.go @@ -29,7 +29,6 @@ type Doer struct { func NewDoer(client *http.Client, userAgent string) *Doer { // EVT: disable HTTPS only to ensure no compatibility issues // client.Transport = newHTTPSOnly(client) - return &Doer{ httpClient: client, userAgent: userAgent, @@ -162,28 +161,3 @@ func checkError(req *http.Request, resp *http.Response) error { return errorDetails } } - -type httpsOnly struct { - rt http.RoundTripper -} - -func newHTTPSOnly(client *http.Client) *httpsOnly { - if client.Transport == nil { - return &httpsOnly{rt: http.DefaultTransport} - } - - return &httpsOnly{rt: client.Transport} -} - -// RoundTrip ensure HTTPS is used. -// Each ACME function is accomplished by the client sending a sequence of HTTPS requests to the server [RFC2818], -// carrying JSON messages [RFC8259]. -// Use of HTTPS is REQUIRED. -// https://datatracker.ietf.org/doc/html/rfc8555#section-6.1 -func (r *httpsOnly) RoundTrip(req *http.Request) (*http.Response, error) { - if req.URL.Scheme != "https" { - return nil, fmt.Errorf("HTTPS is required: %s", req.URL) - } - - return r.rt.RoundTrip(req) -} From cec7e90ac73098d602b39534afde760ca3dea5a3 Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 15:11:29 +0200 Subject: [PATCH 10/13] test: remove unsecesary test --- acme/api/internal/sender/sender_test.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/acme/api/internal/sender/sender_test.go b/acme/api/internal/sender/sender_test.go index e07b3658349..bf0c384c8c2 100644 --- a/acme/api/internal/sender/sender_test.go +++ b/acme/api/internal/sender/sender_test.go @@ -72,16 +72,6 @@ func TestDo_CustomUserAgent(t *testing.T) { assert.Len(t, strings.Split(ua, " "), 5) } -func TestDo_failWithHTTP(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {})) - t.Cleanup(server.Close) - - sender := NewDoer(server.Client(), "test") - - _, err := sender.Post(server.URL, strings.NewReader("data"), "text/plain", nil) - require.ErrorContains(t, err, "HTTPS is required: http://") -} - func Test_checkError(t *testing.T) { testCases := []struct { desc string From e0561e4c2f64aa3d87b83eeb41ca52e112e2e1c7 Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 15:49:44 +0200 Subject: [PATCH 11/13] test: added test on obtain with subject and raw subject --- certificate/certificates_test.go | 78 ++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/certificate/certificates_test.go b/certificate/certificates_test.go index 01839ce2d19..8ea1a543ea3 100644 --- a/certificate/certificates_test.go +++ b/certificate/certificates_test.go @@ -3,6 +3,8 @@ package certificate import ( "crypto/rand" "crypto/rsa" + "crypto/x509/pkix" + "encoding/asn1" "fmt" "net/http" "testing" @@ -174,6 +176,82 @@ Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- ` +func Test_Obtain(t *testing.T) { + server := tester.MockACMEServer(). + Route("POST /newOrder", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + serverURL := fmt.Sprintf("https://%s", req.Context().Value(http.LocalAddrContextKey)) + + rw.Header().Set("Location", serverURL+"/order/1") + servermock.JSONEncode(acme.Order{ + Status: acme.StatusPending, + Identifiers: []acme.Identifier{{Type: "dns", Value: "example.com"}}, + Finalize: serverURL + "/finalize/1", + }).ServeHTTP(rw, req) + })). + Route("POST /finalize/1", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + serverURL := fmt.Sprintf("https://%s", req.Context().Value(http.LocalAddrContextKey)) + + servermock.JSONEncode(acme.Order{ + Status: acme.StatusValid, + Certificate: serverURL + "/certificate", + }).ServeHTTP(rw, req) + })). + Route("POST /certificate", servermock.RawStringResponse(certResponseMock)). + BuildHTTPS(t) + + key, err := rsa.GenerateKey(rand.Reader, 2048) + require.NoError(t, err, "Could not generate test key") + + core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key) + require.NoError(t, err) + + certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048}) + + request := ObtainRequest{ + Domains: []string{"example.com"}, + Subject: pkix.Name{ + CommonName: "example.com", + }, + Bundle: false, + } + + certRes, err := certifier.Obtain(request) + require.NoError(t, err) + assert.NotNil(t, certRes) + assert.Equal(t, "example.com", certRes.Domain) + assert.Contains(t, certRes.CertStableURL, "/certificate") + assert.Contains(t, certRes.CertURL, "/certificate") + assert.Nil(t, certRes.CSR) + assert.NotEmpty(t, certRes.PrivateKey) + assert.Equal(t, certResponseNoBundleMock, string(certRes.Certificate), "Certificate") + assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate") + + var rdns pkix.RDNSequence + rdns = append(rdns, []pkix.AttributeTypeAndValue{{ + Type: []int{2, 5, 4, 3}, + Value: "example.com", + }}) + rawSubject, err := asn1.Marshal(rdns) + require.NoError(t, err, "Could not marshal subject") + // test with raw subject too + request = ObtainRequest{ + Domains: []string{"example.com"}, + RawSubject: rawSubject, + Bundle: false, + } + + certRes, err = certifier.Obtain(request) + require.NoError(t, err) + assert.NotNil(t, certRes) + assert.Equal(t, "example.com", certRes.Domain) + assert.Contains(t, certRes.CertStableURL, "/certificate") + assert.Contains(t, certRes.CertURL, "/certificate") + assert.Nil(t, certRes.CSR) + assert.NotEmpty(t, certRes.PrivateKey) + assert.Equal(t, certResponseNoBundleMock, string(certRes.Certificate), "Certificate") + assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate") +} + func Test_checkResponse(t *testing.T) { server := tester.MockACMEServer(). Route("POST /certificate", servermock.RawStringResponse(certResponseMock)). From 86ecd0fb4e5211f123ab751cd2802afcb89665d1 Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 15:53:04 +0200 Subject: [PATCH 12/13] test: confrom to linters --- certificate/certificates_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/certificate/certificates_test.go b/certificate/certificates_test.go index 8ea1a543ea3..0b0d5b99386 100644 --- a/certificate/certificates_test.go +++ b/certificate/certificates_test.go @@ -227,6 +227,7 @@ func Test_Obtain(t *testing.T) { assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate") var rdns pkix.RDNSequence + rdns = append(rdns, []pkix.AttributeTypeAndValue{{ Type: []int{2, 5, 4, 3}, Value: "example.com", From 6936f034693c7ee4e971f92e91071354ef237621 Mon Sep 17 00:00:00 2001 From: Luca Morgado Date: Tue, 31 Mar 2026 16:21:11 +0200 Subject: [PATCH 13/13] test: move test --- certcrypto/crypto_test.go | 26 +++++++++++ certificate/certificates_test.go | 79 -------------------------------- 2 files changed, 26 insertions(+), 79 deletions(-) diff --git a/certcrypto/crypto_test.go b/certcrypto/crypto_test.go index 6959f44eb65..b3693b43d03 100644 --- a/certcrypto/crypto_test.go +++ b/certcrypto/crypto_test.go @@ -6,6 +6,7 @@ import ( "crypto/rand" "crypto/rsa" "crypto/x509/pkix" + "encoding/asn1" "encoding/pem" "testing" "time" @@ -32,6 +33,20 @@ func TestGenerateCSR(t *testing.T) { privateKey, err := rsa.GenerateKey(rand.Reader, 1024) require.NoError(t, err, "Error generating private key") + var rdns pkix.RDNSequence + + rdns = append(rdns, pkix.RDNSequence{ + {{Type: []int{2, 5, 4, 3}, Value: "example.com"}}, + }...) + rdns = append(rdns, pkix.RDNSequence{ + {{Type: []int{2, 5, 4, 6}, Value: "FR"}}, + }...) + rdns = append(rdns, pkix.RDNSequence{ + {{Type: []int{2, 5, 4, 10}, Value: "EVERTRUST"}}, + }...) + rawSubject, err := asn1.Marshal(rdns) + require.NoError(t, err, "Error marshaling raw subject") + type expected struct { len int error bool @@ -124,6 +139,17 @@ func TestGenerateCSR(t *testing.T) { }, expected: expected{len: 454}, }, + { + desc: "with raw subject", + privateKey: privateKey, + opts: CSROptions{ + Domain: "example.com", + SAN: []string{"example.org"}, + EmailAddresses: []string{"foo@example.com", "bar@example.com"}, + RawSubject: rawSubject, + }, + expected: expected{len: 454}, + }, } for _, test := range testCases { diff --git a/certificate/certificates_test.go b/certificate/certificates_test.go index 0b0d5b99386..01839ce2d19 100644 --- a/certificate/certificates_test.go +++ b/certificate/certificates_test.go @@ -3,8 +3,6 @@ package certificate import ( "crypto/rand" "crypto/rsa" - "crypto/x509/pkix" - "encoding/asn1" "fmt" "net/http" "testing" @@ -176,83 +174,6 @@ Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- ` -func Test_Obtain(t *testing.T) { - server := tester.MockACMEServer(). - Route("POST /newOrder", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - serverURL := fmt.Sprintf("https://%s", req.Context().Value(http.LocalAddrContextKey)) - - rw.Header().Set("Location", serverURL+"/order/1") - servermock.JSONEncode(acme.Order{ - Status: acme.StatusPending, - Identifiers: []acme.Identifier{{Type: "dns", Value: "example.com"}}, - Finalize: serverURL + "/finalize/1", - }).ServeHTTP(rw, req) - })). - Route("POST /finalize/1", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - serverURL := fmt.Sprintf("https://%s", req.Context().Value(http.LocalAddrContextKey)) - - servermock.JSONEncode(acme.Order{ - Status: acme.StatusValid, - Certificate: serverURL + "/certificate", - }).ServeHTTP(rw, req) - })). - Route("POST /certificate", servermock.RawStringResponse(certResponseMock)). - BuildHTTPS(t) - - key, err := rsa.GenerateKey(rand.Reader, 2048) - require.NoError(t, err, "Could not generate test key") - - core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key) - require.NoError(t, err) - - certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048}) - - request := ObtainRequest{ - Domains: []string{"example.com"}, - Subject: pkix.Name{ - CommonName: "example.com", - }, - Bundle: false, - } - - certRes, err := certifier.Obtain(request) - require.NoError(t, err) - assert.NotNil(t, certRes) - assert.Equal(t, "example.com", certRes.Domain) - assert.Contains(t, certRes.CertStableURL, "/certificate") - assert.Contains(t, certRes.CertURL, "/certificate") - assert.Nil(t, certRes.CSR) - assert.NotEmpty(t, certRes.PrivateKey) - assert.Equal(t, certResponseNoBundleMock, string(certRes.Certificate), "Certificate") - assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate") - - var rdns pkix.RDNSequence - - rdns = append(rdns, []pkix.AttributeTypeAndValue{{ - Type: []int{2, 5, 4, 3}, - Value: "example.com", - }}) - rawSubject, err := asn1.Marshal(rdns) - require.NoError(t, err, "Could not marshal subject") - // test with raw subject too - request = ObtainRequest{ - Domains: []string{"example.com"}, - RawSubject: rawSubject, - Bundle: false, - } - - certRes, err = certifier.Obtain(request) - require.NoError(t, err) - assert.NotNil(t, certRes) - assert.Equal(t, "example.com", certRes.Domain) - assert.Contains(t, certRes.CertStableURL, "/certificate") - assert.Contains(t, certRes.CertURL, "/certificate") - assert.Nil(t, certRes.CSR) - assert.NotEmpty(t, certRes.PrivateKey) - assert.Equal(t, certResponseNoBundleMock, string(certRes.Certificate), "Certificate") - assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate") -} - func Test_checkResponse(t *testing.T) { server := tester.MockACMEServer(). Route("POST /certificate", servermock.RawStringResponse(certResponseMock)).