~graywolf/acme-client-portable

e37d59b9e9fd41973bf06dd917d95aa6e4626daf — Wolf 1 year, 4 months ago 9843709
Update from openbsd (2020-05-18 08:53:17 UTC)
10 files changed, 101 insertions(+), 57 deletions(-)

M CVS/Entries
M acme-client.1
M acme-client.conf.5
M dnsproc.c
M extern.h
M json.c
M main.c
M netproc.c
M parse.h
M parse.y
M CVS/Entries => CVS/Entries +21 -21
@@ 2,25 2,25 @@
/jsmn.c/1.1/Mon Jul  8 18:00:44 2019//
/jsmn.h/1.1/Mon Jul  8 18:00:44 2019//
/key.h/1.1/Mon Jul  8 18:00:44 2019//
/Makefile/1.9/Mon Apr 20 01:40:56 2020//
/acctproc.c/1.20/Mon Apr 20 01:40:56 2020//
/acme-client.1/1.33/Mon Apr 20 01:40:58 2020//
/acme-client.conf.5/1.22/Fri Feb 21 13:56:49 2020//
/base64.c/1.9/Mon Apr 20 01:40:56 2020//
/certproc.c/1.12/Mon Apr 20 01:40:56 2020//
/chngproc.c/1.15/Mon Apr 20 01:40:56 2020//
/dbg.c/1.4/Mon Apr 20 01:40:56 2020//
/dnsproc.c/1.10/Mon Apr 20 01:40:56 2020//
/extern.h/1.17/Mon Apr 20 01:40:56 2020//
/fileproc.c/1.16/Mon Apr 20 01:40:56 2020//
/http.c/1.29/Mon Apr 20 01:40:56 2020//
/json.c/1.16/Mon Apr 20 01:40:56 2020//
/key.c/1.2/Mon Apr 20 01:40:56 2020//
/keyproc.c/1.15/Mon Apr 20 01:40:56 2020//
/main.c/1.53/Mon Apr 20 01:40:56 2020//
/netproc.c/1.25/Mon Apr 20 01:40:56 2020//
/parse.h/1.13/Mon Apr 20 01:40:56 2020//
/parse.y/1.39/Mon Apr 20 01:40:56 2020//
/revokeproc.c/1.15/Mon Apr 20 01:40:56 2020//
/util.c/1.12/Mon Apr 20 01:40:56 2020//
/Makefile/1.9/Mon May 18 08:53:14 2020//
/acctproc.c/1.20/Mon May 18 08:53:14 2020//
/acme-client.1/1.34/Mon May 18 08:53:15 2020//
/acme-client.conf.5/1.25/Mon May 18 08:53:15 2020//
/base64.c/1.9/Mon May 18 08:53:14 2020//
/certproc.c/1.12/Mon May 18 08:53:14 2020//
/chngproc.c/1.15/Mon May 18 08:53:14 2020//
/dbg.c/1.4/Mon May 18 08:53:14 2020//
/dnsproc.c/1.11/Mon May 18 08:53:15 2020//
/extern.h/1.18/Mon May 18 08:53:15 2020//
/fileproc.c/1.16/Mon May 18 08:53:14 2020//
/http.c/1.29/Mon May 18 08:53:14 2020//
/json.c/1.17/Mon May 18 08:53:15 2020//
/key.c/1.2/Mon May 18 08:53:14 2020//
/keyproc.c/1.15/Mon May 18 08:53:14 2020//
/main.c/1.54/Mon May 18 08:53:16 2020//
/netproc.c/1.26/Mon May 18 08:53:16 2020//
/parse.h/1.14/Mon May 18 08:53:16 2020//
/parse.y/1.41/Mon May 18 08:53:16 2020//
/revokeproc.c/1.15/Mon May 18 08:53:14 2020//
/util.c/1.12/Mon May 18 08:53:14 2020//
D

M acme-client.1 => acme-client.1 +7 -6
@@ 1,4 1,4 @@
.\"	$OpenBSD: acme-client.1,v 1.32 2019/06/15 17:06:44 florian Exp $
.\"	$OpenBSD: acme-client.1,v 1.33 2020/04/15 03:24:08 millert Exp $
.\"
.\" Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
.\"


@@ 14,7 14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: April 15 2020 $
.Dd $Mdocdate: May 10 2020 $
.Dt ACME-CLIENT 1
.Os
.Sh NAME


