diff --git a/go.mod b/go.mod index 61dc9cf8baf..a34af65363a 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/lucas-clemente/quic-go v0.26.0 github.com/mholt/acmez v1.0.2 github.com/prometheus/client_golang v1.12.1 - github.com/smallstep/certificates v0.18.3-0.20220328195804-49de04661b85 + github.com/smallstep/certificates v0.18.3-0.20220329212333-b42c1dfe64cf github.com/smallstep/cli v0.18.0 github.com/smallstep/nosql v0.4.0 github.com/smallstep/truststore v0.11.0 diff --git a/go.sum b/go.sum index 661d59f2444..b28ef041137 100644 --- a/go.sum +++ b/go.sum @@ -945,8 +945,8 @@ github.com/smallstep/assert v0.0.0-20180720014142-de77670473b5/go.mod h1:TC9A4+R github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= github.com/smallstep/certificates v0.18.0/go.mod h1:8eHwHNg/bRWvNZo9S0uWFVMkS+LSpDYxM4//EgBhkFM= -github.com/smallstep/certificates v0.18.3-0.20220328195804-49de04661b85 h1:iXoo8eraLn0rFbn92eVd8dNjj1jcHcYsOQaqssUPTZ4= -github.com/smallstep/certificates v0.18.3-0.20220328195804-49de04661b85/go.mod h1:K4gQuZo7j4kzQb0zF0A2s6/kiPh3ZhmFThlHh2B+Gwg= +github.com/smallstep/certificates v0.18.3-0.20220329212333-b42c1dfe64cf h1:Ky0hrHTjd/sXrLZj1rKEBYRo/3nmOUIk3xyqnrs04jY= +github.com/smallstep/certificates v0.18.3-0.20220329212333-b42c1dfe64cf/go.mod h1:K4gQuZo7j4kzQb0zF0A2s6/kiPh3ZhmFThlHh2B+Gwg= github.com/smallstep/certinfo v1.5.2/go.mod h1:gA7HBbue0Wwr3kD60P2UtgTIFfMAOC66D3rzYhI0GZ4= github.com/smallstep/cli v0.18.0 h1:BslbUHuMfj/LbVHxuZ4Hv1sL+vAHHidqia4JRoCBwXs= github.com/smallstep/cli v0.18.0/go.mod h1:C8ZSfMm/pKdCHnN1C3Pc44bjIOkBbyuoyq6XjS/K9lI= diff --git a/modules/caddypki/ca.go b/modules/caddypki/ca.go index c9bdeee6beb..ca9ba469f5d 100644 --- a/modules/caddypki/ca.go +++ b/modules/caddypki/ca.go @@ -182,30 +182,51 @@ func (ca CA) IntermediateKey() interface{} { } // NewAuthority returns a new Smallstep-powered signing authority for this CA. -func (ca CA) NewAuthority(authorityConfig AuthorityConfig) (*authority.Authority, error) { +// Note that we receive *CA (a pointer) in this method to ensure the closure within it, which +// executes at a later time, always has the only copy of the CA so it can access the latest, +// renewed certificates since NewAuthority was called. See #4517 and #4669. +func (ca *CA) NewAuthority(authorityConfig AuthorityConfig) (*authority.Authority, error) { // get the root certificate and the issuer cert+key rootCert := ca.RootCertificate() - var issuerCert *x509.Certificate - var issuerKey interface{} + + // set up the signer; cert/key which signs the leaf certs + var signerOption authority.Option if authorityConfig.SignWithRoot { + // if we're signing with root, we can just pass the + // cert/key directly, since it's unlikely to expire + // while Caddy is running (long lifetime) + var issuerCert *x509.Certificate + var issuerKey interface{} issuerCert = rootCert var err error issuerKey, err = ca.RootKey() if err != nil { return nil, fmt.Errorf("loading signing key: %v", err) } + signerOption = authority.WithX509Signer(issuerCert, issuerKey.(crypto.Signer)) } else { - issuerCert = ca.IntermediateCertificate() - issuerKey = ca.IntermediateKey() + // if we're signing with intermediate, we need to make + // sure it's always fresh, because the intermediate may + // renew while Caddy is running (medium lifetime) + signerOption = authority.WithX509SignerFunc(func() ([]*x509.Certificate, crypto.Signer, error) { + issuerCert := ca.IntermediateCertificate() + issuerKey := ca.IntermediateKey().(crypto.Signer) + ca.log.Debug("using intermediate signer", + zap.String("serial", issuerCert.SerialNumber.String()), + zap.String("not_before", issuerCert.NotBefore.String()), + zap.String("not_after", issuerCert.NotAfter.String())) + return []*x509.Certificate{issuerCert}, issuerKey, nil + }) } opts := []authority.Option{ authority.WithConfig(&authority.Config{ AuthorityConfig: authorityConfig.AuthConfig, }), - authority.WithX509Signer(issuerCert, issuerKey.(crypto.Signer)), + signerOption, authority.WithX509RootCerts(rootCert), } + // Add a database if we have one if authorityConfig.DB != nil { opts = append(opts, authority.WithDatabase(*authorityConfig.DB))