Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some cleanups #25

Merged
merged 11 commits into from
Aug 23, 2019
165 changes: 96 additions & 69 deletions neverbleed.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,79 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __linux__
#include <sys/prctl.h>
#endif
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>

#include <openssl/opensslconf.h>
#include <openssl/opensslv.h>

#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER)
/* RSA_METHOD is opaque, so RSA_meth* are used. */
#define NEVERBLEED_OPAQUE_RSA_METHOD
#endif

#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_EC) \
&& (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2090100fL)
/* EC_KEY_METHOD and related APIs are avaliable, so ECDSA is enabled. */
#define NEVERBLEED_ECDSA
#endif

#include <openssl/bn.h>
#ifdef __linux__
#include <sys/prctl.h>
#ifdef NEVERBLEED_ECDSA
#include <openssl/ec.h>
#endif
#include "neverbleed.h"
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>

#if OPENSSL_VERSION_NUMBER < 0x1010000fL \
|| (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)

static void RSA_get0_key(const RSA *rsa, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
{
if (n) {
*n = rsa->n;
}

if (e) {
*e = rsa->e;
}

if (d) {
*d = rsa->d;
}
}

static int RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{
if (n == NULL || e == NULL) {
return 0;
}

BN_free(rsa->n);
BN_free(rsa->e);
BN_free(rsa->d);
rsa->n = n;
rsa->e = e;
rsa->d = d;

return 1;
}

static void RSA_set_flags(RSA *r, int flags)
{
r->flags |= flags;
}

#if (!defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x1010000fL)
#define OPENSSL_1_1_API 1
#else
#define OPENSSL_1_1_API 0
#endif

#include "neverbleed.h"

enum neverbleed_type { NEVERBLEED_TYPE_ERROR, NEVERBLEED_TYPE_RSA, NEVERBLEED_TYPE_ECDSA };

struct expbuf_t {
Expand Down Expand Up @@ -630,45 +684,6 @@ static int sign_stub(struct expbuf_t *buf)
return 0;
}

#if !OPENSSL_1_1_API && (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL)

static void RSA_get0_key(const RSA *rsa, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
{
if (n) {
*n = rsa->n;
}

if (e) {
*e = rsa->e;
}

if (d) {
*d = rsa->d;
}
}

static int RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{
if (n == NULL || e == NULL) {
return 0;
}

BN_free(rsa->n);
BN_free(rsa->e);
BN_free(rsa->d);
rsa->n = n;
rsa->e = e;
rsa->d = d;

return 1;
}

static void RSA_set_flags(RSA *r, int flags)
{
r->flags |= flags;
}
#endif

static EVP_PKEY *create_pkey(neverbleed_t *nb, size_t key_index, const char *ebuf, const char *nbuf)
{
struct st_neverbleed_rsa_exdata_t *exdata;
Expand Down Expand Up @@ -703,7 +718,7 @@ static EVP_PKEY *create_pkey(neverbleed_t *nb, size_t key_index, const char *ebu
return pkey;
}

#if OPENSSL_1_1_API
#ifdef NEVERBLEED_ECDSA

static EC_KEY *daemon_get_ecdsa(size_t key_index)
{
Expand Down Expand Up @@ -969,7 +984,7 @@ int neverbleed_load_private_key_file(neverbleed_t *nb, SSL_CTX *ctx, const char
pkey = create_pkey(nb, index, estr, nstr);
break;
}
#if OPENSSL_1_1_API
#ifdef NEVERBLEED_ECDSA
case NEVERBLEED_TYPE_ECDSA: {
char *ec_pubkeystr;
size_t curve_name;
Expand Down Expand Up @@ -1016,9 +1031,11 @@ static int load_key_stub(struct expbuf_t *buf)
char *estr = NULL, *nstr = NULL, errbuf[NEVERBLEED_ERRBUF_SIZE] = "";
size_t type = NEVERBLEED_TYPE_ERROR;
EVP_PKEY *pkey = NULL;
#ifdef NEVERBLEED_ECDSA
const EC_GROUP *ec_group;
BIGNUM *ec_pubkeybn = NULL;
char *ec_pubkeystr = NULL;
#endif

if ((fn = expbuf_shift_str(buf)) == NULL) {
warnf("%s: failed to parse request", __FUNCTION__);
Expand Down Expand Up @@ -1048,7 +1065,7 @@ static int load_key_stub(struct expbuf_t *buf)
break;
}
case EVP_PKEY_EC: {
#if OPENSSL_1_1_API
#ifdef NEVERBLEED_ECDSA
const EC_POINT *ec_pubkey;
EC_KEY *ec_key;

Expand All @@ -1066,7 +1083,7 @@ static int load_key_stub(struct expbuf_t *buf)
ec_pubkeystr = BN_bn2hex(ec_pubkeybn);
break;
#else
snprintf(errbuf, sizeof(errbuf), "ECDSA support requires OpenSSL >= 1.1.0");
snprintf(errbuf, sizeof(errbuf), "ECDSA support requires OpenSSL >= 1.1.0 or LibreSSL >= 2.9.1");
goto Respond;
#endif
}
Expand All @@ -1084,10 +1101,12 @@ static int load_key_stub(struct expbuf_t *buf)
expbuf_push_str(buf, estr != NULL ? estr : "");
expbuf_push_str(buf, nstr != NULL ? nstr : "");
break;
#ifdef NEVERBLEED_ECDSA
case NEVERBLEED_TYPE_ECDSA:
expbuf_push_num(buf, EC_GROUP_get_curve_name(ec_group));
expbuf_push_str(buf, ec_pubkeystr);
break;
#endif
default:
expbuf_push_str(buf, errbuf);
}
Expand All @@ -1099,10 +1118,12 @@ static int load_key_stub(struct expbuf_t *buf)
OPENSSL_free(estr);
if (nstr != NULL)
OPENSSL_free(nstr);
#ifdef NEVERBLEED_ECDSA
if (ec_pubkeystr != NULL)
OPENSSL_free(ec_pubkeystr);
if (ec_pubkeybn != NULL)
BN_free(ec_pubkeybn);
#endif
if (fp != NULL)
fclose(fp);

Expand Down Expand Up @@ -1311,7 +1332,7 @@ static void *daemon_conn_thread(void *_sock_fd)
} else if (strcmp(cmd, "sign") == 0) {
if (sign_stub(&buf) != 0)
break;
#if OPENSSL_1_1_API
#ifdef NEVERBLEED_ECDSA
} else if (strcmp(cmd, "ecdsa_sign") == 0) {
if (ecdsa_sign_stub(&buf) != 0)
break;
Expand Down Expand Up @@ -1375,7 +1396,7 @@ __attribute__((noreturn)) static void daemon_main(int listen_fd, int close_notif
}
}

#if !OPENSSL_1_1_API
#ifndef NEVERBLEED_OPAQUE_RSA_METHOD

static RSA_METHOD static_rsa_method = {
"privsep RSA method", /* name */
Expand All @@ -1400,33 +1421,39 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf)
{
int pipe_fds[2] = {-1, -1}, listen_fd = -1;
char *tempdir = NULL;
#if OPENSSL_1_1_API
const RSA_METHOD *default_method = RSA_PKCS1_OpenSSL();
EC_KEY_METHOD *ecdsa_method;
const RSA_METHOD *rsa_default_method;
RSA_METHOD *rsa_method;
#ifdef NEVERBLEED_ECDSA
const EC_KEY_METHOD *ecdsa_default_method;
RSA_METHOD *rsa_method = RSA_meth_dup(RSA_PKCS1_OpenSSL());
EC_KEY_METHOD *ecdsa_method;
#endif

#ifdef NEVERBLEED_OPAQUE_RSA_METHOD
rsa_default_method = RSA_PKCS1_OpenSSL();
rsa_method = RSA_meth_dup(rsa_default_method);

RSA_meth_set1_name(rsa_method, "privsep RSA method");
RSA_meth_set_priv_enc(rsa_method, priv_enc_proxy);
RSA_meth_set_priv_dec(rsa_method, priv_dec_proxy);
RSA_meth_set_sign(rsa_method, sign_proxy);
RSA_meth_set_finish(rsa_method, priv_rsa_finish);
#else
rsa_default_method = RSA_PKCS1_SSLeay();
rsa_method = &static_rsa_method;

rsa_method->rsa_pub_enc = rsa_default_method->rsa_pub_enc;
rsa_method->rsa_pub_dec = rsa_default_method->rsa_pub_dec;
rsa_method->rsa_verify = rsa_default_method->rsa_verify;
rsa_method->bn_mod_exp = rsa_default_method->bn_mod_exp;
#endif

/* setup EC_KEY_METHOD for ECDSA */
#ifdef NEVERBLEED_ECDSA
ecdsa_default_method = EC_KEY_get_default_method();
ecdsa_method = EC_KEY_METHOD_new(ecdsa_default_method);

/* it seems sign_sig and sign_setup is not used in TLS ECDSA. */
EC_KEY_METHOD_set_sign(ecdsa_method, ecdsa_sign_proxy, NULL, NULL);
EC_KEY_METHOD_set_init(ecdsa_method, NULL, priv_ecdsa_finish, NULL, NULL, NULL, NULL);
#else
const RSA_METHOD *default_method = RSA_PKCS1_SSLeay();
RSA_METHOD *rsa_method = &static_rsa_method;

rsa_method->rsa_pub_enc = default_method->rsa_pub_enc;
rsa_method->rsa_pub_dec = default_method->rsa_pub_dec;
rsa_method->rsa_verify = default_method->rsa_verify;
rsa_method->bn_mod_exp = default_method->bn_mod_exp;
#endif

/* setup the daemon */
Expand Down Expand Up @@ -1483,7 +1510,7 @@ int neverbleed_init(neverbleed_t *nb, char *errbuf)
/* setup engine */
if ((nb->engine = ENGINE_new()) == NULL || !ENGINE_set_id(nb->engine, "neverbleed") ||
!ENGINE_set_name(nb->engine, "privilege separation software engine") || !ENGINE_set_RSA(nb->engine, rsa_method)
#if OPENSSL_1_1_API
#ifdef NEVERBLEED_ECDSA
|| !ENGINE_set_EC(nb->engine, ecdsa_method)
#endif
) {
Expand Down
20 changes: 19 additions & 1 deletion test.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,24 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <openssl/crypto.h>

#include <openssl/opensslconf.h>
#include <openssl/opensslv.h>

#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_EC) \
&& (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2090100fL)
#define NEVERBLEED_TEST_ECDSA
#endif

#ifdef NEVERBLEED_TEST_ECDSA
#include <openssl/ec.h>
#endif
#include <openssl/evp.h>
#include <openssl/ssl.h>

#include "neverbleed.h"

#ifdef NEVERBLEED_TEST_ECDSA
static void setup_ecc_key(SSL_CTX *ssl_ctx)
{
int nid = NID_X9_62_prime256v1;
Expand All @@ -40,6 +54,7 @@ static void setup_ecc_key(SSL_CTX *ssl_ctx)
SSL_CTX_set_tmp_ecdh(ssl_ctx, key);
EC_KEY_free(key);
}
#endif

int dumb_https_server(unsigned short port, SSL_CTX *ctx)
{
Expand Down Expand Up @@ -100,6 +115,7 @@ int main(int argc, char **argv)
int use_privsep;

/* initialization */
/* FIXME: These APIs are deprecated in favor of OPENSSL_init_crypto in 1.1.0. */
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
Expand All @@ -109,7 +125,9 @@ int main(int argc, char **argv)
}
ctx = SSL_CTX_new(SSLv23_server_method());
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
#ifdef NEVERBLEED_TEST_ECDSA
setup_ecc_key(ctx);
#endif

/* parse args */
if (argc != 5) {
Expand Down