Skip to content

Commit 81760ff

Browse files
davidbenevanlucas
authored andcommitted
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>
1 parent 568d9d0 commit 81760ff

File tree

2 files changed

+140
-29
lines changed

2 files changed

+140
-29
lines changed

src/node_crypto.cc

+137-27
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,77 @@ using v8::Value;
114114

115115

116116
#if OPENSSL_VERSION_NUMBER < 0x10100000L
117+
static void RSA_get0_key(const RSA* r, const BIGNUM** n, const BIGNUM** e,
118+
const BIGNUM** d) {
119+
if (n != nullptr) {
120+
*n = r->n;
121+
}
122+
if (e != nullptr) {
123+
*e = r->e;
124+
}
125+
if (d != nullptr) {
126+
*d = r->d;
127+
}
128+
}
129+
130+
static void DH_get0_pqg(const DH* dh, const BIGNUM** p, const BIGNUM** q,
131+
const BIGNUM** g) {
132+
if (p != nullptr) {
133+
*p = dh->p;
134+
}
135+
if (q != nullptr) {
136+
*q = dh->q;
137+
}
138+
if (g != nullptr) {
139+
*g = dh->g;
140+
}
141+
}
142+
143+
static int DH_set0_pqg(DH* dh, BIGNUM* p, BIGNUM* q, BIGNUM* g) {
144+
if ((dh->p == nullptr && p == nullptr) ||
145+
(dh->g == nullptr && g == nullptr)) {
146+
return 0;
147+
}
148+
149+
if (p != nullptr) {
150+
BN_free(dh->p);
151+
dh->p = p;
152+
}
153+
if (q != nullptr) {
154+
BN_free(dh->q);
155+
dh->q = q;
156+
}
157+
if (g != nullptr) {
158+
BN_free(dh->g);
159+
dh->g = g;
160+
}
161+
162+
return 1;
163+
}
164+
165+
static void DH_get0_key(const DH* dh, const BIGNUM** pub_key,
166+
const BIGNUM** priv_key) {
167+
if (pub_key != nullptr) {
168+
*pub_key = dh->pub_key;
169+
}
170+
if (priv_key != nullptr) {
171+
*priv_key = dh->priv_key;
172+
}
173+
}
174+
175+
static int DH_set0_key(DH* dh, BIGNUM* pub_key, BIGNUM* priv_key) {
176+
if (pub_key != nullptr) {
177+
BN_free(dh->pub_key);
178+
dh->pub_key = pub_key;
179+
}
180+
if (priv_key != nullptr) {
181+
BN_free(dh->priv_key);
182+
dh->priv_key = priv_key;
183+
}
184+
185+
return 1;
186+
}
187+
117188
static void SSL_SESSION_get0_ticket(const SSL_SESSION* s,
118189
const unsigned char** tick, size_t* len) {
119190
*len = s->tlsext_ticklen;
@@ -1015,7 +1086,9 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) {
10151086
if (dh == nullptr)
10161087
return;
10171088

1018-
const int size = BN_num_bits(dh->p);
1089+
const BIGNUM* p;
1090+
DH_get0_pqg(dh, &p, nullptr, nullptr);
1091+
const int size = BN_num_bits(p);
10191092
if (size < 1024) {
10201093
return env->ThrowError("DH parameter is less than 1024 bits");
10211094
} else if (size < 2048) {
@@ -1635,14 +1708,17 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
16351708
rsa = EVP_PKEY_get1_RSA(pkey);
16361709

16371710
if (rsa != nullptr) {
1638-
BN_print(bio, rsa->n);
1711+
const BIGNUM* n;
1712+
const BIGNUM* e;
1713+
RSA_get0_key(rsa, &n, &e, nullptr);
1714+
BN_print(bio, n);
16391715
BIO_get_mem_ptr(bio, &mem);
16401716
info->Set(env->modulus_string(),
16411717
String::NewFromUtf8(env->isolate(), mem->data,
16421718
String::kNormalString, mem->length));
16431719
(void) BIO_reset(bio);
16441720

1645-
uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(rsa->e));
1721+
uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(e));
16461722
uint32_t lo = static_cast<uint32_t>(exponent_word);
16471723
uint32_t hi = static_cast<uint32_t>(exponent_word >> 32);
16481724
if (hi == 0) {
@@ -4633,10 +4709,15 @@ bool DiffieHellman::Init(int primeLength, int g) {
46334709

46344710
bool DiffieHellman::Init(const char* p, int p_len, int g) {
46354711
dh = DH_new();
4636-
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4637-
dh->g = BN_new();
4638-
if (!BN_set_word(dh->g, g))
4712+
BIGNUM* bn_p =
4713+
BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, nullptr);
4714+
BIGNUM* bn_g = BN_new();
4715+
if (!BN_set_word(bn_g, g) ||
4716+
!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) {
4717+
BN_free(bn_p);
4718+
BN_free(bn_g);
46394719
return false;
4720+
}
46404721
bool result = VerifyContext();
46414722
if (!result)
46424723
return false;
@@ -4647,8 +4728,13 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
46474728

46484729
bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
46494730
dh = DH_new();
4650-
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4651-
dh->g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
4731+
BIGNUM *bn_p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4732+
BIGNUM *bn_g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
4733+
if (!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) {
4734+
BN_free(bn_p);
4735+
BN_free(bn_g);
4736+
return false;
4737+
}
46524738
bool result = VerifyContext();
46534739
if (!result)
46544740
return false;
@@ -4736,22 +4822,25 @@ void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
47364822
return ThrowCryptoError(env, ERR_get_error(), "Key generation failed");
47374823
}
47384824

4739-
size_t size = BN_num_bytes(diffieHellman->dh->pub_key);
4825+
const BIGNUM* pub_key;
4826+
DH_get0_key(diffieHellman->dh, &pub_key, nullptr);
4827+
size_t size = BN_num_bytes(pub_key);
47404828
char* data = Malloc(size);
4741-
BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast<unsigned char*>(data));
4829+
BN_bn2bin(pub_key, reinterpret_cast<unsigned char*>(data));
47424830
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
47434831
}
47444832

