Download raw body.
draft-aaron-acme-profiles support for acme-client
https://letsencrypt.org/2025/01/09/acme-profiles/
https://datatracker.ietf.org/doc/draft-aaron-acme-profiles/
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?
Is "domain" the right place? It might make sense to allow this under
"authority" instead of, or as well as, under "domain".
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)
draft-aaron-acme-profiles support for acme-client