forked from TrueCloudLab/certificates
change GenerateCertificateRevocationList to return DER, store DER in db instead of PEM, nicer PEM encoding of CRL, add Mock stubs
This commit is contained in:
parent
56926b9012
commit
8545adea92
5 changed files with 40 additions and 21 deletions
|
@ -46,7 +46,7 @@ type Authority interface {
|
||||||
GetRoots() (federation []*x509.Certificate, err error)
|
GetRoots() (federation []*x509.Certificate, err error)
|
||||||
GetFederation() ([]*x509.Certificate, error)
|
GetFederation() ([]*x509.Certificate, error)
|
||||||
Version() authority.Version
|
Version() authority.Version
|
||||||
GenerateCertificateRevocationList(force bool) (string, error)
|
GenerateCertificateRevocationList(force bool) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TimeDuration is an alias of provisioner.TimeDuration
|
// TimeDuration is an alias of provisioner.TimeDuration
|
||||||
|
|
|
@ -580,6 +580,10 @@ type mockAuthority struct {
|
||||||
version func() authority.Version
|
version func() authority.Version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockAuthority) GenerateCertificateRevocationList(force bool) ([]byte, error) {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: remove once Authorize is deprecated.
|
// TODO: remove once Authorize is deprecated.
|
||||||
func (m *mockAuthority) Authorize(ctx context.Context, ott string) ([]provisioner.SignOption, error) {
|
func (m *mockAuthority) Authorize(ctx context.Context, ott string) ([]provisioner.SignOption, error) {
|
||||||
return m.AuthorizeSign(ott)
|
return m.AuthorizeSign(ott)
|
||||||
|
|
16
api/crl.go
16
api/crl.go
|
@ -1,16 +1,24 @@
|
||||||
package api
|
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) {
|
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 {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pemBytes := pem.EncodeToMemory(&pem.Block{
|
||||||
|
Type: "X509 CRL",
|
||||||
|
Bytes: crlBytes,
|
||||||
|
})
|
||||||
|
|
||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
_, err = w.Write([]byte(crl))
|
_, err = w.Write(pemBytes)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"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).
|
// 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
|
// 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
|
// check for an existing CRL in the database, and return that if its valid
|
||||||
crlInfo, err := a.db.GetCRL()
|
crlInfo, err := a.db.GetCRL()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !force && crlInfo != nil && crlInfo.ExpiresAt.After(time.Now().UTC()) {
|
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
|
// some CAS may not implement the CRLGenerator interface, so check before we proceed
|
||||||
caCRLGenerator, ok := a.x509CAService.(casapi.CertificateAuthorityCRLGenerator)
|
caCRLGenerator, ok := a.x509CAService.(casapi.CertificateAuthorityCRLGenerator)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", errors.Errorf("CRL Generator not implemented")
|
return nil, errors.Errorf("CRL Generator not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
revokedList, err := a.db.GetRevokedCertificates()
|
revokedList, err := a.db.GetRevokedCertificates()
|
||||||
|
@ -529,28 +528,24 @@ func (a *Authority) GenerateCertificateRevocationList(force bool) (string, error
|
||||||
|
|
||||||
certificateRevocationList, err := caCRLGenerator.CreateCertificateRevocationList(&revocationList)
|
certificateRevocationList, err := caCRLGenerator.CreateCertificateRevocationList(&revocationList)
|
||||||
if err != nil {
|
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
|
// 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
|
// expiry time, and the byte-encoded CRL - then store it in the DB
|
||||||
newCRLInfo := db.CertificateRevocationListInfo{
|
newCRLInfo := db.CertificateRevocationListInfo{
|
||||||
Number: n,
|
Number: n,
|
||||||
ExpiresAt: revocationList.NextUpdate,
|
ExpiresAt: revocationList.NextUpdate,
|
||||||
PEM: pemCRL,
|
DER: certificateRevocationList,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.db.StoreCRL(&newCRLInfo)
|
err = a.db.StoreCRL(&newCRLInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, return our CRL PEM
|
// 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.
|
// GetTLSCertificate creates a new leaf certificate to be used by the CA HTTPS server.
|
||||||
|
|
18
db/db.go
18
db/db.go
|
@ -113,12 +113,12 @@ type RevokedCertificateInfo struct {
|
||||||
MTLS bool
|
MTLS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CertificateRevocationListInfo contains a CRL in PEM and associated metadata to allow a decision on whether
|
// CertificateRevocationListInfo contains a CRL in DER format and associated
|
||||||
// to regenerate the CRL or not easier
|
// metadata to allow a decision on whether to regenerate the CRL or not easier
|
||||||
type CertificateRevocationListInfo struct {
|
type CertificateRevocationListInfo struct {
|
||||||
Number int64
|
Number int64
|
||||||
ExpiresAt time.Time
|
ExpiresAt time.Time
|
||||||
PEM string
|
DER []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsRevoked returns whether or not a certificate with the given identifier
|
// IsRevoked returns whether or not a certificate with the given identifier
|
||||||
|
@ -378,6 +378,18 @@ type MockAuthDB struct {
|
||||||
MShutdown func() error
|
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.
|
// IsRevoked mock.
|
||||||
func (m *MockAuthDB) IsRevoked(sn string) (bool, error) {
|
func (m *MockAuthDB) IsRevoked(sn string) (bool, error) {
|
||||||
if m.MIsRevoked != nil {
|
if m.MIsRevoked != nil {
|
||||||
|
|
Loading…
Reference in a new issue