forked from TrueCloudLab/certificates
Add fault tolerance against clock skew accross system on TLS certificates.
This commit is contained in:
parent
1fa35491ea
commit
e67ccd9e3d
3 changed files with 48 additions and 13 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue