forked from TrueCloudLab/certificates
Convert x509util.WithOptions to new modifiers.
This commit is contained in:
parent
dcb962bdde
commit
9032018cf2
1 changed files with 84 additions and 106 deletions
|
@ -6,13 +6,14 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/smallstep/cli/crypto/x509util"
|
"github.com/smallstep/certificates/x509util"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ import (
|
||||||
type Options struct {
|
type Options struct {
|
||||||
NotAfter TimeDuration `json:"notAfter"`
|
NotAfter TimeDuration `json:"notAfter"`
|
||||||
NotBefore TimeDuration `json:"notBefore"`
|
NotBefore TimeDuration `json:"notBefore"`
|
||||||
|
UserData json.RawMessage `json:"data"`
|
||||||
Backdate time.Duration `json:"-"`
|
Backdate time.Duration `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,41 +30,30 @@ type Options struct {
|
||||||
// Sign method.
|
// Sign method.
|
||||||
type SignOption interface{}
|
type SignOption interface{}
|
||||||
|
|
||||||
// CertificateValidator is the interface used to validate a X.509 certificate.
|
// CertificateValidator is an interface used to validate a given X.509 certificate.
|
||||||
type CertificateValidator interface {
|
type CertificateValidator interface {
|
||||||
SignOption
|
Valid(cert *x509.Certificate, opts Options) error
|
||||||
Valid(cert *x509.Certificate, o Options) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CertificateRequestValidator is the interface used to validate a X.509
|
// CertificateRequestValidator is an interface used to validate a given X.509 certificate request.
|
||||||
// certificate request.
|
|
||||||
type CertificateRequestValidator interface {
|
type CertificateRequestValidator interface {
|
||||||
SignOption
|
Valid(cr *x509.CertificateRequest) error
|
||||||
Valid(req *x509.CertificateRequest) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProfileModifier is the interface used to add custom options to the profile
|
// CertificateModifier is an interface used to modify a given X.509 certificate.
|
||||||
// constructor. The options are used to modify the final certificate.
|
// Types implementing this interface will be validated with a
|
||||||
type ProfileModifier interface {
|
// CertificateValidator.
|
||||||
SignOption
|
type CertificateModifier interface {
|
||||||
Option(o Options) x509util.WithOption
|
Modify(cert *x509.Certificate, opts Options) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// CertificateEnforcer is the interface used to modify a certificate after
|
// CertificateEnforcer is an interface used to modify a given X.509 certificate.
|
||||||
// validation.
|
// Types implemented this interface will NOT be validated with a
|
||||||
|
// CertificateValidator.
|
||||||
type CertificateEnforcer interface {
|
type CertificateEnforcer interface {
|
||||||
SignOption
|
|
||||||
Enforce(cert *x509.Certificate) error
|
Enforce(cert *x509.Certificate) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// profileWithOption is a wrapper against x509util.WithOption to conform the
|
|
||||||
// interface.
|
|
||||||
type profileWithOption x509util.WithOption
|
|
||||||
|
|
||||||
func (v profileWithOption) Option(Options) x509util.WithOption {
|
|
||||||
return x509util.WithOption(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// emailOnlyIdentity is a CertificateRequestValidator that checks that the only
|
// emailOnlyIdentity is a CertificateRequestValidator that checks that the only
|
||||||
// SAN provided is the given email address.
|
// SAN provided is the given email address.
|
||||||
type emailOnlyIdentity string
|
type emailOnlyIdentity string
|
||||||
|
@ -254,28 +245,27 @@ func (eee ExtraExtsEnforcer) Enforce(cert *x509.Certificate) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// profileDefaultDuration is a wrapper against x509util.WithOption to conform
|
// profileDefaultDuration is a modifier that sets the certificate
|
||||||
// the SignOption interface.
|
// duration.
|
||||||
type profileDefaultDuration time.Duration
|
type profileDefaultDuration time.Duration
|
||||||
|
|
||||||
func (v profileDefaultDuration) Option(so Options) x509util.WithOption {
|
func (v profileDefaultDuration) Modify(cert *x509.Certificate, so Options) error {
|
||||||
var backdate time.Duration
|
var backdate time.Duration
|
||||||
notBefore := so.NotBefore.Time()
|
notBefore := so.NotBefore.Time()
|
||||||
if notBefore.IsZero() {
|
if notBefore.IsZero() {
|
||||||
notBefore = now()
|
notBefore = now()
|
||||||
backdate = -1 * so.Backdate
|
backdate = -1 * so.Backdate
|
||||||
|
|
||||||
}
|
}
|
||||||
notAfter := so.NotAfter.RelativeTime(notBefore)
|
notAfter := so.NotAfter.RelativeTime(notBefore)
|
||||||
return func(p x509util.Profile) error {
|
if notAfter.IsZero() {
|
||||||
fn := x509util.WithNotBeforeAfterDuration(notBefore, notAfter, time.Duration(v))
|
notAfter = notBefore.Add(time.Duration(v))
|
||||||
if err := fn(p); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
crt := p.Subject()
|
|
||||||
crt.NotBefore = crt.NotBefore.Add(backdate)
|
cert.NotBefore = notBefore.Add(backdate)
|
||||||
|
cert.NotAfter = notAfter
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// profileLimitDuration is an x509 profile option that modifies an x509 validity
|
// profileLimitDuration is an x509 profile option that modifies an x509 validity
|
||||||
// period according to an imposed expiration time.
|
// period according to an imposed expiration time.
|
||||||
|
@ -286,13 +276,11 @@ type profileLimitDuration struct {
|
||||||
|
|
||||||
// Option returns an x509util option that limits the validity period of a
|
// Option returns an x509util option that limits the validity period of a
|
||||||
// certificate to one that is superficially imposed.
|
// certificate to one that is superficially imposed.
|
||||||
func (v profileLimitDuration) Option(so Options) x509util.WithOption {
|
func (v profileLimitDuration) Modify(cert *x509.Certificate, so Options) error {
|
||||||
return func(p x509util.Profile) error {
|
|
||||||
var backdate time.Duration
|
var backdate time.Duration
|
||||||
n := now()
|
|
||||||
notBefore := so.NotBefore.Time()
|
notBefore := so.NotBefore.Time()
|
||||||
if notBefore.IsZero() {
|
if notBefore.IsZero() {
|
||||||
notBefore = n
|
notBefore = now()
|
||||||
backdate = -1 * so.Backdate
|
backdate = -1 * so.Backdate
|
||||||
}
|
}
|
||||||
if notBefore.Before(v.notBefore) {
|
if notBefore.Before(v.notBefore) {
|
||||||
|
@ -315,12 +303,11 @@ func (v profileLimitDuration) Option(so Options) x509util.WithOption {
|
||||||
notAfter = t
|
notAfter = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
crt := p.Subject()
|
|
||||||
crt.NotBefore = notBefore.Add(backdate)
|
cert.NotBefore = notBefore.Add(backdate)
|
||||||
crt.NotAfter = notAfter
|
cert.NotAfter = notAfter
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// validityValidator validates the certificate validity settings.
|
// validityValidator validates the certificate validity settings.
|
||||||
type validityValidator struct {
|
type validityValidator struct {
|
||||||
|
@ -385,23 +372,22 @@ func newForceCNOption(forceCN bool) *forceCNOption {
|
||||||
return &forceCNOption{forceCN}
|
return &forceCNOption{forceCN}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *forceCNOption) Option(Options) x509util.WithOption {
|
func (o *forceCNOption) Modify(cert *x509.Certificate, _ Options) error {
|
||||||
return func(p x509util.Profile) error {
|
|
||||||
if !o.ForceCN {
|
if !o.ForceCN {
|
||||||
// Forcing CN is disabled, do nothing to certificate
|
// Forcing CN is disabled, do nothing to certificate
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
crt := p.Subject()
|
|
||||||
if crt.Subject.CommonName == "" {
|
if cert.Subject.CommonName == "" {
|
||||||
if len(crt.DNSNames) > 0 {
|
if len(cert.DNSNames) > 0 {
|
||||||
crt.Subject.CommonName = crt.DNSNames[0]
|
cert.Subject.CommonName = cert.DNSNames[0]
|
||||||
} else {
|
} else {
|
||||||
return errors.New("Cannot force CN, DNSNames is empty")
|
return errors.New("Cannot force CN, DNSNames is empty")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
type provisionerExtensionOption struct {
|
type provisionerExtensionOption struct {
|
||||||
Type int
|
Type int
|
||||||
|
@ -419,9 +405,7 @@ func newProvisionerExtensionOption(typ Type, name, credentialID string, keyValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *provisionerExtensionOption) Option(Options) x509util.WithOption {
|
func (o *provisionerExtensionOption) Modify(cert *x509.Certificate, _ Options) error {
|
||||||
return func(p x509util.Profile) error {
|
|
||||||
crt := p.Subject()
|
|
||||||
ext, err := createProvisionerExtension(o.Type, o.Name, o.CredentialID, o.KeyValuePairs...)
|
ext, err := createProvisionerExtension(o.Type, o.Name, o.CredentialID, o.KeyValuePairs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -433,10 +417,9 @@ func (o *provisionerExtensionOption) Option(Options) x509util.WithOption {
|
||||||
// ExtraExtension. If we were to append (rather than prepend) the correct
|
// ExtraExtension. If we were to append (rather than prepend) the correct
|
||||||
// stepOIDProvisioner extension, then the resulting certificate would
|
// stepOIDProvisioner extension, then the resulting certificate would
|
||||||
// contain the malicious extension, rather than the one applied by step-ca.
|
// contain the malicious extension, rather than the one applied by step-ca.
|
||||||
crt.ExtraExtensions = append([]pkix.Extension{ext}, crt.ExtraExtensions...)
|
cert.ExtraExtensions = append([]pkix.Extension{ext}, cert.ExtraExtensions...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func createProvisionerExtension(typ int, name, credentialID string, keyValuePairs ...string) (pkix.Extension, error) {
|
func createProvisionerExtension(typ int, name, credentialID string, keyValuePairs ...string) (pkix.Extension, error) {
|
||||||
b, err := asn1.Marshal(stepProvisionerASN1{
|
b, err := asn1.Marshal(stepProvisionerASN1{
|
||||||
|
@ -454,8 +437,3 @@ func createProvisionerExtension(typ int, name, credentialID string, keyValuePair
|
||||||
Value: b,
|
Value: b,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Avoid dead-code warning in profileWithOption
|
|
||||||
_ = profileWithOption(nil)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue