@@ -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.
558558func (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
0 commit comments