Skip to content

Commit

Permalink
caddypki: Load intermediate for signing on-the-fly (#4669)
Browse files Browse the repository at this point in the history
* caddypki: Load intermediate for signing on-the-fly

Fixes #4517

Big thanks to @maraino for adding an API in `smallstep/certificates` so that we can fix this

* Debug log

* Trying a hunch, does it need to be a pointer receiver?

* Clarify pointer receiver

Co-authored-by: Matt Holt <[email protected]>

Co-authored-by: Matt Holt <[email protected]>
  • Loading branch information
francislavoie and mholt authored Apr 13, 2022
1 parent e253523 commit bc15b4b
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 9 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
33 changes: 27 additions & 6 deletions modules/caddypki/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down

0 comments on commit bc15b4b

Please sign in to comment.