Skip to content

Commit afee2ed

Browse files
davidbenrvagg
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 87a066a commit afee2ed

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;
@@ -1008,7 +1079,9 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) {
10081079
if (dh == nullptr)
10091080
return;
10101081

1011-
const int size = BN_num_bits(dh->p);
1082+
const BIGNUM* p;
1083+
DH_get0_pqg(dh, &p, nullptr, nullptr);
1084+
const int size = BN_num_bits(p);
10121085
if (size < 1024) {
10131086
return env->ThrowError("DH parameter is less than 1024 bits");
10141087
} else if (size < 2048) {
@@ -1628,14 +1701,17 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
16281701
rsa = EVP_PKEY_get1_RSA(pkey);
16291702

16301703
if (rsa != nullptr) {
1631-
BN_print(bio, rsa->n);
1704+
const BIGNUM* n;
1705+
const BIGNUM* e;
1706+
RSA_get0_key(rsa, &n, &e, nullptr);
1707+
BN_print(bio, n);
16321708
BIO_get_mem_ptr(bio, &mem);
16331709
info->Set(env->modulus_string(),
16341710
String::NewFromUtf8(env->isolate(), mem->data,
16351711
String::kNormalString, mem->length));
16361712
(void) BIO_reset(bio);
16371713

1638-
uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(rsa->e));
1714+
uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(e));
16391715
uint32_t lo = static_cast<uint32_t>(exponent_word);
16401716
uint32_t hi = static_cast<uint32_t>(exponent_word >> 32);
16411717
if (hi == 0) {
@@ -4602,10 +4678,15 @@ bool DiffieHellman::Init(int primeLength, int g) {
46024678

46034679
bool DiffieHellman::Init(const char* p, int p_len, int g) {
46044680
dh = DH_new();
4605-
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4606-
dh->g = BN_new();
4607-
if (!BN_set_word(dh->g, g))
4681+
BIGNUM* bn_p =
4682+
BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, nullptr);
4683+
BIGNUM* bn_g = BN_new();
4684+
if (!BN_set_word(bn_g, g) ||
4685+
!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) {
4686+
BN_free(bn_p);
4687+
BN_free(bn_g);
46084688
return false;
4689+
}
46094690
bool result = VerifyContext();
46104691
if (!result)
46114692
return false;
@@ -4616,8 +4697,13 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) {
46164697

46174698
bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) {
46184699
dh = DH_new();
4619-
dh->p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4620-
dh->g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
4700+
BIGNUM *bn_p = BN_bin2bn(reinterpret_cast<const unsigned char*>(p), p_len, 0);
4701+
BIGNUM *bn_g = BN_bin2bn(reinterpret_cast<const unsigned char*>(g), g_len, 0);
4702+
if (!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) {
4703+
BN_free(bn_p);
4704+
BN_free(bn_g);
4705+
return false;
4706+
}
46214707
bool result = VerifyContext();
46224708
if (!result)
46234709
return false;
@@ -4705,22 +4791,25 @@ void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
47054791
return ThrowCryptoError(env, ERR_get_error(), "Key generation failed");
47064792
}
47074793

4708-
size_t size = BN_num_bytes(diffieHellman->dh->pub_key);
4794+
const BIGNUM* pub_key;
4795+
DH_get0_key(diffieHellman->dh, &pub_key, nullptr);
4796+
size_t size = BN_num_bytes(pub_key);
47094797
char* data = Malloc(size);
4710-
BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast<unsigned char*>(data));
4798+
BN_bn2bin(pub_key, reinterpret_cast<unsigned char*>(data));
47114799
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
47124800
}
47134801

47144802

47154803
void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
4716-
BIGNUM* (DH::*field), const char* err_if_null) {
4804+
const BIGNUM* (*get_field)(const DH*),
4805+
const char* err_if_null) {
47174806
Environment* env = Environment::GetCurrent(args);
47184807

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

4723-
const BIGNUM* num = (dh->dh)->*field;
4812+
const BIGNUM* num = get_field(dh->dh);
47244813
if (num == nullptr) return env->ThrowError(err_if_null);
47254814

47264815
size_t size = BN_num_bytes(num);
@@ -4730,24 +4819,38 @@ void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
47304819
}
47314820

47324821
void DiffieHellman::GetPrime(const FunctionCallbackInfo<Value>& args) {
4733-
GetField(args, &DH::p, "p is null");
4822+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4823+
const BIGNUM* p;
4824+
DH_get0_pqg(dh, &p, nullptr, nullptr);
4825+
return p;
4826+
}, "p is null");
47344827
}
47354828

47364829

47374830
void DiffieHellman::GetGenerator(const FunctionCallbackInfo<Value>& args) {
4738-
GetField(args, &DH::g, "g is null");
4831+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4832+
const BIGNUM* g;
4833+
DH_get0_pqg(dh, nullptr, nullptr, &g);
4834+
return g;
4835+
}, "g is null");
47394836
}
47404837

47414838

47424839
void DiffieHellman::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
4743-
GetField(args, &DH::pub_key,
4744-
"No public key - did you forget to generate one?");
4840+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4841+
const BIGNUM* pub_key;
4842+
DH_get0_key(dh, &pub_key, nullptr);
4843+
return pub_key;
4844+
}, "No public key - did you forget to generate one?");
47454845
}
47464846

47474847

47484848
void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
4749-
GetField(args, &DH::priv_key,
4750-
"No private key - did you forget to generate one?");
4849+
GetField(args, [](const DH* dh) -> const BIGNUM* {
4850+
const BIGNUM* priv_key;
4851+
DH_get0_key(dh, nullptr, &priv_key);
4852+
return priv_key;
4853+
}, "No private key - did you forget to generate one?");
47514854
}
47524855

47534856

@@ -4823,16 +4926,14 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
48234926
args.GetReturnValue().Set(rc);
48244927
}
48254928

4826-
48274929
void DiffieHellman::SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
4828-
BIGNUM* (DH::*field), const char* what) {
4930+
void (*set_field)(DH*, BIGNUM*), const char* what) {
48294931
Environment* env = Environment::GetCurrent(args);
48304932

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

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

48384939
if (args.Length() == 0) {
@@ -4845,19 +4946,28 @@ void DiffieHellman::SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
48454946
return env->ThrowTypeError(errmsg);
48464947
}
48474948

4848-
*num = BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
4849-
Buffer::Length(args[0]), *num);
4850-
CHECK_NE(*num, nullptr);
4949+
BIGNUM* num =
4950+
BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
4951+
Buffer::Length(args[0]), nullptr);
4952+
CHECK_NE(num, nullptr);
4953+
set_field(dh->dh, num);
48514954
}
48524955

48534956

48544957
void DiffieHellman::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
4855-
SetKey(args, &DH::pub_key, "Public key");
4958+
SetKey(args, [](DH* dh, BIGNUM* num) { DH_set0_key(dh, num, nullptr); },
4959+
"Public key");
48564960
}
48574961

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

48634973

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)