Skip to content

Commit 4db2314

Browse files
committed
crypto: use RSA and DH accessors.
Parts of this were cherry-picked from PR nodejs#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.
1 parent 4b51882 commit 4db2314

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

108108

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

1008-
const int size = BN_num_bits(dh->p);
1079+
const BIGNUM* p;
1080+
DH_get0_pqg(dh, &p, nullptr, nullptr);
1081+
const int size = BN_num_bits(p);
10091082
if (size < 1024) {
10101083
return env->ThrowError("DH parameter is less than 1024 bits");
10111084
} else if (size < 2048) {
@@ -1625,14 +1698,17 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
16251698
rsa = EVP_PKEY_get1_RSA(pkey);
16261699

16271700
if (rsa != nullptr) {
1628-
BN_print(bio, rsa->n);
1701+
const BIGNUM* n;
1702+
const BIGNUM* e;
1703+
RSA_get0_key(rsa, &n, &e, nullptr);
1704+
BN_print(bio, n);
16291705
BIO_get_mem_ptr(bio, &mem);
16301706
info->Set(env->modulus_string(),
16311707
String::NewFromUtf8(env->isolate(), mem->data,
16321708
String::kNormalString, mem->length));
16331709
(void) BIO_reset(bio);
16341710

1635-
uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(rsa->e));
1711+
uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(e));
16361712
uint32_t lo = static_cast<uint32_t>(exponent_word);
16371713
uint32_t hi = static_cast<uint32_t>(exponent_word >> 32);
16381714
if (hi == 0) {
@@ -4599,10 +4675,15 @@ bool DiffieHellman::Init(int primeLength, int g) {
45994675

46004676
bool DiffieHellman::Init(const char* p, int p_len, int g) {
46014677
dh = DH_new();
4602-
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4603-
dh->g = BN_new();
4604-
if (!BN_set_word(dh->g, g))
4678+
BIGNUM* bn_p =
4679+
BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, nullptr);
4680+
BIGNUM* bn_g = BN_new();
4681+
if (!BN_set_word(bn_g, g) ||
4682+
!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) {
4683+
BN_free(bn_p);
4684+
BN_free(bn_g);
46054685
return false;
4686+
}
46064687
bool result = VerifyContext();
46074688
if (!result)
46084689
return false;
@@ -4613,8 +4694,13 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
46134694

46144695
bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
46154696
dh = DH_new();
4616-
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4617-
dh->g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
4697+
BIGNUM *bn_p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4698+
BIGNUM *bn_g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
4699+
if (!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) {
4700+
BN_free(bn_p);
4701+
BN_free(bn_g);
4702+
return false;
4703+
}
46184704
bool result = VerifyContext();
46194705
if (!result)
46204706
return false;
@@ -4702,22 +4788,25 @@ void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
47024788
return ThrowCryptoError(env, ERR_get_error(), "Key generation failed");
47034789
}
47044790

4705-
size_t size = BN_num_bytes(diffieHellman->dh->pub_key);
4791+
const BIGNUM* pub_key;
4792+
DH_get0_key(diffieHellman->dh, &pub_key, nullptr);
4793+
size_t size = BN_num_bytes(pub_key);
47064794
char* data = Malloc(size);
4707-
BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast<unsigned char*>(data));
4795+
BN_bn2bin(pub_key, reinterpret_cast<unsigned char*>(data));
47084796
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
47094797
}
47104798

47114799

47124800
void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
4713-
BIGNUM* (DH::*field), const char* err_if_null) {
4801+
const BIGNUM* (*get_field)(const DH*),
4802+
const char* err_if_null) {
47144803
Environment* env = Environment::GetCurrent(args);
47154804

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

4720-
const BIGNUM* num = (dh->dh)->*field;
4809+
const BIGNUM* num = get_field(dh->dh);
47214810
if (num == nullptr) return env->ThrowError(err_if_null);
47224811

47234812
size_t size = BN_num_bytes(num);
@@ -4727,24 +4816,38 @@ void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
47274816
}
47284817

47294818
void DiffieHellman::GetPrime(const FunctionCallbackInfo<Value>& args) {
4730-
GetField(args, &DH::p, "p is null");
4819+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4820+
const BIGNUM* p;
4821+
DH_get0_pqg(dh, &p, nullptr, nullptr);
4822+
return p;
4823+
}, "p is null");
47314824
}
47324825

47334826

47344827
void DiffieHellman::GetGenerator(const FunctionCallbackInfo<Value>& args) {
4735-
GetField(args, &DH::g, "g is null");
4828+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4829+
const BIGNUM* g;
4830+
DH_get0_pqg(dh, nullptr, nullptr, &g);
4831+
return g;
4832+
}, "g is null");
47364833
}
47374834

47384835

47394836
void DiffieHellman::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
4740-
GetField(args, &DH::pub_key,
4741-
"No public key - did you forget to generate one?");
4837+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4838+
const BIGNUM* pub_key;
4839+
DH_get0_key(dh, &pub_key, nullptr);
4840+
return pub_key;
4841+
}, "No public key - did you forget to generate one?");
47424842
}
47434843

47444844

47454845
void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
4746-
GetField(args, &DH::priv_key,
4747-
"No private key - did you forget to generate one?");
4846+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4847+
const BIGNUM* priv_key;
4848+
DH_get0_key(dh, nullptr, &priv_key);
4849+
return priv_key;
4850+
}, "No private key - did you forget to generate one?");
47484851
}
47494852

47504853

@@ -4820,16 +4923,14 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
48204923
args.GetReturnValue().Set(rc);
48214924
}
48224925

4823-
48244926
void DiffieHellman::SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
4825-
BIGNUM* (DH::*field), const char* what) {
4927+
void (*set_field)(DH*, BIGNUM*), const char* what) {
48264928
Environment* env = Environment::GetCurrent(args);
48274929

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

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

48354936
if (args.Length() == 0) {
@@ -4842,19 +4943,28 @@ void DiffieHellman::SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
48424943
return env->ThrowTypeError(errmsg);
48434944
}
48444945

4845-
*num = BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
4846-
Buffer::Length(args[0]), *num);
4847-
CHECK_NE(*num, nullptr);
4946+
BIGNUM* num =
4947+
BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
4948+
Buffer::Length(args[0]), nullptr);
4949+
CHECK_NE(num, nullptr);
4950+
set_field(dh->dh, num);
48484951
}
48494952

48504953

48514954
void DiffieHellman::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
4852-
SetKey(args, &DH::pub_key, "Public key");
4955+
SetKey(args, [](DH* dh, BIGNUM* num) { DH_set0_key(dh, num, nullptr); },
4956+
"Public key");
48534957
}
48544958

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

48604970

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)