@@ 24,14 24,14 @@
.Nm acme-client
.Op Fl Fnrv
.Op Fl f Ar configfile
.Ar domain
.Ar handle
.Sh DESCRIPTION
.Nm
is an
Automatic Certificate Management Environment (ACME) client:
it looks in its configuration for a domain section
corresponding to the
.Ar domain
.Ar handle
given as command line argument
and uses that configuration to retrieve an X.509 certificate
which can be used to provide domain name validation


@@ 77,8 77,9 @@ Revoke the X.509 certificate.
.It Fl v
Verbose operation.
Specify twice to also trace communication and data transfers.
.It Ar domain
The domain name.
.It Ar handle
The handle of the domain section of the configuration that contains the
details of the certificate to be created, renewed or revoked.
.El
.Sh FILES
.Bl -tag -width "/etc/acme-client.conf" -compact

M acme-client.conf.5 => acme-client.conf.5 +15 -7
@@ 1,4 1,4 @@
.\"	$OpenBSD: acme-client.conf.5,v 1.21 2019/07/04 05:06:06 solene Exp $
.\"	$OpenBSD: acme-client.conf.5,v 1.24 2020/05/12 20:46:30 jmc Exp $
.\"
.\" Copyright (c) 2005 Esben Norby <norby@openbsd.org>
.\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>


@@ 17,7 17,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: February 10 2020 $
.Dd $Mdocdate: May 16 2020 $
.Dt ACME-CLIENT.CONF 5
.Os
.Sh NAME


@@ 102,15 102,23 @@ under which the ACME API is reachable.
.Sh DOMAINS
The certificates to be obtained through ACME.
.Bl -tag -width Ds
.It Ic domain Ar name Brq ...
.It Ic domain Ar handle Brq ...
Each domain section begins with the
.Ic domain
keyword followed by the name to be used as the common name component
of the subject of the X.509 certificate.
keyword followed by an identifier for this domain block.
.El
.Pp
It is followed by a block of options enclosed in curly brackets:
.Bl -tag -width Ds
.It Ic domain name Ar name
The
.Ar name
to be used as the common name component of the subject of the
X.509 certificate.
This is optional.
If not specified, the
.Ar handle
of the domain block will be used as common name.
.It Ic alternative names Brq ...
Specify a list of alternative names for which the certificate will be valid.
The common name is included automatically if this option is present,


@@ 166,9 174,9 @@ will be used.
.Bl -tag -width /etc/examples/acme-client.conf -compact
.It Pa /etc/acme-client.conf
.Xr acme-client 1
configuration file
configuration file.
.It Pa /etc/examples/acme-client.conf
example configuration file
Example configuration file.
.El
.Sh SEE ALSO
.Xr acme-client 1

M dnsproc.c => dnsproc.c +1 -2
@@ 1,4 1,4 @@
/*	$Id: dnsproc.c,v 1.10 2019/11/06 21:05:45 florian Exp $ */
/*	$Id: dnsproc.c,v 1.11 2020/05/10 15:06:07 florian Exp $ */
/*
 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
 *


@@ 160,7 160,6 @@ dnsproc(int nfd)
			last = look;
			look = NULL;
		} else {
			doddbg("%s: cached", look);
			free(look);
			look = NULL;
		}

M extern.h => extern.h +2 -1
@@ 1,4 1,4 @@
/*	$Id: extern.h,v 1.17 2020/02/07 14:34:15 florian Exp $ */
/*	$Id: extern.h,v 1.18 2020/05/10 17:34:07 florian Exp $ */
/*
 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
 *


@@ 159,6 159,7 @@ enum	chngstatus {
struct	chng {
	char		*uri; /* uri on ACME server */
	char		*token; /* token we must offer */
	char		*error; /* "detail" field in case of error */
	size_t		 retry; /* how many times have we tried */
	enum chngstatus	 status; /* challenge accepted? */
};

M json.c => json.c +6 -4
@@ 1,4 1,4 @@
/*	$Id: json.c,v 1.16 2020/01/22 22:25:22 tedu Exp $ */
/*	$Id: json.c,v 1.17 2020/05/10 17:34:07 florian Exp $ */
/*
 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
 *


@@ 265,7 265,6 @@ json_getarray(struct jsmnn *n, const char *name)
	return n->d.obj[i].rhs;
}

#ifdef notyet
/*
 * Extract subtree from the returned JSON object, making sure that it's
 * the correct type.


@@ 292,7 291,6 @@ json_getobj(struct jsmnn *n, const char *name)
		return NULL;
	return n->d.obj[i].rhs;
}
#endif /* notyet */

