Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
585e5ec
crypto: use X509_STORE_CTX_new
davidben Sep 16, 2017
0e8157c
crypto: make node_crypto_bio compat w/ OpenSSL 1.1
davidben Sep 14, 2017
125d448
crypto: estimate kExternalSize
davidben Sep 16, 2017
f407551
crypto: remove unnecessary SSLerr calls
davidben Sep 16, 2017
5d4d7ef
crypto: account for new 1.1.0 SSL APIs
davidben Sep 17, 2017
3397696
crypto: test DH keys work without a public half
davidben Sep 17, 2017
7e55235
crypto: use RSA and DH accessors
davidben Sep 17, 2017
aad2416
crypto: remove locking callbacks for OpenSSL 1.1.0
davidben Sep 18, 2017
43394e1
crypto: make CipherBase 1.1.0-compatible
davidben Sep 20, 2017
1df22a1
crypto: make Hash 1.1.0-compatible
davidben Sep 22, 2017
9bce4db
crypto: make SignBase compatible with OpenSSL 1.1.0
davidben Sep 22, 2017
827f3f0
crypto: Make Hmac 1.1.0-compatible
davidben Sep 22, 2017
21fb3d0
crypto: add compat logic for "DSS1" and "dss1"
davidben Sep 23, 2017
5520305
crypto: hard-code tlsSocket.getCipher().version
davidben Sep 23, 2017
7a3cb8a
test: update test expectations for OpenSSL 1.1.0
davidben Sep 17, 2017
38b15a7
test: remove sha from test expectations
davidben Sep 23, 2017
ba1e140
crypto: emulate OpenSSL 1.0 ticket scheme in 1.1
davidben Sep 23, 2017
47116e3
test: test with a larger RSA key
davidben Sep 23, 2017
edbf1b8
test: revise test-tls-econnreset for OpenSSL 1.1.0
davidben Sep 23, 2017
18ca4e9
crypto: remove deprecated ECDH calls w/ OpenSSL 1.1
davidben Sep 23, 2017
b94a158
test: configure certs in tests
davidben Sep 23, 2017
68f415d
test: fix test-https-agent-session-eviction for 1.1
davidben Sep 23, 2017
3dad5ad
crypto: make ALPN the same for OpenSSL 1.0.2 & 1.1.0
davidben Sep 23, 2017
c0bd411
crypto: clear some SSL_METHOD deprecation warnings
davidben Sep 18, 2017
42e073e
crypto: remove leftover initialization
MylesBorins Jan 23, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
crypto: use RSA and DH accessors
Parts of this were cherry-picked from PR #8491. Note that this only
works with OpenSSL 1.0.2 or 1.1.0g or later. 1.1.0g is, as of writing,
not yet released, but the fix is on the branch. See
openssl/openssl#4384.

PR-URL: #16130
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Rod Vagg <rod@vagg.org>
  • Loading branch information
davidben authored and MylesBorins committed Feb 7, 2018
commit 7e552356b0f66cd3a0fb84bb3e21f4ec07afa68c
164 changes: 137 additions & 27 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,77 @@ using v8::Value;


#if OPENSSL_VERSION_NUMBER < 0x10100000L
static void RSA_get0_key(const RSA* r, const BIGNUM** n, const BIGNUM** e,
const BIGNUM** d) {
if (n != nullptr) {
*n = r->n;
}
if (e != nullptr) {
*e = r->e;
}
if (d != nullptr) {
*d = r->d;
}
}

static void DH_get0_pqg(const DH* dh, const BIGNUM** p, const BIGNUM** q,
const BIGNUM** g) {
if (p != nullptr) {
*p = dh->p;
}
if (q != nullptr) {
*q = dh->q;
}
if (g != nullptr) {
*g = dh->g;
}
}

