diff --git a/test/integration/scep/common_test.go b/test/integration/scep/common_test.go index ca430cf5..d8c0bba1 100644 --- a/test/integration/scep/common_test.go +++ b/test/integration/scep/common_test.go @@ -2,6 +2,7 @@ package sceptest import ( "context" + "crypto" "crypto/rand" "crypto/rsa" "crypto/sha1" @@ -10,6 +11,7 @@ import ( "crypto/x509/pkix" "encoding/asn1" "encoding/base64" + "encoding/json" "errors" "fmt" "io" @@ -17,6 +19,7 @@ import ( "net" "net/http" "net/url" + "path/filepath" "testing" "time" @@ -25,14 +28,19 @@ import ( "github.com/smallstep/pkcs7" "github.com/smallstep/scep" + "go.step.sm/crypto/keyutil" "go.step.sm/crypto/minica" + "go.step.sm/crypto/pemutil" "go.step.sm/crypto/x509util" + "github.com/smallstep/certificates/authority/config" + "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/ca" "github.com/smallstep/certificates/cas/apiv1" ) func newCAClient(t *testing.T, caURL, rootFilepath string) *ca.Client { + t.Helper() caClient, err := ca.NewClient( caURL, ca.WithRootFile(rootFilepath), @@ -72,6 +80,86 @@ func reservePort(t *testing.T) (host, port string) { return } +type testCA struct { + ca *ca.CA + caURL string + rootFilepath string + root *x509.Certificate +} + +func (t *testCA) run() error { + return t.ca.Run() +} + +func (t *testCA) stop() error { + return t.ca.Stop() +} + +func newTestCA(t *testing.T, name string) *testCA { + t.Helper() + + signer, err := keyutil.GenerateSigner("RSA", "", 2048) + require.NoError(t, err) + + dir := t.TempDir() + m, err := minica.New(minica.WithName(name), minica.WithGetSignerFunc(func() (crypto.Signer, error) { + return signer, nil + })) + require.NoError(t, err) + + rootFilepath := filepath.Join(dir, "root.crt") + _, err = pemutil.Serialize(m.Root, pemutil.WithFilename(rootFilepath)) + require.NoError(t, err) + + intermediateCertFilepath := filepath.Join(dir, "intermediate.crt") + _, err = pemutil.Serialize(m.Intermediate, pemutil.WithFilename(intermediateCertFilepath)) + require.NoError(t, err) + + intermediateKeyFilepath := filepath.Join(dir, "intermediate.key") + _, err = pemutil.Serialize(m.Signer, pemutil.WithFilename(intermediateKeyFilepath)) + require.NoError(t, err) + + // get a random address to listen on and connect to; currently no nicer way to get one before starting the server + host, port := reservePort(t) + + prov := &provisioner.SCEP{ + ID: "scep", + Name: "scep", + Type: "SCEP", + ForceCN: false, + ChallengePassword: "", + EncryptionAlgorithmIdentifier: 2, + MinimumPublicKeyLength: 2048, + Claims: &config.GlobalProvisionerClaims, + } + + err = prov.Init(provisioner.Config{}) + require.NoError(t, err) + + cfg := &config.Config{ + Root: []string{rootFilepath}, + IntermediateCert: intermediateCertFilepath, + IntermediateKey: intermediateKeyFilepath, + Address: net.JoinHostPort(host, port), // reuse the address that was just "reserved" + DNSNames: []string{"127.0.0.1", "[::1]", "localhost"}, + AuthorityConfig: &config.AuthConfig{ + AuthorityID: "stepca-test-scep", + DeploymentType: "standalone-test", + Provisioners: provisioner.List{prov}, + }, + Logger: json.RawMessage(`{"format": "text"}`), + } + c, err := ca.New(cfg) + require.NoError(t, err) + + return &testCA{ + ca: c, + caURL: fmt.Sprintf("https://localhost:%s", port), + rootFilepath: rootFilepath, + root: m.Root, + } +} + type client struct { caURL string caCert *x509.Certificate @@ -90,7 +178,7 @@ func createSCEPClient(t *testing.T, caURL string, root *x509.Certificate) *clien Transport: transport, } return &client{ - caURL: caURL, + caURL: fmt.Sprintf("%s/scep/scep", caURL), httpClient: httpClient, } } @@ -301,7 +389,7 @@ func (c *client) requestCertificateEmulatingWindowsClient(t *testing.T, commonNa h := sha1.Sum(publicKeyBytes) subjectKeyId := h[:] - // add subject key ID extension + // create subject key ID extension value, err = asn1.Marshal(subjectKeyId) if err != nil { return nil, fmt.Errorf("failed marshaling subject key ID: %w", err) diff --git a/test/integration/scep/regular_test.go b/test/integration/scep/regular_test.go index fc2d4d58..6e8a958f 100644 --- a/test/integration/scep/regular_test.go +++ b/test/integration/scep/regular_test.go @@ -1,106 +1,40 @@ package sceptest import ( - "crypto" - "encoding/json" - "fmt" - "net" "net/http" - "path/filepath" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "go.step.sm/crypto/keyutil" - "go.step.sm/crypto/minica" - "go.step.sm/crypto/pemutil" - - "github.com/smallstep/certificates/authority/config" - "github.com/smallstep/certificates/authority/provisioner" - "github.com/smallstep/certificates/ca" ) func TestIssuesCertificateUsingRegularSCEPConfiguration(t *testing.T) { - signer, err := keyutil.GenerateSigner("RSA", "", 2048) - require.NoError(t, err) - - dir := t.TempDir() - m, err := minica.New(minica.WithName("Step E2E | SCEP Regular"), minica.WithGetSignerFunc(func() (crypto.Signer, error) { - return signer, nil - })) - require.NoError(t, err) - - rootFilepath := filepath.Join(dir, "root.crt") - _, err = pemutil.Serialize(m.Root, pemutil.WithFilename(rootFilepath)) - require.NoError(t, err) - - intermediateCertFilepath := filepath.Join(dir, "intermediate.crt") - _, err = pemutil.Serialize(m.Intermediate, pemutil.WithFilename(intermediateCertFilepath)) - require.NoError(t, err) - - intermediateKeyFilepath := filepath.Join(dir, "intermediate.key") - _, err = pemutil.Serialize(m.Signer, pemutil.WithFilename(intermediateKeyFilepath)) - require.NoError(t, err) - - // get a random address to listen on and connect to; currently no nicer way to get one before starting the server - // TODO(hs): find/implement a nicer way to expose the CA URL, similar to how e.g. httptest.Server exposes it? - host, port := reservePort(t) - - prov := &provisioner.SCEP{ - ID: "scep", - Name: "scep", - Type: "SCEP", - ForceCN: false, - ChallengePassword: "", - EncryptionAlgorithmIdentifier: 2, - MinimumPublicKeyLength: 2048, - Claims: &config.GlobalProvisionerClaims, - } - - err = prov.Init(provisioner.Config{}) - require.NoError(t, err) - - cfg := &config.Config{ - Root: []string{rootFilepath}, - IntermediateCert: intermediateCertFilepath, - IntermediateKey: intermediateKeyFilepath, - Address: net.JoinHostPort(host, port), // reuse the address that was just "reserved" - DNSNames: []string{"127.0.0.1", "[::1]", "localhost"}, - AuthorityConfig: &config.AuthConfig{ - AuthorityID: "stepca-test-scep", - DeploymentType: "standalone-test", - Provisioners: provisioner.List{prov}, - }, - Logger: json.RawMessage(`{"format": "text"}`), - } - c, err := ca.New(cfg) - require.NoError(t, err) + c := newTestCA(t, "Step E2E | SCEP Regular") var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() - err = c.Run() + err := c.run() require.ErrorIs(t, err, http.ErrServerClosed) }() // instantiate a client for the CA running at the random address - caClient := newCAClient(t, fmt.Sprintf("https://localhost:%s", port), rootFilepath) + caClient := newCAClient(t, c.caURL, c.rootFilepath) requireHealthyCA(t, caClient) - scepClient := createSCEPClient(t, fmt.Sprintf("https://localhost:%s/scep/scep", port), m.Root) + scepClient := createSCEPClient(t, c.caURL, c.root) cert, err := scepClient.requestCertificate(t, "test.localhost", []string{"test.localhost"}) - assert.NoError(t, err) + require.NoError(t, err) require.NotNil(t, cert) assert.Equal(t, "test.localhost", cert.Subject.CommonName) assert.Equal(t, "Step E2E | SCEP Regular Intermediate CA", cert.Issuer.CommonName) // done testing; stop and wait for the server to quit - err = c.Stop() + err = c.stop() require.NoError(t, err) wg.Wait() diff --git a/test/integration/scep/windows_go1.23_test.go b/test/integration/scep/windows_go1.23_test.go index 5a5e8330..1e9fc614 100644 --- a/test/integration/scep/windows_go1.23_test.go +++ b/test/integration/scep/windows_go1.23_test.go @@ -3,26 +3,15 @@ package sceptest import ( - "crypto" "crypto/x509" - "encoding/json" "fmt" - "net" "net/http" - "path/filepath" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.step.sm/crypto/keyutil" - "go.step.sm/crypto/minica" - "go.step.sm/crypto/pemutil" - - "github.com/smallstep/certificates/authority/config" - "github.com/smallstep/certificates/authority/provisioner" - "github.com/smallstep/certificates/ca" legacyx509 "github.com/smallstep/certificates/test/integration/scep/internal/x509" ) @@ -36,77 +25,24 @@ func legacyCertificateParser(der []byte) (*x509.Certificate, error) { } func TestIssuesCertificateToEmulatedWindowsClientGo123(t *testing.T) { - signer, err := keyutil.GenerateSigner("RSA", "", 2048) - require.NoError(t, err) - - dir := t.TempDir() - m, err := minica.New(minica.WithName("Step E2E | SCEP Regular w/ Windows Client"), minica.WithGetSignerFunc(func() (crypto.Signer, error) { - return signer, nil - })) - require.NoError(t, err) - - rootFilepath := filepath.Join(dir, "root.crt") - _, err = pemutil.Serialize(m.Root, pemutil.WithFilename(rootFilepath)) - require.NoError(t, err) - - intermediateCertFilepath := filepath.Join(dir, "intermediate.crt") - _, err = pemutil.Serialize(m.Intermediate, pemutil.WithFilename(intermediateCertFilepath)) - require.NoError(t, err) - - intermediateKeyFilepath := filepath.Join(dir, "intermediate.key") - _, err = pemutil.Serialize(m.Signer, pemutil.WithFilename(intermediateKeyFilepath)) - require.NoError(t, err) - - // get a random address to listen on and connect to; currently no nicer way to get one before starting the server - // TODO(hs): find/implement a nicer way to expose the CA URL, similar to how e.g. httptest.Server exposes it? - host, port := reservePort(t) - - prov := &provisioner.SCEP{ - ID: "scep", - Name: "scep", - Type: "SCEP", - ForceCN: false, - ChallengePassword: "", - EncryptionAlgorithmIdentifier: 2, - MinimumPublicKeyLength: 2048, - Claims: &config.GlobalProvisionerClaims, - } - - err = prov.Init(provisioner.Config{}) - require.NoError(t, err) - - cfg := &config.Config{ - Root: []string{rootFilepath}, - IntermediateCert: intermediateCertFilepath, - IntermediateKey: intermediateKeyFilepath, - Address: net.JoinHostPort(host, port), // reuse the address that was just "reserved" - DNSNames: []string{"127.0.0.1", "[::1]", "localhost"}, - AuthorityConfig: &config.AuthConfig{ - AuthorityID: "stepca-test-scep", - DeploymentType: "standalone-test", - Provisioners: provisioner.List{prov}, - }, - Logger: json.RawMessage(`{"format": "text"}`), - } - c, err := ca.New(cfg) - require.NoError(t, err) + c := newTestCA(t, "Step E2E | SCEP Regular w/ Windows Client") var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() - err = c.Run() + err := c.Run() require.ErrorIs(t, err, http.ErrServerClosed) }() // instantiate a client for the CA running at the random address - caClient := newCAClient(t, fmt.Sprintf("https://localhost:%s", port), rootFilepath) + caClient := newCAClient(t, c.caURL, c.rootFilepath) requireHealthyCA(t, caClient) - scepClient := createSCEPClient(t, fmt.Sprintf("https://localhost:%s/scep/scep", port), m.Root) + scepClient := createSCEPClient(t, c.caURL, c.root) cert, err := scepClient.requestCertificateEmulatingWindowsClient(t, "test.localhost", []string{"test.localhost"}, legacyCertificateParser) - assert.NoError(t, err) + require.NoError(t, err) require.NotNil(t, cert) assert.Equal(t, "test.localhost", cert.Subject.CommonName) diff --git a/test/integration/scep/windows_test.go b/test/integration/scep/windows_test.go index ffd6dc0c..983a9ecd 100644 --- a/test/integration/scep/windows_test.go +++ b/test/integration/scep/windows_test.go @@ -3,107 +3,40 @@ package sceptest import ( - "crypto" "crypto/x509" - "encoding/json" - "fmt" - "net" "net/http" - "path/filepath" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "go.step.sm/crypto/keyutil" - "go.step.sm/crypto/minica" - "go.step.sm/crypto/pemutil" - - "github.com/smallstep/certificates/authority/config" - "github.com/smallstep/certificates/authority/provisioner" - "github.com/smallstep/certificates/ca" ) func TestIssuesCertificateToEmulatedWindowsClient(t *testing.T) { - signer, err := keyutil.GenerateSigner("RSA", "", 2048) - require.NoError(t, err) - - dir := t.TempDir() - m, err := minica.New(minica.WithName("Step E2E | SCEP Regular w/ Windows Client"), minica.WithGetSignerFunc(func() (crypto.Signer, error) { - return signer, nil - })) - require.NoError(t, err) - - rootFilepath := filepath.Join(dir, "root.crt") - _, err = pemutil.Serialize(m.Root, pemutil.WithFilename(rootFilepath)) - require.NoError(t, err) - - intermediateCertFilepath := filepath.Join(dir, "intermediate.crt") - _, err = pemutil.Serialize(m.Intermediate, pemutil.WithFilename(intermediateCertFilepath)) - require.NoError(t, err) - - intermediateKeyFilepath := filepath.Join(dir, "intermediate.key") - _, err = pemutil.Serialize(m.Signer, pemutil.WithFilename(intermediateKeyFilepath)) - require.NoError(t, err) - - // get a random address to listen on and connect to; currently no nicer way to get one before starting the server - // TODO(hs): find/implement a nicer way to expose the CA URL, similar to how e.g. httptest.Server exposes it? - host, port := reservePort(t) - - prov := &provisioner.SCEP{ - ID: "scep", - Name: "scep", - Type: "SCEP", - ForceCN: false, - ChallengePassword: "", - EncryptionAlgorithmIdentifier: 2, - MinimumPublicKeyLength: 2048, - Claims: &config.GlobalProvisionerClaims, - } - - err = prov.Init(provisioner.Config{}) - require.NoError(t, err) - - cfg := &config.Config{ - Root: []string{rootFilepath}, - IntermediateCert: intermediateCertFilepath, - IntermediateKey: intermediateKeyFilepath, - Address: net.JoinHostPort(host, port), // reuse the address that was just "reserved" - DNSNames: []string{"127.0.0.1", "[::1]", "localhost"}, - AuthorityConfig: &config.AuthConfig{ - AuthorityID: "stepca-test-scep", - DeploymentType: "standalone-test", - Provisioners: provisioner.List{prov}, - }, - Logger: json.RawMessage(`{"format": "text"}`), - } - c, err := ca.New(cfg) - require.NoError(t, err) + c := newTestCA(t, "Step E2E | SCEP Regular w/ Windows Client") var wg sync.WaitGroup wg.Add(1) - go func() { defer wg.Done() - err = c.Run() + err := c.run() require.ErrorIs(t, err, http.ErrServerClosed) }() // instantiate a client for the CA running at the random address - caClient := newCAClient(t, fmt.Sprintf("https://localhost:%s", port), rootFilepath) + caClient := newCAClient(t, c.caURL, c.rootFilepath) requireHealthyCA(t, caClient) - scepClient := createSCEPClient(t, fmt.Sprintf("https://localhost:%s/scep/scep", port), m.Root) + scepClient := createSCEPClient(t, c.caURL, c.root) cert, err := scepClient.requestCertificateEmulatingWindowsClient(t, "test.localhost", []string{"test.localhost"}, x509.ParseCertificate) - assert.NoError(t, err) + require.NoError(t, err) require.NotNil(t, cert) assert.Equal(t, "test.localhost", cert.Subject.CommonName) assert.Equal(t, "Step E2E | SCEP Regular w/ Windows Client Intermediate CA", cert.Issuer.CommonName) // done testing; stop and wait for the server to quit - err = c.Stop() + err = c.stop() require.NoError(t, err) wg.Wait()