/*
 * Extract a single string from the returned JSON object, making sure


@@ 375,7 373,7 @@ json_parse_response(struct jsmnn *n)
int
json_parse_challenge(struct jsmnn *n, struct chng *p)
{
	struct jsmnn	*array, *obj;
	struct jsmnn	*array, *obj, *error;
	size_t		 i;
	int		 rc;
	char		*type;


@@ 401,6 399,10 @@ json_parse_challenge(struct jsmnn *n, struct chng *p)
		p->uri = json_getstr(obj, "url");
		p->token = json_getstr(obj, "token");
		p->status = json_parse_response(obj);
		if (p->status == CHNG_INVALID) {
			error = json_getobj(obj, "error");
			p->error = json_getstr(error, "detail");
		}
		return p->uri != NULL && p->token != NULL;
	}


M main.c => main.c +3 -3
@@ 1,4 1,4 @@
/*	$Id: main.c,v 1.53 2020/02/07 14:34:15 florian Exp $ */
/*	$Id: main.c,v 1.54 2020/05/10 12:06:18 benno Exp $ */
/*
 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
 *


@@ 91,7 91,7 @@ main(int argc, char *argv[])
	if (argc != 1)
		goto usage;

	if ((domain = domain_find(conf, argv[0])) == NULL)
	if ((domain = domain_find_handle(conf, argv[0])) == NULL)
		errx(EXIT_FAILURE, "domain %s not found", argv[0]);

	argc--;


@@ 376,6 376,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] domain\n");
	    "usage: acme-client [-Fnrv] [-f configfile] handle\n");
	return EXIT_FAILURE;
}

M netproc.c => netproc.c +18 -4
@@ 1,4 1,4 @@
/*	$Id: netproc.c,v 1.25 2019/08/11 19:44:25 florian Exp $ */
/*	$Id: netproc.c,v 1.26 2020/05/10 17:34:07 florian Exp $ */
/*
 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
 *


@@ 23,6 23,7 @@
#include <string.h>
#include <unistd.h>
#include <tls.h>
#include <vis.h>

#include "http.h"
#include "extern.h"


@@ 664,7 665,7 @@ netproc(int kfd, int afd, int Cfd, int cfd, int dfd, int rfd,
{
	int		 rc = 0;
	size_t		 i;
	char		*cert = NULL, *thumb = NULL, *url = NULL;
	char		*cert = NULL, *thumb = NULL, *url = NULL, *error = NULL;
	struct conn	 c;
	struct capaths	 paths;
	struct order	 order;


@@ 805,7 806,8 @@ netproc(int kfd, int afd, int Cfd, int cfd, int dfd, int rfd,
				    "%d", chngs[i].token, chngs[i].uri,
				    chngs[i].status);

				if (chngs[i].status == CHNG_VALID)
				if (chngs[i].status == CHNG_VALID ||
				    chngs[i].status == CHNG_INVALID)
					continue;

				if (chngs[i].retry++ >= RETRY_MAX) {


@@ 858,8 860,20 @@ netproc(int kfd, int afd, int Cfd, int cfd, int dfd, int rfd,
			sleep(RETRY_DELAY);
	}

	if (order.status != ORDER_VALID)
	if (order.status != ORDER_VALID) {
		for (i = 0; i < order.authsz; i++) {
			dochngreq(&c, order.auths[i], &chngs[i]);
			if (chngs[i].error != NULL) {
				if (stravis(&error, chngs[i].error, VIS_SAFE)
				    != -1) {
					warnx("%s", error);
					free(error);
					error = NULL;
				}
			}
		}
		goto out;
	}

	if (order.certificate == NULL) {
		warnx("no certificate url received");

M parse.h => parse.h +3 -2
@@ 1,4 1,4 @@
/*	$OpenBSD: parse.h,v 1.12 2019/06/14 19:55:08 florian Exp $ */
/*	$OpenBSD: parse.h,v 1.13 2019/06/17 12:42:52 florian Exp $ */
/*
 * Copyright (c) 2016 Sebastian Benoit <benno@openbsd.org>
 *


@@ 45,6 45,7 @@ struct domain_c {
	TAILQ_HEAD(, altname_c)	 altname_list;
	int			 altname_count;
	enum keytype		 keytype;
	char			*handle;
	char			*domain;
	char			*key;
	char			*cert;


@@ 80,7 81,7 @@ int			 cmdline_symset(char *);
/* use these to find a authority or domain by name */
struct authority_c	*authority_find(struct acme_conf *, char *);
struct authority_c	*authority_find0(struct acme_conf *);
struct domain_c		*domain_find(struct acme_conf *, char *);
struct domain_c		*domain_find_handle(struct acme_conf *, char *);

