On 6/3/19 11:53 AM, Renaud Allard wrote:
On 5/29/19 9:58 AM, Florian Obser wrote:
On Wed, May 22, 2019 at 01:33:11PM +0200, Renaud Allard wrote:
The key needs to be generated manually
i.e.: openssl ecparam -genkey -name secp384r1 -out privkey.pem
why not let acme-client generate the key?
Here is a more complete diff where you can use the -E switch to
generate a ECDSA key instead of the RSA one.
I refined a little bit the patch to not put ecdsa functions into rsa.c.
So I renamed rsa.c to key.c and removed the rsa references to functions
which apply to both rsa and ecdsa.
Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/acme-client/Makefile,v
retrieving revision 1.8
diff -u -p -r1.8 Makefile
--- Makefile 3 Jul 2017 22:21:47 -0000 1.8
+++ Makefile 4 Jun 2019 13:50:28 -0000
@@ -2,7 +2,7 @@
PROG= acme-client
SRCS= acctproc.c base64.c certproc.c chngproc.c dbg.c dnsproc.c
SRCS+= fileproc.c http.c jsmn.c json.c keyproc.c main.c netproc.c
-SRCS+= parse.y revokeproc.c rsa.c util.c
+SRCS+= parse.y revokeproc.c key.c util.c
MAN= acme-client.1 acme-client.conf.5
Index: acctproc.c
===================================================================
RCS file: /cvs/src/usr.sbin/acme-client/acctproc.c,v
retrieving revision 1.12
diff -u -p -r1.12 acctproc.c
--- acctproc.c 28 Jul 2018 15:25:23 -0000 1.12
+++ acctproc.c 4 Jun 2019 13:50:28 -0000
@@ -82,8 +82,8 @@ op_thumb_rsa(EVP_PKEY *pkey)
warnx("bn2string");
else if ((exp = bn2string(r->e)) == NULL)
warnx("bn2string");
- else if ((json = json_fmt_thumb_rsa(exp, mod)) == NULL)
- warnx("json_fmt_thumb_rsa");
+ else if ((json = json_fmt_thumb_key(exp, mod)) == NULL)
+ warnx("json_fmt_thumb_key");
free(exp);
free(mod);
@@ -175,10 +175,10 @@ op_sign_rsa(char **head, char **prot, EV
warnx("bn2string");
else if ((exp = bn2string(r->e)) == NULL)
warnx("bn2string");
- else if ((*head = json_fmt_header_rsa(exp, mod)) == NULL)
- warnx("json_fmt_header_rsa");
- else if ((*prot = json_fmt_protected_rsa(exp, mod, nonce)) == NULL)
- warnx("json_fmt_protected_rsa");
+ else if ((*head = json_fmt_header_key(exp, mod)) == NULL)
+ warnx("json_fmt_header_key");
+ else if ((*prot = json_fmt_protected_key(exp, mod, nonce)) == NULL)
+ warnx("json_fmt_protected_key");
else
rc = 1;
@@ -338,7 +338,7 @@ acctproc(int netsock, const char *acctke
goto out;
dodbg("%s: generated RSA account key", acctkey);
} else {
- if ((pkey = rsa_key_load(f, acctkey)) == NULL)
+ if ((pkey = key_load(f, acctkey)) == NULL)
goto out;
doddbg("%s: loaded RSA account key", acctkey);
}
Index: acme-client.1
===================================================================
RCS file: /cvs/src/usr.sbin/acme-client/acme-client.1,v
retrieving revision 1.29
diff -u -p -r1.29 acme-client.1
--- acme-client.1 3 Feb 2019 20:39:35 -0000 1.29
+++ acme-client.1 4 Jun 2019 13:50:28 -0000
@@ -79,7 +79,9 @@ The options are as follows:
.It Fl A
Create a new RSA account key if one does not already exist.
.It Fl D
-Create a new RSA domain key if one does not already exist.
+Create a new (RSA) domain key if one does not already exist.
+.It Fl E
+Switch the new domain key algorithm to ECDSA instead of RSA.
.It Fl F
Force certificate renewal, even if it's too soon.
.It Fl f Ar configfile
Index: ecdsa.h
===================================================================
RCS file: ecdsa.h
diff -N ecdsa.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ecdsa.h 4 Jun 2019 13:50:28 -0000
@@ -0,0 +1,22 @@
+/* $Id: rsa.h,v 1.1 2016/08/31 22:01:42 florian Exp $ */
+/*
+ * Copyright (c) 2019 Renaud Allard <ren...@allard.it>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef ECDSA_H
+#define ECDSA_H
+
+EVP_PKEY *ec_key_create(FILE *, const char *);
+
+#endif /* ! ECDSA_H */
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/acme-client/extern.h,v
retrieving revision 1.10
diff -u -p -r1.10 extern.h
--- extern.h 31 Jan 2019 15:55:48 -0000 1.10
+++ extern.h 4 Jun 2019 13:50:28 -0000
@@ -18,6 +18,7 @@
#define EXTERN_H
#include "parse.h"
+#include "stdbool.h"
#define MAX_SERVERS_DNS 8
@@ -240,11 +241,11 @@ char *json_fmt_challenge(const char *,
char *json_fmt_newauthz(const char *);
char *json_fmt_newcert(const char *);
char *json_fmt_newreg(const char *);
-char *json_fmt_protected_rsa(const char *,
+char *json_fmt_protected_key(const char *,
const char *, const char *);
char *json_fmt_revokecert(const char *);
-char *json_fmt_header_rsa(const char *, const char *);
-char *json_fmt_thumb_rsa(const char *, const char *);
+char *json_fmt_header_key(const char *, const char *);
+char *json_fmt_thumb_key(const char *, const char *);
char *json_fmt_signed(const char *,
const char *, const char *, const char *);
@@ -252,6 +253,11 @@ char *json_fmt_signed(const char *,
* Should we print debugging messages?
*/
int verbose;
+
+/*
+ * Should we switch to ecdsa?
+ */
+bool ecdsa;
/*
* What component is the process within (COMP__MAX for none)?
Index: json.c
===================================================================
RCS file: /cvs/src/usr.sbin/acme-client/json.c,v
retrieving revision 1.11
diff -u -p -r1.11 json.c
--- json.c 31 Jan 2019 15:55:48 -0000 1.11
+++ json.c 4 Jun 2019 13:50:28 -0000
@@ -589,7 +589,7 @@ json_fmt_newcert(const char *cert)
* Header component of json_fmt_signed().
*/
char *
-json_fmt_header_rsa(const char *exp, const char *mod)
+json_fmt_header_key(const char *exp, const char *mod)
{
int c;
char *p;
@@ -611,7 +611,7 @@ json_fmt_header_rsa(const char *exp, con
* Protected component of json_fmt_signed().
*/
char *
-json_fmt_protected_rsa(const char *exp, const char *mod, const char *nce)
+json_fmt_protected_key(const char *exp, const char *mod, const char *nce)
{
int c;
char *p;
@@ -661,7 +661,7 @@ json_fmt_signed(const char *header, cons
* However, it's in the form of a JSON string, so do it here.
*/
char *
-json_fmt_thumb_rsa(const char *exp, const char *mod)
+json_fmt_thumb_key(const char *exp, const char *mod)
{
int c;
char *p;
Index: key.c
===================================================================
RCS file: key.c
diff -N key.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ key.c 4 Jun 2019 13:50:28 -0000
@@ -0,0 +1,150 @@
+/* $Id: rsa.c,v 1.7 2018/07/28 15:25:23 tb Exp $ */
+/*
+ * Copyright (c) 2019 Renaud Allard <ren...@allard.it>
+ * Copyright (c) 2016 Kristaps Dzonsons <krist...@bsd.lv>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <err.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/ecdsa.h>
+#include <openssl/ec.h>
+#include <openssl/obj_mac.h>
+
+#include "rsa.h"
+#include "ecdsa.h"
+
+/*
+ * Default number of bits when creating a new RSA key.
+ */
+#define KBITS 4096
+#define ECCTYPE NID_secp384r1
+
+/*
+ * Create an RSA key with the default KBITS number of bits.
+ */
+EVP_PKEY *
+rsa_key_create(FILE *f, const char *fname)
+{
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ /* First, create the context and the key. */
+
+ if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL) {
+ warnx("EVP_PKEY_CTX_new_id");
+ goto err;
+ } else if (EVP_PKEY_keygen_init(ctx) <= 0) {
+ warnx("EVP_PKEY_keygen_init");
+ goto err;
+ } else if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KBITS) <= 0) {
+ warnx("EVP_PKEY_set_rsa_keygen_bits");
+ goto err;
+ } else if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
+ warnx("EVP_PKEY_keygen");
+ goto err;
+ }
+
+ /* Serialise the key to the disc. */
+
+ if (PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL))
+ goto out;
+
+ warnx("%s: PEM_write_PrivateKey", fname);
+
+err:
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+out:
+ EVP_PKEY_CTX_free(ctx);
+ return pkey;
+}
+
+EVP_PKEY *
+ec_key_create(FILE *f, const char *fname)
+{
+ EC_KEY *eckey = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ if ((eckey = EC_KEY_new()) == NULL ) {
+ warnx("EC_KEY_new");
+ goto err;
+ } else if ((eckey = EC_KEY_new_by_curve_name(ECCTYPE)) == NULL ) {
+ warnx("EC_GROUP_new_by_curve_name");
+ goto err;
+ }
+
+ if (!EC_KEY_generate_key(eckey)) {
+ warnx("EC_KEY_generate_key");
+ goto err;
+ }
+
+ /* set OPENSSL_EC_NAMED_CURVE to be able to load the key */
+
+ EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
+
+ /* Serialise the key to the disc in EC format */
+
+ if (!PEM_write_ECPrivateKey(f, eckey, NULL, NULL, 0, NULL, NULL)) {
+ warnx("PEM_write_ECPrivateKey");
+ goto err;
+ }
+
+ /* Convert the EC key into a PKEY structure */
+
+ if ((pkey=EVP_PKEY_new()) == NULL) {
+ warnx("EVP_PKEY_new");
+ goto err;
+ }
+ if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
+ warnx("EVP_PKEY_assign_EC_KEY");
+ goto err;
+ }
+
+ goto out;
+
+ warnx("%s: PEM_write_ECPrivateKey", fname);
+
+err:
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+out:
+ return pkey;
+}
+
+
+
+EVP_PKEY *
+key_load(FILE *f, const char *fname)
+{
+ EVP_PKEY *pkey;
+
+ pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL);
+ if (pkey == NULL) {
+ warnx("%s: PEM_read_PrivateKey", fname);
+ return NULL;
+ } else if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA ||
+ EVP_PKEY_type(pkey->type) == EVP_PKEY_EC )
+ return pkey;
+
+ warnx("%s: unsupported key type", fname);
+ EVP_PKEY_free(pkey);
+ return NULL;
+}
Index: keyproc.c
===================================================================
RCS file: /cvs/src/usr.sbin/acme-client/keyproc.c,v
retrieving revision 1.11
diff -u -p -r1.11 keyproc.c
--- keyproc.c 29 Jul 2018 20:22:02 -0000 1.11
+++ keyproc.c 4 Jun 2019 13:50:28 -0000
@@ -31,6 +31,7 @@
#include "extern.h"
#include "rsa.h"
+#include "ecdsa.h"
/*
* This was lifted more or less directly from demos/x509/mkreq.c of the
@@ -114,11 +115,17 @@ keyproc(int netsock, const char *keyfile
}
if (newkey) {
- if ((pkey = rsa_key_create(f, keyfile)) == NULL)
- goto out;
- dodbg("%s: generated RSA domain key", keyfile);
+ if (ecdsa) {
+ if ((pkey = ec_key_create(f, keyfile)) == NULL)
+ goto out;
+ dodbg("%s: generated ECDSA domain key", keyfile);
+ } else {
+ if ((pkey = rsa_key_create(f, keyfile)) == NULL)
+ goto out;
+ dodbg("%s: generated RSA domain key", keyfile);
+ }
} else {
- if ((pkey = rsa_key_load(f, keyfile)) == NULL)
+ if ((pkey = key_load(f, keyfile)) == NULL)
goto out;
doddbg("%s: loaded RSA domain key", keyfile);
}
Index: main.c
===================================================================
RCS file: /cvs/src/usr.sbin/acme-client/main.c,v
retrieving revision 1.45
diff -u -p -r1.45 main.c
--- main.c 9 Mar 2019 18:07:40 -0000 1.45
+++ main.c 4 Jun 2019 13:50:28 -0000
@@ -49,6 +49,7 @@ main(int argc, char *argv[])
int popts = 0;
pid_t pids[COMP__MAX];
extern int verbose;
+ extern bool ecdsa;
extern enum comp proccomp;
size_t i, altsz, ne;
@@ -57,7 +58,7 @@ main(int argc, char *argv[])
struct domain_c *domain = NULL;
struct altname_c *ac;
- while ((c = getopt(argc, argv, "ADFnrvf:")) != -1)
+ while ((c = getopt(argc, argv, "ADEFnrvf:")) != -1)
switch (c) {
case 'A':
popts |= ACME_OPT_NEWACCT;
@@ -65,6 +66,10 @@ main(int argc, char *argv[])
case 'D':
popts |= ACME_OPT_NEWDKEY;
break;
+ case 'E':
+ ecdsa = true;
+ popts |= ACME_OPT_DKEYEC;
+ break;
case 'F':
force = 1;
break;
@@ -180,6 +185,10 @@ main(int argc, char *argv[])
!= -1) {
dodbg("%s: domain key exists (not creating)", domain->key);
popts &= ~ACME_OPT_NEWDKEY;
+ }
+
+ if (popts & ACME_OPT_DKEYEC) {
+ ecdsa = true;
}
if (access(chngdir, R_OK) == -1) {
Index: parse.h
===================================================================
RCS file: /cvs/src/usr.sbin/acme-client/parse.h,v
retrieving revision 1.9
diff -u -p -r1.9 parse.h
--- parse.h 27 Nov 2017 16:53:04 -0000 1.9
+++ parse.h 4 Jun 2019 13:50:28 -0000
@@ -61,6 +61,7 @@ struct keyfile {
#define ACME_OPT_NEWACCT 0x00000002
#define ACME_OPT_NEWDKEY 0x00000004
#define ACME_OPT_CHECK 0x00000008
+#define ACME_OPT_DKEYEC 0x00000016
struct acme_conf {
int opts;
Index: rsa.c
===================================================================
RCS file: rsa.c
diff -N rsa.c
--- rsa.c 28 Jul 2018 15:25:23 -0000 1.7
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,88 +0,0 @@
-/* $Id: rsa.c,v 1.7 2018/07/28 15:25:23 tb Exp $ */
-/*
- * Copyright (c) 2016 Kristaps Dzonsons <krist...@bsd.lv>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <err.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/rsa.h>
-
-#include "rsa.h"
-
-/*
- * Default number of bits when creating a new key.
- */
-#define KBITS 4096
-
-/*
- * Create an RSA key with the default KBITS number of bits.
- */
-EVP_PKEY *
-rsa_key_create(FILE *f, const char *fname)
-{
- EVP_PKEY_CTX *ctx = NULL;
- EVP_PKEY *pkey = NULL;
-
- /* First, create the context and the key. */
-
- if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL) {
- warnx("EVP_PKEY_CTX_new_id");
- goto err;
- } else if (EVP_PKEY_keygen_init(ctx) <= 0) {
- warnx("EVP_PKEY_keygen_init");
- goto err;
- } else if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KBITS) <= 0) {
- warnx("EVP_PKEY_set_rsa_keygen_bits");
- goto err;
- } else if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
- warnx("EVP_PKEY_keygen");
- goto err;
- }
-
- /* Serialise the key to the disc. */
-
- if (PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL))
- goto out;
-
- warnx("%s: PEM_write_PrivateKey", fname);
-err:
- EVP_PKEY_free(pkey);
- pkey = NULL;
-out:
- EVP_PKEY_CTX_free(ctx);
- return pkey;
-}
-
-
-EVP_PKEY *
-rsa_key_load(FILE *f, const char *fname)
-{
- EVP_PKEY *pkey;
-
- pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL);
- if (pkey == NULL) {
- warnx("%s: PEM_read_PrivateKey", fname);
- return NULL;
- } else if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA)
- return pkey;
-
- warnx("%s: unsupported key type", fname);
- EVP_PKEY_free(pkey);
- return NULL;
-}
Index: rsa.h
===================================================================
RCS file: /cvs/src/usr.sbin/acme-client/rsa.h,v
retrieving revision 1.1
diff -u -p -r1.1 rsa.h
--- rsa.h 31 Aug 2016 22:01:42 -0000 1.1
+++ rsa.h 4 Jun 2019 13:50:28 -0000
@@ -18,6 +18,6 @@
#define RSA_H
EVP_PKEY *rsa_key_create(FILE *, const char *);
-EVP_PKEY *rsa_key_load(FILE *, const char *);
+EVP_PKEY *key_load(FILE *, const char *);
#endif /* ! RSA_H */