From 440c6957f968fbc655bb6548bb8ffb641c74021d Mon Sep 17 00:00:00 2001 From: Aaron Gable Date: Mon, 28 Jul 2025 15:09:55 -0700 Subject: [PATCH] CA: Truncate notBefore and notAfter to second-level precision (#8319) When generating the validity period of a to-be-issued certificate, truncate the notBefore timestamp to second-level precision, trimming off any nanoseconds which won't be represented in the final certificate. Do the same for the notAfter, although this should be a no-op since only whole numbers of seconds are used to compute it from the notBefore. It's possible that this could cause some of the maxBackdate calculations to fail, because truncation can cause the notBefore timestamp to move up to (nearly) 1 second earlier. However, this only becomes a concern in practice if maxBackdate is set to 10 seconds or less. This results in cleaner logs, since Go only prints the fractional seconds portion of a timestamp if it is non-zero: https://go.dev/play/p/iAeSX3VMrJD Fixes https://github.com/letsencrypt/boulder/issues/8318 --- issuance/cert.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/issuance/cert.go b/issuance/cert.go index fdcf5d6af..bddb41cec 100644 --- a/issuance/cert.go +++ b/issuance/cert.go @@ -142,10 +142,10 @@ func (p *Profile) GenerateValidity(now time.Time) (time.Time, time.Time) { // Don't use the full maxBackdate, to ensure that the actual backdate remains // acceptable throughout the rest of the issuance process. backdate := time.Duration(float64(p.maxBackdate.Nanoseconds()) * 0.9) - notBefore := now.Add(-1 * backdate) + notBefore := now.Add(-1 * backdate).Truncate(time.Second) // Subtract one second, because certificate validity periods are *inclusive* // of their final second (Baseline Requirements, Section 1.6.1). - notAfter := notBefore.Add(p.maxValidity).Add(-1 * time.Second) + notAfter := notBefore.Add(p.maxValidity).Add(-1 * time.Second).Truncate(time.Second) return notBefore, notAfter }