return logical and compliant ARI windows for expiring certs#484
Conversation
If the windowEnd is after the cert's expiry, adjust it to the window end.
| if expires.Before(now) { | ||
| // If the cert has expired, return `RenewalInfoImmediate` instead. | ||
| return RenewalInfoImmediate(now) | ||
| } | ||
|
|
||
| if expires.Before(windowEnd) { | ||
| // If the windowEnd is after the cert's expiry, adjust it to the window end. | ||
| windowStart = expires.Add(-1 * time.Second) | ||
| windowEnd = expires | ||
| } | ||
|
|
||
| if !windowEnd.After(windowStart) { | ||
| // Ensure windowStart is before windowEnd | ||
| windowEnd = expires.Add(-1 * time.Second) | ||
| } |
There was a problem hiding this comment.
There is a lint error here: these lines all have incorrect indentation.
More importantly, I think there's a much simpler version of this logic that accomplishes the same goal:
- If windowEnd is after expires, make it equal to expires
- If windowStart is before issued, make it equal to issued
True, this doesn't explicitly protect against a certificate which has a zero-second validity period, but I'm not worried about that case.
There was a problem hiding this comment.
I did the first element and changed initial spacing. I don't know why my editor was auto-expanding tabs here. I added the windowStart change to issued as well.
I left the last element, however, ensuring windowStart is BEFORE windowEnd - and included a reference to the RFC. The RFC draft explicitly requires windowStart to precede windowEnd, and the payload is invalid otherwise.
Striving to simplify logic has caveats. I prioritized ensuring an ARI compliant payload over edge cases of future notBefore values or zero second validity.
jvanasco
left a comment
There was a problem hiding this comment.
Some requested changes were made; some alternatives were presented.
| if expires.Before(now) { | ||
| // If the cert has expired, return `RenewalInfoImmediate` instead. | ||
| return RenewalInfoImmediate(now) | ||
| } | ||
|
|
||
| if expires.Before(windowEnd) { | ||
| // If the windowEnd is after the cert's expiry, adjust it to the window end. | ||
| windowStart = expires.Add(-1 * time.Second) | ||
| windowEnd = expires | ||
| } | ||
|
|
||
| if !windowEnd.After(windowStart) { | ||
| // Ensure windowStart is before windowEnd | ||
| windowEnd = expires.Add(-1 * time.Second) | ||
| } |
There was a problem hiding this comment.
I did the first element and changed initial spacing. I don't know why my editor was auto-expanding tabs here. I added the windowStart change to issued as well.
I left the last element, however, ensuring windowStart is BEFORE windowEnd - and included a reference to the RFC. The RFC draft explicitly requires windowStart to precede windowEnd, and the payload is invalid otherwise.
Striving to simplify logic has caveats. I prioritized ensuring an ARI compliant payload over edge cases of future notBefore values or zero second validity.
| } | ||
|
|
||
| // Ensure RenewalWindow is not after the expiry | ||
| if windowEnd.After(expires){ |
There was a problem hiding this comment.
You still have formatting issues here, and below. You should be running gofmt automatically.
| if windowEnd.After(expires){ | |
| if windowEnd.After(expires) { |
There was a problem hiding this comment.
Ah! It's not performing on directories, just specific files. Fixed.
| if expires.Before(now) { | ||
| // If the cert has expired, return `RenewalInfoImmediate` instead. | ||
| return RenewalInfoImmediate(now) | ||
| } |
There was a problem hiding this comment.
This is redundant: if we're clamping windowEnd to expires, then an expired cert will always be given a window that is wholly in the past. No need to special case it here. This is why I suggested the removal of this stanza in my previous review.
If you want to keep it anyway, move it above the computation of the ideal window, since none of that computation is necessary for this stanza.
There was a problem hiding this comment.
Oh, that makes sense. I just removed it.
| // Ensure correct start for future issueds | ||
| if windowStart.After(issued){ |
There was a problem hiding this comment.
I didn't suggest this to handle issued timestamps that are in the future. I suggested this to handle the case where the certificate has a validity period of less than 48 hours, so that subtracting 24 hours from a point in the middle of the validity period results in a windowStart that precedes the issued timestamp.
Also, you've reversed the logic from what I suggested. This should be if windowStart.Before(issued) {.
There was a problem hiding this comment.
Sorry, I was trying to do this in one window while debugging another upstream project in the cloud.
|
This should have all the requested changes and formatting. Apologies. I've also tested it against with a client as I couldn't find any ARI tests here. |
* 'main' of https://github.com/letsencrypt/pebble: (35 commits) add overriding of ARI response (letsencrypt#501) wfe: fix a race in `orderForDisplay` (letsencrypt#500) Bump golang.org/x/ dependencies (letsencrypt#499) currectly triggers BadSignatureAlgorithmProblem at JWS parse time (letsencrypt#492) use newer validation subdomain for dns-account-01 (fix CI eggsampler/acme error) (letsencrypt#498) Orders don't have a "deactivated" status. (letsencrypt#301) Update golangci-lint (letsencrypt#488) build(deps): bump github.com/go-jose/go-jose/v4 from 4.0.4 to 4.0.5 (letsencrypt#487) Truncate ARI timestamps to millisecond resolution (letsencrypt#485) return logical and compliant ARI windows for expiring certs (letsencrypt#484) Update dependencies (letsencrypt#481) docs: rm mention of subproblems being unimpl'd (letsencrypt#479) Fix(NOISSUE): Fix docker compose file example in README.md (letsencrypt#475) Add support for ACME Profiles (letsencrypt#473) Simplify KU, EKU, and SKID fields of issued certs (letsencrypt#472) Update golangci-lint to 1.60.2 (letsencrypt#474) Update /x/net for compatibility with go1.23 (letsencrypt#470) Reject extra command line args and fix README invocation (letsencrypt#467) Document exposing API and management ports when not using docker-compose.yaml (letsencrypt#465) Implement latest draft-ietf-acme-ari spec (letsencrypt#461) ...
While testing ARI functionality with extremely short lived certs, Pebble returned illogical data - such as the windowEnd appearing in the future for already expired certs, or after the cert's notAfter.
This PR adjusts
RenewalInfoSimpleto do the following:RenewalInfoImmediatewindowEnd, set thewindowEndto the cert'snotAfterwindowStartto be beforewindowEnd, so remove a second from thewindowStartif needed.I also made the
RenewalInfoImmediatewindow change from-60:-30minutes to-60:-59.59minutes; the sole reason for this change is that it is visually easier to see the change (and not need to do mental math) and recognize this is aRenewalInfoImmediatefrom logs.There are likely better ways to accomplish this, and I may be overlooking some elements from the RFC.
With these changes, Pebble can be configured for certificate validity periods as low as 5-10seconds, enabling quick testing of real (unmocked) flows such as:
replacesAlso: The linting errors existed on creating my fork; there may be some linting errors in this PR - but there is a library issue.