Index | Thread | Search

From:
Lloyd <ng2d68@proton.me>
Subject:
Re: acme-client(8): Adapt renewal calculation for shortlived certificates.
To:
Florian Obser <florian@openbsd.org>
Cc:
tech <tech@openbsd.org>
Date:
Tue, 16 Sep 2025 16:59:26 +0000

Download raw body.

Thread
This is a good idea. I have been improving a patch for IP address
certificates and those are currently issued with 6-day validity.

One of the issues was the fixed setting of 30 days for renewal.

Regards
Lloyd

Florian Obser <florian@openbsd.org> wrote:

> If the lifetime is more than 10 days, renew if less than 1/3 of the
> lifetime is left. Otherwise renew after 1/2 of the remaining lifetime.
> 
> Since we suggest to run the cronjob daily, this is capped at 3 days
> remaining lifetime to have the opportunity to run the cronjob at least
> twice.
> 
> I would like to commit this as soon as the tree unlocks again after
> 7.8. OK?
> 
> diff --git revokeproc.c revokeproc.c
> index 0f1bf32678b..6790211e40b 100644
> --- revokeproc.c
> +++ revokeproc.c
> @@ -32,13 +32,11 @@
> 
> #include "extern.h"
> 
> -#define RENEW_ALLOW (30 * 24 * 60 * 60)
> -
> /*
> - * Convert the X509's expiration time into a time_t value.
> + * Convert the X509's notAfter time into a time_t value.
> */
> static time_t
> -X509expires(X509 *x)
> +X509notafter(X509 *x)
> {
> ASN1_TIME *atim;
> struct tm t;
> @@ -58,6 +56,30 @@ X509expires(X509 x)
> return timegm(&t);
> }
> 
> +/
> + * Convert the X509's notBefore time into a time_t value.
> + */
> +static time_t
> +X509notbefore(X509 *x)
> +{
> + ASN1_TIME *atim;
> + struct tm t;
> +
> + if ((atim = X509_getm_notBefore(x)) == NULL) {
> + warnx("missing notBefore");
> + return -1;
> + }
> +
> + memset(&t, 0, sizeof(t));
> +
> + if (!ASN1_TIME_to_tm(atim, &t)) {
> + warnx("invalid ASN1_TIME");
> + return -1;
> + }
> +
> + return timegm(&t);
> +}
> +
> int
> revokeproc(int fd, const char *certfile, int force,
> int revocate, const char *const *alts, size_t altsz)
> @@ -70,7 +92,8 @@ revokeproc(int fd, const char *certfile, int force,
> X509 x = NULL;
> long lval;
> enum revokeop op, rop;
> - time_t t;
> + time_t notafter, notbefore, cert_validity;
> + time_t remaining_validity, renew_allow;
> size_t j;
> 
> /
> @@ -125,8 +148,13 @@ revokeproc(int fd, const char certfile, int force,
> 
> / Read out the expiration date. */
> 
> - if ((t = X509expires(x)) == -1) {
> - warnx("X509expires");
> + if ((notafter = X509notafter(x)) == -1) {
> + warnx("X509notafter");
> + goto out;
> + }
> +
> + if ((notbefore = X509notbefore(x)) == -1) {
> + warnx("X509notbefore");
> goto out;
> }
> 
> @@ -252,14 +280,35 @@ revokeproc(int fd, const char *certfile, int force,
> goto out;
> }
> 
> - rop = time(NULL) >= (t - RENEW_ALLOW) ? REVOKE_EXP : REVOKE_OK;
> 
> + cert_validity = notafter - notbefore;
> +
> + if (cert_validity < 0) {
> + warnx("Invalid cert, expire time before inception time");
> + rc = -1;
> + goto out;
> + }
> + if (cert_validity > 10 * 24 * 60 * 60)
> 
> + renew_allow = cert_validity / 3;
> + else
> + renew_allow = cert_validity / 2;
> +
> + /* We suggest to run renewals daily. Make sure we have 2 chances. */
> + if (renew_allow < 3 * 24 * 60 *60)
> + renew_allow = 3 * 24 * 60 *60;
> +
> + remaining_validity = notafter - time(NULL);
> +
> + if (remaining_validity < renew_allow)
> + rop = REVOKE_EXP;
> + else
> + rop = REVOKE_OK;
> 
> if (rop == REVOKE_EXP)
> dodbg("%s: certificate renewable: %lld days left",
> - certfile, (long long)(t - time(NULL)) / 24 / 60 / 60);
> + certfile, (long long)(remaining_validity / 24 / 60 / 60));
> else
> dodbg("%s: certificate valid: %lld days left",
> - certfile, (long long)(t - time(NULL)) / 24 / 60 / 60);
> + certfile, (long long)(remaining_validity / 24 / 60 / 60));
> 
> if (rop == REVOKE_OK && force) {
> warnx("%s: %sforcing renewal", certfile,
> 
> --
> In my defence, I have been left unsupervised.