commit f62430d1fadad06b35bd0dcd7e0cc2b0768c7d44
parent 87a826d89b9624f54d95dd150e90e13b967cf1d1
Author: Joris Vink <joris@coders.se>
Date: Wed, 8 Jun 2016 16:31:14 +0200
Isolate ECDSA keys in keymgr as well.
Diffstat:
src/domain.c | | | 175 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
src/keymgr.c | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- |
2 files changed, 206 insertions(+), 60 deletions(-)
diff --git a/src/domain.c b/src/domain.c
@@ -20,7 +20,8 @@
#include <openssl/x509.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
-
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
#include <poll.h>
#endif
@@ -46,15 +47,49 @@ static void domain_load_crl(struct kore_domain *);
#if !defined(KORE_NO_TLS)
static int domain_x509_verify(int, X509_STORE_CTX *);
-static void keymgr_msg_response(struct kore_msg *, const void *);
static void keymgr_init(void);
+static void keymgr_await_data(void);
+static void keymgr_msg_response(struct kore_msg *, const void *);
+
static int keymgr_rsa_init(RSA *);
static int keymgr_rsa_finish(RSA *);
static int keymgr_rsa_privenc(int, const unsigned char *,
unsigned char *, RSA *, int);
+static ECDSA_SIG *keymgr_ecdsa_sign(const unsigned char *, int,
+ const BIGNUM *, const BIGNUM *, EC_KEY *);
+
+#if !defined(OpenBSD)
+/*
+ * Run own ecdsa_method data structure as OpenSSL has this in ecs_locl.h
+ * and does not export this on systems.
+ *
+ * XXX - OpenSSL is merging ECDSA functionality into EC in 1.1.0.
+ */
+struct ecdsa_method {
+ const char *name;
+ ECDSA_SIG *(*ecdsa_do_sign)(const unsigned char *,
+ int, const BIGNUM *, const BIGNUM *, EC_KEY *);
+ int (*ecdsa_sign_setup)(EC_KEY *, BN_CTX *, BIGNUM **,
+ BIGNUM **);
+ int (*ecdsa_do_verify)(const unsigned char *, int,
+ const ECDSA_SIG *, EC_KEY *);
+ int flags;
+ char *app_data;
+};
+#endif
+
+static ECDSA_METHOD keymgr_ecdsa = {
+ "kore ECDSA keymgr method",
+ keymgr_ecdsa_sign,
+ NULL,
+ NULL,
+ 0,
+ NULL
+};
+
static RSA_METHOD keymgr_rsa = {
- "kore RSA keymgr engine",
+ "kore RSA keymgr method",
NULL,
NULL,
keymgr_rsa_privenc,
@@ -167,6 +202,7 @@ kore_domain_sslstart(struct kore_domain *dom)
X509 *x509;
EVP_PKEY *pkey;
STACK_OF(X509_NAME) *certs;
+ EC_KEY *eckey;
X509_STORE *store;
const SSL_METHOD *method;
#if !defined(OPENSSL_NO_EC)
@@ -210,11 +246,22 @@ kore_domain_sslstart(struct kore_domain *dom)
if ((pkey = X509_get_pubkey(x509)) == NULL)
fatal("certificate has no public key");
- if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
- fatal("no RSA public key present");
-
- RSA_set_app_data(rsa, dom);
- RSA_set_method(rsa, &keymgr_rsa);
+ switch (EVP_PKEY_id(pkey)) {
+ case EVP_PKEY_RSA:
+ if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
+ fatal("no RSA public key present");
+ RSA_set_app_data(rsa, dom);
+ RSA_set_method(rsa, &keymgr_rsa);
+ break;
+ case EVP_PKEY_EC:
+ if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL)
+ fatal("no EC public key present");
+ ECDSA_set_ex_data(eckey, 0, dom);
+ ECDSA_set_method(eckey, &keymgr_ecdsa);
+ break;
+ default:
+ fatal("unknown public key in certificate");
+ }
if (!SSL_CTX_use_PrivateKey(dom->ssl_ctx, pkey))
fatal("SSL_CTX_use_PrivateKey(): %s", ssl_errno_s);
@@ -228,12 +275,11 @@ kore_domain_sslstart(struct kore_domain *dom)
SSL_CTX_set_tmp_dh(dom->ssl_ctx, tls_dhparam);
SSL_CTX_set_options(dom->ssl_ctx, SSL_OP_SINGLE_DH_USE);
-#if !defined(OPENSSL_NO_EC)
- if ((ecdh = EC_KEY_new_by_curve_name(NID_secp384r1)) != NULL) {
- SSL_CTX_set_tmp_ecdh(dom->ssl_ctx, ecdh);
- EC_KEY_free(ecdh);
- }
-#endif
+ if ((ecdh = EC_KEY_new_by_curve_name(NID_secp384r1)) == NULL)
+ fatal("EC_KEY_new_by_curve_name: %s", ssl_errno_s);
+
+ SSL_CTX_set_tmp_ecdh(dom->ssl_ctx, ecdh);
+ EC_KEY_free(ecdh);
SSL_CTX_set_options(dom->ssl_ctx, SSL_OP_NO_COMPRESSION);
@@ -407,11 +453,8 @@ keymgr_rsa_privenc(int flen, const unsigned char *from, unsigned char *to,
size_t len;
struct kore_keyreq *req;
struct kore_domain *dom;
- struct pollfd pfd[1];
- u_int64_t start, cur;
len = sizeof(*req) + flen;
-
if (len > sizeof(keymgr_buf))
fatal("keymgr_buf too small");
@@ -431,6 +474,82 @@ keymgr_rsa_privenc(int flen, const unsigned char *from, unsigned char *to,
memcpy(req->domain, dom->domain, req->domain_len);
kore_msg_send(KORE_WORKER_KEYMGR, KORE_MSG_KEYMGR_REQ, keymgr_buf, len);
+ keymgr_await_data();
+
+ ret = -1;
+ if (keymgr_response) {
+ if (keymgr_buflen < INT_MAX &&
+ (int)keymgr_buflen == RSA_size(rsa)) {
+ ret = RSA_size(rsa);
+ memcpy(to, keymgr_buf, RSA_size(rsa));
+ }
+ }
+
+ keymgr_buflen = 0;
+ keymgr_response = 0;
+ kore_platform_event_all(worker->msg[1]->fd, worker->msg[1]);
+
+ return (ret);
+}
+
+static int
+keymgr_rsa_finish(RSA *rsa)
+{
+ return (1);
+}
+
+static ECDSA_SIG *
+keymgr_ecdsa_sign(const unsigned char *dgst, int dgst_len,
+ const BIGNUM *in_kinv, const BIGNUM *in_r, EC_KEY *eckey)
+{
+ size_t len;
+ ECDSA_SIG *sig;
+ const u_int8_t *ptr;
+ struct kore_domain *dom;
+ struct kore_keyreq *req;
+
+ if (in_kinv != NULL || in_r != NULL)
+ return (NULL);
+
+ len = sizeof(*req) + dgst_len;
+ if (len > sizeof(keymgr_buf))
+ fatal("keymgr_buf too small");
+
+ if ((dom = ECDSA_get_ex_data(eckey, 0)) == NULL)
+ fatal("EC_KEY has no domain");
+
+ memset(keymgr_buf, 0, sizeof(keymgr_buf));
+
+ req = (struct kore_keyreq *)keymgr_buf;
+ req->data_len = dgst_len;
+ req->domain_len = strlen(dom->domain);
+
+ memcpy(&req->data[0], dgst, req->data_len);
+ memcpy(req->domain, dom->domain, req->domain_len);
+
+ kore_msg_send(KORE_WORKER_KEYMGR, KORE_MSG_KEYMGR_REQ, keymgr_buf, len);
+ keymgr_await_data();
+
+ if (keymgr_response) {
+ ptr = keymgr_buf;
+ sig = d2i_ECDSA_SIG(NULL, &ptr, keymgr_buflen);
+ } else {
+ sig = NULL;
+ }
+
+ keymgr_buflen = 0;
+ keymgr_response = 0;
+ kore_platform_event_all(worker->msg[1]->fd, worker->msg[1]);
+
+ return (sig);
+}
+
+static void
+keymgr_await_data(void)
+{
+ int ret;
+ struct pollfd pfd[1];
+ u_int64_t start, cur;
/*
* We need to wait until the keymgr responds to us, so keep doing
@@ -482,22 +601,6 @@ keymgr_rsa_privenc(int flen, const unsigned char *from, unsigned char *to,
if (keymgr_response)
break;
}
-
- ret = -1;
-
- if (keymgr_response) {
- if (keymgr_buflen < INT_MAX &&
- (int)keymgr_buflen == RSA_size(rsa)) {
- ret = RSA_size(rsa);
- memcpy(to, keymgr_buf, RSA_size(rsa));
- }
- }
-
- keymgr_buflen = 0;
- keymgr_response = 0;
- kore_platform_event_all(worker->msg[1]->fd, worker->msg[1]);
-
- return (ret);
}
static void
@@ -513,12 +616,6 @@ keymgr_msg_response(struct kore_msg *msg, const void *data)
}
static int
-keymgr_rsa_finish(RSA *rsa)
-{
- return (1);
-}
-
-static int
domain_x509_verify(int ok, X509_STORE_CTX *ctx)
{
X509 *cert;
diff --git a/src/keymgr.c b/src/keymgr.c
@@ -16,7 +16,7 @@
#include <sys/param.h>
-#include <openssl/rsa.h>
+#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>
@@ -27,7 +27,7 @@
#if !defined(KORE_NO_TLS)
struct key {
- RSA *rsa;
+ EVP_PKEY *pkey;
struct kore_domain *dom;
TAILQ_ENTRY(key) list;
};
@@ -39,6 +39,11 @@ static int initialized = 0;
static void keymgr_load_privatekey(struct kore_domain *);
static void keymgr_msg_recv(struct kore_msg *, const void *);
+static void keymgr_rsa_encrypt(struct kore_msg *, const void *,
+ struct key *);
+static void keymgr_ecdsa_sign(struct kore_msg *, const void *,
+ struct key *);
+
void
kore_keymgr_run(void)
{
@@ -101,7 +106,7 @@ kore_keymgr_cleanup(void)
next = TAILQ_NEXT(key, list);
TAILQ_REMOVE(&keys, key, list);
- RSA_free(key->rsa);
+ EVP_PKEY_free(key->pkey);
kore_mem_free(key);
}
}
@@ -121,8 +126,8 @@ keymgr_load_privatekey(struct kore_domain *dom)
key = kore_malloc(sizeof(*key));
key->dom = dom;
- if ((key->rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL)) == NULL)
- fatal("PEM_read_RSAPrivateKey: %s", ssl_errno_s);
+ if ((key->pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)) == NULL)
+ fatal("PEM_read_PrivateKey: %s", ssl_errno_s);
(void)fclose(fp);
kore_mem_free(dom->certkey);
@@ -134,37 +139,81 @@ keymgr_load_privatekey(struct kore_domain *dom)
static void
keymgr_msg_recv(struct kore_msg *msg, const void *data)
{
- int ret;
const struct kore_keyreq *req;
struct key *key;
- size_t keylen;
- u_int8_t buf[1024];
if (msg->length < sizeof(*req))
return;
- key = NULL;
req = (const struct kore_keyreq *)data;
-
if (msg->length != (sizeof(*req) + req->data_len))
return;
+ key = NULL;
TAILQ_FOREACH(key, &keys, list) {
- if (strncmp(key->dom->domain, req->domain, req->domain_len))
- continue;
-
- keylen = RSA_size(key->rsa);
- if (req->data_len > keylen || keylen > sizeof(buf))
- return;
+ if (!strncmp(key->dom->domain, req->domain, req->domain_len))
+ break;
+ }
- ret = RSA_private_encrypt(req->data_len, req->data,
- buf, key->rsa, req->padding);
- if (ret != RSA_size(key->rsa))
- return;
+ if (key == NULL)
+ return;
- kore_msg_send(msg->src, KORE_MSG_KEYMGR_RESP, buf, ret);
+ switch (EVP_PKEY_id(key->pkey)) {
+ case EVP_PKEY_RSA:
+ keymgr_rsa_encrypt(msg, data, key);
+ break;
+ case EVP_PKEY_EC:
+ keymgr_ecdsa_sign(msg, data, key);
+ break;
+ default:
break;
}
}
+static void
+keymgr_rsa_encrypt(struct kore_msg *msg, const void *data, struct key *key)
+{
+ int ret;
+ const struct kore_keyreq *req;
+ size_t keylen;
+ u_int8_t buf[1024];
+
+ req = (const struct kore_keyreq *)data;
+
+ keylen = RSA_size(key->pkey->pkey.rsa);
+ if (req->data_len > keylen || keylen > sizeof(buf))
+ return;
+
+ ret = RSA_private_encrypt(req->data_len, req->data,
+ buf, key->pkey->pkey.rsa, req->padding);
+ if (ret != RSA_size(key->pkey->pkey.rsa))
+ return;
+
+ kore_msg_send(msg->src, KORE_MSG_KEYMGR_RESP, buf, ret);
+}
+
+static void
+keymgr_ecdsa_sign(struct kore_msg *msg, const void *data, struct key *key)
+{
+ size_t len;
+ const struct kore_keyreq *req;
+ unsigned int siglen;
+ u_int8_t sig[1024];
+
+ req = (const struct kore_keyreq *)data;
+
+ len = ECDSA_size(key->pkey->pkey.ec);
+ if (req->data_len > len || len > sizeof(sig))
+ return;
+
+ if (ECDSA_sign(key->pkey->save_type, req->data, req->data_len,
+ sig, &siglen, key->pkey->pkey.ec) == 0)
+ return;
+
+ if (siglen > sizeof(sig))
+ return;
+
+ kore_msg_send(msg->src, KORE_MSG_KEYMGR_RESP, sig, siglen);
+}
+
#endif