diff --git a/.golangci.yml b/.golangci.yml index 238e99ef1..17e75c798 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -211,7 +211,7 @@ linters: text: Logger is a global variable linters: - gochecknoglobals - - path: e2e/(dnschallenge/)?[\d\w]+_test.go + - path: e2e/(dnschallenge/|eab/)?[\d\w]+_test.go text: load is a global variable linters: - gochecknoglobals diff --git a/e2e/eab/eab_test.go b/e2e/eab/eab_test.go new file mode 100644 index 000000000..0710a7b06 --- /dev/null +++ b/e2e/eab/eab_test.go @@ -0,0 +1,123 @@ +package eab + +import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "os" + "testing" + + "github.com/go-acme/lego/v5/acme" + "github.com/go-acme/lego/v5/certificate" + "github.com/go-acme/lego/v5/challenge/http01" + "github.com/go-acme/lego/v5/e2e/loader" + "github.com/go-acme/lego/v5/lego" + "github.com/go-acme/lego/v5/registration" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + testDomain1 = "acme.localhost" +) + +const ( + testEmail1 = "lego@example.com" +) + +const caDirectory = "https://localhost:16000/dir" + +var load = loader.EnvLoader{ + PebbleOptions: &loader.CmdOption{ + HealthCheckURL: caDirectory, + Args: []string{"-strict", "-config", "fixtures/pebble-config-eab.json"}, + Env: []string{"PEBBLE_VA_NOSLEEP=1", "PEBBLE_WFE_NONCEREJECT=20"}, + Dir: "../", + }, + LegoOptions: []string{ + "LEGO_CA_CERTIFICATES=../fixtures/certs/pebble.minica.pem", + "LEGO_DEBUG_ACME_HTTP_CLIENT=1", + }, +} + +func TestMain(m *testing.M) { + os.Exit(load.MainTest(context.Background(), m)) +} + +func TestChallengeHTTP_Run_EAB(t *testing.T) { + loader.CleanLegoFiles(t.Context()) + + err := load.RunLego(t.Context(), + "run", + "-m", testEmail1, + "--accept-tos", + "-s", caDirectory, + "-d", testDomain1, + "--http", + "--http.port", ":5006", + "--eab", + "--eab.kid", "kid-3", + "--eab.hmac", "HjudV5qnbreN-n9WyFSH-t4HXuEx_XFen45zuxY-G1h6fr74V3cUM_dVlwQZBWmc", + ) + if err != nil { + t.Fatal(err) + } +} + +func TestChallengeHTTP_Client_Obtain_EAB(t *testing.T) { + t.Setenv("LEGO_CA_CERTIFICATES", "../fixtures/certs/pebble.minica.pem") + + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + require.NoError(t, err, "Could not generate test key") + + user := &fakeUser{privateKey: privateKey} + config := lego.NewConfig(user) + config.CADirURL = load.PebbleOptions.HealthCheckURL + + client, err := lego.NewClient(config) + require.NoError(t, err) + + err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", "5006")) + require.NoError(t, err) + + ctx := t.Context() + + options := registration.RegisterEABOptions{ + TermsOfServiceAgreed: true, + Kid: "kid-3", + HmacEncoded: "HjudV5qnbreN-n9WyFSH-t4HXuEx_XFen45zuxY-G1h6fr74V3cUM_dVlwQZBWmc", + } + + reg, err := client.Registration.RegisterWithExternalAccountBinding(ctx, options) + require.NoError(t, err) + + user.registration = reg + + request := certificate.ObtainRequest{ + Domains: []string{testDomain1}, + Bundle: true, + } + + resource, err := client.Certificate.Obtain(ctx, request) + require.NoError(t, err) + + require.NotNil(t, resource) + assert.Equal(t, testDomain1, resource.ID) + assert.Equal(t, []string{testDomain1}, resource.Domains) + assert.Regexp(t, `https://localhost:16000/certZ/[\w\d]{14,}`, resource.CertURL) + assert.Regexp(t, `https://localhost:16000/certZ/[\w\d]{14,}`, resource.CertStableURL) + assert.NotEmpty(t, resource.Certificate) + assert.NotEmpty(t, resource.IssuerCertificate) + assert.Empty(t, resource.CSR) +} + +type fakeUser struct { + email string + privateKey crypto.PrivateKey + registration *acme.ExtendedAccount +} + +func (f *fakeUser) GetEmail() string { return f.email } +func (f *fakeUser) GetRegistration() *acme.ExtendedAccount { return f.registration } +func (f *fakeUser) GetPrivateKey() crypto.PrivateKey { return f.privateKey } diff --git a/e2e/fixtures/pebble-config-eab.json b/e2e/fixtures/pebble-config-eab.json new file mode 100644 index 000000000..3fb8e1973 --- /dev/null +++ b/e2e/fixtures/pebble-config-eab.json @@ -0,0 +1,25 @@ +{ + "pebble": { + "listenAddress": "0.0.0.0:16000", + "certificate": "fixtures/certs/localhost/cert.pem", + "privateKey": "fixtures/certs/localhost/key.pem", + "httpPort": 5006, + "tlsPort": 5005, + "externalAccountBindingRequired": true, + "externalAccountMACKeys": { + "kid-1": "zWNDZM6eQGHWpSRTPal5eIUYFTu7EajVIoguysqZ9wG44nMEtx3MUAsUDkMTQ12W", + "kid-2": "b10lLJs8l1GPIzsLP0s6pMt8O0XVGnfTaCeROxQM0BIt2XrJMDHJZBM5NuQmQJQH", + "kid-3": "HjudV5qnbreN-n9WyFSH-t4HXuEx_XFen45zuxY-G1h6fr74V3cUM_dVlwQZBWmc" + }, + "profiles": { + "default": { + "description": "The profile you know and love", + "validityPeriod": 7776000 + }, + "shortlived": { + "description": "A short-lived cert profile, without actual enforcement", + "validityPeriod": 518400 + } + } + } +}