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 95daf3a62bef0b9c84101eecbb464fd474566f45
parent b73343aea4de14c17f852300c29e474c88b256f5
Author: Joris Vink <joris@coders.se>
Date:   Mon, 22 May 2017 14:31:38 +0200

Add support for openssl 1.1.0 release line.

Eventually I will phase out 1.0.2 down the line to get rid of the
nightmare that is the 2 different APIs.

This commit adds full support for building kore with 1.1.0e while
retaining the privsep keymanager support.

based on excellent work done by @hiwk.

Diffstat:
src/domain.c | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
src/keymgr.c | 25++++++++++++++++++-------
2 files changed, 119 insertions(+), 14 deletions(-)

diff --git a/src/domain.c b/src/domain.c @@ -14,6 +14,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/* + * XXX - Lots of OPENSSL ifdefs here for 1.0.2 and 1.1.0 release lines. + * The idea is to only support 1.1.0 down the line and remove the 1.0.2 goo. + */ + #include <sys/param.h> #if !defined(KORE_NO_TLS) @@ -63,12 +68,14 @@ static int keymgr_rsa_privenc(int, const unsigned char *, static ECDSA_SIG *keymgr_ecdsa_sign(const unsigned char *, int, const BIGNUM *, const BIGNUM *, EC_KEY *); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +static RSA_METHOD *keymgr_rsa_meth = NULL; +static EC_KEY_METHOD *keymgr_ec_meth = NULL; +#else #if !defined(LIBRESSL_VERSION_TEXT) /* * 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; @@ -109,12 +116,32 @@ static RSA_METHOD keymgr_rsa = { NULL }; -#endif +#endif /* OPENSSL_VERSION_NUMBER */ +#endif /* KORE_NO_TLS */ void kore_domain_init(void) { TAILQ_INIT(&domains); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (keymgr_rsa_meth == NULL) { + if ((keymgr_rsa_meth = RSA_meth_new("kore RSA keymgr method", + RSA_METHOD_FLAG_NO_CHECK)) == NULL) + fatal("failed to allocate RSA method"); + } + + RSA_meth_set_init(keymgr_rsa_meth, keymgr_rsa_init); + RSA_meth_set_finish(keymgr_rsa_meth, keymgr_rsa_finish); + RSA_meth_set_priv_enc(keymgr_rsa_meth, keymgr_rsa_privenc); + + if (keymgr_ec_meth == NULL) { + if ((keymgr_ec_meth = EC_KEY_METHOD_new(NULL)) == NULL) + fatal("failed to allocate EC KEY method"); + } + + EC_KEY_METHOD_set_sign(keymgr_ec_meth, NULL, NULL, keymgr_ecdsa_sign); +#endif } void @@ -126,6 +153,18 @@ kore_domain_cleanup(void) TAILQ_REMOVE(&domains, dom, list); kore_domain_free(dom); } + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (keymgr_rsa_meth != NULL) { + RSA_meth_free(keymgr_rsa_meth); + keymgr_rsa_meth = NULL; + } + + if (keymgr_ec_meth != NULL) { + EC_KEY_METHOD_free(keymgr_ec_meth); + keymgr_ec_meth = NULL; + } +#endif } int @@ -215,6 +254,10 @@ kore_domain_tlsinit(struct kore_domain *dom) kore_debug("kore_domain_sslstart(%s)", dom->domain); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if ((method = TLS_method()) == NULL) + fatal("TLS_method(): %s", ssl_errno_s); +#else switch (tls_version) { case KORE_TLS_VERSION_1_2: method = TLSv1_2_server_method(); @@ -229,16 +272,40 @@ kore_domain_tlsinit(struct kore_domain *dom) fatal("unknown tls_version: %d", tls_version); return; } +#endif + + if ((dom->ssl_ctx = SSL_CTX_new(method)) == NULL) + fatal("SSL_ctx_new(): %s", ssl_errno_s); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (!SSL_CTX_set_min_proto_version(dom->ssl_ctx, TLS1_VERSION)) + fatal("SSL_CTX_set_min_proto_version: %s", ssl_errno_s); + if (!SSL_CTX_set_max_proto_version(dom->ssl_ctx, TLS1_2_VERSION)) + fatal("SSL_CTX_set_max_proto_version: %s", ssl_errno_s); - dom->ssl_ctx = SSL_CTX_new(method); - if (dom->ssl_ctx == NULL) - fatal("kore_domain_sslstart(): SSL_ctx_new(): %s", ssl_errno_s); + switch (tls_version) { + case KORE_TLS_VERSION_1_2: + if (!SSL_CTX_set_min_proto_version(dom->ssl_ctx, + TLS1_2_VERSION)) + fatal("SSL_CTX_set_min_proto_version: %s", ssl_errno_s); + break; + case KORE_TLS_VERSION_1_0: + if (!SSL_CTX_set_max_proto_version(dom->ssl_ctx, TLS1_VERSION)) + fatal("SSL_CTX_set_min_proto_version: %s", ssl_errno_s); + break; + case KORE_TLS_VERSION_BOTH: + break; + default: + fatal("unknown tls_version: %d", tls_version); + return; + } +#endif if (!SSL_CTX_use_certificate_chain_file(dom->ssl_ctx, dom->certfile)) { fatal("SSL_CTX_use_certificate_chain_file(%s): %s", dom->certfile, ssl_errno_s); } - if ((in = BIO_new(BIO_s_file_internal())) == NULL) + if ((in = BIO_new(BIO_s_file())) == NULL) fatal("BIO_new: %s", ssl_errno_s); if (BIO_read_filename(in, dom->certfile) <= 0) fatal("BIO_read_filename: %s", ssl_errno_s); @@ -255,13 +322,22 @@ kore_domain_tlsinit(struct kore_domain *dom) if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) fatal("no RSA public key present"); RSA_set_app_data(rsa, dom); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + RSA_set_method(rsa, keymgr_rsa_meth); +#else RSA_set_method(rsa, &keymgr_rsa); +#endif break; case EVP_PKEY_EC: if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) fatal("no EC public key present"); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EC_KEY_set_ex_data(eckey, 0, dom); + EC_KEY_set_method(eckey, keymgr_ec_meth); +#else ECDSA_set_ex_data(eckey, 0, dom); ECDSA_set_method(eckey, &keymgr_ecdsa); +#endif break; default: fatal("unknown public key in certificate"); @@ -319,8 +395,10 @@ kore_domain_tlsinit(struct kore_domain *dom) * from its OpenSSL in base so we don't need to care about it. */ #if !defined(LIBRESSL_VERSION_TEXT) +#if OPENSSL_VERSION_NUMBER < 0x10100000L dom->ssl_ctx->freelist_max_len = 0; #endif +#endif SSL_CTX_set_mode(dom->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); if (tls_version == KORE_TLS_VERSION_BOTH) { @@ -436,16 +514,27 @@ keymgr_init(void) if ((meth = RSA_get_default_method()) == NULL) fatal("failed to obtain RSA method"); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + RSA_meth_set_pub_enc(keymgr_rsa_meth, RSA_meth_get_pub_enc(meth)); + RSA_meth_set_pub_dec(keymgr_rsa_meth, RSA_meth_get_pub_dec(meth)); + RSA_meth_set_bn_mod_exp(keymgr_rsa_meth, RSA_meth_get_bn_mod_exp(meth)); +#else keymgr_rsa.rsa_pub_enc = meth->rsa_pub_enc; keymgr_rsa.rsa_pub_dec = meth->rsa_pub_dec; keymgr_rsa.bn_mod_exp = meth->bn_mod_exp; +#endif } static int keymgr_rsa_init(RSA *rsa) { if (rsa != NULL) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + RSA_set_flags(rsa, RSA_flags(rsa) | + RSA_FLAG_EXT_PKEY | RSA_METHOD_FLAG_NO_CHECK); +#else rsa->flags |= RSA_FLAG_EXT_PKEY | RSA_METHOD_FLAG_NO_CHECK; +#endif return (1); } @@ -522,8 +611,13 @@ keymgr_ecdsa_sign(const unsigned char *dgst, int dgst_len, if (len > sizeof(keymgr_buf)) fatal("keymgr_buf too small"); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if ((dom = EC_KEY_get_ex_data(eckey, 0)) == NULL) + fatal("EC_KEY has no domain"); +#else if ((dom = ECDSA_get_ex_data(eckey, 0)) == NULL) fatal("EC_KEY has no domain"); +#endif memset(keymgr_buf, 0, sizeof(keymgr_buf)); diff --git a/src/keymgr.c b/src/keymgr.c @@ -318,19 +318,25 @@ static void keymgr_rsa_encrypt(struct kore_msg *msg, const void *data, struct key *key) { int ret; + RSA *rsa; 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 OPENSSL_VERSION_NUMBER >= 0x10100000L + rsa = EVP_PKEY_get0_RSA(key->pkey); +#else + rsa = key->pkey->pkey.rsa; +#endif + keylen = RSA_size(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)) + buf, rsa, req->padding); + if (ret != RSA_size(rsa)) return; kore_msg_send(msg->src, KORE_MSG_KEYMGR_RESP, buf, ret); @@ -340,18 +346,23 @@ static void keymgr_ecdsa_sign(struct kore_msg *msg, const void *data, struct key *key) { size_t len; + EC_KEY *ec; 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 OPENSSL_VERSION_NUMBER >= 0x10100000L + ec = EVP_PKEY_get0_EC_KEY(key->pkey); +#else + ec = key->pkey->pkey.ec; +#endif + len = ECDSA_size(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) + if (ECDSA_sign(EVP_PKEY_NONE, req->data, req->data_len, + sig, &siglen, ec) == 0) return; if (siglen > sizeof(sig))