Skip to content

Commit c8c99b9

Browse files
davidbenMylesBorins
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 <[email protected]> Reviewed-By: Rod Vagg <[email protected]>
1 parent 90281d9 commit c8c99b9

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
@@ -115,6 +115,77 @@ using v8::Value;
115115

116116

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

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

16331706
if (rsa != nullptr) {
1634-
BN_print(bio, rsa->n);
1707+
const BIGNUM* n;
1708+
const BIGNUM* e;
1709+
RSA_get0_key(rsa, &n, &e, nullptr);
1710+
BN_print(bio, n);
16351711
BIO_get_mem_ptr(bio, &mem);
16361712
info->Set(env->modulus_string(),
16371713
String::NewFromUtf8(env->isolate(), mem->data,
16381714
String::kNormalString, mem->length));
16391715
(void) BIO_reset(bio);
16401716

1641-
uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(rsa->e));
1717+
uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(e));
16421718
uint32_t lo = static_cast<uint32_t>(exponent_word);
16431719
uint32_t hi = static_cast<uint32_t>(exponent_word >> 32);
16441720
if (hi == 0) {
@@ -4719,10 +4795,15 @@ bool DiffieHellman::Init(int primeLength, int g) {
47194795

47204796
bool DiffieHellman::Init(const char* p, int p_len, int g) {
47214797
dh = DH_new();
4722-
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4723-
dh->g = BN_new();
4724-
if (!BN_set_word(dh->g, g))
4798+
BIGNUM* bn_p =
4799+
BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, nullptr);
4800+
BIGNUM* bn_g = BN_new();
4801+
if (!BN_set_word(bn_g, g) ||
4802+
!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) {
4803+
BN_free(bn_p);
4804+
BN_free(bn_g);
47254805
return false;
4806+
}
47264807
bool result = VerifyContext();
47274808
if (!result)
47284809
return false;
@@ -4733,8 +4814,13 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
47334814

47344815
bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
47354816
dh = DH_new();
4736-
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4737-
dh->g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
4817+
BIGNUM *bn_p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4818+
BIGNUM *bn_g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
4819+
if (!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) {
4820+
BN_free(bn_p);
4821+
BN_free(bn_g);
4822+
return false;
4823+
}
47384824
bool result = VerifyContext();
47394825
if (!result)
47404826
return false;
@@ -4822,22 +4908,25 @@ void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
48224908
return ThrowCryptoError(env, ERR_get_error(), "Key generation failed");
48234909
}
48244910

4825-
size_t size = BN_num_bytes(diffieHellman->dh->pub_key);
4911+
const BIGNUM* pub_key;
4912+
DH_get0_key(diffieHellman->dh, &pub_key, nullptr);
4913+
size_t size = BN_num_bytes(pub_key);
48264914
char* data = Malloc(size);
4827-
BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast<unsigned char*>(data));
4915+
BN_bn2bin(pub_key, reinterpret_cast<unsigned char*>(data));
48284916
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
48294917
}
48304918

48314919

48324920
void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
4833-
BIGNUM* (DH::*field), const char* err_if_null) {
4921+
const BIGNUM* (*get_field)(const DH*),
4922+
const char* err_if_null) {
48344923
Environment* env = Environment::GetCurrent(args);
48354924

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

4840-
const BIGNUM* num = (dh->dh)->*field;
4929+
const BIGNUM* num = get_field(dh->dh);
48414930
if (num == nullptr) return env->ThrowError(err_if_null);
48424931

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

48494938
void DiffieHellman::GetPrime(const FunctionCallbackInfo<Value>& args) {
4850-
GetField(args, &DH::p, "p is null");
4939+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4940+
const BIGNUM* p;
4941+
DH_get0_pqg(dh, &p, nullptr, nullptr);
4942+
return p;
4943+
}, "p is null");
48514944
}
48524945

48534946

48544947
void DiffieHellman::GetGenerator(const FunctionCallbackInfo<Value>& args) {
4855-
GetField(args, &DH::g, "g is null");
4948+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4949+
const BIGNUM* g;
4950+
DH_get0_pqg(dh, nullptr, nullptr, &g);
4951+
return g;
4952+
}, "g is null");
48564953
}
48574954

48584955

48594956
void DiffieHellman::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
4860-
GetField(args, &DH::pub_key,
4861-
"No public key - did you forget to generate one?");
4957+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4958+
const BIGNUM* pub_key;
4959+
DH_get0_key(dh, &pub_key, nullptr);
4960+
return pub_key;
4961+
}, "No public key - did you forget to generate one?");
48624962
}
48634963

48644964

48654965
void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
4866-
GetField(args, &DH::priv_key,
4867-
"No private key - did you forget to generate one?");
4966+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4967+
const BIGNUM* priv_key;
4968+
DH_get0_key(dh, nullptr, &priv_key);
4969+
return priv_key;
4970+
}, "No private key - did you forget to generate one?");
48684971
}
48694972

48704973

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

4943-
49445046
void DiffieHellman::SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
4945-
BIGNUM* (DH::*field), const char* what) {
5047+
void (*set_field)(DH*, BIGNUM*), const char* what) {
49465048
Environment* env = Environment::GetCurrent(args);
49475049

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

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

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

4965-
*num = BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
4966-
Buffer::Length(args[0]), *num);
4967-
CHECK_NE(*num, nullptr);
5066+
BIGNUM* num =
5067+
BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
5068+
Buffer::Length(args[0]), nullptr);
5069+
CHECK_NE(num, nullptr);
5070+
set_field(dh->dh, num);
49685071
}
49695072

49705073

49715074
void DiffieHellman::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
4972-
SetKey(args, &DH::pub_key, "Public key");
5075+
SetKey(args, [](DH* dh, BIGNUM* num) { DH_set0_key(dh, num, nullptr); },
5076+
"Public key");
49735077
}
49745078

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

49805090

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)