Skip to content

Commit 2cfc589

Browse files
committed
Potential fixes for ARI: blocking, and wrong issuer
1 parent 258b532 commit 2cfc589

File tree

3 files changed

+39
-31
lines changed

3 files changed

+39
-31
lines changed

acmeclient.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ func (iss *ACMEIssuer) newBasicACMEClient() (*acmez.Client, error) {
278278
Directory: caURL,
279279
UserAgent: buildUAString(),
280280
HTTPClient: iss.httpClient,
281-
Logger: slog.New(zapslog.NewHandler(iss.Logger.Named("acme_client").Core(), nil)),
281+
Logger: slog.New(zapslog.NewHandler(iss.Logger.Named("acme_client").Core())),
282282
},
283283
}, nil
284284
}

handshake.go

+37-29
Original file line numberDiff line numberDiff line change
@@ -556,12 +556,28 @@ func (cfg *Config) obtainOnDemandCertificate(ctx context.Context, hello *tls.Cli
556556
//
557557
// This function is safe for use by multiple concurrent goroutines.
558558
func (cfg *Config) handshakeMaintenance(ctx context.Context, hello *tls.ClientHelloInfo, cert Certificate) (Certificate, error) {
559-
logger := cfg.Logger.Named("on_demand")
559+
logger := cfg.Logger.Named("on_demand").With(
560+
zap.Strings("identifiers", cert.Names),
561+
zap.String("server_name", hello.ServerName))
562+
563+
renewIfNecessary := func(ctx context.Context, hello *tls.ClientHelloInfo, cert Certificate) (Certificate, error) {
564+
if cfg.certNeedsRenewal(cert.Leaf, cert.ari, true) {
565+
// Check if the certificate still exists on disk. If not, we need to obtain a new one.
566+
// This can happen if the certificate was cleaned up by the storage cleaner, but still
567+
// remains in the in-memory cache.
568+
if !cfg.storageHasCertResourcesAnyIssuer(ctx, cert.Names[0]) {
569+
logger.Debug("certificate not found on disk; obtaining new certificate")
570+
return cfg.obtainOnDemandCertificate(ctx, hello)
571+
}
572+
// Otherwise, renew the certificate.
573+
return cfg.renewDynamicCertificate(ctx, hello, cert)
574+
}
575+
return cert, nil
576+
}
560577

561578
// Check OCSP staple validity
562579
if cert.ocsp != nil && !freshOCSP(cert.ocsp) {
563580
logger.Debug("OCSP response needs refreshing",
564-
zap.Strings("identifiers", cert.Names),
565581
zap.Int("ocsp_status", cert.ocsp.Status),
566582
zap.Time("this_update", cert.ocsp.ThisUpdate),
567583
zap.Time("next_update", cert.ocsp.NextUpdate))
@@ -570,13 +586,9 @@ func (cfg *Config) handshakeMaintenance(ctx context.Context, hello *tls.ClientHe
570586
if err != nil {
571587
// An error with OCSP stapling is not the end of the world, and in fact, is
572588
// quite common considering not all certs have issuer URLs that support it.
573-
logger.Warn("stapling OCSP",
574-
zap.String("server_name", hello.ServerName),
575-
zap.Strings("sans", cert.Names),
576-
zap.Error(err))
589+
logger.Warn("stapling OCSP", zap.Error(err))
577590
} else {
578591
logger.Debug("successfully stapled new OCSP response",
579-
zap.Strings("identifiers", cert.Names),
580592
zap.Int("ocsp_status", cert.ocsp.Status),
581593
zap.Time("this_update", cert.ocsp.ThisUpdate),
582594
zap.Time("next_update", cert.ocsp.NextUpdate))
@@ -590,41 +602,37 @@ func (cfg *Config) handshakeMaintenance(ctx context.Context, hello *tls.ClientHe
590602

591603
// Check ARI status
592604
if !cfg.DisableARI && cert.ari.NeedsRefresh() {
593-
// we ignore the second return value here because we go on to check renewal status below regardless
594-
var err error
595-
cert, _, err = cfg.updateARI(ctx, cert, logger)
596-
if err != nil {
597-
logger.Error("updated ARI", zap.Error(err))
598-
}
605+
// update ARI in a goroutine to avoid blocking an active handshake, since the results of
606+
// this do not strictly affect the handshake; even though the cert may be updated with
607+
// the new ARI, it is also updated in the cache and in storage, so future handshakes
608+
// will utilize it
609+
go func(ctx context.Context, hello *tls.ClientHelloInfo, cert Certificate, logger *zap.Logger) {
610+
var err error
611+
// we ignore the second return value here because we check renewal status below regardless
612+
cert, _, err = cfg.updateARI(ctx, cert, logger)
613+
if err != nil {
614+
logger.Error("updating ARI", zap.Error(err))
615+
}
616+
_, err = renewIfNecessary(ctx, hello, cert)
617+
if err != nil {
618+
logger.Error("renewing certificate based on updated ARI", zap.Error(err))
619+
}
620+
}(ctx, hello, cert, logger)
599621
}
600622

601623
// We attempt to replace any certificates that were revoked.
602624
// Crucially, this happens OUTSIDE a lock on the certCache.
603625
if certShouldBeForceRenewed(cert) {
604626
logger.Warn("on-demand certificate's OCSP status is REVOKED; will try to forcefully renew",
605-
zap.Strings("identifiers", cert.Names),
606627
zap.Int("ocsp_status", cert.ocsp.Status),
607628
zap.Time("revoked_at", cert.ocsp.RevokedAt),
608629
zap.Time("this_update", cert.ocsp.ThisUpdate),
609630
zap.Time("next_update", cert.ocsp.NextUpdate))
610631
return cfg.renewDynamicCertificate(ctx, hello, cert)
611632
}
612633

613-
// Check cert expiration
614-
if cfg.certNeedsRenewal(cert.Leaf, cert.ari, true) {
615-
// Check if the certificate still exists on disk. If not, we need to obtain a new one.
616-
// This can happen if the certificate was cleaned up by the storage cleaner, but still
617-
// remains in the in-memory cache.
618-
if !cfg.storageHasCertResourcesAnyIssuer(ctx, cert.Names[0]) {
619-
logger.Debug("certificate not found on disk; obtaining new certificate",
620-
zap.Strings("identifiers", cert.Names))
621-
return cfg.obtainOnDemandCertificate(ctx, hello)
622-
}
623-
// Otherwise, renew the certificate.
624-
return cfg.renewDynamicCertificate(ctx, hello, cert)
625-
}
626-
627-
return cert, nil
634+
// Since renewal conditions may have changed, do a renewal if necessary
635+
return renewIfNecessary(ctx, hello, cert)
628636
}
629637

630638
// renewDynamicCertificate renews the certificate for name using cfg. It returns the

maintain.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ func (cfg *Config) updateARI(ctx context.Context, cert Certificate, logger *zap.
523523

524524
// of the issuers configured, hopefully one of them is the ACME CA we got the cert from
525525
for _, iss := range cfg.Issuers {
526-
if ariGetter, ok := iss.(RenewalInfoGetter); ok {
526+
if ariGetter, ok := iss.(RenewalInfoGetter); ok && iss.IssuerKey() == cert.issuerKey {
527527
newARI, err = ariGetter.GetRenewalInfo(ctx, cert) // be sure to use existing newARI variable so we can compare against old value in the defer
528528
if err != nil {
529529
// could be anything, but a common error might simply be the "wrong" ACME CA

0 commit comments

Comments
 (0)