int			 domain_valid(const char *);


M parse.y => parse.y +25 -7
@@ 1,4 1,4 @@
/*	$OpenBSD: parse.y,v 1.38 2019/06/17 12:42:52 florian Exp $ */
/*	$OpenBSD: parse.y,v 1.40 2020/05/10 12:06:18 benno Exp $ */

/*
 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>


@@ 101,7 101,7 @@ typedef struct {
%}

%token	AUTHORITY URL API ACCOUNT
%token	DOMAIN ALTERNATIVE NAMES CERT FULL CHAIN KEY SIGN WITH CHALLENGEDIR
%token	DOMAIN ALTERNATIVE NAME NAMES CERT FULL CHAIN KEY SIGN WITH CHALLENGEDIR
%token	YES NO
%token	INCLUDE
%token	ERROR


@@ 247,6 247,11 @@ domain		: DOMAIN STRING {
				YYERROR;
			}
		} '{' optnl domainopts_l '}' {
			if (domain->domain == NULL) {
				if ((domain->domain = strdup(domain->handle))
				    == NULL)
					err(EXIT_FAILURE, "strdup");
			}
			/* enforce minimum config here */
			if (domain->key == NULL) {
				yyerror("no domain key file specified for "


@@ 273,6 278,16 @@ domainopts_l	: domainopts_l domainoptsl nl
		;

domainoptsl	: ALTERNATIVE NAMES '{' altname_l '}'
		| DOMAIN NAME STRING {
			char *s;
			if (domain->domain != NULL) {
				yyerror("duplicate domain name");
				YYERROR;
			}
			if ((s = strdup($3)) == NULL)
				err(EXIT_FAILURE, "strdup");
			domain->domain = s;
		}
		| DOMAIN KEY STRING keytype {
			char *s;
			if (domain->key != NULL) {


@@ 442,6 457,7 @@ lookup(char *s)
		{"full",		FULL},
		{"include",		INCLUDE},
		{"key",			KEY},
		{"name",		NAME},
		{"names",		NAMES},
		{"rsa",			RSA},
		{"sign",		SIGN},


@@ 932,26 948,26 @@ conf_new_domain(struct acme_conf *c, char *s)
{
	struct domain_c *d;

	d = domain_find(c, s);
	d = domain_find_handle(c, s);
	if (d != NULL)
		return (NULL);
	if ((d = calloc(1, sizeof(struct domain_c))) == NULL)
		err(EXIT_FAILURE, "%s", __func__);
	TAILQ_INSERT_TAIL(&c->domain_list, d, entry);

	d->domain = s;
	d->handle = s;
	TAILQ_INIT(&d->altname_list);

	return d;
}

struct domain_c *
domain_find(struct acme_conf *c, char *s)
domain_find_handle(struct acme_conf *c, char *s)
{
	struct domain_c	*d;

	TAILQ_FOREACH(d, &c->domain_list, entry) {
		if (strncmp(d->domain, s, DOMAIN_MAXLEN) == 0) {
		if (strncmp(d->handle, s, DOMAIN_MAXLEN) == 0) {
			return d;
		}
	}


@@ 1031,7 1047,9 @@ print_config(struct acme_conf *xconf)
	}
	TAILQ_FOREACH(d, &xconf->domain_list, entry) {
		f = 0;
		printf("domain %s {\n", d->domain);
		printf("domain %s {\n", d->handle);
		if (d->domain != NULL)
			printf("\tdomain name \"%s\"\n", d->domain);
		TAILQ_FOREACH(ac, &d->altname_list, entry) {
			if (!f)
				printf("\talternative names {");