From: Florian Obser Subject: Re: acme-client: support for external account binding To: Jonathan Matthew Cc: Theo Buehler , tech@openbsd.org, sthen@openbsd.org Date: Fri, 08 May 2026 09:58:50 +0200 On 2026-05-06 15:36 +10, Jonathan Matthew wrote: > Thanks, here's an updated version with comments addressed. reads good, I don't have a way to test. OK florian > > Index: acctproc.c > =================================================================== > RCS file: /cvs/src/usr.sbin/acme-client/acctproc.c,v > diff -u -p -u -p -r1.32 acctproc.c > --- acctproc.c 29 Aug 2023 14:44:53 -0000 1.32 > +++ acctproc.c 6 May 2026 03:58:31 -0000 > @@ -28,6 +28,7 @@ > #include > #include > #include > +#include > #include > #include > > @@ -182,18 +183,13 @@ out: > } > > static int > -op_sign_rsa(char **prot, EVP_PKEY *pkey, const char *nonce, const char *url) > +op_sign_rsa(char **jwk, EVP_PKEY *pkey) > { > char *exp = NULL, *mod = NULL; > int rc = 0; > RSA *r; > > - *prot = NULL; > - > - /* > - * First, extract relevant portions of our private key. > - * Finally, format the header combined with the nonce. > - */ > + *jwk = NULL; > > if ((r = EVP_PKEY_get0_RSA(pkey)) == NULL) > warnx("EVP_PKEY_get0_RSA"); > @@ -201,8 +197,8 @@ op_sign_rsa(char **prot, EVP_PKEY *pkey, > warnx("bn2string"); > else if ((exp = bn2string(RSA_get0_e(r))) == NULL) > warnx("bn2string"); > - else if ((*prot = json_fmt_protected_rsa(exp, mod, nonce, url)) == NULL) > - warnx("json_fmt_protected_rsa"); > + else if ((*jwk = json_fmt_jwk_rsa(exp, mod)) == NULL) > + warnx("json_fmt_jwk_rsa"); > else > rc = 1; > > @@ -212,14 +208,14 @@ op_sign_rsa(char **prot, EVP_PKEY *pkey, > } > > static int > -op_sign_ec(char **prot, EVP_PKEY *pkey, const char *nonce, const char *url) > +op_sign_ec(char **jwk, EVP_PKEY *pkey) > { > BIGNUM *X = NULL, *Y = NULL; > EC_KEY *ec = NULL; > char *x = NULL, *y = NULL; > int rc = 0; > > - *prot = NULL; > + *jwk = NULL; > > if ((ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) > warnx("EVP_PKEY_get0_EC_KEY"); > @@ -234,8 +230,8 @@ op_sign_ec(char **prot, EVP_PKEY *pkey, > warnx("bn2string"); > else if ((y = bn2string(Y)) == NULL) > warnx("bn2string"); > - else if ((*prot = json_fmt_protected_ec(x, y, nonce, url)) == NULL) > - warnx("json_fmt_protected_ec"); > + else if ((*jwk = json_fmt_jwk_ec(x, y)) == NULL) > + warnx("json_fmt_jwk_ec"); > else > rc = 1; > > @@ -262,6 +258,7 @@ op_sign(int fd, EVP_PKEY *pkey, enum acc > char *prot = NULL, *prot64 = NULL; > char *sign = NULL, *dig64 = NULL, *fin = NULL; > char *url = NULL, *kid = NULL, *alg = NULL; > + char *jwk = NULL; > const unsigned char *digp; > unsigned char *dig = NULL, *buf = NULL; > size_t digsz; > @@ -309,17 +306,21 @@ op_sign(int fd, EVP_PKEY *pkey, enum acc > } else { > switch (EVP_PKEY_base_id(pkey)) { > case EVP_PKEY_RSA: > - if (!op_sign_rsa(&prot, pkey, nonce, url)) > + if (!op_sign_rsa(&jwk, pkey)) > goto out; > break; > case EVP_PKEY_EC: > - if (!op_sign_ec(&prot, pkey, nonce, url)) > + if (!op_sign_ec(&jwk, pkey)) > goto out; > break; > default: > warnx("EVP_PKEY_base_id"); > goto out; > } > + > + prot = json_fmt_protected_jwk(alg, jwk, nonce, url); > + if (prot == NULL) > + goto out; > } > > /* The header combined with the nonce, base64. */ > @@ -434,6 +435,7 @@ out: > free(pay64); > free(url); > free(nonce); > + free(jwk); > free(kid); > free(prot); > free(prot64); > @@ -444,8 +446,96 @@ out: > return rc; > } > > +static int > +op_eab(int fd, EVP_PKEY *pkey, const char *eab_kid, > + const unsigned char *eab_key, int eab_key_len) > +{ > + char *url = NULL; > + char *prot = NULL, *prot64 = NULL; > + char *jwk = NULL, *pay64 = NULL; > + char *sign = NULL; > + char *dig64 = NULL, *fin = NULL; > + unsigned char dig[EVP_MAX_MD_SIZE]; > + unsigned int digsz; > + int sign_len, rc = 0; > + > + if ((url = readstr(fd, COMM_URL)) == NULL) > + goto out; > + > + /* protected component: algorithm, EAB key ID, new account URL */ > + if ((prot = json_fmt_protected_eab(eab_kid, url)) == NULL) { > + warnx("json_fmt_protected_eab"); > + goto out; > + } > + > + if ((prot64 = base64buf_url(prot, strlen(prot))) == NULL) { > + warnx("base64buf_url"); > + goto out; > + } > + > + /* payload component: account public key */ > + switch (EVP_PKEY_base_id(pkey)) { > + case EVP_PKEY_RSA: > + if (!op_sign_rsa(&jwk, pkey)) > + goto out; > + break; > + case EVP_PKEY_EC: > + if (!op_sign_ec(&jwk, pkey)) > + goto out; > + break; > + default: > + warnx("EVP_PKEY_base_id"); > + goto out; > + } > + > + if ((pay64 = base64buf_url(jwk, strlen(jwk))) == NULL) { > + warnx("base64buf_url"); > + goto out; > + } > + > + sign_len = asprintf(&sign, "%s.%s", prot64, pay64); > + if (sign_len == -1) { > + warn("asprintf"); > + sign = NULL; > + goto out; > + } > + > + /* sign with the EAB key */ > + if (HMAC(EVP_sha256(), eab_key, eab_key_len, sign, sign_len, dig, > + &digsz) == NULL) { > + warnx("HMAC"); > + goto out; > + } > + > + if ((dig64 = base64buf_url((char *)dig, digsz)) == NULL) { > + warnx("base64buf_url"); > + goto out; > + } > + > + if ((fin = json_fmt_signed(prot64, pay64, dig64)) == NULL) { > + warnx("json_fmt_signed"); > + goto out; > + } else if (writestr(fd, COMM_REQ, fin) < 0) { > + goto out; > + } > + > + rc = 1; > +out: > + > + free(fin); > + free(dig64); > + free(sign); > + free(pay64); > + free(jwk); > + free(prot64); > + free(prot); > + free(url); > + return rc; > +} > + > int > -acctproc(int netsock, const char *acctkey, enum keytype keytype) > +acctproc(int netsock, const char *acctkey, enum keytype keytype, > + const char *eab_kid, const unsigned char *eab_key, int eab_key_len) > { > FILE *f = NULL; > EVP_PKEY *pkey = NULL; > @@ -522,7 +612,7 @@ acctproc(int netsock, const char *acctke > if ((lval = readop(netsock, COMM_ACCT)) == 0) > op = ACCT_STOP; > else if (lval == ACCT_SIGN || lval == ACCT_KID_SIGN || > - lval == ACCT_THUMBPRINT) > + lval == ACCT_THUMBPRINT || lval == ACCT_EAB) > op = lval; > > if (ACCT__MAX == op) { > @@ -542,6 +632,12 @@ acctproc(int netsock, const char *acctke > if (op_thumbprint(netsock, pkey)) > break; > warnx("op_thumbprint"); > + goto out; > + case ACCT_EAB: > + if (op_eab(netsock, pkey, eab_kid, eab_key, > + eab_key_len)) > + break; > + warnx("op_eab"); > goto out; > default: > abort(); > Index: acme-client.1 > =================================================================== > RCS file: /cvs/src/usr.sbin/acme-client/acme-client.1,v > diff -u -p -u -p -r1.43 acme-client.1 > --- acme-client.1 18 Sep 2025 14:13:27 -0000 1.43 > +++ acme-client.1 6 May 2026 03:58:31 -0000 > @@ -24,6 +24,7 @@ > .Nm acme-client > .Op Fl Fnrv > .Op Fl f Ar configfile > +.Op Fl e Ar keyid:key > .Ar handle > .Sh DESCRIPTION > .Nm > @@ -67,10 +68,27 @@ location "/.well-known/acme-challenge/*" > } > .Ed > .Pp > +Some signing authorities require the client to perform external account > +binding to associate the ACME account key generated by > +.Nm > +with an existing account in a non-ACME system such as a CA customer database. > +To enable ACME account binding, the CA operating the ACME server needs to > +provide the ACME client with a base64url-encoded MAC key and a key identifier > +string, using some mechanism outside of ACME. > +These can be supplied to > +.Nm > +using the > +.Fl e > +command line argument. > +.Pp > The options are as follows: > .Bl -tag -width Ds > .It Fl F > Force certificate renewal, regardless of remaining lifetime. > +.It Fl e Ar key-id:key > +Specify external account binding parameters. > +This consists of the key identifier string and the base64url-encoded MAC key > +separated by a colon. > .It Fl f Ar configfile > Specify an alternative configuration file. > .It Fl n > Index: base64.c > =================================================================== > RCS file: /cvs/src/usr.sbin/acme-client/base64.c,v > diff -u -p -u -p -r1.9 base64.c > --- base64.c 24 Jan 2017 13:32:55 -0000 1.9 > +++ base64.c 6 May 2026 03:58:31 -0000 > @@ -19,6 +19,7 @@ > #include > > #include > +#include > > #include "extern.h" > > @@ -64,4 +65,70 @@ base64buf_url(const char *data, size_t l > } > > return buf; > +} > + > +static const u_int8_t index_64[128] = { > + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, > + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, > + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, > + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, > + 255, 255, 255, 255, 255, 62, 255, 255, 52, 53, > + 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, > + 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, > + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, > + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, > + 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, > + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, > + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, > + 49, 50, 51, 255, 255, 255, 255, 255 > +}; > +#define CHAR64(c) ( (c) > 127 ? 255 : index_64[(c)]) > + > +int > +unbase64buf_url(const unsigned char *data, unsigned char **decoded) > +{ > + unsigned char *out, *bp; > + const unsigned char *p; > + unsigned char c1, c2, c3, c4; > + int len; > + > + len = strlen(data); > + out = malloc(len); > + if (out == NULL) > + return -1; > + > + p = data; > + bp = out; > + while (p < data + len) { > + c1 = CHAR64(*p); > + /* Invalid data */ > + if (c1 == 255) > + return -1; > + > + c2 = CHAR64(*(p + 1)); > + if (c2 == 255) > + return -1; > + > + *bp++ = (c1 << 2) | ((c2 & 0x30) >> 4); > + if ((p + 2) >= data + len) > + break; > + > + c3 = CHAR64(*(p + 2)); > + if (c3 == 255) > + return -1; > + > + *bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2); > + if ((p + 3) >= data + len) > + break; > + > + c4 = CHAR64(*(p + 3)); > + if (c4 == 255) > + return -1; > + *bp++ = ((c3 & 0x03) << 6) | c4; > + > + p += 4; > + } > + > + *decoded = out; > + return (bp - out); > } > Index: extern.h > =================================================================== > RCS file: /cvs/src/usr.sbin/acme-client/extern.h,v > diff -u -p -u -p -r1.23 extern.h > --- extern.h 23 Feb 2026 10:27:49 -0000 1.23 > +++ extern.h 6 May 2026 03:58:31 -0000 > @@ -34,6 +34,7 @@ enum acctop { > ACCT_SIGN, > ACCT_KID_SIGN, > ACCT_THUMBPRINT, > + ACCT_EAB, > ACCT__MAX > }; > > @@ -200,7 +201,8 @@ __BEGIN_DECLS > * Start with our components. > * These are all isolated and talk to each other using sockets. > */ > -int acctproc(int, const char *, enum keytype); > +int acctproc(int, const char *, enum keytype, const char *, > + const unsigned char *, int); > int certproc(int, int); > int chngproc(int, const char *); > int dnsproc(int); > @@ -209,7 +211,7 @@ int fileproc(int, const char *, const > const char *); > int keyproc(int, struct domain_c *); > int netproc(int, int, int, int, int, int, int, > - struct authority_c *, struct domain_c *); > + struct authority_c *, struct domain_c *, int); > > /* > * Debugging functions. > @@ -240,6 +242,7 @@ int checkexit_ext(int *, pid_t, enum c > */ > size_t base64len(size_t); > char *base64buf_url(const char *, size_t); > +int unbase64buf_url(const unsigned char *, unsigned char **); > > /* > * JSON parsing routines. > @@ -259,18 +262,19 @@ 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_newacc(const char *, const char *); > char *json_fmt_neworder(struct domain_c *); > -char *json_fmt_protected_rsa(const char *, > - const char *, const char *, const char *); > -char *json_fmt_protected_ec(const char *, const char *, const char *, > - const char *); > -char *json_fmt_protected_kid(const char*, const char *, const char *, > - const char *); > +char *json_fmt_jwk_rsa(const char *, const char *); > +char *json_fmt_jwk_ec(const char *, const char *); > +char *json_fmt_protected_jwk(const char *, const char *, > + const char *, const char *); > +char *json_fmt_protected_kid(const char *, const char *, > + const char *, const char *); > char *json_fmt_revokecert(const char *); > char *json_fmt_thumb_rsa(const char *, const char *); > char *json_fmt_thumb_ec(const char *, const char *); > char *json_fmt_signed(const char *, const char *, const char *); > +char *json_fmt_protected_eab(const char *, const char *); > > /* > * Should we print debugging messages? > Index: json.c > =================================================================== > RCS file: /cvs/src/usr.sbin/acme-client/json.c,v > diff -u -p -u -p -r1.23 json.c > --- json.c 23 Feb 2026 10:27:49 -0000 1.23 > +++ json.c 6 May 2026 03:58:31 -0000 > @@ -618,7 +618,7 @@ json_fmt_chkacc(void) > * Format the "newAccount" resource request. > */ > char * > -json_fmt_newacc(const char *contact) > +json_fmt_newacc(const char *contact, const char *eab) > { > int c; > char *p, *cnt = NULL; > @@ -630,6 +630,18 @@ json_fmt_newacc(const char *contact) > return NULL; > } > } > + if (eab != NULL) { > + char *ecnt = NULL; > + c = asprintf(&ecnt, "%s\"externalAccountBinding\": %s, ", > + cnt == NULL ? "" : cnt, eab); > + if (c == -1) { > + warn("asprintf"); > + return NULL; > + } > + > + free(cnt); > + cnt = ecnt; > + } > > c = asprintf(&p, "{" > "%s" > @@ -737,23 +749,35 @@ json_fmt_newcert(const char *cert) > } > > /* > - * Protected component of json_fmt_signed(). > + * Format an RSA public key in JWK format. > */ > char * > -json_fmt_protected_rsa(const char *exp, const char *mod, const char *nce, > - const char *url) > +json_fmt_jwk_rsa(const char *exp, const char *mod) > { > int c; > char *p; > > - c = asprintf(&p, "{" > - "\"alg\": \"RS256\", " > - "\"jwk\": " > - "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}, " > - "\"nonce\": \"%s\", " > - "\"url\": \"%s\"" > - "}", > - exp, mod, nce, url); > + c = asprintf(&p, "{\"e\": \"%s\", \"kty\": \"RSA\", \"n\": \"%s\"}", > + exp, mod); > + if (c == -1) { > + warn("asprintf"); > + p = NULL; > + } > + return p; > +} > + > +/* > + * Format an EC public key in JWK format. > + */ > +char * > +json_fmt_jwk_ec(const char *x, const char *y) > +{ > + int c; > + char *p; > + > + c = asprintf(&p, "{\"crv\": \"P-384\", \"kty\": \"EC\"," > + " \"x\": \"%s\", \"y\": \"%s\"}", > + x, y); > if (c == -1) { > warn("asprintf"); > p = NULL; > @@ -765,19 +789,19 @@ json_fmt_protected_rsa(const char *exp, > * Protected component of json_fmt_signed(). > */ > char * > -json_fmt_protected_ec(const char *x, const char *y, const char *nce, > +json_fmt_protected_jwk(const char *alg, const char *jwk, const char *nce, > const char *url) > { > int c; > char *p; > > c = asprintf(&p, "{" > - "\"alg\": \"ES384\", " > - "\"jwk\": " > - "{\"crv\": \"P-384\", \"kty\": \"EC\", \"x\": \"%s\", " > - "\"y\": \"%s\"}, \"nonce\": \"%s\", \"url\": \"%s\"" > + "\"alg\": \"%s\", " > + "\"jwk\": %s, " > + "\"nonce\": \"%s\", " > + "\"url\": \"%s\"" > "}", > - x, y, nce, url); > + alg, jwk, nce, url); > if (c == -1) { > warn("asprintf"); > p = NULL; > @@ -871,6 +895,28 @@ json_fmt_thumb_ec(const char *x, const c > c = asprintf(&p, "{\"crv\":\"P-384\",\"kty\":\"EC\",\"x\":\"%s\"," > "\"y\":\"%s\"}", > x, y); > + if (c == -1) { > + warn("asprintf"); > + p = NULL; > + } > + return p; > +} > + > +/* > + * Protected component of external account binding. > + */ > +char * > +json_fmt_protected_eab(const char *keyid, const char *url) > +{ > + int c; > + char *p; > + > + c = asprintf(&p, "{" > + "\"alg\": \"HS256\", " > + "\"kid\": \"%s\", " > + "\"url\": \"%s\"" > + "}", > + keyid, url); > if (c == -1) { > warn("asprintf"); > p = NULL; > Index: main.c > =================================================================== > RCS file: /cvs/src/usr.sbin/acme-client/main.c,v > diff -u -p -u -p -r1.58 main.c > --- main.c 23 Feb 2026 10:27:49 -0000 1.58 > +++ main.c 6 May 2026 03:58:31 -0000 > @@ -43,12 +43,14 @@ main(int argc, char *argv[]) > char *certdir = NULL; > char *chngdir = NULL, *auth = NULL; > char *conffile = CONF_FILE; > + char *eab = NULL, *eab_key_enc = NULL; > char *tmps, *tmpsd; > + unsigned char *eab_key = NULL; > int key_fds[2], acct_fds[2], chng_fds[2], cert_fds[2]; > int file_fds[2], dns_fds[2], rvk_fds[2]; > int force = 0; > int c, rc, revocate = 0; > - int popts = 0; > + int popts = 0, eab_key_len; > pid_t pids[COMP__MAX]; > size_t ne; > > @@ -60,11 +62,14 @@ main(int argc, char *argv[]) > if (setlocale(LC_CTYPE, "C") == NULL) > errx(1, "setlocale"); > > - while ((c = getopt(argc, argv, "Fnrvf:")) != -1) > + while ((c = getopt(argc, argv, "Fe:nrvf:")) != -1) > switch (c) { > case 'F': > force = 1; > break; > + case 'e': > + eab = strdup(optarg); > + break; > case 'f': > if ((conffile = strdup(optarg)) == NULL) > err(EXIT_FAILURE, "strdup"); > @@ -166,6 +171,22 @@ main(int argc, char *argv[]) > ne++; > } > > + if (eab != NULL) { > + eab_key_enc = eab; > + eab = strsep(&eab_key_enc, ":"); > + if (eab_key_enc == NULL) { > + warnx("EAB parameters must be in the format keyid:key"); > + ne++; > + } else { > + eab_key_len = unbase64buf_url( > + (unsigned char *)eab_key_enc, &eab_key); > + if (eab_key_len == -1) { > + warnx("unable to decode EAB key"); > + ne++; > + } > + } > + } > + > if (ne > 0) > return EXIT_FAILURE; > > @@ -222,7 +243,7 @@ main(int argc, char *argv[]) > c = netproc(key_fds[1], acct_fds[1], > chng_fds[1], cert_fds[1], > dns_fds[1], rvk_fds[1], > - revocate, authority, domain); > + revocate, authority, domain, eab != NULL); > exit(c ? EXIT_SUCCESS : EXIT_FAILURE); > } > > @@ -267,7 +288,7 @@ main(int argc, char *argv[]) > close(file_fds[0]); > close(file_fds[1]); > c = acctproc(acct_fds[0], authority->account, > - authority->keytype); > + authority->keytype, eab, eab_key, eab_key_len); > exit(c ? EXIT_SUCCESS : EXIT_FAILURE); > } > > @@ -378,6 +399,6 @@ main(int argc, char *argv[]) > return rc != COMP__MAX ? EXIT_FAILURE : (c == 2 ? EXIT_SUCCESS : 2); > usage: > fprintf(stderr, > - "usage: acme-client [-Fnrv] [-f configfile] handle\n"); > + "usage: acme-client [-Fnrv] [-f configfile] [-e kid:key] handle\n"); > return EXIT_FAILURE; > } > Index: netproc.c > =================================================================== > RCS file: /cvs/src/usr.sbin/acme-client/netproc.c,v > diff -u -p -u -p -r1.46 netproc.c > --- netproc.c 23 Feb 2026 10:27:49 -0000 1.46 > +++ netproc.c 6 May 2026 03:58:31 -0000 > @@ -408,14 +408,30 @@ sreq(struct conn *c, const char *addr, i > * Returns non-zero on success. > */ > static int > -donewacc(struct conn *c, const struct capaths *p, const char *contact) > +donewacc(struct conn *c, const struct capaths *p, const char *contact, > + int eab) > { > struct jsmnn *j = NULL; > int rc = 0; > char *req, *detail, *error = NULL, *accturi = NULL; > + char *eab_json = NULL; > long lc; > > - if ((req = json_fmt_newacc(contact)) == NULL) > + if (eab) { > + /* ask acct proc to produce eab json */ > + if (writeop(c->fd, COMM_ACCT, ACCT_EAB) <= 0) { > + return -1; > + } else if (writestr(c->fd, COMM_URL, p->newaccount) <= 0) { > + return -1; > + } > + > + /* Now read back the signed payload. */ > + if ((eab_json = readstr(c->fd, COMM_REQ)) == NULL) { > + return -1; > + } > + } > + > + if ((req = json_fmt_newacc(contact, eab_json)) == NULL) > warnx("json_fmt_newacc"); > else if ((lc = sreq(c, p->newaccount, 0, req, &c->kid)) < 0) > warnx("%s: bad comm", p->newaccount); > @@ -455,7 +471,8 @@ donewacc(struct conn *c, const struct ca > * Returns non-zero on success. > */ > static int > -dochkacc(struct conn *c, const struct capaths *p, const char *contact) > +dochkacc(struct conn *c, const struct capaths *p, const char *contact, > + int eab) > { > int rc = 0; > char *req, *accturi = NULL; > @@ -470,7 +487,7 @@ dochkacc(struct conn *c, const struct ca > else if (c->buf.buf == NULL || c->buf.sz == 0) > warnx("%s: empty response", p->newaccount); > else if (lc == 400) > - rc = donewacc(c, p, contact); > + rc = donewacc(c, p, contact, eab); > else > rc = 1; > > @@ -723,7 +740,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, > - struct domain_c *domain) > + struct domain_c *domain, int eab) > { > int rc = 0, retries = 0; > size_t i; > @@ -805,7 +822,7 @@ netproc(int kfd, int afd, int Cfd, int c > c.newnonce = paths.newnonce; > > /* Check if our account already exists or create it. */ > - if (!dochkacc(&c, &paths, authority->contact)) > + if (!dochkacc(&c, &paths, authority->contact, eab)) > goto out; > > /* > -- In my defence, I have been left unsupervised.