Add fault tolerance against clock skew accross system on TLS certificates.

This commit is contained in:
Mariano Cano 2020-01-02 17:48:28 -08:00 committed by max furman
parent e6cafb89b6
commit 5565d61bf3
3 changed files with 48 additions and 13 deletions

View file

@ -28,6 +28,7 @@ var (
MaxVersion: 1.2,
Renegotiation: false,
}
defaultBackdate = time.Minute
defaultDisableRenewal = false
defaultEnableSSHCA = false
globalProvisionerClaims = provisioner.Claims{
@ -65,10 +66,11 @@ type Config struct {
// AuthConfig represents the configuration options for the authority.
type AuthConfig struct {
Provisioners provisioner.List `json:"provisioners"`
Template *x509util.ASN1DN `json:"template,omitempty"`
Claims *provisioner.Claims `json:"claims,omitempty"`
DisableIssuedAtCheck bool `json:"disableIssuedAtCheck,omitempty"`
Provisioners provisioner.List `json:"provisioners"`
Template *x509util.ASN1DN `json:"template,omitempty"`
Claims *provisioner.Claims `json:"claims,omitempty"`
DisableIssuedAtCheck bool `json:"disableIssuedAtCheck,omitempty"`
Backdate *provisioner.Duration `json:"backdate,omitempty"`
}
// Validate validates the authority configuration.
@ -91,6 +93,17 @@ func (c *AuthConfig) Validate(audiences provisioner.Audiences) error {
if c.Template == nil {
c.Template = &x509util.ASN1DN{}
}
if c.Backdate != nil {
if c.Backdate.Duration < 0 {
return errors.New("authority.backdate cannot be less than 0")
}
} else {
c.Backdate = &provisioner.Duration{
Duration: defaultBackdate,
}
}
return nil
}

View file

@ -15,10 +15,12 @@ import (
"golang.org/x/crypto/ed25519"
)
// Options contains the options that can be passed to the Sign method.
// Options contains the options that can be passed to the Sign method. Backdate
// is automatically filled and can only be configured in the CA.
type Options struct {
NotAfter TimeDuration `json:"notAfter"`
NotBefore TimeDuration `json:"notBefore"`
NotAfter TimeDuration `json:"notAfter"`
NotBefore TimeDuration `json:"notBefore"`
Backdate time.Duration `json:"-"`
}
// SignOption is the interface used to collect all extra options used in the
@ -189,12 +191,22 @@ func (v emailAddressesValidator) Valid(req *x509.CertificateRequest) error {
type profileDefaultDuration time.Duration
func (v profileDefaultDuration) Option(so Options) x509util.WithOption {
var backdate time.Duration
notBefore := so.NotBefore.Time()
if notBefore.IsZero() {
notBefore = time.Now()
backdate = -1 * so.Backdate
}
notAfter := so.NotAfter.RelativeTime(notBefore)
return x509util.WithNotBeforeAfterDuration(notBefore, notAfter, time.Duration(v))
return func(p x509util.Profile) error {
fn := x509util.WithNotBeforeAfterDuration(notBefore, notAfter, time.Duration(v))
if err := fn(p); err != nil {
return err
}
crt := p.Subject()
crt.NotBefore = crt.NotBefore.Add(backdate)
return nil
}
}
// profileLimitDuration is an x509 profile option that modifies an x509 validity
@ -208,10 +220,12 @@ type profileLimitDuration struct {
// certificate to one that is superficially imposed.
func (v profileLimitDuration) Option(so Options) x509util.WithOption {
return func(p x509util.Profile) error {
var backdate time.Duration
n := now()
notBefore := so.NotBefore.Time()
if notBefore.IsZero() {
notBefore = n
backdate = -1 * so.Backdate
}
if notBefore.After(v.notAfter) {
return errors.Errorf("provisioning credential expiration (%s) is before "+
@ -232,7 +246,7 @@ func (v profileLimitDuration) Option(so Options) x509util.WithOption {
}
}
crt := p.Subject()
crt.NotBefore = notBefore
crt.NotBefore = notBefore.Add(backdate)
crt.NotAfter = notAfter
return nil
}
@ -255,9 +269,10 @@ func (v *validityValidator) Valid(crt *x509.Certificate) error {
var (
na = crt.NotAfter
nb = crt.NotBefore
d = na.Sub(nb)
now = time.Now()
)
// Get duration from to not take into account the backdate.
var d = na.Sub(now)
if na.Before(now) {
return errors.Errorf("NotAfter: %v cannot be in the past", na)

View file

@ -65,6 +65,10 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Opti
certValidators = []provisioner.CertificateValidator{}
issIdentity = a.intermediateIdentity
)
// Set backdate with the configured value
signOpts.Backdate = a.config.AuthorityConfig.Backdate.Duration
for _, op := range extraOpts {
switch k := op.(type) {
case provisioner.CertificateValidator:
@ -136,14 +140,17 @@ func (a *Authority) Renew(oldCert *x509.Certificate) ([]*x509.Certificate, error
// Issuer
issIdentity := a.intermediateIdentity
now := time.Now().UTC()
// Durations
backdate := a.config.AuthorityConfig.Backdate.Duration
duration := oldCert.NotAfter.Sub(oldCert.NotBefore)
now := time.Now().UTC()
newCert := &x509.Certificate{
PublicKey: oldCert.PublicKey,
Issuer: issIdentity.Crt.Subject,
Subject: oldCert.Subject,
NotBefore: now,
NotAfter: now.Add(duration),
NotBefore: now.Add(-1 * backdate),
NotAfter: now.Add(duration - backdate),
KeyUsage: oldCert.KeyUsage,
UnhandledCriticalExtensions: oldCert.UnhandledCriticalExtensions,
ExtKeyUsage: oldCert.ExtKeyUsage,