2020-09-09 02:26:32 +00:00
|
|
|
package softcas
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2020-09-11 02:09:46 +00:00
|
|
|
"crypto"
|
2020-09-09 02:26:32 +00:00
|
|
|
"crypto/x509"
|
2020-09-11 02:09:46 +00:00
|
|
|
"errors"
|
|
|
|
"time"
|
2020-09-09 02:26:32 +00:00
|
|
|
|
|
|
|
"github.com/smallstep/certificates/cas/apiv1"
|
|
|
|
"go.step.sm/crypto/x509util"
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
apiv1.Register(apiv1.SoftCAS, func(ctx context.Context, opts apiv1.Options) (apiv1.CertificateAuthorityService, error) {
|
|
|
|
return New(ctx, opts)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-11 02:09:46 +00:00
|
|
|
var now = func() time.Time {
|
|
|
|
return time.Now()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SoftCAS implements a Certificate Authority Service using Golang or KMS
|
|
|
|
// crypto. This is the default CAS used in step-ca.
|
|
|
|
type SoftCAS struct {
|
|
|
|
Issuer *x509.Certificate
|
|
|
|
Signer crypto.Signer
|
|
|
|
}
|
2020-09-09 02:26:32 +00:00
|
|
|
|
2020-09-11 02:09:46 +00:00
|
|
|
// New creates a new CertificateAuthorityService implementation using Golang or KMS
|
2020-09-09 02:26:32 +00:00
|
|
|
// crypto.
|
|
|
|
func New(ctx context.Context, opts apiv1.Options) (*SoftCAS, error) {
|
2020-09-11 02:09:46 +00:00
|
|
|
switch {
|
|
|
|
case opts.Issuer == nil:
|
|
|
|
return nil, errors.New("softCAS 'issuer' cannot be nil")
|
|
|
|
case opts.Signer == nil:
|
|
|
|
return nil, errors.New("softCAS 'signer' cannot be nil")
|
|
|
|
}
|
|
|
|
return &SoftCAS{
|
|
|
|
Issuer: opts.Issuer,
|
|
|
|
Signer: opts.Signer,
|
|
|
|
}, nil
|
2020-09-09 02:26:32 +00:00
|
|
|
}
|
|
|
|
|
2020-09-11 02:09:46 +00:00
|
|
|
// CreateCertificate signs a new certificate using Golang or KMS crypto.
|
2020-09-09 02:26:32 +00:00
|
|
|
func (c *SoftCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1.CreateCertificateResponse, error) {
|
2020-09-11 02:09:46 +00:00
|
|
|
switch {
|
|
|
|
case req.Template == nil:
|
|
|
|
return nil, errors.New("createCertificateRequest `template` cannot be nil")
|
|
|
|
case req.Lifetime == 0:
|
|
|
|
return nil, errors.New("createCertificateRequest `lifetime` cannot be 0")
|
|
|
|
}
|
|
|
|
|
|
|
|
t := now()
|
2020-09-16 02:37:02 +00:00
|
|
|
// Provisioners can also set specific values.
|
2020-09-16 01:14:21 +00:00
|
|
|
if req.Template.NotBefore.IsZero() {
|
|
|
|
req.Template.NotBefore = t.Add(-1 * req.Backdate)
|
|
|
|
}
|
|
|
|
if req.Template.NotAfter.IsZero() {
|
|
|
|
req.Template.NotAfter = t.Add(req.Lifetime)
|
|
|
|
}
|
2020-09-11 02:09:46 +00:00
|
|
|
req.Template.Issuer = c.Issuer.Subject
|
|
|
|
|
|
|
|
cert, err := x509util.CreateCertificate(req.Template, c.Issuer, req.Template.PublicKey, c.Signer)
|
2020-09-09 02:26:32 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &apiv1.CreateCertificateResponse{
|
|
|
|
Certificate: cert,
|
|
|
|
CertificateChain: []*x509.Certificate{
|
2020-09-11 02:09:46 +00:00
|
|
|
c.Issuer,
|
2020-09-09 02:26:32 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-09-11 02:09:46 +00:00
|
|
|
// RenewCertificate signs the given certificate template using Golang or KMS crypto.
|
2020-09-09 02:26:32 +00:00
|
|
|
func (c *SoftCAS) RenewCertificate(req *apiv1.RenewCertificateRequest) (*apiv1.RenewCertificateResponse, error) {
|
2020-09-11 02:09:46 +00:00
|
|
|
switch {
|
|
|
|
case req.Template == nil:
|
|
|
|
return nil, errors.New("createCertificateRequest `template` cannot be nil")
|
|
|
|
case req.Lifetime == 0:
|
|
|
|
return nil, errors.New("createCertificateRequest `lifetime` cannot be 0")
|
|
|
|
}
|
|
|
|
|
|
|
|
t := now()
|
|
|
|
req.Template.NotBefore = t.Add(-1 * req.Backdate)
|
|
|
|
req.Template.NotAfter = t.Add(req.Lifetime)
|
|
|
|
req.Template.Issuer = c.Issuer.Subject
|
|
|
|
|
|
|
|
cert, err := x509util.CreateCertificate(req.Template, c.Issuer, req.Template.PublicKey, c.Signer)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &apiv1.RenewCertificateResponse{
|
|
|
|
Certificate: cert,
|
|
|
|
CertificateChain: []*x509.Certificate{
|
|
|
|
c.Issuer,
|
|
|
|
},
|
|
|
|
}, nil
|
2020-09-09 02:26:32 +00:00
|
|
|
}
|
|
|
|
|
2020-09-16 01:14:21 +00:00
|
|
|
// RevokeCertificate revokes the given certificate in step-ca. In SoftCAS this
|
|
|
|
// operation is a no-op as the actual revoke will happen when we store the entry
|
|
|
|
// in the db.
|
2020-09-09 02:26:32 +00:00
|
|
|
func (c *SoftCAS) RevokeCertificate(req *apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) {
|
2020-09-16 01:14:21 +00:00
|
|
|
return &apiv1.RevokeCertificateResponse{
|
|
|
|
Certificate: req.Certificate,
|
|
|
|
CertificateChain: []*x509.Certificate{
|
|
|
|
c.Issuer,
|
|
|
|
},
|
|
|
|
}, nil
|
2020-09-09 02:26:32 +00:00
|
|
|
}
|