static int DH_set0_pqg(DH* dh, BIGNUM* p, BIGNUM* q, BIGNUM* g) {
if ((dh->p == nullptr && p == nullptr) ||
(dh->g == nullptr && g == nullptr)) {
return 0;
}

if (p != nullptr) {
BN_free(dh->p);
dh->p = p;
}
if (q != nullptr) {
BN_free(dh->q);
dh->q = q;
}
if (g != nullptr) {
BN_free(dh->g);
dh->g = g;
}

return 1;
}

static void DH_get0_key(const DH* dh, const BIGNUM** pub_key,
const BIGNUM** priv_key) {
if (pub_key != nullptr) {
*pub_key = dh->pub_key;
}
if (priv_key != nullptr) {
*priv_key = dh->priv_key;
}
}

static int DH_set0_key(DH* dh, BIGNUM* pub_key, BIGNUM* priv_key) {
if (pub_key != nullptr) {
BN_free(dh->pub_key);
dh->pub_key = pub_key;
}
if (priv_key != nullptr) {
BN_free(dh->priv_key);
dh->priv_key = priv_key;
}

return 1;
}

static void SSL_SESSION_get0_ticket(const SSL_SESSION* s,
const unsigned char** tick, size_t* len) {
*len = s->tlsext_ticklen;
Expand Down Expand Up @@ -1011,7 +1082,9 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) {
if (dh == nullptr)
return;

const int size = BN_num_bits(dh->p);
const BIGNUM* p;
DH_get0_pqg(dh, &p, nullptr, nullptr);
const int size = BN_num_bits(p);
if (size < 1024) {
return env->ThrowError("DH parameter is less than 1024 bits");
} else if (size < 2048) {
Expand Down Expand Up @@ -1631,14 +1704,17 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
rsa = EVP_PKEY_get1_RSA(pkey);

if (rsa != nullptr) {
BN_print(bio, rsa->n);
const BIGNUM* n;
const BIGNUM* e;
RSA_get0_key(rsa, &n, &e, nullptr);
BN_print(bio, n);
BIO_get_mem_ptr(bio, &mem);
info->Set(env->modulus_string(),
String::NewFromUtf8(env->isolate(), mem->data,
String::kNormalString, mem->length));
(void) BIO_reset(bio);

uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(rsa->e));
uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(e));
uint32_t lo = static_cast<uint32_t>(exponent_word);
uint32_t hi = static_cast<uint32_t>(exponent_word >> 32);
if (hi == 0) {
Expand Down Expand Up @@ -4719,10 +4795,15 @@ bool DiffieHellman::Init(int primeLength, int g) {

bool DiffieHellman::Init(const char* p, int p_len, int g) {
dh = DH_new();
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
dh->g = BN_new();
if (!BN_set_word(dh->g, g))
BIGNUM* bn_p =
BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, nullptr);
BIGNUM* bn_g = BN_new();
if (!BN_set_word(bn_g, g) ||
!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) {
BN_free(bn_p);
BN_free(bn_g);
return false;
}
bool result = VerifyContext();
if (!result)
return false;
Expand All @@ -4733,8 +4814,13 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {

bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
dh = DH_new();
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
dh->g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
BIGNUM *bn_p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
BIGNUM *bn_g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
if (!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) {
BN_free(bn_p);
BN_free(bn_g);
return false;
}
bool result = VerifyContext();
if (!result)
return false;
Expand Down Expand Up @@ -4822,22 +4908,25 @@ void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
return ThrowCryptoError(env, ERR_get_error(), "Key generation failed");
}

size_t size = BN_num_bytes(diffieHellman->dh->pub_key);
const BIGNUM* pub_key;
DH_get0_key(diffieHellman->dh, &pub_key, nullptr);
size_t size = BN_num_bytes(pub_key);
char* data = Malloc(size);
BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast<unsigned char*>(data));
BN_bn2bin(pub_key, reinterpret_cast<unsigned char*>(data));
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
}


void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
BIGNUM* (DH::*field), const char* err_if_null) {
const BIGNUM* (*get_field)(const DH*),
const char* err_if_null) {
Environment* env = Environment::GetCurrent(args);

DiffieHellman* dh;
ASSIGN_OR_RETURN_UNWRAP(&dh, args.Holder());
if (!dh->initialised_) return env->ThrowError("Not initialized");

const BIGNUM* num = (dh->dh)->*field;
const BIGNUM* num = get_field(dh->dh);
if (num == nullptr) return env->ThrowError(err_if_null);

size_t size = BN_num_bytes(num);
Expand All @@ -4847,24 +4936,38 @@ void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
}

