diff --git a/api/api.go b/api/api.go index d8cfa15f..75a0397b 100644 --- a/api/api.go +++ b/api/api.go @@ -46,7 +46,7 @@ type Authority interface { GetRoots() (federation []*x509.Certificate, err error) GetFederation() ([]*x509.Certificate, error) Version() authority.Version - GenerateCertificateRevocationList(force bool) (string, error) + GenerateCertificateRevocationList(force bool) ([]byte, error) } // TimeDuration is an alias of provisioner.TimeDuration diff --git a/api/api_test.go b/api/api_test.go index 89596165..aef6db77 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -580,6 +580,10 @@ type mockAuthority struct { version func() authority.Version } +func (m *mockAuthority) GenerateCertificateRevocationList(force bool) ([]byte, error) { + panic("implement me") +} + // TODO: remove once Authorize is deprecated. func (m *mockAuthority) Authorize(ctx context.Context, ott string) ([]provisioner.SignOption, error) { return m.AuthorizeSign(ott) diff --git a/api/crl.go b/api/crl.go index 50b29d6c..46758777 100644 --- a/api/crl.go +++ b/api/crl.go @@ -1,16 +1,24 @@ package api -import "net/http" +import ( + "encoding/pem" + "net/http" +) -// CRL is an HTTP handler that returns the current CRL +// CRL is an HTTP handler that returns the current CRL in PEM format func (h *caHandler) CRL(w http.ResponseWriter, r *http.Request) { - crl, err := h.Authority.GenerateCertificateRevocationList(false) + crlBytes, err := h.Authority.GenerateCertificateRevocationList(false) if err != nil { w.WriteHeader(500) return } + pemBytes := pem.EncodeToMemory(&pem.Block{ + Type: "X509 CRL", + Bytes: crlBytes, + }) + w.WriteHeader(200) - _, err = w.Write([]byte(crl)) + _, err = w.Write(pemBytes) } diff --git a/authority/tls.go b/authority/tls.go index 0bd4a7e7..b46cb40d 100644 --- a/authority/tls.go +++ b/authority/tls.go @@ -9,7 +9,6 @@ import ( "encoding/asn1" "encoding/base64" "encoding/pem" - "fmt" "math/big" "net/http" "time" @@ -469,24 +468,24 @@ func (a *Authority) revokeSSH(crt *ssh.Certificate, rci *db.RevokedCertificateIn // a new CRL on demand if it has expired (or a CRL does not already exist). // // force set to true will force regeneration of the CRL regardless of whether it has actually expired -func (a *Authority) GenerateCertificateRevocationList(force bool) (string, error) { +func (a *Authority) GenerateCertificateRevocationList(force bool) ([]byte, error) { // check for an existing CRL in the database, and return that if its valid crlInfo, err := a.db.GetCRL() if err != nil { - return "", err + return nil, err } if !force && crlInfo != nil && crlInfo.ExpiresAt.After(time.Now().UTC()) { - return crlInfo.PEM, nil + return crlInfo.DER, nil } // some CAS may not implement the CRLGenerator interface, so check before we proceed caCRLGenerator, ok := a.x509CAService.(casapi.CertificateAuthorityCRLGenerator) if !ok { - return "", errors.Errorf("CRL Generator not implemented") + return nil, errors.Errorf("CRL Generator not implemented") } revokedList, err := a.db.GetRevokedCertificates() @@ -529,28 +528,24 @@ func (a *Authority) GenerateCertificateRevocationList(force bool) (string, error certificateRevocationList, err := caCRLGenerator.CreateCertificateRevocationList(&revocationList) if err != nil { - return "", err + return nil, err } - // Quick and dirty PEM encoding - // TODO: clean this up - pemCRL := fmt.Sprintf("-----BEGIN X509 CRL-----\n%s\n-----END X509 CRL-----\n", base64.StdEncoding.EncodeToString(certificateRevocationList)) - // Create a new db.CertificateRevocationListInfo, which stores the new Number we just generated, the // expiry time, and the byte-encoded CRL - then store it in the DB newCRLInfo := db.CertificateRevocationListInfo{ Number: n, ExpiresAt: revocationList.NextUpdate, - PEM: pemCRL, + DER: certificateRevocationList, } err = a.db.StoreCRL(&newCRLInfo) if err != nil { - return "", err + return nil, err } // Finally, return our CRL PEM - return pemCRL, nil + return certificateRevocationList, nil } // GetTLSCertificate creates a new leaf certificate to be used by the CA HTTPS server. diff --git a/db/db.go b/db/db.go index 5826d7b9..72c4ec71 100644 --- a/db/db.go +++ b/db/db.go @@ -113,12 +113,12 @@ type RevokedCertificateInfo struct { MTLS bool } -// CertificateRevocationListInfo contains a CRL in PEM and associated metadata to allow a decision on whether -// to regenerate the CRL or not easier +// CertificateRevocationListInfo contains a CRL in DER format and associated +// metadata to allow a decision on whether to regenerate the CRL or not easier type CertificateRevocationListInfo struct { Number int64 ExpiresAt time.Time - PEM string + DER []byte } // IsRevoked returns whether or not a certificate with the given identifier @@ -378,6 +378,18 @@ type MockAuthDB struct { MShutdown func() error } +func (m *MockAuthDB) GetRevokedCertificates() (*[]RevokedCertificateInfo, error) { + panic("implement me") +} + +func (m *MockAuthDB) GetCRL() (*CertificateRevocationListInfo, error) { + panic("implement me") +} + +func (m *MockAuthDB) StoreCRL(info *CertificateRevocationListInfo) error { + panic("implement me") +} + // IsRevoked mock. func (m *MockAuthDB) IsRevoked(sn string) (bool, error) { if m.MIsRevoked != nil {