kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

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