47454833

47464834
void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
4747-
BIGNUM* (DH::*field), const char* err_if_null) {
4835+
const BIGNUM* (*get_field)(const DH*),
4836+
const char* err_if_null) {
47484837
Environment* env = Environment::GetCurrent(args);
47494838

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

4754-
const BIGNUM* num = (dh->dh)->*field;
4843+
const BIGNUM* num = get_field(dh->dh);
47554844
if (num == nullptr) return env->ThrowError(err_if_null);
47564845

47574846
size_t size = BN_num_bytes(num);
@@ -4761,24 +4850,38 @@ void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
47614850
}
47624851

47634852
void DiffieHellman::GetPrime(const FunctionCallbackInfo<Value>& args) {
4764-
GetField(args, &DH::p, "p is null");
4853+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4854+
const BIGNUM* p;
4855+
DH_get0_pqg(dh, &p, nullptr, nullptr);
4856+
return p;
4857+
}, "p is null");
47654858
}
47664859

47674860

47684861
void DiffieHellman::GetGenerator(const FunctionCallbackInfo<Value>& args) {
4769-
GetField(args, &DH::g, "g is null");
4862+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4863+
const BIGNUM* g;
4864+
DH_get0_pqg(dh, nullptr, nullptr, &g);
4865+
return g;
4866+
}, "g is null");
47704867
}
47714868

47724869

47734870
void DiffieHellman::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
4774-
GetField(args, &DH::pub_key,
4775-
"No public key - did you forget to generate one?");
4871+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4872+
const BIGNUM* pub_key;
4873+
DH_get0_key(dh, &pub_key, nullptr);
4874+
return pub_key;
4875+
}, "No public key - did you forget to generate one?");
47764876
}
47774877

47784878

47794879
void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
4780-
GetField(args, &DH::priv_key,
4781-
"No private key - did you forget to generate one?");
4880+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4881+
const BIGNUM* priv_key;
4882+
DH_get0_key(dh, nullptr, &priv_key);
4883+
return priv_key;
4884+
}, "No private key - did you forget to generate one?");
47824885
}
47834886

47844887

@@ -4854,16 +4957,14 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
48544957
args.GetReturnValue().Set(rc);
48554958
}
48564959

4857-
48584960
void DiffieHellman::SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
4859-
BIGNUM* (DH::*field), const char* what) {
4961+
void (*set_field)(DH*, BIGNUM*), const char* what) {
48604962
Environment* env = Environment::GetCurrent(args);
48614963

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

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

48694970
if (args.Length() == 0) {
@@ -4876,19 +4977,28 @@ void DiffieHellman::SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
48764977
return env->ThrowTypeError(errmsg);
48774978
}
48784979

4879-
*num = BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
4880-
Buffer::Length(args[0]), *num);
4881-
CHECK_NE(*num, nullptr);
4980+
BIGNUM* num =
4981+
BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
4982+
Buffer::Length(args[0]), nullptr);
4983+
CHECK_NE(num, nullptr);
4984+
set_field(dh->dh, num);
48824985
}
48834986

48844987

48854988
void DiffieHellman::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
4886-
SetKey(args, &DH::pub_key, "Public key");
4989+
SetKey(args, [](DH* dh, BIGNUM* num) { DH_set0_key(dh, num, nullptr); },
4990+
"Public key");
48874991
}
48884992

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

48945004

src/node_crypto.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -707,9 +707,10 @@ class DiffieHellman : public BaseObject {
707707

708708
private:
709709
static void GetField(const v8::FunctionCallbackInfo<v8::Value>& args,
710-
BIGNUM* (DH::*field), const char* err_if_null);
710+
const BIGNUM* (*get_field)(const DH*),
711+
const char* err_if_null);
711712
static void SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
712-
BIGNUM* (DH::*field), const char* what);
713+
void (*set_field)(DH*, BIGNUM*), const char* what);
713714
bool VerifyContext();
714715

715716
bool initialised_;

0 commit comments

Comments
 (0)