Skip to content

Conversation

@oliverpool
Copy link
Contributor

This should help address #361:
instead of always indicating the replaced cert, only fill this field if the ARI suggested window is not over.

This is not a perfect solution (ideally the alreadyReplaced response should be explicitly handled), however it should prevent having the current case of unrenewable certificates.

@mholt
Copy link
Member

mholt commented Jan 7, 2026

Thanks for the PR!

Hmm, I am not sure if the time relative to the ARI window's end is the right condition for whether to set replaces. The certificate could be renewed before, during, or after the window for various reasons, and so replaces should still be set. The key requirement, I think, is that it needs to be set on the first (and ideally only) renewal of the certificate of the same SAN.

That specific requirement still baffles me, and in ietf-wg-acme/acme-ari#56 I requested that renewal/replacing be idempotent, and questioned the reason to reject orders when a certificate has already been replaced. ("So what?") It seems like the point should be to reconcile the state between client and server, but the server is the only one that cares -- the client just needs a cert, it doesn't really care about checking off what replaces what.

So anyway, I disagree with the approach taken by the spec (or at least LE's implementation), as it introduces unnecessary complexity and confusion. (This is not the first time, alas. I've raised errata before, but it was ultimately ignored.)

Note that the recommended approach by the spec authors is to retry without the replaces field.

I wonder if we should make that specific retry a little more deliberate closer to where it happens so that it works for the GetCertificate case, or, as you suggested in the issue, store the retry state along with the certificate, though I hate storing state so I want to avoid that).

@oliverpool
Copy link
Contributor Author

Hmm, I am not sure if the time relative to the ARI window's end is the right condition for whether to set replaces.

Currently the replace field is only set if ARI is enabled. My PR tightens this condition to “if ARI is set, supported by the server and not in the past” (the server-support is needed according to https://github.com/ietf-wg-acme/acme-ari/blob/main/rfc9773.md#extensions-to-the-order-object “Clients SHOULD NOT include this field if the ACME server has not indicated that it supports this protocol”)


My understanding of (one) ARI usecase is to be able to quickly rotate certificates after an issuer had some security issues. In this case, it might be interesting for the issuer to know when the “wrong” certificate has been replaced, to actively revoke it (hence the "replace" field).

In this (rare) case, the certmagic client will have a big problem (revoked certificate, but the new one didn’t make it somehow).

In all cases, if the ARI window is in the past, it likely means that the attempts made during the ARI window failed. So the issuer might not get the replacement info, but at least the client will not be stuck with an expiring certificate.

@oliverpool
Copy link
Contributor Author

Another approach would be to catch this specific error code and retry immediately without the replace field (in this case).

@mholt
Copy link
Member

mholt commented Jan 12, 2026

I'm leaning toward the other approach!

I will close this for now. Thanks!

@mholt mholt closed this Jan 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants