/src/node/src/crypto/crypto_dh.cc
Line  | Count  | Source  | 
1  |  | #include "crypto/crypto_dh.h"  | 
2  |  | #include "async_wrap-inl.h"  | 
3  |  | #include "base_object-inl.h"  | 
4  |  | #include "crypto/crypto_keys.h"  | 
5  |  | #include "crypto/crypto_util.h"  | 
6  |  | #include "env-inl.h"  | 
7  |  | #include "memory_tracker-inl.h"  | 
8  |  | #include "ncrypto.h"  | 
9  |  | #include "node_errors.h"  | 
10  |  | #ifndef OPENSSL_IS_BORINGSSL  | 
11  |  | #include "openssl/bnerr.h"  | 
12  |  | #endif  | 
13  |  | #include "openssl/dh.h"  | 
14  |  | #include "threadpoolwork-inl.h"  | 
15  |  | #include "v8.h"  | 
16  |  |  | 
17  |  | namespace node { | 
18  |  |  | 
19  |  | using ncrypto::BignumPointer;  | 
20  |  | using ncrypto::DataPointer;  | 
21  |  | using ncrypto::DHPointer;  | 
22  |  | using ncrypto::EVPKeyCtxPointer;  | 
23  |  | using ncrypto::EVPKeyPointer;  | 
24  |  | using v8::ArrayBuffer;  | 
25  |  | using v8::BackingStoreInitializationMode;  | 
26  |  | using v8::BackingStoreOnFailureMode;  | 
27  |  | using v8::ConstructorBehavior;  | 
28  |  | using v8::Context;  | 
29  |  | using v8::DontDelete;  | 
30  |  | using v8::FunctionCallback;  | 
31  |  | using v8::FunctionCallbackInfo;  | 
32  |  | using v8::FunctionTemplate;  | 
33  |  | using v8::Int32;  | 
34  |  | using v8::Isolate;  | 
35  |  | using v8::JustVoid;  | 
36  |  | using v8::Local;  | 
37  |  | using v8::Maybe;  | 
38  |  | using v8::MaybeLocal;  | 
39  |  | using v8::Nothing;  | 
40  |  | using v8::Object;  | 
41  |  | using v8::PropertyAttribute;  | 
42  |  | using v8::ReadOnly;  | 
43  |  | using v8::SideEffectType;  | 
44  |  | using v8::Signature;  | 
45  |  | using v8::String;  | 
46  |  | using v8::Value;  | 
47  |  |  | 
48  |  | namespace crypto { | 
49  |  | DiffieHellman::DiffieHellman(Environment* env, Local<Object> wrap, DHPointer dh)  | 
50  | 0  |     : BaseObject(env, wrap), dh_(std::move(dh)) { | 
51  | 0  |   MakeWeak();  | 
52  | 0  | }  | 
53  |  |  | 
54  | 0  | void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const { | 
55  | 0  |   tracker->TrackFieldWithSize("dh", dh_ ? kSizeOf_DH : 0); | 
56  | 0  | }  | 
57  |  |  | 
58  |  | namespace { | 
59  | 0  | MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) { | 
60  | 0  |   struct Flag { | 
61  | 0  |     bool secure;  | 
62  | 0  |   };  | 
63  |  | #ifdef V8_ENABLE_SANDBOX  | 
64  |  |   auto backing = ArrayBuffer::NewBackingStore(  | 
65  |  |       env->isolate(),  | 
66  |  |       data.size(),  | 
67  |  |       BackingStoreInitializationMode::kUninitialized,  | 
68  |  |       BackingStoreOnFailureMode::kReturnNull);  | 
69  |  |   if (!backing) { | 
70  |  |     THROW_ERR_MEMORY_ALLOCATION_FAILED(env);  | 
71  |  |     return MaybeLocal<Value>();  | 
72  |  |   }  | 
73  |  |   if (data.size() > 0) { | 
74  |  |     memcpy(backing->Data(), data.get(), data.size());  | 
75  |  |   }  | 
76  |  | #else  | 
77  | 0  |   auto backing = ArrayBuffer::NewBackingStore(  | 
78  | 0  |       data.get(),  | 
79  | 0  |       data.size(),  | 
80  | 0  |       [](void* data, size_t len, void* ptr) { | 
81  | 0  |         std::unique_ptr<Flag> flag(static_cast<Flag*>(ptr));  | 
82  | 0  |         DataPointer free_me(data, len, flag->secure);  | 
83  | 0  |       },  | 
84  | 0  |       new Flag{data.isSecure()}); | 
85  | 0  |   data.release();  | 
86  | 0  | #endif  // V8_ENABLE_SANDBOX  | 
87  |  | 
  | 
88  | 0  |   auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));  | 
89  | 0  |   return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>());  | 
90  | 0  | }  | 
91  |  |  | 
92  | 0  | void DiffieHellmanGroup(const FunctionCallbackInfo<Value>& args) { | 
93  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
94  | 0  |   CHECK_EQ(args.Length(), 1);  | 
95  | 0  |   THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "Group name");  | 
96  | 0  |   const node::Utf8Value group_name(env->isolate(), args[0]);  | 
97  |  | 
  | 
98  | 0  |   DHPointer dh = DHPointer::FromGroup(group_name.ToStringView());  | 
99  | 0  |   if (!dh) { | 
100  | 0  |     return THROW_ERR_CRYPTO_UNKNOWN_DH_GROUP(env);  | 
101  | 0  |   }  | 
102  |  |  | 
103  | 0  |   new DiffieHellman(env, args.This(), std::move(dh));  | 
104  | 0  | }  | 
105  |  |  | 
106  | 0  | void New(const FunctionCallbackInfo<Value>& args) { | 
107  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
108  |  | 
  | 
109  | 0  |   if (args.Length() != 2) { | 
110  | 0  |     return THROW_ERR_MISSING_ARGS(env, "Constructor must have two arguments");  | 
111  | 0  |   }  | 
112  |  |  | 
113  | 0  |   if (args[0]->IsInt32()) { | 
114  | 0  |     int32_t bits = args[0].As<Int32>()->Value();  | 
115  | 0  |     if (bits < 2) { | 
116  | 0  | #ifndef OPENSSL_IS_BORINGSSL  | 
117  | 0  | #if OPENSSL_VERSION_MAJOR >= 3  | 
118  | 0  |       ERR_put_error(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_SMALL, __FILE__, __LINE__);  | 
119  |  | #else  | 
120  |  |       ERR_put_error(ERR_LIB_BN, 0, BN_R_BITS_TOO_SMALL, __FILE__, __LINE__);  | 
121  |  | #endif  // OPENSSL_VERSION_MAJOR >= 3  | 
122  |  | #else   // OPENSSL_IS_BORINGSSL  | 
123  |  |       OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL);  | 
124  |  | #endif  // OPENSSL_IS_BORINGSSL  | 
125  | 0  |       return ThrowCryptoError(env, ERR_get_error(), "Invalid prime length");  | 
126  | 0  |     }  | 
127  |  |  | 
128  |  |     // If the first argument is an Int32 then we are generating a new  | 
129  |  |     // prime and then using that to generate the Diffie-Hellman parameters.  | 
130  |  |     // The second argument must be an Int32 as well.  | 
131  | 0  |     if (!args[1]->IsInt32()) { | 
132  | 0  |       return THROW_ERR_INVALID_ARG_TYPE(env,  | 
133  | 0  |                                         "Second argument must be an int32");  | 
134  | 0  |     }  | 
135  | 0  |     int32_t generator = args[1].As<Int32>()->Value();  | 
136  | 0  |     if (generator < 2) { | 
137  | 0  | #ifndef OPENSSL_IS_BORINGSSL  | 
138  | 0  |       ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);  | 
139  |  | #else  | 
140  |  |       OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);  | 
141  |  | #endif  | 
142  | 0  |       return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");  | 
143  | 0  |     }  | 
144  |  |  | 
145  | 0  |     auto dh = DHPointer::New(bits, generator);  | 
146  | 0  |     if (!dh) { | 
147  | 0  |       return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid DH parameters");  | 
148  | 0  |     }  | 
149  | 0  |     new DiffieHellman(env, args.This(), std::move(dh));  | 
150  | 0  |     return;  | 
151  | 0  |   }  | 
152  |  |  | 
153  |  |   // The first argument must be an ArrayBuffer or ArrayBufferView with the  | 
154  |  |   // prime, and the second argument must be an int32 with the generator  | 
155  |  |   // or an ArrayBuffer or ArrayBufferView with the generator.  | 
156  |  |  | 
157  | 0  |   ArrayBufferOrViewContents<char> arg0(args[0]);  | 
158  | 0  |   if (!arg0.CheckSizeInt32()) [[unlikely]]  | 
159  | 0  |     return THROW_ERR_OUT_OF_RANGE(env, "prime is too big");  | 
160  |  |  | 
161  | 0  |   BignumPointer bn_p(reinterpret_cast<uint8_t*>(arg0.data()), arg0.size());  | 
162  | 0  |   BignumPointer bn_g;  | 
163  | 0  |   if (!bn_p) { | 
164  | 0  |     return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid prime");  | 
165  | 0  |   }  | 
166  |  |  | 
167  | 0  |   if (args[1]->IsInt32()) { | 
168  | 0  |     int32_t generator = args[1].As<Int32>()->Value();  | 
169  | 0  |     if (generator < 2) { | 
170  | 0  | #ifndef OPENSSL_IS_BORINGSSL  | 
171  | 0  |       ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);  | 
172  |  | #else  | 
173  |  |       OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);  | 
174  |  | #endif  | 
175  | 0  |       return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");  | 
176  | 0  |     }  | 
177  | 0  |     bn_g = BignumPointer::New();  | 
178  | 0  |     if (!bn_g.setWord(generator)) { | 
179  | 0  | #ifndef OPENSSL_IS_BORINGSSL  | 
180  | 0  |       ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);  | 
181  |  | #else  | 
182  |  |       OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);  | 
183  |  | #endif  | 
184  | 0  |       return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");  | 
185  | 0  |     }  | 
186  | 0  |   } else { | 
187  | 0  |     ArrayBufferOrViewContents<char> arg1(args[1]);  | 
188  | 0  |     if (!arg1.CheckSizeInt32()) [[unlikely]]  | 
189  | 0  |       return THROW_ERR_OUT_OF_RANGE(env, "generator is too big");  | 
190  | 0  |     bn_g = BignumPointer(reinterpret_cast<uint8_t*>(arg1.data()), arg1.size());  | 
191  | 0  |     if (!bn_g) { | 
192  | 0  | #ifndef OPENSSL_IS_BORINGSSL  | 
193  | 0  |       ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);  | 
194  |  | #else  | 
195  |  |       OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);  | 
196  |  | #endif  | 
197  | 0  |       return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");  | 
198  | 0  |     }  | 
199  | 0  |     if (bn_g.getWord() < 2) { | 
200  | 0  | #ifndef OPENSSL_IS_BORINGSSL  | 
201  | 0  |       ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);  | 
202  |  | #else  | 
203  |  |       OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);  | 
204  |  | #endif  | 
205  | 0  |       return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");  | 
206  | 0  |     }  | 
207  | 0  |   }  | 
208  |  |  | 
209  | 0  |   auto dh = DHPointer::New(std::move(bn_p), std::move(bn_g));  | 
210  | 0  |   if (!dh) { | 
211  | 0  |     return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid DH parameters");  | 
212  | 0  |   }  | 
213  | 0  |   new DiffieHellman(env, args.This(), std::move(dh));  | 
214  | 0  | }  | 
215  |  |  | 
216  | 0  | void GenerateKeys(const FunctionCallbackInfo<Value>& args) { | 
217  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
218  | 0  |   DiffieHellman* diffieHellman;  | 
219  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());  | 
220  | 0  |   DHPointer& dh = *diffieHellman;  | 
221  |  | 
  | 
222  | 0  |   auto dp = dh.generateKeys();  | 
223  | 0  |   if (!dp) { | 
224  | 0  |     return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Key generation failed");  | 
225  | 0  |   }  | 
226  |  |  | 
227  | 0  |   Local<Value> buffer;  | 
228  | 0  |   if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) { | 
229  | 0  |     args.GetReturnValue().Set(buffer);  | 
230  | 0  |   }  | 
231  | 0  | }  | 
232  |  |  | 
233  | 0  | void GetPrime(const FunctionCallbackInfo<Value>& args) { | 
234  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
235  | 0  |   DiffieHellman* diffieHellman;  | 
236  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());  | 
237  | 0  |   DHPointer& dh = *diffieHellman;  | 
238  |  | 
  | 
239  | 0  |   auto dp = dh.getPrime();  | 
240  | 0  |   if (!dp) { | 
241  | 0  |     return THROW_ERR_CRYPTO_INVALID_STATE(env, "p is null");  | 
242  | 0  |   }  | 
243  | 0  |   Local<Value> buffer;  | 
244  | 0  |   if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) { | 
245  | 0  |     args.GetReturnValue().Set(buffer);  | 
246  | 0  |   }  | 
247  | 0  | }  | 
248  |  |  | 
249  | 0  | void GetGenerator(const FunctionCallbackInfo<Value>& args) { | 
250  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
251  | 0  |   DiffieHellman* diffieHellman;  | 
252  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());  | 
253  | 0  |   DHPointer& dh = *diffieHellman;  | 
254  |  | 
  | 
255  | 0  |   auto dp = dh.getGenerator();  | 
256  | 0  |   if (!dp) { | 
257  | 0  |     return THROW_ERR_CRYPTO_INVALID_STATE(env, "g is null");  | 
258  | 0  |   }  | 
259  | 0  |   Local<Value> buffer;  | 
260  | 0  |   if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) { | 
261  | 0  |     args.GetReturnValue().Set(buffer);  | 
262  | 0  |   }  | 
263  | 0  | }  | 
264  |  |  | 
265  | 0  | void GetPublicKey(const FunctionCallbackInfo<Value>& args) { | 
266  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
267  | 0  |   DiffieHellman* diffieHellman;  | 
268  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());  | 
269  | 0  |   DHPointer& dh = *diffieHellman;  | 
270  |  | 
  | 
271  | 0  |   auto dp = dh.getPublicKey();  | 
272  | 0  |   if (!dp) { | 
273  | 0  |     return THROW_ERR_CRYPTO_INVALID_STATE(  | 
274  | 0  |         env, "No public key - did you forget to generate one?");  | 
275  | 0  |   }  | 
276  | 0  |   Local<Value> buffer;  | 
277  | 0  |   if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) { | 
278  | 0  |     args.GetReturnValue().Set(buffer);  | 
279  | 0  |   }  | 
280  | 0  | }  | 
281  |  |  | 
282  | 0  | void GetPrivateKey(const FunctionCallbackInfo<Value>& args) { | 
283  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
284  | 0  |   DiffieHellman* diffieHellman;  | 
285  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());  | 
286  | 0  |   DHPointer& dh = *diffieHellman;  | 
287  |  | 
  | 
288  | 0  |   auto dp = dh.getPrivateKey();  | 
289  | 0  |   if (!dp) { | 
290  | 0  |     return THROW_ERR_CRYPTO_INVALID_STATE(  | 
291  | 0  |         env, "No private key - did you forget to generate one?");  | 
292  | 0  |   }  | 
293  | 0  |   Local<Value> buffer;  | 
294  | 0  |   if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) { | 
295  | 0  |     args.GetReturnValue().Set(buffer);  | 
296  | 0  |   }  | 
297  | 0  | }  | 
298  |  |  | 
299  | 0  | void ComputeSecret(const FunctionCallbackInfo<Value>& args) { | 
300  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
301  | 0  |   DiffieHellman* diffieHellman;  | 
302  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());  | 
303  | 0  |   DHPointer& dh = *diffieHellman;  | 
304  |  | 
  | 
305  | 0  |   CHECK_EQ(args.Length(), 1);  | 
306  | 0  |   ArrayBufferOrViewContents<unsigned char> key_buf(args[0]);  | 
307  | 0  |   if (!key_buf.CheckSizeInt32()) [[unlikely]]  | 
308  | 0  |     return THROW_ERR_OUT_OF_RANGE(env, "secret is too big");  | 
309  | 0  |   BignumPointer key(key_buf.data(), key_buf.size());  | 
310  |  | 
  | 
311  | 0  |   switch (dh.checkPublicKey(key)) { | 
312  | 0  |     case DHPointer::CheckPublicKeyResult::INVALID:  | 
313  |  |       // Fall-through  | 
314  | 0  |     case DHPointer::CheckPublicKeyResult::CHECK_FAILED:  | 
315  | 0  |       return THROW_ERR_CRYPTO_INVALID_KEYTYPE(env,  | 
316  | 0  |                                               "Unspecified validation error");  | 
317  | 0  |     case DHPointer::CheckPublicKeyResult::TOO_SMALL:  | 
318  | 0  |       return THROW_ERR_CRYPTO_INVALID_KEYLEN(env, "Supplied key is too small");  | 
319  | 0  |     case DHPointer::CheckPublicKeyResult::TOO_LARGE:  | 
320  | 0  |       return THROW_ERR_CRYPTO_INVALID_KEYLEN(env, "Supplied key is too large");  | 
321  | 0  |     case DHPointer::CheckPublicKeyResult::NONE:  | 
322  | 0  |       break;  | 
323  | 0  |   }  | 
324  |  |  | 
325  | 0  |   auto dp = dh.computeSecret(key);  | 
326  |  | 
  | 
327  | 0  |   Local<Value> buffer;  | 
328  | 0  |   if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) { | 
329  | 0  |     args.GetReturnValue().Set(buffer);  | 
330  | 0  |   }  | 
331  | 0  | }  | 
332  |  |  | 
333  | 0  | void SetPublicKey(const FunctionCallbackInfo<Value>& args) { | 
334  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
335  | 0  |   DiffieHellman* diffieHellman;  | 
336  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());  | 
337  | 0  |   DHPointer& dh = *diffieHellman;  | 
338  | 0  |   CHECK_EQ(args.Length(), 1);  | 
339  | 0  |   ArrayBufferOrViewContents<unsigned char> buf(args[0]);  | 
340  | 0  |   if (!buf.CheckSizeInt32()) [[unlikely]]  | 
341  | 0  |     return THROW_ERR_OUT_OF_RANGE(env, "buf is too big");  | 
342  | 0  |   BignumPointer num(buf.data(), buf.size());  | 
343  | 0  |   CHECK(num);  | 
344  | 0  |   CHECK(dh.setPublicKey(std::move(num)));  | 
345  | 0  | }  | 
346  |  |  | 
347  | 0  | void SetPrivateKey(const FunctionCallbackInfo<Value>& args) { | 
348  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
349  | 0  |   DiffieHellman* diffieHellman;  | 
350  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());  | 
351  | 0  |   DHPointer& dh = *diffieHellman;  | 
352  | 0  |   CHECK_EQ(args.Length(), 1);  | 
353  | 0  |   ArrayBufferOrViewContents<unsigned char> buf(args[0]);  | 
354  | 0  |   if (!buf.CheckSizeInt32()) [[unlikely]]  | 
355  | 0  |     return THROW_ERR_OUT_OF_RANGE(env, "buf is too big");  | 
356  | 0  |   BignumPointer num(buf.data(), buf.size());  | 
357  | 0  |   CHECK(num);  | 
358  | 0  |   CHECK(dh.setPrivateKey(std::move(num)));  | 
359  | 0  | }  | 
360  |  |  | 
361  | 0  | void Check(const FunctionCallbackInfo<Value>& args) { | 
362  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
363  | 0  |   DiffieHellman* diffieHellman;  | 
364  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());  | 
365  |  |  | 
366  | 0  |   DHPointer& dh = *diffieHellman;  | 
367  | 0  |   auto result = dh.check();  | 
368  | 0  |   if (result == DHPointer::CheckResult::CHECK_FAILED) { | 
369  | 0  |     return THROW_ERR_CRYPTO_OPERATION_FAILED(env,  | 
370  | 0  |                                              "Checking DH parameters failed");  | 
371  | 0  |   }  | 
372  |  |  | 
373  | 0  |   args.GetReturnValue().Set(static_cast<int>(result));  | 
374  | 0  | }  | 
375  |  |  | 
376  |  | }  // namespace  | 
377  |  |  | 
378  |  | // The input arguments to DhKeyPairGenJob can vary  | 
379  |  | //   1. CryptoJobMode  | 
380  |  | // and either  | 
381  |  | //   2. Group name (as a string)  | 
382  |  | // or  | 
383  |  | //   2. Prime or Prime Length  | 
384  |  | //   3. Generator  | 
385  |  | // Followed by the public and private key encoding parameters:  | 
386  |  | //   * Public format  | 
387  |  | //   * Public type  | 
388  |  | //   * Private format  | 
389  |  | //   * Private type  | 
390  |  | //   * Cipher  | 
391  |  | //   * Passphrase  | 
392  |  | Maybe<void> DhKeyGenTraits::AdditionalConfig(  | 
393  |  |     CryptoJobMode mode,  | 
394  |  |     const FunctionCallbackInfo<Value>& args,  | 
395  |  |     unsigned int* offset,  | 
396  | 0  |     DhKeyPairGenConfig* params) { | 
397  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
398  |  | 
  | 
399  | 0  |   if (args[*offset]->IsString()) { | 
400  | 0  |     Utf8Value group_name(env->isolate(), args[*offset]);  | 
401  | 0  |     auto group = DHPointer::FindGroup(group_name.ToStringView());  | 
402  | 0  |     if (!group) { | 
403  | 0  |       THROW_ERR_CRYPTO_UNKNOWN_DH_GROUP(env);  | 
404  | 0  |       return Nothing<void>();  | 
405  | 0  |     }  | 
406  |  |  | 
407  | 0  |     static constexpr int kStandardizedGenerator = 2;  | 
408  |  | 
  | 
409  | 0  |     params->params.prime = std::move(group);  | 
410  | 0  |     params->params.generator = kStandardizedGenerator;  | 
411  | 0  |     *offset += 1;  | 
412  | 0  |   } else { | 
413  | 0  |     if (args[*offset]->IsInt32()) { | 
414  | 0  |       int size = args[*offset].As<Int32>()->Value();  | 
415  | 0  |       if (size < 0) { | 
416  | 0  |         THROW_ERR_OUT_OF_RANGE(env, "Invalid prime size");  | 
417  | 0  |         return Nothing<void>();  | 
418  | 0  |       }  | 
419  | 0  |       params->params.prime = size;  | 
420  | 0  |     } else { | 
421  | 0  |       ArrayBufferOrViewContents<unsigned char> input(args[*offset]);  | 
422  | 0  |       if (!input.CheckSizeInt32()) [[unlikely]] { | 
423  | 0  |         THROW_ERR_OUT_OF_RANGE(env, "prime is too big");  | 
424  | 0  |         return Nothing<void>();  | 
425  | 0  |       }  | 
426  | 0  |       params->params.prime = BignumPointer(input.data(), input.size());  | 
427  | 0  |     }  | 
428  |  |  | 
429  | 0  |     CHECK(args[*offset + 1]->IsInt32());  | 
430  | 0  |     params->params.generator = args[*offset + 1].As<Int32>()->Value();  | 
431  | 0  |     *offset += 2;  | 
432  | 0  |   }  | 
433  |  |  | 
434  | 0  |   return JustVoid();  | 
435  | 0  | }  | 
436  |  |  | 
437  | 0  | EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) { | 
438  | 0  |   EVPKeyPointer key_params;  | 
439  | 0  |   if (BignumPointer* prime_fixed_value =  | 
440  | 0  |           std::get_if<BignumPointer>(¶ms->params.prime)) { | 
441  | 0  |     auto prime = prime_fixed_value->clone();  | 
442  | 0  |     auto bn_g = BignumPointer::New();  | 
443  | 0  |     if (!prime || !bn_g || !bn_g.setWord(params->params.generator)) { | 
444  | 0  |       return {}; | 
445  | 0  |     }  | 
446  | 0  |     auto dh = DHPointer::New(std::move(prime), std::move(bn_g));  | 
447  | 0  |     if (!dh) return {}; | 
448  |  |  | 
449  | 0  |     key_params = EVPKeyPointer::NewDH(std::move(dh));  | 
450  | 0  |   } else if (std::get_if<int>(¶ms->params.prime)) { | 
451  | 0  |     auto param_ctx = EVPKeyCtxPointer::NewFromID(EVP_PKEY_DH);  | 
452  | 0  | #ifndef OPENSSL_IS_BORINGSSL  | 
453  | 0  |     int* prime_size = std::get_if<int>(¶ms->params.prime);  | 
454  | 0  |     if (!param_ctx.initForParamgen() ||  | 
455  | 0  |         !param_ctx.setDhParameters(*prime_size, params->params.generator)) { | 
456  | 0  |       return {}; | 
457  | 0  |     }  | 
458  |  |  | 
459  | 0  |     key_params = param_ctx.paramgen();  | 
460  |  | #else  | 
461  |  |     return {}; | 
462  |  | #endif  | 
463  | 0  |   } else { | 
464  | 0  |     UNREACHABLE();  | 
465  | 0  |   }  | 
466  |  |  | 
467  | 0  |   if (!key_params) return {}; | 
468  |  |  | 
469  | 0  |   EVPKeyCtxPointer ctx = key_params.newCtx();  | 
470  | 0  |   if (!ctx.initForKeygen()) return {}; | 
471  |  |  | 
472  | 0  |   return ctx;  | 
473  | 0  | }  | 
474  |  |  | 
475  |  | Maybe<void> DHKeyExportTraits::AdditionalConfig(  | 
476  |  |     const FunctionCallbackInfo<Value>& args,  | 
477  |  |     unsigned int offset,  | 
478  | 0  |     DHKeyExportConfig* params) { | 
479  | 0  |   return JustVoid();  | 
480  | 0  | }  | 
481  |  |  | 
482  |  | WebCryptoKeyExportStatus DHKeyExportTraits::DoExport(  | 
483  |  |     const KeyObjectData& key_data,  | 
484  |  |     WebCryptoKeyFormat format,  | 
485  |  |     const DHKeyExportConfig& params,  | 
486  | 0  |     ByteSource* out) { | 
487  | 0  |   CHECK_NE(key_data.GetKeyType(), kKeyTypeSecret);  | 
488  |  |  | 
489  | 0  |   switch (format) { | 
490  | 0  |     case kWebCryptoKeyFormatPKCS8:  | 
491  | 0  |       if (key_data.GetKeyType() != kKeyTypePrivate)  | 
492  | 0  |         return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;  | 
493  | 0  |       return PKEY_PKCS8_Export(key_data, out);  | 
494  | 0  |     case kWebCryptoKeyFormatSPKI:  | 
495  | 0  |       if (key_data.GetKeyType() != kKeyTypePublic)  | 
496  | 0  |         return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;  | 
497  | 0  |       return PKEY_SPKI_Export(key_data, out);  | 
498  | 0  |     default:  | 
499  | 0  |       UNREACHABLE();  | 
500  | 0  |   }  | 
501  | 0  | }  | 
502  |  |  | 
503  |  | Maybe<void> DHBitsTraits::AdditionalConfig(  | 
504  |  |     CryptoJobMode mode,  | 
505  |  |     const FunctionCallbackInfo<Value>& args,  | 
506  |  |     unsigned int offset,  | 
507  | 0  |     DHBitsConfig* params) { | 
508  | 0  |   CHECK(args[offset]->IsObject());  // public key  | 
509  | 0  |   CHECK(args[offset + 1]->IsObject());  // private key  | 
510  |  |  | 
511  | 0  |   KeyObjectHandle* private_key;  | 
512  | 0  |   KeyObjectHandle* public_key;  | 
513  |  | 
  | 
514  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&public_key, args[offset], Nothing<void>());  | 
515  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 1], Nothing<void>());  | 
516  |  |  | 
517  | 0  |   CHECK(private_key->Data().GetKeyType() == kKeyTypePrivate);  | 
518  | 0  |   CHECK(public_key->Data().GetKeyType() != kKeyTypeSecret);  | 
519  |  |  | 
520  | 0  |   params->public_key = public_key->Data().addRef();  | 
521  | 0  |   params->private_key = private_key->Data().addRef();  | 
522  |  | 
  | 
523  | 0  |   return JustVoid();  | 
524  | 0  | }  | 
525  |  |  | 
526  |  | MaybeLocal<Value> DHBitsTraits::EncodeOutput(Environment* env,  | 
527  |  |                                              const DHBitsConfig& params,  | 
528  | 0  |                                              ByteSource* out) { | 
529  | 0  |   return out->ToArrayBuffer(env);  | 
530  | 0  | }  | 
531  |  |  | 
532  |  | bool DHBitsTraits::DeriveBits(Environment* env,  | 
533  |  |                               const DHBitsConfig& params,  | 
534  |  |                               ByteSource* out,  | 
535  | 0  |                               CryptoJobMode mode) { | 
536  | 0  |   auto dp = DHPointer::stateless(params.private_key.GetAsymmetricKey(),  | 
537  | 0  |                                  params.public_key.GetAsymmetricKey());  | 
538  | 0  |   if (!dp) { | 
539  | 0  |     bool can_throw = mode == CryptoJobMode::kCryptoJobSync;  | 
540  |  | 
  | 
541  | 0  |     if (can_throw) { | 
542  | 0  |       unsigned long err = ERR_get_error();  // NOLINT(runtime/int)  | 
543  | 0  |       if (err) ThrowCryptoError(env, err, "diffieHellman failed");  | 
544  | 0  |     }  | 
545  | 0  |     return false;  | 
546  | 0  |   }  | 
547  |  |  | 
548  | 0  |   *out = ByteSource::Allocated(dp.release());  | 
549  | 0  |   CHECK(!out->empty());  | 
550  | 0  |   return true;  | 
551  | 0  | }  | 
552  |  |  | 
553  |  | bool GetDhKeyDetail(Environment* env,  | 
554  |  |                     const KeyObjectData& key,  | 
555  | 0  |                     Local<Object> target) { | 
556  | 0  |   CHECK_EQ(key.GetAsymmetricKey().id(), EVP_PKEY_DH);  | 
557  | 0  |   return true;  | 
558  | 0  | }  | 
559  |  |  | 
560  | 0  | void DiffieHellman::Initialize(Environment* env, Local<Object> target) { | 
561  | 0  |   Isolate* isolate = env->isolate();  | 
562  | 0  |   Local<Context> context = env->context();  | 
563  | 0  |   auto make = [&](Local<String> name, FunctionCallback callback) { | 
564  | 0  |     Local<FunctionTemplate> t = NewFunctionTemplate(isolate, callback);  | 
565  |  | 
  | 
566  | 0  |     const PropertyAttribute attributes =  | 
567  | 0  |         static_cast<PropertyAttribute>(ReadOnly | DontDelete);  | 
568  |  | 
  | 
569  | 0  |     t->InstanceTemplate()->SetInternalFieldCount(  | 
570  | 0  |         DiffieHellman::kInternalFieldCount);  | 
571  |  | 
  | 
572  | 0  |     SetProtoMethod(isolate, t, "generateKeys", GenerateKeys);  | 
573  | 0  |     SetProtoMethod(isolate, t, "computeSecret", ComputeSecret);  | 
574  | 0  |     SetProtoMethodNoSideEffect(isolate, t, "getPrime", GetPrime);  | 
575  | 0  |     SetProtoMethodNoSideEffect(isolate, t, "getGenerator", GetGenerator);  | 
576  | 0  |     SetProtoMethodNoSideEffect(isolate, t, "getPublicKey", GetPublicKey);  | 
577  | 0  |     SetProtoMethodNoSideEffect(isolate, t, "getPrivateKey", GetPrivateKey);  | 
578  | 0  |     SetProtoMethod(isolate, t, "setPublicKey", SetPublicKey);  | 
579  | 0  |     SetProtoMethod(isolate, t, "setPrivateKey", SetPrivateKey);  | 
580  |  | 
  | 
581  | 0  |     Local<FunctionTemplate> verify_error_getter_templ =  | 
582  | 0  |         FunctionTemplate::New(isolate,  | 
583  | 0  |                               Check,  | 
584  | 0  |                               Local<Value>(),  | 
585  | 0  |                               Signature::New(env->isolate(), t),  | 
586  | 0  |                               /* length */ 0,  | 
587  | 0  |                               ConstructorBehavior::kThrow,  | 
588  | 0  |                               SideEffectType::kHasNoSideEffect);  | 
589  |  | 
  | 
590  | 0  |     t->InstanceTemplate()->SetAccessorProperty(env->verify_error_string(),  | 
591  | 0  |                                                verify_error_getter_templ,  | 
592  | 0  |                                                Local<FunctionTemplate>(),  | 
593  | 0  |                                                attributes);  | 
594  |  | 
  | 
595  | 0  |     SetConstructorFunction(context, target, name, t);  | 
596  | 0  |   };  | 
597  |  | 
  | 
598  | 0  |   make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellman"), New);  | 
599  | 0  |   make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellmanGroup"),  | 
600  | 0  |        DiffieHellmanGroup);  | 
601  |  | 
  | 
602  | 0  |   DHKeyPairGenJob::Initialize(env, target);  | 
603  | 0  |   DHKeyExportJob::Initialize(env, target);  | 
604  | 0  |   DHBitsJob::Initialize(env, target);  | 
605  | 0  | }  | 
606  |  |  | 
607  |  | void DiffieHellman::RegisterExternalReferences(  | 
608  | 0  |     ExternalReferenceRegistry* registry) { | 
609  | 0  |   registry->Register(New);  | 
610  | 0  |   registry->Register(DiffieHellmanGroup);  | 
611  |  | 
  | 
612  | 0  |   registry->Register(GenerateKeys);  | 
613  | 0  |   registry->Register(ComputeSecret);  | 
614  | 0  |   registry->Register(GetPrime);  | 
615  | 0  |   registry->Register(GetGenerator);  | 
616  | 0  |   registry->Register(GetPublicKey);  | 
617  | 0  |   registry->Register(GetPrivateKey);  | 
618  | 0  |   registry->Register(SetPublicKey);  | 
619  | 0  |   registry->Register(SetPrivateKey);  | 
620  |  | 
  | 
621  | 0  |   registry->Register(Check);  | 
622  |  | 
  | 
623  | 0  |   DHKeyPairGenJob::RegisterExternalReferences(registry);  | 
624  | 0  |   DHKeyExportJob::RegisterExternalReferences(registry);  | 
625  | 0  |   DHBitsJob::RegisterExternalReferences(registry);  | 
626  | 0  | }  | 
627  |  |  | 
628  |  | }  // namespace crypto  | 
629  |  | }  // namespace node  |