acme-client(1) and Buypass Go SSL

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

acme-client(1) and Buypass Go SSL

Bartosz Kuzma
Hello,

I've tried to get a certificate from Buypass Go SSL provider using
acme-client(1) but it ends with the following error:

acme-client: https://api.buypass.com/acme-v02/new-acct: bad HTTP: 400
acme-client: transfer buffer:
[{"type":"urn:ietf:params:acme:error:malformed","d
etail":"Email is a required
contact","code":400,"message":"MALFORMED_BAD_REQUEST
","details":"HTTP 400 Bad Request"}] (164 bytes)

Buypass Go SSL requires that optional field contact in Account Objects
will contain email address.

I've added new option "contact" to acme-client.conf to fullfil this
requirement. It is also required to change MARKER in certproc.c to fix
line endings handling in pem files.

--
Kind regards, Bartosz Kuzma.

acme-client.patch (10K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: acme-client(1) and Buypass Go SSL

Sebastian Benoit-3
Bartosz Kuzma([hidden email]) on 2020.04.20 18:51:17 +0200:

> Hello,
>
> I've tried to get a certificate from Buypass Go SSL provider using
> acme-client(1) but it ends with the following error:
>
> acme-client: https://api.buypass.com/acme-v02/new-acct: bad HTTP: 400
> acme-client: transfer buffer:
> [{"type":"urn:ietf:params:acme:error:malformed","d
> etail":"Email is a required
> contact","code":400,"message":"MALFORMED_BAD_REQUEST
> ","details":"HTTP 400 Bad Request"}] (164 bytes)
>
> Buypass Go SSL requires that optional field contact in Account Objects
> will contain email address.
>
> I've added new option "contact" to acme-client.conf to fullfil this
> requirement.

Thanks, that looks ok.

> It is also required to change MARKER in certproc.c to fix
> line endings handling in pem files.

Can you explain what happens there?

/Benno

> --
> Kind regards, Bartosz Kuzma.

> Index: usr.sbin/acme-client/acme-client.conf.5
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/acme-client.conf.5,v
> retrieving revision 1.22
> diff -u -p -r1.22 acme-client.conf.5
> --- usr.sbin/acme-client/acme-client.conf.5 10 Feb 2020 13:18:21 -0000 1.22
> +++ usr.sbin/acme-client/acme-client.conf.5 20 Apr 2020 16:24:46 -0000
> @@ -98,6 +98,10 @@ It defaults to
>  Specify the
>  .Ar url
>  under which the ACME API is reachable.
> +.It Ic contact Ar contact
> +Optional
> +.Ar contact
> +URLs that the authority can use to contact the client for issues related to this account.
>  .El
>  .Sh DOMAINS
>  The certificates to be obtained through ACME.
> Index: usr.sbin/acme-client/certproc.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/certproc.c,v
> retrieving revision 1.12
> diff -u -p -r1.12 certproc.c
> --- usr.sbin/acme-client/certproc.c 7 Jun 2019 08:07:52 -0000 1.12
> +++ usr.sbin/acme-client/certproc.c 20 Apr 2020 16:24:46 -0000
> @@ -28,7 +28,7 @@
>  
>  #include "extern.h"
>  
> -#define MARKER "-----END CERTIFICATE-----\n"
> +#define MARKER "-----END CERTIFICATE-----"
>  
>  int
>  certproc(int netsock, int filesock)
> @@ -94,6 +94,12 @@ certproc(int netsock, int filesock)
>   }
>  
>   chaincp += strlen(MARKER);
> +
> + if ((chaincp = strchr(chaincp, '-')) == NULL) {
> + warn("strchr");
> + goto out;
> + }
> +
>   if ((chain = strdup(chaincp)) == NULL) {
>   warn("strdup");
>   goto out;
> Index: usr.sbin/acme-client/extern.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/extern.h,v
> retrieving revision 1.17
> diff -u -p -r1.17 extern.h
> --- usr.sbin/acme-client/extern.h 7 Feb 2020 14:34:15 -0000 1.17
> +++ usr.sbin/acme-client/extern.h 20 Apr 2020 16:24:46 -0000
> @@ -261,13 +261,13 @@ int json_parse_capaths(struct jsmnn *,
>  
>  char *json_fmt_newcert(const char *);
>  char *json_fmt_chkacc(void);
> -char *json_fmt_newacc(void);
> +char *json_fmt_newacc(const char *);
>  char *json_fmt_neworder(const char *const *, size_t);
>  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 *,
> +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 *);
> Index: usr.sbin/acme-client/json.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/json.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 json.c
> --- usr.sbin/acme-client/json.c 22 Jan 2020 22:25:22 -0000 1.16
> +++ usr.sbin/acme-client/json.c 20 Apr 2020 16:24:46 -0000
> @@ -616,19 +616,30 @@ json_fmt_chkacc(void)
>   * Format the "newAccount" resource request.
>   */
>  char *
> -json_fmt_newacc(void)
> +json_fmt_newacc(const char *contact)
>  {
>   int c;
> - char *p;
> + char *p, *cnt;
> +
> + c = asprintf(&cnt, "\"contact\": [ \"%s\" ], ", contact);
> + if (c == -1) {
> + warn("asprintf");
> + goto err;
> + }
>  
>   c = asprintf(&p, "{"
> +    "%s"
>      "\"termsOfServiceAgreed\": true"
> -    "}");
> +    "}", contact == NULL ? "" : cnt);
> + free(cnt);
>   if (c == -1) {
>   warn("asprintf");
>   p = NULL;
>   }
>   return p;
> +
> +err:
> + return NULL;
>  }
>  
>  /*
> Index: usr.sbin/acme-client/netproc.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/netproc.c,v
> retrieving revision 1.25
> diff -u -p -r1.25 netproc.c
> --- usr.sbin/acme-client/netproc.c 11 Aug 2019 19:44:25 -0000 1.25
> +++ usr.sbin/acme-client/netproc.c 20 Apr 2020 16:24:46 -0000
> @@ -368,13 +368,13 @@ sreq(struct conn *c, const char *addr, i
>   * Returns non-zero on success.
>   */
>  static int
> -donewacc(struct conn *c, const struct capaths *p)
> +donewacc(struct conn *c, const struct capaths *p, const char *contact)
>  {
>   int rc = 0;
>   char *req;
>   long lc;
>  
> - if ((req = json_fmt_newacc()) == NULL)
> + if ((req = json_fmt_newacc(contact)) == NULL)
>   warnx("json_fmt_newacc");
>   else if ((lc = sreq(c, p->newaccount, 0, req, &c->kid)) < 0)
>   warnx("%s: bad comm", p->newaccount);
> @@ -397,7 +397,7 @@ donewacc(struct conn *c, const struct ca
>   * Returns non-zero on success.
>   */
>  static int
> -dochkacc(struct conn *c, const struct capaths *p)
> +dochkacc(struct conn *c, const struct capaths *p, const char *contact)
>  {
>   int rc = 0;
>   char *req;
> @@ -412,7 +412,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);
> + rc = donewacc(c, p, contact);
>   else
>   rc = 1;
>  
> @@ -742,7 +742,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))
> + if (!dochkacc(&c, &paths, authority->contact))
>   goto out;
>  
>   /*
> Index: usr.sbin/acme-client/parse.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/parse.h,v
> retrieving revision 1.13
> diff -u -p -r1.13 parse.h
> --- usr.sbin/acme-client/parse.h 17 Jun 2019 12:42:52 -0000 1.13
> +++ usr.sbin/acme-client/parse.h 20 Apr 2020 16:24:46 -0000
> @@ -38,6 +38,7 @@ struct authority_c {
>   char *api;
>   char *account;
>   enum keytype keytype;
> + char *contact;
>  };
>  
>  struct domain_c {
> Index: usr.sbin/acme-client/parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/parse.y,v
> retrieving revision 1.39
> diff -u -p -r1.39 parse.y
> --- usr.sbin/acme-client/parse.y 27 Dec 2019 16:56:40 -0000 1.39
> +++ usr.sbin/acme-client/parse.y 20 Apr 2020 16:24:47 -0000
> @@ -100,7 +100,7 @@ typedef struct {
>  
>  %}
>  
> -%token AUTHORITY URL API ACCOUNT
> +%token AUTHORITY URL API ACCOUNT CONTACT
>  %token DOMAIN ALTERNATIVE NAMES CERT FULL CHAIN KEY SIGN WITH CHALLENGEDIR
>  %token YES NO
>  %token INCLUDE
> @@ -230,6 +230,16 @@ authorityoptsl : API URL STRING {
>   auth->account = s;
>   auth->keytype = $4;
>   }
> + | CONTACT STRING {
> + char *s;
> + if (auth->contact != NULL) {
> + yyerror("duplicate contact");
> + YYERROR;
> + }
> + if ((s = strdup($2)) == NULL)
> + err(EXIT_FAILURE, "strdup");
> + auth->contact = s;
> + }
>   ;
>  
>  domain : DOMAIN STRING {
> @@ -437,6 +447,7 @@ lookup(char *s)
>   {"certificate", CERT},
>   {"chain", CHAIN},
>   {"challengedir", CHALLENGEDIR},
> + {"contact", CONTACT},
>   {"domain", DOMAIN},
>   {"ecdsa", ECDSA},
>   {"full", FULL},
> Index: etc/examples/acme-client.conf
> ===================================================================
> RCS file: /cvs/src/etc/examples/acme-client.conf,v
> retrieving revision 1.2
> diff -u -p -r1.2 acme-client.conf
> --- etc/examples/acme-client.conf 7 Jun 2019 08:08:30 -0000 1.2
> +++ etc/examples/acme-client.conf 20 Apr 2020 16:24:56 -0000
> @@ -11,6 +11,18 @@ authority letsencrypt-staging {
>   account key "/etc/acme/letsencrypt-staging-privkey.pem"
>  }
>  
> +authority buypass {
> +    api url "https://api.buypass.com/acme/directory"
> +    account key "/etc/acme/buypass-privkey.pem"
> +    contact "mailto:[hidden email]"
> +}
> +
> +authority buypass-test {
> +    api url "https://api.test4.buypass.no/acme/directory"
> +    account key "/etc/acme/buypass-test-privkey.pem"
> +    contact "mailto:[hidden email]"
> +}
> +
>  domain example.com {
>   alternative names { secure.example.com }
>   domain key "/etc/ssl/private/example.com.key"

Reply | Threaded
Open this post in threaded view
|

Re: acme-client(1) and Buypass Go SSL

Florian Obser-2
In reply to this post by Bartosz Kuzma
Hi,

thanks for working on this and finding another acme implementor!

On Mon, Apr 20, 2020 at 06:51:17PM +0200, Bartosz Kuzma wrote:

> Hello,
>
> I've tried to get a certificate from Buypass Go SSL provider using
> acme-client(1) but it ends with the following error:
>
> acme-client: https://api.buypass.com/acme-v02/new-acct: bad HTTP: 400
> acme-client: transfer buffer:
> [{"type":"urn:ietf:params:acme:error:malformed","d
> etail":"Email is a required
> contact","code":400,"message":"MALFORMED_BAD_REQUEST
> ","details":"HTTP 400 Bad Request"}] (164 bytes)
>
> Buypass Go SSL requires that optional field contact in Account Objects
> will contain email address.
>
> I've added new option "contact" to acme-client.conf to fullfil this
> requirement. It is also required to change MARKER in certproc.c to fix line
> endings handling in pem files.

they are leaving out the last newline?

>
> --
> Kind regards, Bartosz Kuzma.

> Index: usr.sbin/acme-client/acme-client.conf.5
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/acme-client.conf.5,v
> retrieving revision 1.22
> diff -u -p -r1.22 acme-client.conf.5
> --- usr.sbin/acme-client/acme-client.conf.5 10 Feb 2020 13:18:21 -0000 1.22
> +++ usr.sbin/acme-client/acme-client.conf.5 20 Apr 2020 16:24:46 -0000
> @@ -98,6 +98,10 @@ It defaults to
>  Specify the
>  .Ar url
>  under which the ACME API is reachable.
> +.It Ic contact Ar contact
> +Optional
> +.Ar contact
> +URLs that the authority can use to contact the client for issues related to this account.

I think we should call it emails. That's what people actually have.
According to the RFC it's a list of contacts, but I'm fine with having only one.

>  .El
>  .Sh DOMAINS
>  The certificates to be obtained through ACME.
> Index: usr.sbin/acme-client/certproc.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/certproc.c,v
> retrieving revision 1.12
> diff -u -p -r1.12 certproc.c
> --- usr.sbin/acme-client/certproc.c 7 Jun 2019 08:07:52 -0000 1.12
> +++ usr.sbin/acme-client/certproc.c 20 Apr 2020 16:24:46 -0000
> @@ -28,7 +28,7 @@
>  
>  #include "extern.h"
>  
> -#define MARKER "-----END CERTIFICATE-----\n"
> +#define MARKER "-----END CERTIFICATE-----"
>  
>  int
>  certproc(int netsock, int filesock)
> @@ -94,6 +94,12 @@ certproc(int netsock, int filesock)
>   }
>  
>   chaincp += strlen(MARKER);
> +
> + if ((chaincp = strchr(chaincp, '-')) == NULL) {
> + warn("strchr");
> + goto out;
> + }
> +

I don't quite understand what this is doing.

>   if ((chain = strdup(chaincp)) == NULL) {
>   warn("strdup");
>   goto out;
> Index: usr.sbin/acme-client/extern.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/extern.h,v
> retrieving revision 1.17
> diff -u -p -r1.17 extern.h
> --- usr.sbin/acme-client/extern.h 7 Feb 2020 14:34:15 -0000 1.17
> +++ usr.sbin/acme-client/extern.h 20 Apr 2020 16:24:46 -0000
> @@ -261,13 +261,13 @@ int json_parse_capaths(struct jsmnn *,
>  
>  char *json_fmt_newcert(const char *);
>  char *json_fmt_chkacc(void);
> -char *json_fmt_newacc(void);
> +char *json_fmt_newacc(const char *);
>  char *json_fmt_neworder(const char *const *, size_t);
>  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 *,
> +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 *);
> Index: usr.sbin/acme-client/json.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/json.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 json.c
> --- usr.sbin/acme-client/json.c 22 Jan 2020 22:25:22 -0000 1.16
> +++ usr.sbin/acme-client/json.c 20 Apr 2020 16:24:46 -0000
> @@ -616,19 +616,30 @@ json_fmt_chkacc(void)
>   * Format the "newAccount" resource request.
>   */
>  char *
> -json_fmt_newacc(void)
> +json_fmt_newacc(const char *contact)
>  {
>   int c;
> - char *p;
> + char *p, *cnt;
> +
> + c = asprintf(&cnt, "\"contact\": [ \"%s\" ], ", contact);
> + if (c == -1) {
> + warn("asprintf");
> + goto err;
> + }
>  

bzzzrt, you can't do this. contact might be NULL, you already need to
check it here, not just further down.

In this particular case I think it's fine do something like this, makes the error handling easier, you don't need a goto etc.

        if (contact == NULL) {
                p = strdup("{"
                    "\"termsOfServiceAgreed\": true"
                    "}");
        } else {
                c = asprintf(&p, "{"
                    "\"contact\": [ \"mailto:%s\" ], "
                    "\"termsOfServiceAgreed\": true"
                    "}", contact);
                if (c == -1)
                        p = NULL;
        }

yes, we have two places now for the template string, but they are
close enough together and I don't see them change that often (read: never).

Also not the mailto, I think we should just put an email address in
the config file and fill in the mailto ourselves.

The rest reads good, haven't tried it yet though.

Thanks,
Florian

>   c = asprintf(&p, "{"
> +    "%s"
>      "\"termsOfServiceAgreed\": true"
> -    "}");
> +    "}", contact == NULL ? "" : cnt);
> + free(cnt);
>   if (c == -1) {
>   warn("asprintf");
>   p = NULL;
>   }
>   return p;
> +
> +err:
> + return NULL;
>  }
>  
>  /*
> Index: usr.sbin/acme-client/netproc.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/netproc.c,v
> retrieving revision 1.25
> diff -u -p -r1.25 netproc.c
> --- usr.sbin/acme-client/netproc.c 11 Aug 2019 19:44:25 -0000 1.25
> +++ usr.sbin/acme-client/netproc.c 20 Apr 2020 16:24:46 -0000
> @@ -368,13 +368,13 @@ sreq(struct conn *c, const char *addr, i
>   * Returns non-zero on success.
>   */
>  static int
> -donewacc(struct conn *c, const struct capaths *p)
> +donewacc(struct conn *c, const struct capaths *p, const char *contact)
>  {
>   int rc = 0;
>   char *req;
>   long lc;
>  
> - if ((req = json_fmt_newacc()) == NULL)
> + if ((req = json_fmt_newacc(contact)) == NULL)
>   warnx("json_fmt_newacc");
>   else if ((lc = sreq(c, p->newaccount, 0, req, &c->kid)) < 0)
>   warnx("%s: bad comm", p->newaccount);
> @@ -397,7 +397,7 @@ donewacc(struct conn *c, const struct ca
>   * Returns non-zero on success.
>   */
>  static int
> -dochkacc(struct conn *c, const struct capaths *p)
> +dochkacc(struct conn *c, const struct capaths *p, const char *contact)
>  {
>   int rc = 0;
>   char *req;
> @@ -412,7 +412,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);
> + rc = donewacc(c, p, contact);
>   else
>   rc = 1;
>  
> @@ -742,7 +742,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))
> + if (!dochkacc(&c, &paths, authority->contact))
>   goto out;
>  
>   /*
> Index: usr.sbin/acme-client/parse.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/parse.h,v
> retrieving revision 1.13
> diff -u -p -r1.13 parse.h
> --- usr.sbin/acme-client/parse.h 17 Jun 2019 12:42:52 -0000 1.13
> +++ usr.sbin/acme-client/parse.h 20 Apr 2020 16:24:46 -0000
> @@ -38,6 +38,7 @@ struct authority_c {
>   char *api;
>   char *account;
>   enum keytype keytype;
> + char *contact;
>  };
>  
>  struct domain_c {
> Index: usr.sbin/acme-client/parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/acme-client/parse.y,v
> retrieving revision 1.39
> diff -u -p -r1.39 parse.y
> --- usr.sbin/acme-client/parse.y 27 Dec 2019 16:56:40 -0000 1.39
> +++ usr.sbin/acme-client/parse.y 20 Apr 2020 16:24:47 -0000
> @@ -100,7 +100,7 @@ typedef struct {
>  
>  %}
>  
> -%token AUTHORITY URL API ACCOUNT
> +%token AUTHORITY URL API ACCOUNT CONTACT
>  %token DOMAIN ALTERNATIVE NAMES CERT FULL CHAIN KEY SIGN WITH CHALLENGEDIR
>  %token YES NO
>  %token INCLUDE
> @@ -230,6 +230,16 @@ authorityoptsl : API URL STRING {
>   auth->account = s;
>   auth->keytype = $4;
>   }
> + | CONTACT STRING {
> + char *s;
> + if (auth->contact != NULL) {
> + yyerror("duplicate contact");
> + YYERROR;
> + }
> + if ((s = strdup($2)) == NULL)
> + err(EXIT_FAILURE, "strdup");
> + auth->contact = s;
> + }
>   ;
>  
>  domain : DOMAIN STRING {
> @@ -437,6 +447,7 @@ lookup(char *s)
>   {"certificate", CERT},
>   {"chain", CHAIN},
>   {"challengedir", CHALLENGEDIR},
> + {"contact", CONTACT},
>   {"domain", DOMAIN},
>   {"ecdsa", ECDSA},
>   {"full", FULL},
> Index: etc/examples/acme-client.conf
> ===================================================================
> RCS file: /cvs/src/etc/examples/acme-client.conf,v
> retrieving revision 1.2
> diff -u -p -r1.2 acme-client.conf
> --- etc/examples/acme-client.conf 7 Jun 2019 08:08:30 -0000 1.2
> +++ etc/examples/acme-client.conf 20 Apr 2020 16:24:56 -0000
> @@ -11,6 +11,18 @@ authority letsencrypt-staging {
>   account key "/etc/acme/letsencrypt-staging-privkey.pem"
>  }
>  
> +authority buypass {
> +    api url "https://api.buypass.com/acme/directory"
> +    account key "/etc/acme/buypass-privkey.pem"
> +    contact "mailto:[hidden email]"
> +}
> +
> +authority buypass-test {
> +    api url "https://api.test4.buypass.no/acme/directory"
> +    account key "/etc/acme/buypass-test-privkey.pem"
> +    contact "mailto:[hidden email]"
> +}
> +
>  domain example.com {
>   alternative names { secure.example.com }
>   domain key "/etc/ssl/private/example.com.key"


--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: acme-client(1) and Buypass Go SSL

Bartosz Kuzma
Hello,

thanks for looking at this!

On 21/04/2020 17:43, Florian Obser wrote:

> Hi,
>
> thanks for working on this and finding another acme implementor!
>
> On Mon, Apr 20, 2020 at 06:51:17PM +0200, Bartosz Kuzma wrote:
>> Hello,
>>
>> I've tried to get a certificate from Buypass Go SSL provider using
>> acme-client(1) but it ends with the following error:
>>
>> acme-client: https://api.buypass.com/acme-v02/new-acct: bad HTTP: 400
>> acme-client: transfer buffer:
>> [{"type":"urn:ietf:params:acme:error:malformed","d
>> etail":"Email is a required
>> contact","code":400,"message":"MALFORMED_BAD_REQUEST
>> ","details":"HTTP 400 Bad Request"}] (164 bytes)
>>
>> Buypass Go SSL requires that optional field contact in Account Objects
>> will contain email address.
>>
>> I've added new option "contact" to acme-client.conf to fullfil this
>> requirement. It is also required to change MARKER in certproc.c to fix line
>> endings handling in pem files.
>
> they are leaving out the last newline?
It seems that chain can be provided with "\n" or "\r\n" line separator.
I removed it from MARKER to handle both cases.

>
>>
>> --
>> Kind regards, Bartosz Kuzma.
>
>> Index: usr.sbin/acme-client/acme-client.conf.5
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/acme-client/acme-client.conf.5,v
>> retrieving revision 1.22
>> diff -u -p -r1.22 acme-client.conf.5
>> --- usr.sbin/acme-client/acme-client.conf.5 10 Feb 2020 13:18:21 -0000 1.22
>> +++ usr.sbin/acme-client/acme-client.conf.5 20 Apr 2020 16:24:46 -0000
>> @@ -98,6 +98,10 @@ It defaults to
>>   Specify the
>>   .Ar url
>>   under which the ACME API is reachable.
>> +.It Ic contact Ar contact
>> +Optional
>> +.Ar contact
>> +URLs that the authority can use to contact the client for issues related to this account.
>
> I think we should call it emails. That's what people actually have.
> According to the RFC it's a list of contacts, but I'm fine with having only one.
For me one contact is also enough.

>
>>   .El
>>   .Sh DOMAINS
>>   The certificates to be obtained through ACME.
>> Index: usr.sbin/acme-client/certproc.c
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/acme-client/certproc.c,v
>> retrieving revision 1.12
>> diff -u -p -r1.12 certproc.c
>> --- usr.sbin/acme-client/certproc.c 7 Jun 2019 08:07:52 -0000 1.12
>> +++ usr.sbin/acme-client/certproc.c 20 Apr 2020 16:24:46 -0000
>> @@ -28,7 +28,7 @@
>>  
>>   #include "extern.h"
>>  
>> -#define MARKER "-----END CERTIFICATE-----\n"
>> +#define MARKER "-----END CERTIFICATE-----"
>>  
>>   int
>>   certproc(int netsock, int filesock)
>> @@ -94,6 +94,12 @@ certproc(int netsock, int filesock)
>>   }
>>  
>>   chaincp += strlen(MARKER);
>> +
>> + if ((chaincp = strchr(chaincp, '-')) == NULL) {
>> + warn("strchr");
>> + goto out;
>> + }
>> +
>
> I don't quite understand what this is doing.
>
Because I removed new line character from MARKER strchr() just move
pointer to -----BEGIN CERTIFICATE---- to skip any new lines character
from chain. It can be replaced by strstr("-----BEGIN CERTIFICATE-----")
if this improve readability.

>>   if ((chain = strdup(chaincp)) == NULL) {
>>   warn("strdup");
>>   goto out;
>> Index: usr.sbin/acme-client/json.c
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/acme-client/json.c,v
>> retrieving revision 1.16
>> diff -u -p -r1.16 json.c
>> --- usr.sbin/acme-client/json.c 22 Jan 2020 22:25:22 -0000 1.16
>> +++ usr.sbin/acme-client/json.c 20 Apr 2020 16:24:46 -0000
>> @@ -616,19 +616,30 @@ json_fmt_chkacc(void)
>>    * Format the "newAccount" resource request.
>>    */
>>   char *
>> -json_fmt_newacc(void)
>> +json_fmt_newacc(const char *contact)
>>   {
>>   int c;
>> - char *p;
>> + char *p, *cnt;
>> +
>> + c = asprintf(&cnt, "\"contact\": [ \"%s\" ], ", contact);
>> + if (c == -1) {
>> + warn("asprintf");
>> + goto err;
>> + }
>>  
>
> bzzzrt, you can't do this. contact might be NULL, you already need to
> check it here, not just further down.
You are right! I've improved json_fmt_newacc function and it should be
good now.

> In this particular case I think it's fine do something like this, makes the error handling easier, you don't need a goto etc.
>
> if (contact == NULL) {
> p = strdup("{"
>    "\"termsOfServiceAgreed\": true"
>    "}");
> } else {
> c = asprintf(&p, "{"
>    "\"contact\": [ \"mailto:%s\" ], "
>    "\"termsOfServiceAgreed\": true"
>    "}", contact);
> if (c == -1)
> p = NULL;
> }
>
> yes, we have two places now for the template string, but they are
> close enough together and I don't see them change that often (read: never).
>
> Also not the mailto, I think we should just put an email address in
> the config file and fill in the mailto ourselves.
>
For me having contact here is more generic approach and allow us to
handle more cases than just email. But if you prefer I can change it to
email.

> The rest reads good, haven't tried it yet though.
>
> Thanks,
> Florian
>

Kind regards, Bartosz Kuzma.

acme-client.patch (10K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: acme-client(1) and Buypass Go SSL

Sebastian Benoit-3
Bartosz Kuzma([hidden email]) on 2020.04.21 20:59:54 +0200:

> Hello,
>
> thanks for looking at this!
>
> On 21/04/2020 17:43, Florian Obser wrote:
> >Hi,
> >
> >thanks for working on this and finding another acme implementor!
> >
> >On Mon, Apr 20, 2020 at 06:51:17PM +0200, Bartosz Kuzma wrote:
> >>Hello,
> >>
> >>I've tried to get a certificate from Buypass Go SSL provider using
> >>acme-client(1) but it ends with the following error:
> >>
> >>acme-client: https://api.buypass.com/acme-v02/new-acct: bad HTTP: 400
> >>acme-client: transfer buffer:
> >>[{"type":"urn:ietf:params:acme:error:malformed","d
> >>etail":"Email is a required
> >>contact","code":400,"message":"MALFORMED_BAD_REQUEST
> >>","details":"HTTP 400 Bad Request"}] (164 bytes)
> >>
> >>Buypass Go SSL requires that optional field contact in Account Objects
> >>will contain email address.
> >>
> >>I've added new option "contact" to acme-client.conf to fullfil this
> >>requirement. It is also required to change MARKER in certproc.c to fix
> >>line
> >>endings handling in pem files.
> >
> >they are leaving out the last newline?
>
> It seems that chain can be provided with "\n" or "\r\n" line separator.
> I removed it from MARKER to handle both cases.
>
> >
> >>
> >>--
> >>Kind regards, Bartosz Kuzma.
> >
> >>Index: usr.sbin/acme-client/acme-client.conf.5
> >>===================================================================
> >>RCS file: /cvs/src/usr.sbin/acme-client/acme-client.conf.5,v
> >>retrieving revision 1.22
> >>diff -u -p -r1.22 acme-client.conf.5
> >>--- usr.sbin/acme-client/acme-client.conf.5 10 Feb 2020 13:18:21 -0000
> >>1.22
> >>+++ usr.sbin/acme-client/acme-client.conf.5 20 Apr 2020 16:24:46 -0000
> >>@@ -98,6 +98,10 @@ It defaults to
> >>  Specify the
> >>  .Ar url
> >>  under which the ACME API is reachable.
> >>+.It Ic contact Ar contact
> >>+Optional
> >>+.Ar contact
> >>+URLs that the authority can use to contact the client for issues related
> >>to this account.
> >
> >I think we should call it emails. That's what people actually have.
> >According to the RFC it's a list of contacts, but I'm fine with having
> >only one.
>
> For me one contact is also enough.
>
> >
> >>  .El
> >>  .Sh DOMAINS
> >>  The certificates to be obtained through ACME.
> >>Index: usr.sbin/acme-client/certproc.c
> >>===================================================================
> >>RCS file: /cvs/src/usr.sbin/acme-client/certproc.c,v
> >>retrieving revision 1.12
> >>diff -u -p -r1.12 certproc.c
> >>--- usr.sbin/acme-client/certproc.c 7 Jun 2019 08:07:52 -0000 1.12
> >>+++ usr.sbin/acme-client/certproc.c 20 Apr 2020 16:24:46 -0000
> >>@@ -28,7 +28,7 @@
> >>  
> >>  #include "extern.h"
> >>  
> >>-#define MARKER "-----END CERTIFICATE-----\n"
> >>+#define MARKER "-----END CERTIFICATE-----"
> >>  
> >>  int
> >>  certproc(int netsock, int filesock)
> >>@@ -94,6 +94,12 @@ certproc(int netsock, int filesock)
> >>   }
> >>  
> >>   chaincp += strlen(MARKER);
> >>+
> >>+ if ((chaincp = strchr(chaincp, '-')) == NULL) {
> >>+ warn("strchr");
> >>+ goto out;
> >>+ }
> >>+
> >
> >I don't quite understand what this is doing.
> >
> Because I removed new line character from MARKER strchr() just move
> pointer to -----BEGIN CERTIFICATE---- to skip any new lines character
> from chain. It can be replaced by strstr("-----BEGIN CERTIFICATE-----")
> if this improve readability.

The warn() should be a warnx() then, because strchr() does not set errno.
When it returns NULL it just means that it did not find the string. So

   warnx("invalid certificate chain");

would be a good error message here i think.

Reply | Threaded
Open this post in threaded view
|

Re: acme-client(1) and Buypass Go SSL

Bartosz Kuzma


On 21/04/2020 21:17, Sebastian Benoit wrote:

> Bartosz Kuzma([hidden email]) on 2020.04.21 20:59:54 +0200:
>> Hello,
>>
>> thanks for looking at this!
>>
>> On 21/04/2020 17:43, Florian Obser wrote:
>>> Hi,
>>>
>>> thanks for working on this and finding another acme implementor!
>>>
>>> On Mon, Apr 20, 2020 at 06:51:17PM +0200, Bartosz Kuzma wrote:
>>>> Hello,
>>>>
>>>> I've tried to get a certificate from Buypass Go SSL provider using
>>>> acme-client(1) but it ends with the following error:
>>>>
>>>> acme-client: https://api.buypass.com/acme-v02/new-acct: bad HTTP: 400
>>>> acme-client: transfer buffer:
>>>> [{"type":"urn:ietf:params:acme:error:malformed","d
>>>> etail":"Email is a required
>>>> contact","code":400,"message":"MALFORMED_BAD_REQUEST
>>>> ","details":"HTTP 400 Bad Request"}] (164 bytes)
>>>>
>>>> Buypass Go SSL requires that optional field contact in Account Objects
>>>> will contain email address.
>>>>
>>>> I've added new option "contact" to acme-client.conf to fullfil this
>>>> requirement. It is also required to change MARKER in certproc.c to fix
>>>> line
>>>> endings handling in pem files.
>>>
>>> they are leaving out the last newline?
>>
>> It seems that chain can be provided with "\n" or "\r\n" line separator.
>> I removed it from MARKER to handle both cases.
>>
>>>
>>>>
>>>> --
>>>> Kind regards, Bartosz Kuzma.
>>>
>>>> Index: usr.sbin/acme-client/acme-client.conf.5
>>>> ===================================================================
>>>> RCS file: /cvs/src/usr.sbin/acme-client/acme-client.conf.5,v
>>>> retrieving revision 1.22
>>>> diff -u -p -r1.22 acme-client.conf.5
>>>> --- usr.sbin/acme-client/acme-client.conf.5 10 Feb 2020 13:18:21 -0000
>>>> 1.22
>>>> +++ usr.sbin/acme-client/acme-client.conf.5 20 Apr 2020 16:24:46 -0000
>>>> @@ -98,6 +98,10 @@ It defaults to
>>>>   Specify the
>>>>   .Ar url
>>>>   under which the ACME API is reachable.
>>>> +.It Ic contact Ar contact
>>>> +Optional
>>>> +.Ar contact
>>>> +URLs that the authority can use to contact the client for issues related
>>>> to this account.
>>>
>>> I think we should call it emails. That's what people actually have.
>>> According to the RFC it's a list of contacts, but I'm fine with having
>>> only one.
>>
>> For me one contact is also enough.
>>
>>>
>>>>   .El
>>>>   .Sh DOMAINS
>>>>   The certificates to be obtained through ACME.
>>>> Index: usr.sbin/acme-client/certproc.c
>>>> ===================================================================
>>>> RCS file: /cvs/src/usr.sbin/acme-client/certproc.c,v
>>>> retrieving revision 1.12
>>>> diff -u -p -r1.12 certproc.c
>>>> --- usr.sbin/acme-client/certproc.c 7 Jun 2019 08:07:52 -0000 1.12
>>>> +++ usr.sbin/acme-client/certproc.c 20 Apr 2020 16:24:46 -0000
>>>> @@ -28,7 +28,7 @@
>>>>  
>>>>   #include "extern.h"
>>>>  
>>>> -#define MARKER "-----END CERTIFICATE-----\n"
>>>> +#define MARKER "-----END CERTIFICATE-----"
>>>>  
>>>>   int
>>>>   certproc(int netsock, int filesock)
>>>> @@ -94,6 +94,12 @@ certproc(int netsock, int filesock)
>>>>   }
>>>>  
>>>>   chaincp += strlen(MARKER);
>>>> +
>>>> + if ((chaincp = strchr(chaincp, '-')) == NULL) {
>>>> + warn("strchr");
>>>> + goto out;
>>>> + }
>>>> +
>>>
>>> I don't quite understand what this is doing.
>>>
>> Because I removed new line character from MARKER strchr() just move
>> pointer to -----BEGIN CERTIFICATE---- to skip any new lines character
>> from chain. It can be replaced by strstr("-----BEGIN CERTIFICATE-----")
>> if this improve readability.
>
> The warn() should be a warnx() then, because strchr() does not set errno.
> When it returns NULL it just means that it did not find the string. So
>
>     warnx("invalid certificate chain");
>
> would be a good error message here i think.
>

Thanks for pointing it. I was not aware of that.

Kind bartosz Kuzma.

Reply | Threaded
Open this post in threaded view
|

Re: acme-client(1) and Buypass Go SSL

Bartosz Kuzma
In reply to this post by Sebastian Benoit-3
I fixed warn() and changed certproc.c to be less confusing.

On 21/04/2020 21:17, Sebastian Benoit wrote:

> Bartosz Kuzma([hidden email]) on 2020.04.21 20:59:54 +0200:
>> Hello,
>>
>> thanks for looking at this!
>>
>> On 21/04/2020 17:43, Florian Obser wrote:
>>> Hi,
>>>
>>> thanks for working on this and finding another acme implementor!
>>>
>>> On Mon, Apr 20, 2020 at 06:51:17PM +0200, Bartosz Kuzma wrote:
>>>> Hello,
>>>>
>>>> I've tried to get a certificate from Buypass Go SSL provider using
>>>> acme-client(1) but it ends with the following error:
>>>>
>>>> acme-client: https://api.buypass.com/acme-v02/new-acct: bad HTTP: 400
>>>> acme-client: transfer buffer:
>>>> [{"type":"urn:ietf:params:acme:error:malformed","d
>>>> etail":"Email is a required
>>>> contact","code":400,"message":"MALFORMED_BAD_REQUEST
>>>> ","details":"HTTP 400 Bad Request"}] (164 bytes)
>>>>
>>>> Buypass Go SSL requires that optional field contact in Account Objects
>>>> will contain email address.
>>>>
>>>> I've added new option "contact" to acme-client.conf to fullfil this
>>>> requirement. It is also required to change MARKER in certproc.c to fix
>>>> line
>>>> endings handling in pem files.
>>>
>>> they are leaving out the last newline?
>>
>> It seems that chain can be provided with "\n" or "\r\n" line separator.
>> I removed it from MARKER to handle both cases.
>>
>>>
>>>>
>>>> --
>>>> Kind regards, Bartosz Kuzma.
>>>
>>>> Index: usr.sbin/acme-client/acme-client.conf.5
>>>> ===================================================================
>>>> RCS file: /cvs/src/usr.sbin/acme-client/acme-client.conf.5,v
>>>> retrieving revision 1.22
>>>> diff -u -p -r1.22 acme-client.conf.5
>>>> --- usr.sbin/acme-client/acme-client.conf.5 10 Feb 2020 13:18:21 -0000
>>>> 1.22
>>>> +++ usr.sbin/acme-client/acme-client.conf.5 20 Apr 2020 16:24:46 -0000
>>>> @@ -98,6 +98,10 @@ It defaults to
>>>>   Specify the
>>>>   .Ar url
>>>>   under which the ACME API is reachable.
>>>> +.It Ic contact Ar contact
>>>> +Optional
>>>> +.Ar contact
>>>> +URLs that the authority can use to contact the client for issues related
>>>> to this account.
>>>
>>> I think we should call it emails. That's what people actually have.
>>> According to the RFC it's a list of contacts, but I'm fine with having
>>> only one.
>>
>> For me one contact is also enough.
>>
>>>
>>>>   .El
>>>>   .Sh DOMAINS
>>>>   The certificates to be obtained through ACME.
>>>> Index: usr.sbin/acme-client/certproc.c
>>>> ===================================================================
>>>> RCS file: /cvs/src/usr.sbin/acme-client/certproc.c,v
>>>> retrieving revision 1.12
>>>> diff -u -p -r1.12 certproc.c
>>>> --- usr.sbin/acme-client/certproc.c 7 Jun 2019 08:07:52 -0000 1.12
>>>> +++ usr.sbin/acme-client/certproc.c 20 Apr 2020 16:24:46 -0000
>>>> @@ -28,7 +28,7 @@
>>>>  
>>>>   #include "extern.h"
>>>>  
>>>> -#define MARKER "-----END CERTIFICATE-----\n"
>>>> +#define MARKER "-----END CERTIFICATE-----"
>>>>  
>>>>   int
>>>>   certproc(int netsock, int filesock)
>>>> @@ -94,6 +94,12 @@ certproc(int netsock, int filesock)
>>>>   }
>>>>  
>>>>   chaincp += strlen(MARKER);
>>>> +
>>>> + if ((chaincp = strchr(chaincp, '-')) == NULL) {
>>>> + warn("strchr");
>>>> + goto out;
>>>> + }
>>>> +
>>>
>>> I don't quite understand what this is doing.
>>>
>> Because I removed new line character from MARKER strchr() just move
>> pointer to -----BEGIN CERTIFICATE---- to skip any new lines character
>> from chain. It can be replaced by strstr("-----BEGIN CERTIFICATE-----")
>> if this improve readability.
>
> The warn() should be a warnx() then, because strchr() does not set errno.
> When it returns NULL it just means that it did not find the string. So
>
>     warnx("invalid certificate chain");
>
> would be a good error message here i think.
>

acme-client.patch (10K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: acme-client(1) and Buypass Go SSL

Florian Obser-2

This fell through the cracks back in April.

We need to be able to provide contact information to use the
buypass.com acme api.

OK?

diff --git etc/examples/acme-client.conf etc/examples/acme-client.conf
index 32ecd8e8655..40d231725ac 100644
--- etc/examples/acme-client.conf
+++ etc/examples/acme-client.conf
@@ -11,6 +11,18 @@ authority letsencrypt-staging {
  account key "/etc/acme/letsencrypt-staging-privkey.pem"
 }
 
+authority buypass {
+    api url "https://api.buypass.com/acme/directory"
+    account key "/etc/acme/buypass-privkey.pem"
+    contact "mailto:[hidden email]"
+}
+
+authority buypass-test {
+    api url "https://api.test4.buypass.no/acme/directory"
+    account key "/etc/acme/buypass-test-privkey.pem"
+    contact "mailto:[hidden email]"
+}
+
 domain example.com {
  alternative names { secure.example.com }
  domain key "/etc/ssl/private/example.com.key"
diff --git usr.sbin/acme-client/acme-client.conf.5 usr.sbin/acme-client/acme-client.conf.5
index 08a47a76ab7..41994d13676 100644
--- usr.sbin/acme-client/acme-client.conf.5
+++ usr.sbin/acme-client/acme-client.conf.5
@@ -98,6 +98,11 @@ It defaults to
 Specify the
 .Ar url
 under which the ACME API is reachable.
+.It Ic contact Ar contact
+Optional
+.Ar contact
+URLs that the authority can use to contact the client for issues related to
+this account.
 .El
 .Sh DOMAINS
 The certificates to be obtained through ACME.
diff --git usr.sbin/acme-client/extern.h usr.sbin/acme-client/extern.h
index 364425b0500..ee341e0950f 100644
--- usr.sbin/acme-client/extern.h
+++ usr.sbin/acme-client/extern.h
@@ -263,7 +263,7 @@ char *json_getstr(struct jsmnn *, const char *);
 
 char *json_fmt_newcert(const char *);
 char *json_fmt_chkacc(void);
-char *json_fmt_newacc(void);
+char *json_fmt_newacc(const char *);
 char *json_fmt_neworder(const char *const *, size_t);
 char *json_fmt_protected_rsa(const char *,
  const char *, const char *, const char *);
diff --git usr.sbin/acme-client/json.c usr.sbin/acme-client/json.c
index a6762eeb258..9201f8d2fc3 100644
--- usr.sbin/acme-client/json.c
+++ usr.sbin/acme-client/json.c
@@ -618,14 +618,24 @@ json_fmt_chkacc(void)
  * Format the "newAccount" resource request.
  */
 char *
-json_fmt_newacc(void)
+json_fmt_newacc(const char *contact)
 {
  int c;
- char *p;
+ char *p, *cnt = NULL;
+
+ if (contact != NULL) {
+ c = asprintf(&cnt, "\"contact\": [ \"%s\" ], ", contact);
+ if (c == -1) {
+ warn("asprintf");
+ return NULL;
+ }
+ }
 
  c = asprintf(&p, "{"
+    "%s"
     "\"termsOfServiceAgreed\": true"
-    "}");
+    "}", cnt == NULL ? "" : cnt);
+ free(cnt);
  if (c == -1) {
  warn("asprintf");
  p = NULL;
diff --git usr.sbin/acme-client/netproc.c usr.sbin/acme-client/netproc.c
index 05e36897c38..4490450003e 100644
--- usr.sbin/acme-client/netproc.c
+++ usr.sbin/acme-client/netproc.c
@@ -369,14 +369,14 @@ sreq(struct conn *c, const char *addr, int kid, const char *req, char **loc)
  * Returns non-zero on success.
  */
 static int
-donewacc(struct conn *c, const struct capaths *p)
+donewacc(struct conn *c, const struct capaths *p, const char *contact)
 {
  struct jsmnn *j = NULL;
  int rc = 0;
  char *req, *detail, *error = NULL;
  long lc;
 
- if ((req = json_fmt_newacc()) == NULL)
+ if ((req = json_fmt_newacc(contact)) == NULL)
  warnx("json_fmt_newacc");
  else if ((lc = sreq(c, p->newaccount, 0, req, &c->kid)) < 0)
  warnx("%s: bad comm", p->newaccount);
@@ -410,7 +410,7 @@ donewacc(struct conn *c, const struct capaths *p)
  * Returns non-zero on success.
  */
 static int
-dochkacc(struct conn *c, const struct capaths *p)
+dochkacc(struct conn *c, const struct capaths *p, const char *contact)
 {
  int rc = 0;
  char *req;
@@ -425,7 +425,7 @@ dochkacc(struct conn *c, const struct capaths *p)
  else if (c->buf.buf == NULL || c->buf.sz == 0)
  warnx("%s: empty response", p->newaccount);
  else if (lc == 400)
- rc = donewacc(c, p);
+ rc = donewacc(c, p, contact);
  else
  rc = 1;
 
@@ -755,7 +755,7 @@ netproc(int kfd, int afd, int Cfd, int cfd, int dfd, int rfd,
  c.newnonce = paths.newnonce;
 
  /* Check if our account already exists or create it. */
- if (!dochkacc(&c, &paths))
+ if (!dochkacc(&c, &paths, authority->contact))
  goto out;
 
  /*
diff --git usr.sbin/acme-client/parse.h usr.sbin/acme-client/parse.h
index 9de5a490f69..c928a9de7da 100644
--- usr.sbin/acme-client/parse.h
+++ usr.sbin/acme-client/parse.h
@@ -38,6 +38,7 @@ struct authority_c {
  char *api;
  char *account;
  enum keytype keytype;
+ char *contact;
 };
 
 struct domain_c {
diff --git usr.sbin/acme-client/parse.y usr.sbin/acme-client/parse.y
index 120f253a63f..c39b922f764 100644
--- usr.sbin/acme-client/parse.y
+++ usr.sbin/acme-client/parse.y
@@ -100,7 +100,7 @@ typedef struct {
 
 %}
 
-%token AUTHORITY URL API ACCOUNT
+%token AUTHORITY URL API ACCOUNT CONTACT
 %token DOMAIN ALTERNATIVE NAME NAMES CERT FULL CHAIN KEY SIGN WITH CHALLENGEDIR
 %token YES NO
 %token INCLUDE
@@ -230,6 +230,16 @@ authorityoptsl : API URL STRING {
  auth->account = s;
  auth->keytype = $4;
  }
+ | CONTACT STRING {
+ char *s;
+ if (auth->contact != NULL) {
+ yyerror("duplicate contact");
+ YYERROR;
+ }
+ if ((s = strdup($2)) == NULL)
+ err(EXIT_FAILURE, "strdup");
+ auth->contact = s;
+ }
  ;
 
 domain : DOMAIN STRING {
@@ -452,6 +462,7 @@ lookup(char *s)
  {"certificate", CERT},
  {"chain", CHAIN},
  {"challengedir", CHALLENGEDIR},
+ {"contact", CONTACT},
  {"domain", DOMAIN},
  {"ecdsa", ECDSA},
  {"full", FULL},


--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: acme-client(1) and Buypass Go SSL

Sebastian Benoit-3
ok!

Florian Obser([hidden email]) on 2020.09.14 17:15:37 +0200:

>
> This fell through the cracks back in April.
>
> We need to be able to provide contact information to use the
> buypass.com acme api.
>
> OK?
>
> diff --git etc/examples/acme-client.conf etc/examples/acme-client.conf
> index 32ecd8e8655..40d231725ac 100644
> --- etc/examples/acme-client.conf
> +++ etc/examples/acme-client.conf
> @@ -11,6 +11,18 @@ authority letsencrypt-staging {
>   account key "/etc/acme/letsencrypt-staging-privkey.pem"
>  }
>  
> +authority buypass {
> +    api url "https://api.buypass.com/acme/directory"
> +    account key "/etc/acme/buypass-privkey.pem"
> +    contact "mailto:[hidden email]"
> +}
> +
> +authority buypass-test {
> +    api url "https://api.test4.buypass.no/acme/directory"
> +    account key "/etc/acme/buypass-test-privkey.pem"
> +    contact "mailto:[hidden email]"
> +}
> +
>  domain example.com {
>   alternative names { secure.example.com }
>   domain key "/etc/ssl/private/example.com.key"
> diff --git usr.sbin/acme-client/acme-client.conf.5 usr.sbin/acme-client/acme-client.conf.5
> index 08a47a76ab7..41994d13676 100644
> --- usr.sbin/acme-client/acme-client.conf.5
> +++ usr.sbin/acme-client/acme-client.conf.5
> @@ -98,6 +98,11 @@ It defaults to
>  Specify the
>  .Ar url
>  under which the ACME API is reachable.
> +.It Ic contact Ar contact
> +Optional
> +.Ar contact
> +URLs that the authority can use to contact the client for issues related to
> +this account.
>  .El
>  .Sh DOMAINS
>  The certificates to be obtained through ACME.
> diff --git usr.sbin/acme-client/extern.h usr.sbin/acme-client/extern.h
> index 364425b0500..ee341e0950f 100644
> --- usr.sbin/acme-client/extern.h
> +++ usr.sbin/acme-client/extern.h
> @@ -263,7 +263,7 @@ char *json_getstr(struct jsmnn *, const char *);
>  
>  char *json_fmt_newcert(const char *);
>  char *json_fmt_chkacc(void);
> -char *json_fmt_newacc(void);
> +char *json_fmt_newacc(const char *);
>  char *json_fmt_neworder(const char *const *, size_t);
>  char *json_fmt_protected_rsa(const char *,
>   const char *, const char *, const char *);
> diff --git usr.sbin/acme-client/json.c usr.sbin/acme-client/json.c
> index a6762eeb258..9201f8d2fc3 100644
> --- usr.sbin/acme-client/json.c
> +++ usr.sbin/acme-client/json.c
> @@ -618,14 +618,24 @@ json_fmt_chkacc(void)
>   * Format the "newAccount" resource request.
>   */
>  char *
> -json_fmt_newacc(void)
> +json_fmt_newacc(const char *contact)
>  {
>   int c;
> - char *p;
> + char *p, *cnt = NULL;
> +
> + if (contact != NULL) {
> + c = asprintf(&cnt, "\"contact\": [ \"%s\" ], ", contact);
> + if (c == -1) {
> + warn("asprintf");
> + return NULL;
> + }
> + }
>  
>   c = asprintf(&p, "{"
> +    "%s"
>      "\"termsOfServiceAgreed\": true"
> -    "}");
> +    "}", cnt == NULL ? "" : cnt);
> + free(cnt);
>   if (c == -1) {
>   warn("asprintf");
>   p = NULL;
> diff --git usr.sbin/acme-client/netproc.c usr.sbin/acme-client/netproc.c
> index 05e36897c38..4490450003e 100644
> --- usr.sbin/acme-client/netproc.c
> +++ usr.sbin/acme-client/netproc.c
> @@ -369,14 +369,14 @@ sreq(struct conn *c, const char *addr, int kid, const char *req, char **loc)
>   * Returns non-zero on success.
>   */
>  static int
> -donewacc(struct conn *c, const struct capaths *p)
> +donewacc(struct conn *c, const struct capaths *p, const char *contact)
>  {
>   struct jsmnn *j = NULL;
>   int rc = 0;
>   char *req, *detail, *error = NULL;
>   long lc;
>  
> - if ((req = json_fmt_newacc()) == NULL)
> + if ((req = json_fmt_newacc(contact)) == NULL)
>   warnx("json_fmt_newacc");
>   else if ((lc = sreq(c, p->newaccount, 0, req, &c->kid)) < 0)
>   warnx("%s: bad comm", p->newaccount);
> @@ -410,7 +410,7 @@ donewacc(struct conn *c, const struct capaths *p)
>   * Returns non-zero on success.
>   */
>  static int
> -dochkacc(struct conn *c, const struct capaths *p)
> +dochkacc(struct conn *c, const struct capaths *p, const char *contact)
>  {
>   int rc = 0;
>   char *req;
> @@ -425,7 +425,7 @@ dochkacc(struct conn *c, const struct capaths *p)
>   else if (c->buf.buf == NULL || c->buf.sz == 0)
>   warnx("%s: empty response", p->newaccount);
>   else if (lc == 400)
> - rc = donewacc(c, p);
> + rc = donewacc(c, p, contact);
>   else
>   rc = 1;
>  
> @@ -755,7 +755,7 @@ netproc(int kfd, int afd, int Cfd, int cfd, int dfd, int rfd,
>   c.newnonce = paths.newnonce;
>  
>   /* Check if our account already exists or create it. */
> - if (!dochkacc(&c, &paths))
> + if (!dochkacc(&c, &paths, authority->contact))
>   goto out;
>  
>   /*
> diff --git usr.sbin/acme-client/parse.h usr.sbin/acme-client/parse.h
> index 9de5a490f69..c928a9de7da 100644
> --- usr.sbin/acme-client/parse.h
> +++ usr.sbin/acme-client/parse.h
> @@ -38,6 +38,7 @@ struct authority_c {
>   char *api;
>   char *account;
>   enum keytype keytype;
> + char *contact;
>  };
>  
>  struct domain_c {
> diff --git usr.sbin/acme-client/parse.y usr.sbin/acme-client/parse.y
> index 120f253a63f..c39b922f764 100644
> --- usr.sbin/acme-client/parse.y
> +++ usr.sbin/acme-client/parse.y
> @@ -100,7 +100,7 @@ typedef struct {
>  
>  %}
>  
> -%token AUTHORITY URL API ACCOUNT
> +%token AUTHORITY URL API ACCOUNT CONTACT
>  %token DOMAIN ALTERNATIVE NAME NAMES CERT FULL CHAIN KEY SIGN WITH CHALLENGEDIR
>  %token YES NO
>  %token INCLUDE
> @@ -230,6 +230,16 @@ authorityoptsl : API URL STRING {
>   auth->account = s;
>   auth->keytype = $4;
>   }
> + | CONTACT STRING {
> + char *s;
> + if (auth->contact != NULL) {
> + yyerror("duplicate contact");
> + YYERROR;
> + }
> + if ((s = strdup($2)) == NULL)
> + err(EXIT_FAILURE, "strdup");
> + auth->contact = s;
> + }
>   ;
>  
>  domain : DOMAIN STRING {
> @@ -452,6 +462,7 @@ lookup(char *s)
>   {"certificate", CERT},
>   {"chain", CHAIN},
>   {"challengedir", CHALLENGEDIR},
> + {"contact", CONTACT},
>   {"domain", DOMAIN},
>   {"ecdsa", ECDSA},
>   {"full", FULL},
>
>
> --
> I'm not entirely sure you are real.
>