Download raw body.
draft-aaron-acme-profiles support for acme-client
On 2025-01-11 11:12 UTC, Stuart Henderson <stu@spacehopper.org> wrote:
> https://letsencrypt.org/2025/01/09/acme-profiles/
> https://datatracker.ietf.org/doc/draft-aaron-acme-profiles/
individual submission, eh?
>
> letsencrypt are allowing selection of different certificate profiles via an
> extension to newOrder. Initially the options are "classic" (as now) and
> "tlsserver" which follows some CA/B recommendations, resulting in these
> changes:
>
> ...
> Signature Algorithm: sha256WithRSAEncryption
> Issuer: C=US, O=(STAGING) Let's Encrypt, CN=(STAGING) Wannabe Watercress R11
> Validity
> Not Before: xxx
> Not After : xxx
> - Subject: CN=xxx
> + Subject:
> Subject Public Key Info:
> ...
> X509v3 extensions:
> X509v3 Key Usage: critical
> - Digital Signature, Key Encipherment
> + Digital Signature
> X509v3 Extended Key Usage:
> - TLS Web Server Authentication, TLS Web Client Authentication
> + TLS Web Server Authentication
> X509v3 Basic Constraints: critical
> CA:FALSE
> - X509v3 Subject Key Identifier:
> - xxx
> X509v3 Authority Key Identifier:
> keyid:xxx
>
> As explained in their announcement, it's currently supported by
> letsencrypt's staging environment but not the production one yet.
> In the future they will also be allowing an *optional* selection
> of "shortlived" with the above changes and also cutting validity
> to 6 days.
>
> (This is probably a precursor to cutting validity by default, but
> my gut feeling is that they'd probably drop to ~30 days but still
> allow sites to select shorter validity if they want).
>
> Here's an implementation of "profile" for acme-client done as a
> setting for the domain.
>
> Thoughts?
>
> Do we want this yet?
it feels a bit early, but the diff is not too invasive. If you want to
put it in and play around with it, OK florian
>
> Is "domain" the right place? It might make sense to allow this under
> "authority" instead of, or as well as, under "domain".
as well as would be neat, with domain overriding authority.
>
> Index: acme-client.conf.5
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/acme-client.conf.5,v
> diff -u -p -r1.29 acme-client.conf.5
> --- acme-client.conf.5 11 Jan 2021 07:23:42 -0000 1.29
> +++ acme-client.conf.5 11 Jan 2025 10:50:51 -0000
> @@ -187,6 +187,9 @@ A backup with name
> is created if
> .Ar file
> exists.
> +.It Ic profile Ar profile
> +The certificate profile to be requested.
> +If this setting is absent, no profile request is made.
> .It Ic sign with Ar authority
> The certificate authority (as declared above in the
> .Sx AUTHORITIES
> Index: extern.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/extern.h,v
> diff -u -p -r1.21 extern.h
> --- extern.h 21 May 2024 05:00:48 -0000 1.21
> +++ extern.h 11 Jan 2025 10:50:51 -0000
> @@ -212,7 +212,7 @@ int keyproc(int, const char *, const c
> enum keytype);
> int netproc(int, int, int, int, int, int, int,
> struct authority_c *, const char *const *,
> - size_t);
> + size_t, const char *);
>
> /*
> * Debugging functions.
> @@ -263,7 +263,7 @@ char *json_getstr(struct jsmnn *, const
> char *json_fmt_newcert(const char *);
> char *json_fmt_chkacc(void);
> char *json_fmt_newacc(const char *);
> -char *json_fmt_neworder(const char *const *, size_t);
> +char *json_fmt_neworder(const char *const *, size_t, const char *);
> char *json_fmt_protected_rsa(const char *,
> const char *, const char *, const char *);
> char *json_fmt_protected_ec(const char *, const char *, const char *,
> Index: json.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/json.c,v
> diff -u -p -r1.21 json.c
> --- json.c 14 Sep 2020 16:00:17 -0000 1.21
> +++ json.c 11 Jan 2025 10:50:51 -0000
> @@ -647,7 +647,7 @@ json_fmt_newacc(const char *contact)
> * Format the "newOrder" resource request
> */
> char *
> -json_fmt_neworder(const char *const *alts, size_t altsz)
> +json_fmt_neworder(const char *const *alts, size_t altsz, const char *profile)
> {
> size_t i;
> int c;
> @@ -669,7 +669,10 @@ json_fmt_neworder(const char *const *alt
> }
> t = p;
> }
> - c = asprintf(&p, "%s ] }", t);
> + if (profile == NULL)
> + c = asprintf(&p, "%s ] }", t);
> + else
> + c = asprintf(&p, "%s ], \"profile\": \"%s\" }", t, profile);
> free(t);
> if (c == -1) {
> warn("asprintf");
> Index: main.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/main.c,v
> diff -u -p -r1.56 main.c
> --- main.c 19 Jun 2024 13:13:25 -0000 1.56
> +++ main.c 11 Jan 2025 10:50:51 -0000
> @@ -224,7 +224,8 @@ main(int argc, char *argv[])
> chng_fds[1], cert_fds[1],
> dns_fds[1], rvk_fds[1],
> revocate, authority,
> - (const char *const *)alts, altsz);
> + (const char *const *)alts, altsz,
> + domain->profile);
> exit(c ? EXIT_SUCCESS : EXIT_FAILURE);
> }
>
> Index: netproc.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/netproc.c,v
> diff -u -p -r1.37 netproc.c
> --- netproc.c 10 Oct 2024 09:39:35 -0000 1.37
> +++ netproc.c 11 Jan 2025 10:50:51 -0000
> @@ -441,14 +441,14 @@ dochkacc(struct conn *c, const struct ca
> */
> static int
> doneworder(struct conn *c, const char *const *alts, size_t altsz,
> - struct order *order, const struct capaths *p)
> + struct order *order, const struct capaths *p, const char *profile)
> {
> struct jsmnn *j = NULL;
> int rc = 0;
> char *req;
> long lc;
>
> - if ((req = json_fmt_neworder(alts, altsz)) == NULL)
> + if ((req = json_fmt_neworder(alts, altsz, profile)) == NULL)
> warnx("json_fmt_neworder");
> else if ((lc = sreq(c, p->neworder, 1, req, &order->uri)) < 0)
> warnx("%s: bad comm", p->neworder);
> @@ -671,7 +671,7 @@ dodirs(struct conn *c, const char *addr,
> int
> netproc(int kfd, int afd, int Cfd, int cfd, int dfd, int rfd,
> int revocate, struct authority_c *authority,
> - const char *const *alts, size_t altsz)
> + const char *const *alts, size_t altsz, const char *profile)
> {
> int rc = 0;
> size_t i;
> @@ -762,7 +762,7 @@ netproc(int kfd, int afd, int Cfd, int c
> * Following that, submit the request to the CA then notify the
> * certproc, which will in turn notify the fileproc.
> * XXX currently we can only sign with the account key, the RFC
> - * also mentions signing with the privat key of the cert itself.
> + * also mentions signing with the private key of the cert itself.
> */
> if (revocate) {
> if ((cert = readstr(rfd, COMM_CSR)) == NULL)
> @@ -776,7 +776,7 @@ netproc(int kfd, int afd, int Cfd, int c
>
> memset(&order, 0, sizeof(order));
>
> - if (!doneworder(&c, alts, altsz, &order, &paths))
> + if (!doneworder(&c, alts, altsz, &order, &paths, profile))
> goto out;
>
> chngs = calloc(order.authsz, sizeof(struct chng));
> Index: parse.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/parse.h,v
> diff -u -p -r1.15 parse.h
> --- parse.h 14 Sep 2020 16:00:17 -0000 1.15
> +++ parse.h 11 Jan 2025 10:50:51 -0000
> @@ -54,6 +54,7 @@ struct domain_c {
> char *fullchain;
> char *auth;
> char *challengedir;
> + char *profile;
> };
>
> struct altname_c {
> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/parse.y,v
> diff -u -p -r1.45 parse.y
> --- parse.y 15 Dec 2022 08:06:13 -0000 1.45
> +++ parse.y 11 Jan 2025 10:50:51 -0000
> @@ -101,7 +101,8 @@ typedef struct {
> %}
>
> %token AUTHORITY URL API ACCOUNT CONTACT
> -%token DOMAIN ALTERNATIVE NAME NAMES CERT FULL CHAIN KEY SIGN WITH CHALLENGEDIR
> +%token DOMAIN ALTERNATIVE NAME NAMES CERT FULL CHAIN KEY SIGN WITH
> +%token CHALLENGEDIR PROFILE
> %token YES NO
> %token INCLUDE
> %token ERROR
> @@ -393,6 +394,16 @@ domainoptsl : ALTERNATIVE NAMES '{' optn
> err(EXIT_FAILURE, "strdup");
> domain->challengedir = s;
> }
> + | PROFILE STRING {
> + char *s;
> + if (domain->profile != NULL) {
> + yyerror("duplicate profile");
> + YYERROR;
> + }
> + if ((s = strdup($2)) == NULL)
> + err(EXIT_FAILURE, "strdup");
> + domain->profile = s;
> + }
> ;
>
> altname_l : altname optcommanl altname_l
> @@ -470,6 +481,7 @@ lookup(char *s)
> {"key", KEY},
> {"name", NAME},
> {"names", NAMES},
> + {"profile", PROFILE},
> {"rsa", RSA},
> {"sign", SIGN},
> {"url", URL},
> @@ -1081,6 +1093,8 @@ print_config(struct acme_conf *xconf)
> if (d->fullchain != NULL)
> printf("\tdomain full chain certificate \"%s\"\n",
> d->fullchain);
> + if (d->profile != NULL)
> + printf("\tprofile \"%s\"\n", d->profile);
> if (d->auth != NULL)
> printf("\tsign with \"%s\"\n", d->auth);
> if (d->challengedir != NULL)
>
--
In my defence, I have been left unsupervised.
draft-aaron-acme-profiles support for acme-client