void DiffieHellman::GetPrime(const FunctionCallbackInfo<Value>& args) {
GetField(args, &DH::p, "p is null");
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* p;
DH_get0_pqg(dh, &p, nullptr, nullptr);
return p;
}, "p is null");
}


void DiffieHellman::GetGenerator(const FunctionCallbackInfo<Value>& args) {
GetField(args, &DH::g, "g is null");
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* g;
DH_get0_pqg(dh, nullptr, nullptr, &g);
return g;
}, "g is null");
}


void DiffieHellman::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
GetField(args, &DH::pub_key,
"No public key - did you forget to generate one?");
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* pub_key;
DH_get0_key(dh, &pub_key, nullptr);
return pub_key;
}, "No public key - did you forget to generate one?");
}


void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
GetField(args, &DH::priv_key,
"No private key - did you forget to generate one?");
GetField(args, [](const DH* dh) -> const BIGNUM* {
const BIGNUM* priv_key;
DH_get0_key(dh, nullptr, &priv_key);
return priv_key;
}, "No private key - did you forget to generate one?");
}


Expand Down Expand Up @@ -4940,16 +5043,14 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(rc);
}


void DiffieHellman::SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
BIGNUM* (DH::*field), const char* what) {
void (*set_field)(DH*, BIGNUM*), const char* what) {
Environment* env = Environment::GetCurrent(args);

DiffieHellman* dh;
ASSIGN_OR_RETURN_UNWRAP(&dh, args.Holder());
if (!dh->initialised_) return env->ThrowError("Not initialized");

BIGNUM** num = &((dh->dh)->*field);
char errmsg[64];

if (args.Length() == 0) {
Expand All @@ -4962,19 +5063,28 @@ void DiffieHellman::SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
return env->ThrowTypeError(errmsg);
}

*num = BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
Buffer::Length(args[0]), *num);
CHECK_NE(*num, nullptr);
BIGNUM* num =
BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
Buffer::Length(args[0]), nullptr);
CHECK_NE(num, nullptr);
set_field(dh->dh, num);
}


void DiffieHellman::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
SetKey(args, &DH::pub_key, "Public key");
SetKey(args, [](DH* dh, BIGNUM* num) { DH_set0_key(dh, num, nullptr); },
"Public key");
}


void DiffieHellman::SetPrivateKey(const FunctionCallbackInfo<Value>& args) {
SetKey(args, &DH::priv_key, "Private key");
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
OPENSSL_VERSION_NUMBER < 0x10100070L
// Older versions of OpenSSL 1.1.0 have a DH_set0_key which does not work for
// Node. See https://github.com/openssl/openssl/pull/4384.
#error "OpenSSL 1.1.0 revisions before 1.1.0g are not supported"
#endif
SetKey(args, [](DH* dh, BIGNUM* num) { DH_set0_key(dh, nullptr, num); },
"Private key");
}


Expand Down
5 changes: 3 additions & 2 deletions src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -707,9 +707,10 @@ class DiffieHellman : public BaseObject {

private:
static void GetField(const v8::FunctionCallbackInfo<v8::Value>& args,
BIGNUM* (DH::*field), const char* err_if_null);
const BIGNUM* (*get_field)(const DH*),
const char* err_if_null);
static void SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
BIGNUM* (DH::*field), const char* what);
void (*set_field)(DH*, BIGNUM*), const char* what);
bool VerifyContext();

bool initialised_;
Expand Down