Add fault tolerance against clock skew accross system on TLS certificates.
This commit is contained in:
parent
e6cafb89b6
commit
5565d61bf3
3 changed files with 48 additions and 13 deletions
|
@ -28,6 +28,7 @@ var (
|
||||||
MaxVersion: 1.2,
|
MaxVersion: 1.2,
|
||||||
Renegotiation: false,
|
Renegotiation: false,
|
||||||
}
|
}
|
||||||
|
defaultBackdate = time.Minute
|
||||||
defaultDisableRenewal = false
|
defaultDisableRenewal = false
|
||||||
defaultEnableSSHCA = false
|
defaultEnableSSHCA = false
|
||||||
globalProvisionerClaims = provisioner.Claims{
|
globalProvisionerClaims = provisioner.Claims{
|
||||||
|
@ -65,10 +66,11 @@ type Config struct {
|
||||||
|
|
||||||
// AuthConfig represents the configuration options for the authority.
|
// AuthConfig represents the configuration options for the authority.
|
||||||
type AuthConfig struct {
|
type AuthConfig struct {
|
||||||
Provisioners provisioner.List `json:"provisioners"`
|
Provisioners provisioner.List `json:"provisioners"`
|
||||||
Template *x509util.ASN1DN `json:"template,omitempty"`
|
Template *x509util.ASN1DN `json:"template,omitempty"`
|
||||||
Claims *provisioner.Claims `json:"claims,omitempty"`
|
Claims *provisioner.Claims `json:"claims,omitempty"`
|
||||||
DisableIssuedAtCheck bool `json:"disableIssuedAtCheck,omitempty"`
|
DisableIssuedAtCheck bool `json:"disableIssuedAtCheck,omitempty"`
|
||||||
|
Backdate *provisioner.Duration `json:"backdate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the authority configuration.
|
// Validate validates the authority configuration.
|
||||||
|
@ -91,6 +93,17 @@ func (c *AuthConfig) Validate(audiences provisioner.Audiences) error {
|
||||||
if c.Template == nil {
|
if c.Template == nil {
|
||||||
c.Template = &x509util.ASN1DN{}
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,12 @@ import (
|
||||||
"golang.org/x/crypto/ed25519"
|
"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 {
|
type Options struct {
|
||||||
NotAfter TimeDuration `json:"notAfter"`
|
NotAfter TimeDuration `json:"notAfter"`
|
||||||
NotBefore TimeDuration `json:"notBefore"`
|
NotBefore TimeDuration `json:"notBefore"`
|
||||||
|
Backdate time.Duration `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignOption is the interface used to collect all extra options used in the
|
// 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
|
type profileDefaultDuration time.Duration
|
||||||
|
|
||||||
func (v profileDefaultDuration) Option(so Options) x509util.WithOption {
|
func (v profileDefaultDuration) Option(so Options) x509util.WithOption {
|
||||||
|
var backdate time.Duration
|
||||||
notBefore := so.NotBefore.Time()
|
notBefore := so.NotBefore.Time()
|
||||||
if notBefore.IsZero() {
|
if notBefore.IsZero() {
|
||||||
notBefore = time.Now()
|
notBefore = time.Now()
|
||||||
|
backdate = -1 * so.Backdate
|
||||||
}
|
}
|
||||||
notAfter := so.NotAfter.RelativeTime(notBefore)
|
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
|
// 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.
|
// certificate to one that is superficially imposed.
|
||||||
func (v profileLimitDuration) Option(so Options) x509util.WithOption {
|
func (v profileLimitDuration) Option(so Options) x509util.WithOption {
|
||||||
return func(p x509util.Profile) error {
|
return func(p x509util.Profile) error {
|
||||||
|
var backdate time.Duration
|
||||||
n := now()
|
n := now()
|
||||||
notBefore := so.NotBefore.Time()
|
notBefore := so.NotBefore.Time()
|
||||||
if notBefore.IsZero() {
|
if notBefore.IsZero() {
|
||||||
notBefore = n
|
notBefore = n
|
||||||
|
backdate = -1 * so.Backdate
|
||||||
}
|
}
|
||||||
if notBefore.After(v.notAfter) {
|
if notBefore.After(v.notAfter) {
|
||||||
return errors.Errorf("provisioning credential expiration (%s) is before "+
|
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 := p.Subject()
|
||||||
crt.NotBefore = notBefore
|
crt.NotBefore = notBefore.Add(backdate)
|
||||||
crt.NotAfter = notAfter
|
crt.NotAfter = notAfter
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -255,9 +269,10 @@ func (v *validityValidator) Valid(crt *x509.Certificate) error {
|
||||||
var (
|
var (
|
||||||
na = crt.NotAfter
|
na = crt.NotAfter
|
||||||
nb = crt.NotBefore
|
nb = crt.NotBefore
|
||||||
d = na.Sub(nb)
|
|
||||||
now = time.Now()
|
now = time.Now()
|
||||||
)
|
)
|
||||||
|
// Get duration from to not take into account the backdate.
|
||||||
|
var d = na.Sub(now)
|
||||||
|
|
||||||
if na.Before(now) {
|
if na.Before(now) {
|
||||||
return errors.Errorf("NotAfter: %v cannot be in the past", na)
|
return errors.Errorf("NotAfter: %v cannot be in the past", na)
|
||||||
|
|
|
@ -65,6 +65,10 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Opti
|
||||||
certValidators = []provisioner.CertificateValidator{}
|
certValidators = []provisioner.CertificateValidator{}
|
||||||
issIdentity = a.intermediateIdentity
|
issIdentity = a.intermediateIdentity
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Set backdate with the configured value
|
||||||
|
signOpts.Backdate = a.config.AuthorityConfig.Backdate.Duration
|
||||||
|
|
||||||
for _, op := range extraOpts {
|
for _, op := range extraOpts {
|
||||||
switch k := op.(type) {
|
switch k := op.(type) {
|
||||||
case provisioner.CertificateValidator:
|
case provisioner.CertificateValidator:
|
||||||
|
@ -136,14 +140,17 @@ func (a *Authority) Renew(oldCert *x509.Certificate) ([]*x509.Certificate, error
|
||||||
// Issuer
|
// Issuer
|
||||||
issIdentity := a.intermediateIdentity
|
issIdentity := a.intermediateIdentity
|
||||||
|
|
||||||
now := time.Now().UTC()
|
// Durations
|
||||||
|
backdate := a.config.AuthorityConfig.Backdate.Duration
|
||||||
duration := oldCert.NotAfter.Sub(oldCert.NotBefore)
|
duration := oldCert.NotAfter.Sub(oldCert.NotBefore)
|
||||||
|
now := time.Now().UTC()
|
||||||
|
|
||||||
newCert := &x509.Certificate{
|
newCert := &x509.Certificate{
|
||||||
PublicKey: oldCert.PublicKey,
|
PublicKey: oldCert.PublicKey,
|
||||||
Issuer: issIdentity.Crt.Subject,
|
Issuer: issIdentity.Crt.Subject,
|
||||||
Subject: oldCert.Subject,
|
Subject: oldCert.Subject,
|
||||||
NotBefore: now,
|
NotBefore: now.Add(-1 * backdate),
|
||||||
NotAfter: now.Add(duration),
|
NotAfter: now.Add(duration - backdate),
|
||||||
KeyUsage: oldCert.KeyUsage,
|
KeyUsage: oldCert.KeyUsage,
|
||||||
UnhandledCriticalExtensions: oldCert.UnhandledCriticalExtensions,
|
UnhandledCriticalExtensions: oldCert.UnhandledCriticalExtensions,
|
||||||
ExtKeyUsage: oldCert.ExtKeyUsage,
|
ExtKeyUsage: oldCert.ExtKeyUsage,
|
||||||
|
|
Loading…
Reference in a new issue