Isolate ECDSA keys in keymgr as well.

This commit is contained in:
Joris Vink 2016-06-08 16:31:14 +02:00
parent 87a826d89b
commit f62430d1fa
2 changed files with 206 additions and 60 deletions

View File

@ -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
@ -512,12 +615,6 @@ keymgr_msg_response(struct kore_msg *msg, const void *data)
memcpy(keymgr_buf, data, keymgr_buflen);
}
static int
keymgr_rsa_finish(RSA *rsa)
{
return (1);
}
static int
domain_x509_verify(int ok, X509_STORE_CTX *ctx)
{

View File

@ -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;
if (!strncmp(key->dom->domain, req->domain, req->domain_len))
break;
}
keylen = RSA_size(key->rsa);
if (req->data_len > keylen || keylen > sizeof(buf))
return;
if (key == NULL)
return;
ret = RSA_private_encrypt(req->data_len, req->data,
buf, key->rsa, req->padding);
if (ret != RSA_size(key->rsa))
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