From 3f07eb597a731872465820a2c6a4381d08d89b68 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Thu, 5 Aug 2021 18:45:50 -0700 Subject: [PATCH] Implement revocation using linkedca. --- authority/linkedca.go | 46 +++++++++++++++++++++++++++++++++++++++++++ authority/tls.go | 25 +++++++++++++++++++++-- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/authority/linkedca.go b/authority/linkedca.go index e0678aca..9c816e1e 100644 --- a/authority/linkedca.go +++ b/authority/linkedca.go @@ -15,6 +15,7 @@ import ( "time" "github.com/pkg/errors" + "github.com/smallstep/certificates/db" "go.step.sm/crypto/jose" "go.step.sm/crypto/keyutil" "go.step.sm/crypto/tlsutil" @@ -257,6 +258,34 @@ func (c *linkedCaClient) StoreSSHCertificate(crt *ssh.Certificate) error { return errors.Wrap(err, "error posting ssh certificate") } +func (c *linkedCaClient) Revoke(crt *x509.Certificate, rci *db.RevokedCertificateInfo) error { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + _, err := c.client.RevokeCertificate(ctx, &linkedca.RevokeCertificateRequest{ + Serial: rci.Serial, + PemCertificate: serializeCertificate(crt), + Reason: rci.Reason, + ReasonCode: linkedca.RevocationReasonCode(rci.ReasonCode), + Passive: true, + }) + + return errors.Wrap(err, "error revoking certificate") +} + +func (c *linkedCaClient) RevokeSSH(ssh *ssh.Certificate, rci *db.RevokedCertificateInfo) error { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + _, err := c.client.RevokeSSHCertificate(ctx, &linkedca.RevokeSSHCertificateRequest{ + Serial: rci.Serial, + Certificate: serializeSSHCertificate(ssh), + Reason: rci.Reason, + ReasonCode: linkedca.RevocationReasonCode(rci.ReasonCode), + Passive: true, + }) + + return errors.Wrap(err, "error revoking ssh certificate") +} + func (c *linkedCaClient) IsRevoked(serial string) (bool, error) { ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() @@ -281,6 +310,16 @@ func (c *linkedCaClient) IsSSHRevoked(serial string) (bool, error) { return resp.Status != linkedca.RevocationStatus_ACTIVE, nil } +func serializeCertificate(crt *x509.Certificate) string { + if crt == nil { + return "" + } + return string(pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: crt.Raw, + })) +} + func serializeCertificateChain(fullchain ...*x509.Certificate) string { var chain string for _, crt := range fullchain { @@ -292,6 +331,13 @@ func serializeCertificateChain(fullchain ...*x509.Certificate) string { return chain } +func serializeSSHCertificate(crt *ssh.Certificate) string { + if crt == nil { + return "" + } + return string(ssh.MarshalAuthorizedKey(crt)) +} + func getAuthority(sans []string) (string, error) { for _, s := range sans { if strings.HasPrefix(s, "urn:smallstep:authority:") { diff --git a/authority/tls.go b/authority/tls.go index 32d6f3c6..90c70fc3 100644 --- a/authority/tls.go +++ b/authority/tls.go @@ -21,6 +21,7 @@ import ( "go.step.sm/crypto/keyutil" "go.step.sm/crypto/pemutil" "go.step.sm/crypto/x509util" + "golang.org/x/crypto/ssh" ) // GetTLSOptions returns the tls options configured. @@ -397,7 +398,7 @@ func (a *Authority) Revoke(ctx context.Context, revokeOpts *RevokeOptions) error } if provisioner.MethodFromContext(ctx) == provisioner.SSHRevokeMethod { - err = a.db.RevokeSSH(rci) + err = a.revokeSSH(nil, rci) } else { // Revoke an X.509 certificate using CAS. If the certificate is not // provided we will try to read it from the db. If the read fails we @@ -424,7 +425,7 @@ func (a *Authority) Revoke(ctx context.Context, revokeOpts *RevokeOptions) error } // Save as revoked in the Db. - err = a.db.Revoke(rci) + err = a.revoke(revokedCert, rci) } switch err { case nil: @@ -439,6 +440,26 @@ func (a *Authority) Revoke(ctx context.Context, revokeOpts *RevokeOptions) error } } +func (a *Authority) revoke(crt *x509.Certificate, rci *db.RevokedCertificateInfo) error { + if lca, ok := a.adminDB.(interface { + Revoke(*x509.Certificate, *db.RevokedCertificateInfo) error + }); ok { + println(true) + return lca.Revoke(crt, rci) + } + println(false) + return a.db.Revoke(rci) +} + +func (a *Authority) revokeSSH(crt *ssh.Certificate, rci *db.RevokedCertificateInfo) error { + if lca, ok := a.adminDB.(interface { + RevokeSSH(*ssh.Certificate, *db.RevokedCertificateInfo) error + }); ok { + return lca.RevokeSSH(crt, rci) + } + return a.db.Revoke(rci) +} + // GetTLSCertificate creates a new leaf certificate to be used by the CA HTTPS server. func (a *Authority) GetTLSCertificate() (*tls.Certificate, error) { fatal := func(err error) (*tls.Certificate, error) {