Hi,
Two diffs below. The first moves ecdsa_method declaration from
ecs_locl.h to ecdsa.h, as ecs_locl.h is not installed in
/usr/include/openssl/.
The second one adds DSA and ECDSA capabilities to relayd ca engine, and
also checks that when using a DSA certificate, we have enabled EDH in
the relevant proto section. Requirements have been documented in
relayd.conf(5).
It works, but it surely needs some refactoring and style tweaks.
Comments ?
[Diff #1]
Index: ecdsa.h
===================================================================
RCS file: /cvs/src/lib/libssl/src/crypto/ecdsa/ecdsa.h,v
retrieving revision 1.2
diff -u -p -u -r1.2 ecdsa.h
--- ecdsa.h 12 Jun 2014 15:49:29 -0000 1.2
+++ ecdsa.h 8 Nov 2014 18:30:58 -0000
@@ -75,11 +75,36 @@
extern "C" {
#endif
-typedef struct ECDSA_SIG_st
- {
+typedef struct ECDSA_SIG_st ECDSA_SIG;
+
+struct ecdsa_method {
+ const char *name;
+ ECDSA_SIG *(*ecdsa_do_sign)(const unsigned char *dgst, int dgst_len,
+ const BIGNUM *inv, const BIGNUM *rp, EC_KEY *eckey);
+ int (*ecdsa_sign_setup)(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv,
+ BIGNUM **r);
+ int (*ecdsa_do_verify)(const unsigned char *dgst, int dgst_len,
+ const ECDSA_SIG *sig, EC_KEY *eckey);
+#if 0
+ int (*init)(EC_KEY *eckey);
+ int (*finish)(EC_KEY *eckey);
+#endif
+ int flags;
+ char *app_data;
+};
+
+/* If this flag is set the ECDSA method is FIPS compliant and can be used
+ * in FIPS mode. This is set in the validated module method. If an
+ * application sets this flag in its own methods it is its responsibility
+ * to ensure the result is compliant.
+ */
+
+#define ECDSA_FLAG_FIPS_METHOD 0x1
+
+struct ECDSA_SIG_st {
BIGNUM *r;
BIGNUM *s;
- } ECDSA_SIG;
+};
/** Allocates and initialize a ECDSA_SIG structure
* \return pointer to a ECDSA_SIG structure or NULL if an error occurred
Index: ecs_locl.h
===================================================================
RCS file: /cvs/src/lib/libssl/src/crypto/ecdsa/ecs_locl.h,v
retrieving revision 1.2
diff -u -p -u -r1.2 ecs_locl.h
--- ecs_locl.h 12 Jun 2014 15:49:29 -0000 1.2
+++ ecs_locl.h 8 Nov 2014 18:30:58 -0000
@@ -65,31 +65,6 @@
extern "C" {
#endif
-struct ecdsa_method
- {
- const char *name;
- ECDSA_SIG *(*ecdsa_do_sign)(const unsigned char *dgst, int dgst_len,
- const BIGNUM *inv, const BIGNUM *rp, EC_KEY *eckey);
- int (*ecdsa_sign_setup)(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv,
- BIGNUM **r);
- int (*ecdsa_do_verify)(const unsigned char *dgst, int dgst_len,
- const ECDSA_SIG *sig, EC_KEY *eckey);
-#if 0
- int (*init)(EC_KEY *eckey);
- int (*finish)(EC_KEY *eckey);
-#endif
- int flags;
- char *app_data;
- };
-
-/* If this flag is set the ECDSA method is FIPS compliant and can be used
- * in FIPS mode. This is set in the validated module method. If an
- * application sets this flag in its own methods it is its responsibility
- * to ensure the result is compliant.
- */
-
-#define ECDSA_FLAG_FIPS_METHOD 0x1
-
typedef struct ecdsa_data_st {
/* EC_KEY_METH_DATA part */
int (*init)(EC_KEY *);
[Diff #2]
Index: ca.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/ca.c,v
retrieving revision 1.9
diff -u -p -u -r1.9 ca.c
--- ca.c 2 Oct 2014 19:16:31 -0000 1.9
+++ ca.c 8 Nov 2014 18:26:15 -0000
@@ -32,9 +32,13 @@
#include <stdlib.h>
#include <errno.h>
+#include <openssl/ossl_typ.h>
+#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/ecdsa.h>
#include <openssl/engine.h>
#include "relayd.h"
@@ -60,6 +64,30 @@ int rsae_verify(int dtype, const u_char
u_int, const RSA *);
int rsae_keygen(RSA *, int, BIGNUM *, BN_GENCB *);
+
+DSA_SIG *dsae_do_sign(const unsigned char *, int, DSA *);
+int dsae_sign_setup(DSA *, BN_CTX *, BIGNUM **, BIGNUM **);
+int dsae_do_verify(const unsigned char *, int, DSA_SIG *,
+ DSA *);
+int dsae_mod_exp(DSA *, BIGNUM *, BIGNUM *, BIGNUM *,
+ BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *,
+ BN_MONT_CTX *);
+int dsae_bn_mod_exp(DSA *, BIGNUM *, BIGNUM *,
+ const BIGNUM *, const BIGNUM *, BN_CTX *,
+ BN_MONT_CTX *);
+int dsae_init(DSA *);
+int dsae_finish(DSA *);
+int dsae_paramgen(DSA *, int, const unsigned char *, int,
+ int *, unsigned long *, BN_GENCB *);
+int dsae_keygen(DSA *);
+
+ECDSA_SIG *ecdsae_do_sign(const unsigned char *, int ,
+ const BIGNUM *, const BIGNUM *, EC_KEY *);
+int ecdsae_sign_setup(EC_KEY *, BN_CTX *, BIGNUM **,
+ BIGNUM **);
+int ecdsae_do_verify(const unsigned char *, int,
+ const ECDSA_SIG *, EC_KEY *);
+
static struct relayd *env = NULL;
extern int proc_id;
@@ -174,14 +202,22 @@ ca_dispatch_relay(int fd, struct privsep
{
struct ctl_keyop cko;
EVP_PKEY *pkey;
- RSA *rsa;
- u_char *from = NULL, *to = NULL;
+ RSA *rsa = NULL;
+ DSA *dsa = NULL;
+ EC_KEY *ecdsa = NULL;
+ DSA_SIG *dsa_sig = NULL;
+ ECDSA_SIG *ecdsa_sig = NULL;
+ u_char *from = NULL, *to = NULL, *toptr = NULL;
+ u_char *k_der = NULL, *r_der = NULL;
+ BIGNUM *k = NULL, *r = NULL, *k_orig, *r_orig;
struct iovec iov[2];
int c = 0;
switch (imsg->hdr.type) {
case IMSG_CA_PRIVENC:
case IMSG_CA_PRIVDEC:
+ case IMSG_CA_DSA_SIGN:
+ case IMSG_CA_ECDSA_SIGN:
IMSG_SIZE_CHECK(imsg, (&cko));
bcopy(imsg->data, &cko, sizeof(cko));
if (cko.cko_proc > env->sc_prefork_relay)
@@ -190,25 +226,89 @@ ca_dispatch_relay(int fd, struct privsep
if (IMSG_DATA_SIZE(imsg) != (sizeof(cko) + cko.cko_flen))
fatalx("ca_dispatch_relay: "
"invalid key operation");
- if ((pkey = pkey_find(env, cko.cko_id)) == NULL ||
- (rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
+
+ if ((pkey = pkey_find(env, cko.cko_id)) == NULL)
fatalx("ca_dispatch_relay: "
- "invalid relay key or id");
+ "invalid relay key id");
- DPRINTF("%s:%d: key id %d", __func__, __LINE__, cko.cko_id);
+ DPRINTF("%s:%d: key id %d, type %d", __func__, __LINE__,
cko.cko_id, pkey->save_type);
+
+ switch (imsg->hdr.type) {
+ case IMSG_CA_PRIVENC:
+ case IMSG_CA_PRIVDEC:
+ if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
+ fatalx("ca_dispatch_relay: "
+ "invalid relay key type");
+ if ((cko.cko_klen != 0) ||
+ (cko.cko_rlen != 0))
+ fatalx("ca_dispatch_relay: "
+ "invalid parameters, should be zeroed");
+ break;
+ case IMSG_CA_DSA_SIGN:
+ if ((dsa = EVP_PKEY_get1_DSA(pkey)) == NULL)
+ fatalx("ca_dispatch_relay: "
+ "invalid relay key type");
+ break;
+ case IMSG_CA_ECDSA_SIGN:
+ if ((ecdsa = EVP_PKEY_get1_EC_KEY(pkey)) == NULL)
+ fatalx("ca_dispatch_relay: "
+ "invalid relay key type");
+ break;
+ }
from = (u_char *)imsg->data + sizeof(cko);
if ((to = calloc(1, cko.cko_tlen)) == NULL)
fatalx("ca_dispatch_relay: calloc");
+ toptr = to;
+
+ k_der = from + cko.cko_flen;
+ if ((cko.cko_klen > 0) &&
+ (k = BN_bin2bn(k_der, cko.cko_klen, NULL)) == NULL)
+ fatalx("ca_dispatch_relay: invalid k");
+
+ r_der = k_der + cko.cko_klen;
+ if ((cko.cko_rlen > 0) &&
+ (r = BN_bin2bn(r_der, cko.cko_rlen, NULL)) == NULL)
+ fatalx("ca_dispatch_relay: invalid r");
switch (imsg->hdr.type) {
case IMSG_CA_PRIVENC:
cko.cko_tlen = RSA_private_encrypt(cko.cko_flen,
from, to, rsa, cko.cko_padding);
+ RSA_free(rsa);
break;
case IMSG_CA_PRIVDEC:
cko.cko_tlen = RSA_private_decrypt(cko.cko_flen,
from, to, rsa, cko.cko_padding);
+ RSA_free(rsa);
+ break;
+ case IMSG_CA_DSA_SIGN:
+ k_orig = dsa->kinv;
+ dsa->kinv = k;
+ r_orig = dsa->r;
+ dsa->r = r;
+ dsa_sig = DSA_do_sign(from, cko.cko_flen, dsa);
+ if (dsa_sig == NULL)
+ fatalx("ca_dispatch_relay: DSA_do_sign");
+ cko.cko_tlen = i2d_DSA_SIG(dsa_sig, &toptr);
+ dsa->kinv = k_orig;
+ dsa->r = r_orig;
+ DSA_SIG_free(dsa_sig);
+ DSA_free(dsa);
+ BN_free(k);
+ BN_free(r);
+ break;
+ case IMSG_CA_ECDSA_SIGN:
+ ecdsa_sig = ECDSA_do_sign_ex(from, cko.cko_flen, k,
+ r, ecdsa);
+ if (ecdsa_sig == NULL)
+ fatalx("ca_dispatch_relay: "
+ "ECDSA_do_sign_ex");
+ cko.cko_tlen = i2d_ECDSA_SIG(ecdsa_sig, &toptr);
+ ECDSA_SIG_free(ecdsa_sig);
+ EC_KEY_free(ecdsa);
+ BN_free(k);
+ BN_free(r);
break;
}
@@ -223,7 +323,6 @@ ca_dispatch_relay(int fd, struct privsep
imsg->hdr.type, -1, iov, c);
free(to);
- RSA_free(rsa);
break;
default:
return (-1);
@@ -284,6 +383,8 @@ rsae_send_imsg(int flen, const u_char *f
cko.cko_flen = flen;
cko.cko_tlen = RSA_size(rsa);
cko.cko_padding = padding;
+ cko.cko_klen = 0;
+ cko.cko_rlen = 0;
iov[cnt].iov_base = &cko;
iov[cnt++].iov_len = sizeof(cko);
@@ -420,6 +521,335 @@ rsae_keygen(RSA *rsa, int bits, BIGNUM *
return (rsa_default->rsa_keygen(rsa, bits, e, cb));
}
+/*
+ * DSA privsep engine (called from unprivileged processes)
+ */
+
+const DSA_METHOD *dsa_default = NULL;
+
+static DSA_METHOD dsae_method = {
+ "DSA privsep method",
+ dsae_do_sign,
+ dsae_sign_setup,
+ dsae_do_verify,
+ dsae_mod_exp,
+ dsae_bn_mod_exp,
+ dsae_init,
+ dsae_finish,
+ 0,
+ NULL,
+ dsae_paramgen,
+ dsae_keygen
+};
+
+DSA_SIG *
+dsae_do_sign(const unsigned char *dgst, int dlen, DSA *dsa)
+{
+ /* IMSG call */
+ /* non need to send BN_MONT as it is only used during verify
+ * and we are only going to assume a server role */
+
+ struct ctl_keyop cko;
+ int retlen, klen = 0, rlen = 0;
+ objid_t *id;
+ struct iovec iov[4];
+ struct imsgbuf *ibuf;
+ struct imsgev *iev;
+ struct imsg imsg;
+ int n, done = 0, cnt = 0;
+ const unsigned char *toptr;
+ DSA_SIG *retsig = NULL;
+
+ if ((id = DSA_get_ex_data(dsa, 0)) == NULL)
+ return NULL;
+
+ DPRINTF("%s: requesting signing for key %d", __func__, *id);
+
+ iev = proc_iev(env->sc_ps, PROC_CA, proc_id);
+ ibuf = &iev->ibuf;
+
+ /*
+ * XXX this could be nicer...
+ */
+
+ if (dsa->kinv != NULL)
+ klen = BN_num_bytes(dsa->kinv);
+ if (dsa->r != NULL)
+ rlen = BN_num_bytes(dsa->r);
+
+ cko.cko_id = *id;
+ cko.cko_proc = proc_id;
+ cko.cko_flen = dlen;
+ cko.cko_tlen = DSA_size(dsa);
+ cko.cko_padding = 0;
+ cko.cko_klen = klen;
+ cko.cko_rlen = rlen;
+
+ iov[cnt].iov_base = &cko;
+ iov[cnt++].iov_len = sizeof(cko);
+ iov[cnt].iov_base = (void *)dgst;
+ iov[cnt++].iov_len = dlen;
+ if (klen > 0) {
+ iov[cnt].iov_base = calloc(1, klen);
+ if (iov[cnt].iov_base == NULL)
+ fatalx("dsae_do_sign: calloc");
+ BN_bn2bin(dsa->kinv, iov[cnt].iov_base);
+ iov[cnt++].iov_len = klen;
+ }
+ if (rlen > 0) {
+ iov[cnt].iov_base = calloc(1, rlen);
+ if (iov[cnt].iov_base == NULL)
+ fatalx("dsae_do_sign: calloc");
+ BN_bn2bin(dsa->r, iov[cnt].iov_base);
+ iov[cnt++].iov_len = rlen;
+ }
+
+ /*
+ * Send a synchronous imsg because we cannot defer the DSA
+ * operation in OpenSSL's engine layer.
+ */
+ imsg_composev(ibuf, IMSG_CA_DSA_SIGN, 0, 0, -1, iov, cnt);
+ imsg_flush(ibuf);
+ if (cnt > 2)
+ free(iov[2].iov_base);
+ if (cnt > 3)
+ free(iov[3].iov_base);
+
+ while (!done) {
+ if ((n = imsg_read(ibuf)) == -1)
+ fatalx("imsg_read");
+ if (n == 0)
+ fatalx("pipe closed");
+
+ while (!done) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatalx("imsg_get error");
+ if (n == 0)
+ break;
+ if (imsg.hdr.type != IMSG_CA_DSA_SIGN)
+ fatalx("invalid response");
+
+ IMSG_SIZE_CHECK(&imsg, (&cko));
+ memcpy(&cko, imsg.data, sizeof(cko));
+ if (IMSG_DATA_SIZE(&imsg) !=
+ (sizeof(cko) + cko.cko_tlen))
+ fatalx("data size");
+
+ retlen = cko.cko_tlen;
+ if (retlen) {
+ toptr = (u_char *)imsg.data + sizeof(cko);
+ retsig = d2i_DSA_SIG(NULL,
+ &toptr, retlen);
+ }
+ done = 1;
+
+ imsg_free(&imsg);
+ }
+ }
+ imsg_event_add(iev);
+
+ return (retsig);
+}
+
+int
+dsae_sign_setup(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (dsa_default->dsa_sign_setup(dsa, ctx_in, kinvp, rp));
+}
+
+int
+dsae_do_verify(const unsigned char *dgst, int dgst_len, DSA_SIG *sig,
+ DSA *dsa)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (dsa_default->dsa_do_verify(dgst, dgst_len, sig, dsa));
+}
+
+int
+dsae_mod_exp(DSA *dsa, BIGNUM *rr, BIGNUM *a1, BIGNUM *p1, BIGNUM *a2,
+ BIGNUM *p2, BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (dsa_default->dsa_mod_exp(dsa, rr, a1, p1, a2, p2, m,
+ ctx, in_mont));
+}
+
+int
+dsae_bn_mod_exp(DSA *dsa, BIGNUM *r, BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (dsa_default->bn_mod_exp(dsa, r, a, p, m, ctx,
+ m_ctx));
+}
+
+int
+dsae_init(DSA *dsa)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (dsa_default->init(dsa));
+}
+
+int
+dsae_finish(DSA *dsa)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (dsa_default->finish(dsa));
+}
+
+int
+dsae_paramgen(DSA *dsa, int bits, const unsigned char *seed, int seed_len,
+ int *counter_ret, unsigned long *h_ret, BN_GENCB *cb)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (dsa_default->dsa_paramgen(dsa, bits, seed, seed_len,
+ counter_ret, h_ret, cb));
+}
+
+int
+dsae_keygen(DSA *dsa)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (dsa_default->dsa_keygen(dsa));
+}
+
+/*
+ * ECDSA privsep engine (called from unprivileged processes)
+ */
+
+const ECDSA_METHOD *ecdsa_default = NULL;
+
+static ECDSA_METHOD ecdsae_method = {
+ "ECDSA privsep engine",
+ ecdsae_do_sign,
+ ecdsae_sign_setup,
+ ecdsae_do_verify,
+ 0,
+ NULL
+};
+
+ECDSA_SIG *
+ecdsae_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
+ const BIGNUM *rp, EC_KEY *eckey)
+{
+ struct ctl_keyop cko;
+ int retlen, klen = 0, rlen = 0;
+ objid_t *id;
+ struct iovec iov[4];
+ struct imsgbuf *ibuf;
+ struct imsgev *iev;
+ struct imsg imsg;
+ int n, done = 0, cnt = 0;
+ const unsigned char *toptr;
+ ECDSA_SIG *retsig = NULL;
+
+ if ((id = ECDSA_get_ex_data(eckey, 0)) == NULL)
+ return NULL;
+
+ DPRINTF("%s: requesting signing for key %d", __func__, *id);
+
+ iev = proc_iev(env->sc_ps, PROC_CA, proc_id);
+ ibuf = &iev->ibuf;
+
+ /*
+ * XXX this could be nicer...
+ */
+
+ if (inv != NULL)
+ klen = BN_num_bytes(inv);
+ if (rp != NULL)
+ rlen = BN_num_bytes(rp);
+
+ cko.cko_id = *id;
+ cko.cko_proc = proc_id;
+ cko.cko_flen = dgst_len;
+ cko.cko_tlen = ECDSA_size(eckey);
+ cko.cko_padding = 0;
+ cko.cko_klen = klen;
+ cko.cko_rlen = rlen;
+
+ iov[cnt].iov_base = &cko;
+ iov[cnt++].iov_len = sizeof(cko);
+ iov[cnt].iov_base = (void *)dgst;
+ iov[cnt++].iov_len = dgst_len;
+ if (klen > 0) {
+ iov[cnt].iov_base = malloc(klen);
+ if (iov[cnt].iov_base == NULL)
+ fatalx("ecdsae_do_sign: calloc");
+ BN_bn2bin(inv, iov[cnt].iov_base);
+ iov[cnt++].iov_len = klen;
+ }
+ if (rlen > 0) {
+ iov[cnt].iov_base = malloc(rlen);
+ if (iov[cnt].iov_base == NULL)
+ fatalx("ecdsae_do_sign: calloc");
+ BN_bn2bin(rp, iov[cnt].iov_base);
+ iov[cnt++].iov_len = rlen;
+ }
+
+ /*
+ * Send a synchronous imsg because we cannot defer the ECDSA
+ * operation in OpenSSL's engine layer.
+ */
+ imsg_composev(ibuf, IMSG_CA_ECDSA_SIGN, 0, 0, -1, iov, cnt);
+ imsg_flush(ibuf);
+ if (cnt > 2)
+ free(iov[2].iov_base);
+ if (cnt > 3)
+ free(iov[3].iov_base);
+
+ while (!done) {
+ if ((n = imsg_read(ibuf)) == -1)
+ fatalx("imsg_read");
+ if (n == 0)
+ fatalx("pipe closed");
+
+ while (!done) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatalx("imsg_get error");
+ if (n == 0)
+ break;
+ if (imsg.hdr.type != IMSG_CA_ECDSA_SIGN)
+ fatalx("invalid response");
+
+ IMSG_SIZE_CHECK(&imsg, (&cko));
+ memcpy(&cko, imsg.data, sizeof(cko));
+ if (IMSG_DATA_SIZE(&imsg) !=
+ (sizeof(cko) + cko.cko_tlen))
+ fatalx("data size");
+
+ retlen = cko.cko_tlen;
+ if (retlen) {
+ toptr = (u_char *)imsg.data + sizeof(cko);
+ retsig = d2i_ECDSA_SIG(NULL,
+ &toptr, retlen);
+ }
+ done = 1;
+
+ imsg_free(&imsg);
+ }
+ }
+ imsg_event_add(iev);
+
+ return (retsig);
+}
+
+int
+ecdsae_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, BIGNUM **r)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (ecdsa_default->ecdsa_sign_setup(eckey, ctx, kinv, r));
+}
+
+int
+ecdsae_do_verify(const unsigned char *dgst, int dgst_len, const ECDSA_SIG *sig,
+ EC_KEY *eckey)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (ecdsa_default->ecdsa_do_verify(dgst, dgst_len, sig, eckey));
+}
+
void
ca_engine_init(struct relayd *x_env)
{
@@ -471,6 +901,88 @@ ca_engine_init(struct relayd *x_env)
}
if (!ENGINE_set_default_RSA(e)) {
errstr = "ENGINE_set_default_RSA";
+ goto fail;
+ }
+
+ /* XXX copy-paste from above, must be a better way */
+
+ if ((e = ENGINE_get_default_DSA()) == NULL) {
+ if ((e = ENGINE_new()) == NULL) {
+ errstr = "ENGINE_new";
+ goto fail;
+ }
+ if (!ENGINE_set_name(e, dsae_method.name)) {
+ errstr = "ENGINE_set_name";
+ goto fail;
+ }
+ if ((dsa_default = DSA_get_default_method()) == NULL) {
+ errstr = "DSA_get_default_method";
+ goto fail;
+ }
+ } else if ((dsa_default = ENGINE_get_DSA(e)) == NULL) {
+ errstr = "ENGINE_get_DSA";
+ goto fail;
+ }
+
+ if ((name = ENGINE_get_name(e)) == NULL)
+ name = "unknown DSA engine";
+
+ log_debug("%s: using %s", __func__, name);
+
+ if (dsa_default->dsa_mod_exp == NULL)
+ dsae_method.dsa_mod_exp = NULL;
+ if (dsa_default->bn_mod_exp == NULL)
+ dsae_method.bn_mod_exp = NULL;
+ if (dsa_default->dsa_paramgen == NULL)
+ dsae_method.dsa_paramgen = NULL;
+ if (dsa_default->dsa_keygen == NULL)
+ dsae_method.dsa_keygen = NULL;
+ dsae_method.flags = dsa_default->flags |
+ ~(DSA_FLAG_CACHE_MONT_P);
+ dsae_method.app_data = dsa_default->app_data;
+
+ if (!ENGINE_set_DSA(e, &dsae_method)) {
+ errstr = "ENGINE_set_DSA";
+ goto fail;
+ }
+ if (!ENGINE_set_default_DSA(e)) {
+ errstr = "ENGINE_set_default_DSA";
+ goto fail;
+ }
+
+ /* XXX copy-paste from above, must be a better way */
+
+ if ((e = ENGINE_get_default_ECDSA()) == NULL) {
+ if ((e = ENGINE_new()) == NULL) {
+ errstr = "ENGINE_new";
+ goto fail;
+ }
+ if (!ENGINE_set_name(e, ecdsae_method.name)) {
+ errstr = "ENGINE_set_name";
+ goto fail;
+ }
+ if ((ecdsa_default = ECDSA_get_default_method()) == NULL) {
+ errstr = "ECDSA_get_default_method";
+ goto fail;
+ }
+ } else if ((ecdsa_default = ENGINE_get_ECDSA(e)) == NULL) {
+ errstr = "ENGINE_get_ECDSA";
+ goto fail;
+ }
+
+ if ((name = ENGINE_get_name(e)) == NULL)
+ name = "unknown ECDSA engine";
+
+ log_debug("%s: using %s", __func__, name);
+
+ ecdsae_method.app_data = ecdsa_default->app_data;
+
+ if (!ENGINE_set_ECDSA(e, &ecdsae_method)) {
+ errstr = "ENGINE_set_ECDSA";
+ goto fail;
+ }
+ if (!ENGINE_set_default_ECDSA(e)) {
+ errstr = "ENGINE_set_default_ECDSA";
goto fail;
}
Index: relay.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.179
diff -u -p -u -r1.179 relay.c
--- relay.c 25 Oct 2014 03:23:49 -0000 1.179
+++ relay.c 8 Nov 2014 18:26:21 -0000
@@ -42,6 +42,7 @@
#include <event.h>
#include <fnmatch.h>
+#include <openssl/err.h>
#include <openssl/dh.h>
#include <openssl/ssl.h>
@@ -2038,6 +2039,18 @@ relay_ssl_ctx_create(struct relay *rlay)
rlay->rl_ssl_cert, rlay->rl_conf.ssl_cert_len,
&rlay->rl_ssl_x509, &rlay->rl_ssl_pkey))
goto err;
+
+ /*
+ * All of LibReSSL DSS cipher suites require DHE.
+ * If DHE is disablid, fail early and loudly.
+ * XXX - kludgy. static.
+ */
+ if ((rlay->rl_ssl_pkey->save_type) == EVP_PKEY_DSA &&
+ (proto->ssldhparams <= 0)) {
+ SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY,
+ SSL_R_UNABLE_TO_FIND_DH_PARAMETERS);
+ goto err;
+ }
if (!SSL_CTX_check_private_key(ctx))
goto err;
Index: relayd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v
retrieving revision 1.151
diff -u -p -u -r1.151 relayd.conf.5
--- relayd.conf.5 21 Oct 2014 02:29:54 -0000 1.151
+++ relayd.conf.5 8 Nov 2014 18:26:26 -0000
@@ -675,7 +675,14 @@ and
.Pa /etc/ssl/address.crt .
See
.Xr ssl 8
-for details about SSL server certificates.
+for details about SSL server certificates. Note that all of LibreSSL
+ciphers require you to use EDH with DSA certificates, so you must enable
+the
+.Ic edh
+ssl option if you wish to use such certificates; see the
+.Sx PROTOCOLS
+section below.
+
.It Ic protocol Ar name
Use the specified protocol definition for the relay.
The generic TCP protocol options will be used by default;
Index: relayd.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
retrieving revision 1.195
diff -u -p -u -r1.195 relayd.h
--- relayd.h 2 Nov 2014 13:59:40 -0000 1.195
+++ relayd.h 8 Nov 2014 18:26:26 -0000
@@ -233,6 +233,8 @@ struct ctl_keyop {
int cko_flen;
int cko_tlen;
int cko_padding;
+ int cko_klen;
+ int cko_rlen;
};
struct ctl_stats {
@@ -936,7 +938,9 @@ enum imsg_type {
IMSG_CFG_RELAY_TABLE,
IMSG_CFG_DONE,
IMSG_CA_PRIVENC,
- IMSG_CA_PRIVDEC
+ IMSG_CA_PRIVDEC,
+ IMSG_CA_DSA_SIGN,
+ IMSG_CA_ECDSA_SIGN
};
enum privsep_procid {
Index: ssl.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/ssl.c,v
retrieving revision 1.25
diff -u -p -u -r1.25 ssl.c
--- ssl.c 10 Jul 2014 12:50:05 -0000 1.25
+++ ssl.c 8 Nov 2014 18:26:26 -0000
@@ -36,6 +36,8 @@
#include <openssl/err.h>
#include <openssl/engine.h>
#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/ecdsa.h>
#include "relayd.h"
@@ -413,6 +415,8 @@ ssl_load_pkey(const void *data, size_t d
X509 *x509 = NULL;
EVP_PKEY *pkey = NULL;
RSA *rsa = NULL;
+ DSA *dsa = NULL;
+ EC_KEY *ecdsa = NULL;
void *exdata = NULL;
if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
@@ -434,15 +438,48 @@ ssl_load_pkey(const void *data, size_t d
BIO_free(in);
if (data != NULL && datalen) {
- if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL ||
- (exdata = malloc(datalen)) == NULL) {
- SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_EVP_LIB);
- goto fail;
- }
+ switch (pkey->save_type) {
+ case EVP_PKEY_RSA:
+ if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL ||
+ (exdata = malloc(datalen)) == NULL) {
+ SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY,
+ ERR_R_EVP_LIB);
+ goto fail;
+ }
+ memcpy(exdata, data, datalen);
+ if (RSA_set_ex_data(rsa, 0, exdata) == 0)
+ goto fail;
+ /* dereference, will be cleaned up with pkey */
+ RSA_free(rsa);
+ break;
+ case EVP_PKEY_DSA:
+ if ((dsa = EVP_PKEY_get1_DSA(pkey)) == NULL ||
+ (exdata = malloc(datalen)) == NULL) {
+ SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY,
+ ERR_R_EVP_LIB);
+ goto fail;
+ }
+ memcpy(exdata, data, datalen);
+ if (DSA_set_ex_data(dsa, 0, exdata) == 0)
+ goto fail;
+ /* dereference, will be cleaned up with pkey */
+ DSA_free(dsa);
+ break;
+ case EVP_PKEY_EC:
+ if ((ecdsa = EVP_PKEY_get1_EC_KEY(pkey)) == NULL ||
+ (exdata = malloc(datalen)) == NULL) {
+ SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY,
+ ERR_R_EVP_LIB);
+ goto fail;
+ }
+ memcpy(exdata, data, datalen);
+ if (ECDSA_set_ex_data(ecdsa, 0, exdata) == 0)
+ goto fail;
- memcpy(exdata, data, datalen);
- RSA_set_ex_data(rsa, 0, exdata);
- RSA_free(rsa); /* dereference, will be cleaned up with pkey */
+ /* dereference, will be cleaned up with pkey */
+ EC_KEY_free(ecdsa);
+ break;
+ }
}
*x509ptr = x509;
@@ -453,6 +490,10 @@ ssl_load_pkey(const void *data, size_t d
fail:
if (rsa != NULL)
RSA_free(rsa);
+ if (dsa != NULL)
+ DSA_free(dsa);
+ if (ecdsa != NULL)
+ EC_KEY_free(ecdsa);
if (in != NULL)
BIO_free(in);
if (pkey != NULL)