diff --git a/api/api_test.go b/api/api_test.go index 485244b9..de573097 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -199,6 +199,7 @@ type mockAuthority struct { getEncryptedKey func(kid string) (string, error) getRoots func() ([]*x509.Certificate, error) getFederation func() ([]*x509.Certificate, error) + getCRL func() ([]byte, error) signSSH func(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) signSSHAddUser func(ctx context.Context, key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error) renewSSH func(ctx context.Context, cert *ssh.Certificate) (*ssh.Certificate, error) @@ -213,7 +214,11 @@ type mockAuthority struct { } func (m *mockAuthority) GetCertificateRevocationList() ([]byte, error) { - panic("implement me") + if m.getCRL != nil { + return m.getCRL() + } + + return m.ret1.([]byte), m.err } // TODO: remove once Authorize is deprecated. @@ -776,6 +781,45 @@ func (m *mockProvisioner) AuthorizeSSHRekey(ctx context.Context, token string) ( return m.ret1.(*ssh.Certificate), m.ret2.([]provisioner.SignOption), m.err } +func Test_CRLGeneration(t *testing.T) { + tests := []struct { + name string + err error + statusCode int + expected []byte + }{ + {"empty", nil, http.StatusOK, nil}, + } + + chiCtx := chi.NewRouteContext() + req := httptest.NewRequest("GET", "http://example.com/crl", nil) + req = req.WithContext(context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx)) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockMustAuthority(t, &mockAuthority{ret1: tt.expected, err: tt.err}) + w := httptest.NewRecorder() + CRL(w, req) + res := w.Result() + + if res.StatusCode != tt.statusCode { + t.Errorf("caHandler.CRL StatusCode = %d, wants %d", res.StatusCode, tt.statusCode) + } + + body, err := io.ReadAll(res.Body) + res.Body.Close() + if err != nil { + t.Errorf("caHandler.Root unexpected error = %v", err) + } + if tt.statusCode == 200 { + if !bytes.Equal(bytes.TrimSpace(body), tt.expected) { + t.Errorf("caHandler.Root CRL = %s, wants %s", body, tt.expected) + } + } + }) + } +} + func Test_caHandler_Route(t *testing.T) { type fields struct { Authority Authority diff --git a/api/crl.go b/api/crl.go index 45024470..ce0d8f73 100644 --- a/api/crl.go +++ b/api/crl.go @@ -9,8 +9,8 @@ import ( ) // CRL is an HTTP handler that returns the current CRL in DER or PEM format -func (h *caHandler) CRL(w http.ResponseWriter, r *http.Request) { - crlBytes, err := h.Authority.GetCertificateRevocationList() +func CRL(w http.ResponseWriter, r *http.Request) { + crlBytes, err := mustAuthority(r.Context()).GetCertificateRevocationList() _, formatAsPEM := r.URL.Query()["pem"] diff --git a/db/db.go b/db/db.go index b93b23ca..ee8007c1 100644 --- a/db/db.go +++ b/db/db.go @@ -255,9 +255,9 @@ func (db *DB) GetRevokedCertificates() (*[]RevokedCertificateInfo, error) { return nil, err } - if !data.ExpiresAt.IsZero() && data.ExpiresAt.After(now) { + if !data.RevokedAt.IsZero() && data.RevokedAt.After(now) { revokedCerts = append(revokedCerts, data) - } else if data.ExpiresAt.IsZero() { + } else if data.RevokedAt.IsZero() { cert, err := db.GetCertificate(data.Serial) if err != nil { revokedCerts = append(revokedCerts, data) // a revoked certificate may not be in the database, diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 67c5673d..328fba69 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -119,6 +119,11 @@ starting the CA. * `address`: e.g. `127.0.0.1:8080` - address and port on which the CA will bind and respond to requests. +* `crl`: Certificate Revocation List settings: + - generate: Enable/Disable CRL generation (`true` to generate, `false` to disable) + + - cacheDuration: Time between CRL regeneration task. E.g if set to `5m`, step-ca will regenerate the CRL every 5 minutes. + * `dnsNames`: comma separated list of DNS Name(s) for the CA. * `logger`: the default logging format for the CA is `text`. The other option