1 |
|
|
#include "crypto/crypto_ecdh.h" |
2 |
|
|
#include "crypto/crypto_common.h" |
3 |
|
|
#include "crypto/crypto_util.h" |
4 |
|
|
#include "allocated_buffer-inl.h" |
5 |
|
|
#include "async_wrap-inl.h" |
6 |
|
|
#include "base_object-inl.h" |
7 |
|
|
#include "env-inl.h" |
8 |
|
|
#include "memory_tracker-inl.h" |
9 |
|
|
#include "node_buffer.h" |
10 |
|
|
#include "threadpoolwork-inl.h" |
11 |
|
|
#include "v8.h" |
12 |
|
|
|
13 |
|
|
#include <openssl/bn.h> |
14 |
|
|
#include <openssl/ec.h> |
15 |
|
|
#include <openssl/ecdh.h> |
16 |
|
|
|
17 |
|
|
namespace node { |
18 |
|
|
|
19 |
|
|
using v8::Array; |
20 |
|
|
using v8::FunctionCallbackInfo; |
21 |
|
|
using v8::FunctionTemplate; |
22 |
|
|
using v8::Int32; |
23 |
|
|
using v8::Just; |
24 |
|
|
using v8::Local; |
25 |
|
|
using v8::Maybe; |
26 |
|
|
using v8::Nothing; |
27 |
|
|
using v8::Object; |
28 |
|
|
using v8::String; |
29 |
|
|
using v8::Uint32; |
30 |
|
|
using v8::Value; |
31 |
|
|
|
32 |
|
|
namespace crypto { |
33 |
|
|
namespace { |
34 |
|
131 |
int GetCurveFromName(const char* name) { |
35 |
|
131 |
int nid = EC_curve_nist2nid(name); |
36 |
✓✓ |
131 |
if (nid == NID_undef) |
37 |
|
10 |
nid = OBJ_sn2nid(name); |
38 |
|
131 |
return nid; |
39 |
|
|
} |
40 |
|
|
} // namespace |
41 |
|
|
|
42 |
|
653 |
void ECDH::Initialize(Environment* env, Local<Object> target) { |
43 |
|
653 |
Local<FunctionTemplate> t = env->NewFunctionTemplate(New); |
44 |
|
1308 |
t->Inherit(BaseObject::GetConstructorTemplate(env)); |
45 |
|
|
|
46 |
|
1308 |
t->InstanceTemplate()->SetInternalFieldCount(ECDH::kInternalFieldCount); |
47 |
|
|
|
48 |
|
654 |
env->SetProtoMethod(t, "generateKeys", GenerateKeys); |
49 |
|
654 |
env->SetProtoMethod(t, "computeSecret", ComputeSecret); |
50 |
|
654 |
env->SetProtoMethodNoSideEffect(t, "getPublicKey", GetPublicKey); |
51 |
|
654 |
env->SetProtoMethodNoSideEffect(t, "getPrivateKey", GetPrivateKey); |
52 |
|
654 |
env->SetProtoMethod(t, "setPublicKey", SetPublicKey); |
53 |
|
654 |
env->SetProtoMethod(t, "setPrivateKey", SetPrivateKey); |
54 |
|
|
|
55 |
|
1308 |
target->Set(env->context(), |
56 |
|
|
FIXED_ONE_BYTE_STRING(env->isolate(), "ECDH"), |
57 |
|
3924 |
t->GetFunction(env->context()).ToLocalChecked()).Check(); |
58 |
|
|
|
59 |
|
654 |
env->SetMethodNoSideEffect(target, "ECDHConvertKey", ECDH::ConvertKey); |
60 |
|
654 |
env->SetMethodNoSideEffect(target, "getCurves", ECDH::GetCurves); |
61 |
|
|
|
62 |
|
654 |
ECDHBitsJob::Initialize(env, target); |
63 |
|
653 |
ECKeyPairGenJob::Initialize(env, target); |
64 |
|
653 |
ECKeyExportJob::Initialize(env, target); |
65 |
|
|
|
66 |
|
654 |
NODE_DEFINE_CONSTANT(target, OPENSSL_EC_NAMED_CURVE); |
67 |
|
1962 |
NODE_DEFINE_CONSTANT(target, OPENSSL_EC_EXPLICIT_CURVE); |
68 |
|
3269 |
} |
69 |
|
3266 |
|
70 |
|
3273 |
void ECDH::GetCurves(const FunctionCallbackInfo<Value>& args) { |
71 |
|
1312 |
Environment* env = Environment::GetCurrent(args); |
72 |
|
4 |
const size_t num_curves = EC_get_builtin_curves(nullptr, 0); |
73 |
|
|
|
74 |
✓✗ |
4 |
if (num_curves) { |
75 |
|
4 |
std::vector<EC_builtin_curve> curves(num_curves); |
76 |
|
|
|
77 |
✓✗ |
4 |
if (EC_get_builtin_curves(curves.data(), num_curves)) { |
78 |
✗✓ |
8 |
std::vector<Local<Value>> arr(num_curves); |
79 |
|
|
|
80 |
✓✓ |
332 |
for (size_t i = 0; i < num_curves; i++) |
81 |
|
656 |
arr[i] = OneByteString(env->isolate(), OBJ_nid2sn(curves[i].nid)); |
82 |
|
|
|
83 |
|
12 |
args.GetReturnValue().Set( |
84 |
|
|
Array::New(env->isolate(), arr.data(), arr.size())); |
85 |
|
4 |
return; |
86 |
|
|
} |
87 |
|
|
} |
88 |
|
|
|
89 |
|
|
args.GetReturnValue().Set(Array::New(env->isolate())); |
90 |
|
|
} |
91 |
|
|
|
92 |
|
10 |
ECDH::ECDH(Environment* env, Local<Object> wrap, ECKeyPointer&& key) |
93 |
|
|
: BaseObject(env, wrap), |
94 |
|
10 |
key_(std::move(key)), |
95 |
|
20 |
group_(EC_KEY_get0_group(key_.get())) { |
96 |
|
10 |
MakeWeak(); |
97 |
✗✓ |
10 |
CHECK_NOT_NULL(group_); |
98 |
|
10 |
} |
99 |
|
|
|
100 |
|
|
void ECDH::MemoryInfo(MemoryTracker* tracker) const { |
101 |
|
|
tracker->TrackFieldWithSize("key", key_ ? kSizeOf_EC_KEY : 0); |
102 |
|
|
} |
103 |
|
|
|
104 |
|
20 |
ECDH::~ECDH() {} |
105 |
|
|
|
106 |
|
10 |
void ECDH::New(const FunctionCallbackInfo<Value>& args) { |
107 |
|
10 |
Environment* env = Environment::GetCurrent(args); |
108 |
|
|
|
109 |
|
20 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
110 |
|
|
|
111 |
|
|
// TODO(indutny): Support raw curves? |
112 |
✗✓ |
30 |
CHECK(args[0]->IsString()); |
113 |
✓✗ |
20 |
node::Utf8Value curve(env->isolate(), args[0]); |
114 |
|
|
|
115 |
|
10 |
int nid = OBJ_sn2nid(*curve); |
116 |
✗✓ |
10 |
if (nid == NID_undef) |
117 |
|
|
return THROW_ERR_CRYPTO_INVALID_CURVE(env); |
118 |
|
|
|
119 |
✓✗ |
20 |
ECKeyPointer key(EC_KEY_new_by_curve_name(nid)); |
120 |
✗✓ |
10 |
if (!key) |
121 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
122 |
|
|
"Failed to create key using named curve"); |
123 |
|
|
|
124 |
✓✗ |
10 |
new ECDH(env, args.This(), std::move(key)); |
125 |
|
|
} |
126 |
|
|
|
127 |
|
5 |
void ECDH::GenerateKeys(const FunctionCallbackInfo<Value>& args) { |
128 |
|
5 |
Environment* env = Environment::GetCurrent(args); |
129 |
|
|
|
130 |
|
|
ECDH* ecdh; |
131 |
✗✓ |
5 |
ASSIGN_OR_RETURN_UNWRAP(&ecdh, args.Holder()); |
132 |
|
|
|
133 |
✗✓ |
5 |
if (!EC_KEY_generate_key(ecdh->key_.get())) |
134 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to generate key"); |
135 |
|
|
} |
136 |
|
|
|
137 |
|
18 |
ECPointPointer ECDH::BufferToPoint(Environment* env, |
138 |
|
|
const EC_GROUP* group, |
139 |
|
|
Local<Value> buf) { |
140 |
|
|
int r; |
141 |
|
|
|
142 |
|
36 |
ECPointPointer pub(EC_POINT_new(group)); |
143 |
✗✓ |
18 |
if (!pub) { |
144 |
|
|
THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
145 |
|
|
"Failed to allocate EC_POINT for a public key"); |
146 |
|
|
return pub; |
147 |
|
|
} |
148 |
|
|
|
149 |
|
36 |
ArrayBufferOrViewContents<unsigned char> input(buf); |
150 |
✗✓ |
18 |
if (UNLIKELY(!input.CheckSizeInt32())) { |
151 |
|
|
THROW_ERR_OUT_OF_RANGE(env, "buffer is too big"); |
152 |
|
|
return ECPointPointer(); |
153 |
|
|
} |
154 |
|
36 |
r = EC_POINT_oct2point( |
155 |
|
|
group, |
156 |
|
|
pub.get(), |
157 |
|
18 |
input.data(), |
158 |
|
|
input.size(), |
159 |
|
18 |
nullptr); |
160 |
✓✓ |
18 |
if (!r) |
161 |
|
4 |
return ECPointPointer(); |
162 |
|
|
|
163 |
|
14 |
return pub; |
164 |
|
|
} |
165 |
|
|
|
166 |
|
7 |
void ECDH::ComputeSecret(const FunctionCallbackInfo<Value>& args) { |
167 |
|
7 |
Environment* env = Environment::GetCurrent(args); |
168 |
|
|
|
169 |
✗✓ |
7 |
CHECK(IsAnyByteSource(args[0])); |
170 |
|
|
|
171 |
|
|
ECDH* ecdh; |
172 |
✗✓ |
10 |
ASSIGN_OR_RETURN_UNWRAP(&ecdh, args.Holder()); |
173 |
|
|
|
174 |
|
11 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
175 |
|
|
|
176 |
✓✓ |
7 |
if (!ecdh->IsKeyPairValid()) |
177 |
|
1 |
return THROW_ERR_CRYPTO_INVALID_KEYPAIR(env); |
178 |
|
|
|
179 |
|
|
ECPointPointer pub( |
180 |
|
|
ECDH::BufferToPoint(env, |
181 |
|
|
ecdh->group_, |
182 |
✓✓ |
10 |
args[0])); |
183 |
✓✓ |
6 |
if (!pub) { |
184 |
|
6 |
args.GetReturnValue().Set( |
185 |
|
|
FIXED_ONE_BYTE_STRING(env->isolate(), |
186 |
|
|
"ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY")); |
187 |
|
2 |
return; |
188 |
|
|
} |
189 |
|
|
|
190 |
|
|
// NOTE: field_size is in bits |
191 |
|
4 |
int field_size = EC_GROUP_get_degree(ecdh->group_); |
192 |
|
4 |
size_t out_len = (field_size + 7) / 8; |
193 |
✓✓ |
8 |
AllocatedBuffer out = AllocatedBuffer::AllocateManaged(env, out_len); |
194 |
|
|
|
195 |
|
|
int r = ECDH_compute_key( |
196 |
|
4 |
out.data(), out_len, pub.get(), ecdh->key_.get(), nullptr); |
197 |
✗✓ |
4 |
if (!r) |
198 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to compute ECDH key"); |
199 |
|
|
|
200 |
✓✗ |
12 |
args.GetReturnValue().Set(out.ToBuffer().FromMaybe(Local<Value>())); |
201 |
|
|
} |
202 |
|
|
|
203 |
|
21 |
void ECDH::GetPublicKey(const FunctionCallbackInfo<Value>& args) { |
204 |
|
21 |
Environment* env = Environment::GetCurrent(args); |
205 |
|
|
|
206 |
|
|
// Conversion form |
207 |
✗✓ |
21 |
CHECK_EQ(args.Length(), 1); |
208 |
|
|
|
209 |
|
|
ECDH* ecdh; |
210 |
✗✓ |
22 |
ASSIGN_OR_RETURN_UNWRAP(&ecdh, args.Holder()); |
211 |
|
|
|
212 |
|
21 |
const EC_GROUP* group = EC_KEY_get0_group(ecdh->key_.get()); |
213 |
|
21 |
const EC_POINT* pub = EC_KEY_get0_public_key(ecdh->key_.get()); |
214 |
✓✓ |
21 |
if (pub == nullptr) |
215 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
216 |
|
1 |
"Failed to get ECDH public key"); |
217 |
|
|
|
218 |
✗✓ |
40 |
CHECK(args[0]->IsUint32()); |
219 |
|
60 |
uint32_t val = args[0].As<Uint32>()->Value(); |
220 |
|
20 |
point_conversion_form_t form = static_cast<point_conversion_form_t>(val); |
221 |
|
|
|
222 |
|
|
const char* error; |
223 |
|
|
Local<Object> buf; |
224 |
✗✓ |
40 |
if (!ECPointToBuffer(env, group, pub, form, &error).ToLocal(&buf)) |
225 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, error); |
226 |
|
40 |
args.GetReturnValue().Set(buf); |
227 |
|
|
} |
228 |
|
|
|
229 |
|
7 |
void ECDH::GetPrivateKey(const FunctionCallbackInfo<Value>& args) { |
230 |
|
7 |
Environment* env = Environment::GetCurrent(args); |
231 |
|
|
|
232 |
|
|
ECDH* ecdh; |
233 |
✗✓ |
8 |
ASSIGN_OR_RETURN_UNWRAP(&ecdh, args.Holder()); |
234 |
|
|
|
235 |
|
7 |
const BIGNUM* b = EC_KEY_get0_private_key(ecdh->key_.get()); |
236 |
✓✓ |
7 |
if (b == nullptr) |
237 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
238 |
|
1 |
"Failed to get ECDH private key"); |
239 |
|
|
|
240 |
|
6 |
const int size = BN_num_bytes(b); |
241 |
|
12 |
AllocatedBuffer out = AllocatedBuffer::AllocateManaged(env, size); |
242 |
✗✓ |
6 |
CHECK_EQ(size, BN_bn2binpad(b, |
243 |
|
|
reinterpret_cast<unsigned char*>(out.data()), |
244 |
|
|
size)); |
245 |
|
|
|
246 |
|
18 |
args.GetReturnValue().Set(out.ToBuffer().FromMaybe(Local<Value>())); |
247 |
|
|
} |
248 |
|
|
|
249 |
|
7 |
void ECDH::SetPrivateKey(const FunctionCallbackInfo<Value>& args) { |
250 |
|
7 |
Environment* env = Environment::GetCurrent(args); |
251 |
|
|
|
252 |
|
|
ECDH* ecdh; |
253 |
✗✓ |
10 |
ASSIGN_OR_RETURN_UNWRAP(&ecdh, args.Holder()); |
254 |
|
|
|
255 |
|
11 |
ArrayBufferOrViewContents<unsigned char> priv_buffer(args[0]); |
256 |
✗✓ |
7 |
if (UNLIKELY(!priv_buffer.CheckSizeInt32())) |
257 |
|
|
return THROW_ERR_OUT_OF_RANGE(env, "key is too big"); |
258 |
|
|
|
259 |
|
|
BignumPointer priv(BN_bin2bn( |
260 |
✓✓ |
11 |
priv_buffer.data(), priv_buffer.size(), nullptr)); |
261 |
✗✓ |
7 |
if (!priv) { |
262 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
263 |
|
|
"Failed to convert Buffer to BN"); |
264 |
|
|
} |
265 |
|
|
|
266 |
✓✓ |
7 |
if (!ecdh->IsKeyValidForCurve(priv)) { |
267 |
|
|
return THROW_ERR_CRYPTO_INVALID_KEYTYPE(env, |
268 |
|
3 |
"Private key is not valid for specified curve."); |
269 |
|
|
} |
270 |
|
|
|
271 |
✓✓ |
8 |
ECKeyPointer new_key(EC_KEY_dup(ecdh->key_.get())); |
272 |
✗✓ |
4 |
CHECK(new_key); |
273 |
|
|
|
274 |
|
4 |
int result = EC_KEY_set_private_key(new_key.get(), priv.get()); |
275 |
|
4 |
priv.reset(); |
276 |
|
|
|
277 |
✗✓ |
4 |
if (!result) { |
278 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
279 |
|
|
"Failed to convert BN to a private key"); |
280 |
|
|
} |
281 |
|
|
|
282 |
✓✗ |
8 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
283 |
|
4 |
USE(&mark_pop_error_on_return); |
284 |
|
|
|
285 |
|
4 |
const BIGNUM* priv_key = EC_KEY_get0_private_key(new_key.get()); |
286 |
✗✓ |
4 |
CHECK_NOT_NULL(priv_key); |
287 |
|
|
|
288 |
✓✗ |
8 |
ECPointPointer pub(EC_POINT_new(ecdh->group_)); |
289 |
✗✓ |
4 |
CHECK(pub); |
290 |
|
|
|
291 |
✗✓ |
4 |
if (!EC_POINT_mul(ecdh->group_, pub.get(), priv_key, |
292 |
|
|
nullptr, nullptr, nullptr)) { |
293 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
294 |
|
|
"Failed to generate ECDH public key"); |
295 |
|
|
} |
296 |
|
|
|
297 |
✗✓ |
4 |
if (!EC_KEY_set_public_key(new_key.get(), pub.get())) |
298 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
299 |
|
|
"Failed to set generated public key"); |
300 |
|
|
|
301 |
|
4 |
EC_KEY_copy(ecdh->key_.get(), new_key.get()); |
302 |
✓✗ |
4 |
ecdh->group_ = EC_KEY_get0_group(ecdh->key_.get()); |
303 |
|
|
} |
304 |
|
|
|
305 |
|
5 |
void ECDH::SetPublicKey(const FunctionCallbackInfo<Value>& args) { |
306 |
|
5 |
Environment* env = Environment::GetCurrent(args); |
307 |
|
|
|
308 |
|
|
ECDH* ecdh; |
309 |
✗✓ |
6 |
ASSIGN_OR_RETURN_UNWRAP(&ecdh, args.Holder()); |
310 |
|
|
|
311 |
✗✓ |
5 |
CHECK(IsAnyByteSource(args[0])); |
312 |
|
|
|
313 |
|
9 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
314 |
|
|
|
315 |
|
|
ECPointPointer pub( |
316 |
|
|
ECDH::BufferToPoint(env, |
317 |
|
|
ecdh->group_, |
318 |
✓✓ |
9 |
args[0])); |
319 |
✓✓ |
5 |
if (!pub) { |
320 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
321 |
|
1 |
"Failed to convert Buffer to EC_POINT"); |
322 |
|
|
} |
323 |
|
|
|
324 |
|
4 |
int r = EC_KEY_set_public_key(ecdh->key_.get(), pub.get()); |
325 |
✗✓ |
4 |
if (!r) { |
326 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
327 |
|
|
"Failed to set EC_POINT as the public key"); |
328 |
|
|
} |
329 |
|
|
} |
330 |
|
|
|
331 |
|
7 |
bool ECDH::IsKeyValidForCurve(const BignumPointer& private_key) { |
332 |
✗✓ |
7 |
CHECK(group_); |
333 |
✗✓ |
7 |
CHECK(private_key); |
334 |
|
|
// Private keys must be in the range [1, n-1]. |
335 |
|
|
// Ref: Section 3.2.1 - http://www.secg.org/sec1-v2.pdf |
336 |
✓✓ |
7 |
if (BN_cmp(private_key.get(), BN_value_one()) < 0) { |
337 |
|
1 |
return false; |
338 |
|
|
} |
339 |
|
12 |
BignumPointer order(BN_new()); |
340 |
✗✓ |
6 |
CHECK(order); |
341 |
✓✗✓✓
|
12 |
return EC_GROUP_get_order(group_, order.get(), nullptr) && |
342 |
|
12 |
BN_cmp(private_key.get(), order.get()) < 0; |
343 |
|
|
} |
344 |
|
|
|
345 |
|
7 |
bool ECDH::IsKeyPairValid() { |
346 |
|
14 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
347 |
|
7 |
USE(&mark_pop_error_on_return); |
348 |
|
14 |
return 1 == EC_KEY_check_key(key_.get()); |
349 |
|
|
} |
350 |
|
|
|
351 |
|
|
// Convert the input public key to compressed, uncompressed, or hybrid formats. |
352 |
|
8 |
void ECDH::ConvertKey(const FunctionCallbackInfo<Value>& args) { |
353 |
|
14 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
354 |
|
8 |
Environment* env = Environment::GetCurrent(args); |
355 |
|
|
|
356 |
✗✓ |
8 |
CHECK_EQ(args.Length(), 3); |
357 |
✗✓ |
8 |
CHECK(IsAnyByteSource(args[0])); |
358 |
|
|
|
359 |
✓✓ |
14 |
ArrayBufferOrViewContents<char> args0(args[0]); |
360 |
✗✓ |
8 |
if (UNLIKELY(!args0.CheckSizeInt32())) |
361 |
|
|
return THROW_ERR_OUT_OF_RANGE(env, "key is too big"); |
362 |
✗✓ |
8 |
if (args0.size() == 0) |
363 |
|
|
return args.GetReturnValue().SetEmptyString(); |
364 |
|
|
|
365 |
✓✓ |
14 |
node::Utf8Value curve(env->isolate(), args[1]); |
366 |
|
|
|
367 |
|
8 |
int nid = OBJ_sn2nid(*curve); |
368 |
✓✓ |
8 |
if (nid == NID_undef) |
369 |
|
1 |
return THROW_ERR_CRYPTO_INVALID_CURVE(env); |
370 |
|
|
|
371 |
|
|
ECGroupPointer group( |
372 |
✓✓ |
13 |
EC_GROUP_new_by_curve_name(nid)); |
373 |
✗✓ |
7 |
if (group == nullptr) |
374 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to get EC_GROUP"); |
375 |
|
|
|
376 |
|
|
ECPointPointer pub( |
377 |
|
|
ECDH::BufferToPoint(env, |
378 |
|
7 |
group.get(), |
379 |
✓✓ |
13 |
args[0])); |
380 |
|
|
|
381 |
✓✓ |
7 |
if (pub == nullptr) { |
382 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, |
383 |
|
1 |
"Failed to convert Buffer to EC_POINT"); |
384 |
|
|
} |
385 |
|
|
|
386 |
✗✓ |
12 |
CHECK(args[2]->IsUint32()); |
387 |
|
18 |
uint32_t val = args[2].As<Uint32>()->Value(); |
388 |
|
6 |
point_conversion_form_t form = static_cast<point_conversion_form_t>(val); |
389 |
|
|
|
390 |
|
|
const char* error; |
391 |
|
|
Local<Object> buf; |
392 |
✗✓ |
12 |
if (!ECPointToBuffer(env, group.get(), pub.get(), form, &error).ToLocal(&buf)) |
393 |
|
|
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, error); |
394 |
✓✓ |
12 |
args.GetReturnValue().Set(buf); |
395 |
|
|
} |
396 |
|
|
|
397 |
|
20 |
Maybe<bool> ECDHBitsTraits::EncodeOutput( |
398 |
|
|
Environment* env, |
399 |
|
|
const ECDHBitsConfig& params, |
400 |
|
|
ByteSource* out, |
401 |
|
|
v8::Local<v8::Value>* result) { |
402 |
|
40 |
*result = out->ToArrayBuffer(env); |
403 |
|
20 |
return Just(!result->IsEmpty()); |
404 |
|
|
} |
405 |
|
|
|
406 |
|
20 |
Maybe<bool> ECDHBitsTraits::AdditionalConfig( |
407 |
|
|
CryptoJobMode mode, |
408 |
|
|
const FunctionCallbackInfo<Value>& args, |
409 |
|
|
unsigned int offset, |
410 |
|
|
ECDHBitsConfig* params) { |
411 |
|
20 |
Environment* env = Environment::GetCurrent(args); |
412 |
|
|
|
413 |
✗✓ |
80 |
CHECK(args[offset]->IsString()); // curve name |
414 |
✗✓ |
60 |
CHECK(args[offset + 1]->IsObject()); // public key |
415 |
✗✓ |
60 |
CHECK(args[offset + 2]->IsObject()); // private key |
416 |
|
|
|
417 |
|
|
KeyObjectHandle* private_key; |
418 |
|
|
KeyObjectHandle* public_key; |
419 |
|
|
|
420 |
|
60 |
Utf8Value name(env->isolate(), args[offset]); |
421 |
✗✓ |
40 |
ASSIGN_OR_RETURN_UNWRAP(&public_key, args[offset + 1], Nothing<bool>()); |
422 |
✗✓ |
40 |
ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 2], Nothing<bool>()); |
423 |
|
|
|
424 |
✓✗✗✓ ✗✓ |
40 |
if (private_key->Data()->GetKeyType() != kKeyTypePrivate || |
425 |
|
20 |
public_key->Data()->GetKeyType() != kKeyTypePublic) { |
426 |
|
|
THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); |
427 |
|
|
return Nothing<bool>(); |
428 |
|
|
} |
429 |
|
|
|
430 |
|
40 |
params->private_key = ECKeyPointer( |
431 |
|
|
EC_KEY_dup( |
432 |
|
60 |
EVP_PKEY_get1_EC_KEY(private_key->Data()->GetAsymmetricKey().get()))); |
433 |
✗✓ |
20 |
if (!params->private_key) { |
434 |
|
|
THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); |
435 |
|
|
return Nothing<bool>(); |
436 |
|
|
} |
437 |
|
|
|
438 |
|
40 |
params->public_key = ECKeyPointer( |
439 |
|
|
EC_KEY_dup( |
440 |
|
60 |
EVP_PKEY_get1_EC_KEY(public_key->Data()->GetAsymmetricKey().get()))); |
441 |
✗✓ |
20 |
if (!params->public_key) { |
442 |
|
|
THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); |
443 |
|
|
return Nothing<bool>(); |
444 |
|
|
} |
445 |
|
|
|
446 |
|
20 |
params->group = EC_KEY_get0_group(params->private_key.get()); |
447 |
|
|
|
448 |
|
20 |
return Just(true); |
449 |
|
|
} |
450 |
|
|
|
451 |
|
20 |
bool ECDHBitsTraits::DeriveBits( |
452 |
|
|
Environment* env, |
453 |
|
|
const ECDHBitsConfig& params, |
454 |
|
|
ByteSource* out) { |
455 |
✗✓ |
20 |
if (params.group == nullptr) |
456 |
|
|
return false; |
457 |
✗✓ |
20 |
CHECK_EQ(EC_KEY_check_key(params.private_key.get()), 1); |
458 |
✗✓ |
20 |
CHECK_EQ(EC_KEY_check_key(params.public_key.get()), 1); |
459 |
|
20 |
const EC_POINT* pub = EC_KEY_get0_public_key(params.public_key.get()); |
460 |
|
20 |
int field_size = EC_GROUP_get_degree(params.group); |
461 |
|
20 |
size_t len = (field_size + 7) / 8; |
462 |
|
20 |
char* data = MallocOpenSSL<char>(len); |
463 |
|
40 |
ByteSource buf = ByteSource::Allocated(data, len); |
464 |
✗✓ |
20 |
if (ECDH_compute_key( |
465 |
|
|
data, |
466 |
|
|
len, |
467 |
|
|
pub, |
468 |
|
20 |
params.private_key.get(), |
469 |
|
|
nullptr) <= 0) { |
470 |
|
|
return false; |
471 |
|
|
} |
472 |
|
20 |
*out = std::move(buf); |
473 |
|
20 |
return true; |
474 |
|
|
} |
475 |
|
|
|
476 |
|
62 |
EVPKeyCtxPointer EcKeyGenTraits::Setup(EcKeyPairGenConfig* params) { |
477 |
|
124 |
EVPKeyCtxPointer param_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr)); |
478 |
|
62 |
EVP_PKEY* raw_params = nullptr; |
479 |
✓✗✗✓
|
186 |
if (!param_ctx || |
480 |
✓✗ |
124 |
EVP_PKEY_paramgen_init(param_ctx.get()) <= 0 || |
481 |
|
62 |
EVP_PKEY_CTX_set_ec_paramgen_curve_nid( |
482 |
✓✗ |
62 |
param_ctx.get(), params->params.curve_nid) <= 0 || |
483 |
|
62 |
EVP_PKEY_CTX_set_ec_param_enc( |
484 |
✓✗✗✓
|
124 |
param_ctx.get(), params->params.param_encoding) <= 0 || |
485 |
|
62 |
EVP_PKEY_paramgen(param_ctx.get(), &raw_params) <= 0) { |
486 |
|
|
return EVPKeyCtxPointer(); |
487 |
|
|
} |
488 |
|
124 |
EVPKeyPointer key_params(raw_params); |
489 |
|
124 |
EVPKeyCtxPointer key_ctx(EVP_PKEY_CTX_new(key_params.get(), nullptr)); |
490 |
|
|
|
491 |
✓✗✗✓ ✗✓ |
62 |
if (!key_ctx || EVP_PKEY_keygen_init(key_ctx.get()) <= 0) |
492 |
|
|
return EVPKeyCtxPointer(); |
493 |
|
|
|
494 |
|
62 |
return key_ctx; |
495 |
|
|
} |
496 |
|
|
|
497 |
|
|
// EcKeyPairGenJob input arguments |
498 |
|
|
// 1. CryptoJobMode |
499 |
|
|
// 2. Curve Name |
500 |
|
|
// 3. Param Encoding |
501 |
|
|
// 4. Public Format |
502 |
|
|
// 5. Public Type |
503 |
|
|
// 6. Private Format |
504 |
|
|
// 7. Private Type |
505 |
|
|
// 8. Cipher |
506 |
|
|
// 9. Passphrase |
507 |
|
63 |
Maybe<bool> EcKeyGenTraits::AdditionalConfig( |
508 |
|
|
CryptoJobMode mode, |
509 |
|
|
const FunctionCallbackInfo<Value>& args, |
510 |
|
|
unsigned int* offset, |
511 |
|
|
EcKeyPairGenConfig* params) { |
512 |
|
63 |
Environment* env = Environment::GetCurrent(args); |
513 |
✗✓ |
252 |
CHECK(args[*offset]->IsString()); // curve name |
514 |
✗✓ |
189 |
CHECK(args[*offset + 1]->IsInt32()); // param encoding |
515 |
|
|
|
516 |
|
189 |
Utf8Value curve_name(env->isolate(), args[*offset]); |
517 |
|
63 |
params->params.curve_nid = GetCurveFromName(*curve_name); |
518 |
✓✓ |
63 |
if (params->params.curve_nid == NID_undef) { |
519 |
|
1 |
THROW_ERR_CRYPTO_INVALID_CURVE(env); |
520 |
|
1 |
return Nothing<bool>(); |
521 |
|
|
} |
522 |
|
|
|
523 |
|
248 |
params->params.param_encoding = args[*offset + 1].As<Int32>()->Value(); |
524 |
✓✓✗✓
|
65 |
if (params->params.param_encoding != OPENSSL_EC_NAMED_CURVE && |
525 |
|
3 |
params->params.param_encoding != OPENSSL_EC_EXPLICIT_CURVE) { |
526 |
|
|
THROW_ERR_OUT_OF_RANGE(env, "Invalid param_encoding specified"); |
527 |
|
|
return Nothing<bool>(); |
528 |
|
|
} |
529 |
|
|
|
530 |
|
62 |
*offset += 2; |
531 |
|
|
|
532 |
|
62 |
return Just(true); |
533 |
|
|
} |
534 |
|
|
|
535 |
|
|
namespace { |
536 |
|
|
WebCryptoKeyExportStatus EC_Raw_Export( |
537 |
|
|
KeyObjectData* key_data, |
538 |
|
|
const ECKeyExportConfig& params, |
539 |
|
|
ByteSource* out) { |
540 |
|
|
CHECK(key_data->GetAsymmetricKey()); |
541 |
|
|
|
542 |
|
|
EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key_data->GetAsymmetricKey().get()); |
543 |
|
|
CHECK_NOT_NULL(ec_key); |
544 |
|
|
|
545 |
|
|
const EC_GROUP* group = EC_KEY_get0_group(ec_key); |
546 |
|
|
const EC_POINT* point = EC_KEY_get0_public_key(ec_key); |
547 |
|
|
point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED; |
548 |
|
|
|
549 |
|
|
// Get the allocated data size... |
550 |
|
|
size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr); |
551 |
|
|
if (len == 0) |
552 |
|
|
return WebCryptoKeyExportStatus::FAILED; |
553 |
|
|
|
554 |
|
|
unsigned char* data = MallocOpenSSL<unsigned char>(len); |
555 |
|
|
size_t check_len = EC_POINT_point2oct(group, point, form, data, len, nullptr); |
556 |
|
|
if (check_len == 0) |
557 |
|
|
return WebCryptoKeyExportStatus::FAILED; |
558 |
|
|
|
559 |
|
|
CHECK_EQ(len, check_len); |
560 |
|
|
|
561 |
|
|
*out = ByteSource::Allocated(reinterpret_cast<char*>(data), len); |
562 |
|
|
|
563 |
|
|
return WebCryptoKeyExportStatus::OK; |
564 |
|
|
} |
565 |
|
|
} // namespace |
566 |
|
|
|
567 |
|
70 |
Maybe<bool> ECKeyExportTraits::AdditionalConfig( |
568 |
|
|
const FunctionCallbackInfo<Value>& args, |
569 |
|
|
unsigned int offset, |
570 |
|
|
ECKeyExportConfig* params) { |
571 |
|
70 |
return Just(true); |
572 |
|
|
} |
573 |
|
|
|
574 |
|
70 |
WebCryptoKeyExportStatus ECKeyExportTraits::DoExport( |
575 |
|
|
std::shared_ptr<KeyObjectData> key_data, |
576 |
|
|
WebCryptoKeyFormat format, |
577 |
|
|
const ECKeyExportConfig& params, |
578 |
|
|
ByteSource* out) { |
579 |
✗✓ |
70 |
CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret); |
580 |
|
|
|
581 |
✗✓✓✗
|
70 |
switch (format) { |
582 |
|
|
case kWebCryptoKeyFormatRaw: |
583 |
|
|
if (key_data->GetKeyType() != kKeyTypePublic) |
584 |
|
|
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; |
585 |
|
|
return EC_Raw_Export(key_data.get(), params, out); |
586 |
|
|
case kWebCryptoKeyFormatPKCS8: |
587 |
✗✓ |
33 |
if (key_data->GetKeyType() != kKeyTypePrivate) |
588 |
|
|
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; |
589 |
|
33 |
return PKEY_PKCS8_Export(key_data.get(), out); |
590 |
|
|
case kWebCryptoKeyFormatSPKI: |
591 |
✗✓ |
37 |
if (key_data->GetKeyType() != kKeyTypePublic) |
592 |
|
|
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; |
593 |
|
37 |
return PKEY_SPKI_Export(key_data.get(), out); |
594 |
|
|
default: |
595 |
|
|
UNREACHABLE(); |
596 |
|
|
} |
597 |
|
|
} |
598 |
|
|
|
599 |
|
70 |
Maybe<bool> ExportJWKEcKey( |
600 |
|
|
Environment* env, |
601 |
|
|
std::shared_ptr<KeyObjectData> key, |
602 |
|
|
Local<Object> target) { |
603 |
|
140 |
ManagedEVPPKey pkey = key->GetAsymmetricKey(); |
604 |
✗✓ |
70 |
CHECK_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_EC); |
605 |
|
|
|
606 |
|
70 |
EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey.get()); |
607 |
✗✓ |
70 |
CHECK_NOT_NULL(ec); |
608 |
|
|
|
609 |
|
70 |
const EC_POINT* pub = EC_KEY_get0_public_key(ec); |
610 |
|
70 |
const EC_GROUP* group = EC_KEY_get0_group(ec); |
611 |
|
|
|
612 |
|
70 |
int degree_bits = EC_GROUP_get_degree(group); |
613 |
|
|
int degree_bytes = |
614 |
|
70 |
(degree_bits / CHAR_BIT) + (7 + (degree_bits % CHAR_BIT)) / 8; |
615 |
|
|
|
616 |
|
140 |
BignumPointer x(BN_new()); |
617 |
|
140 |
BignumPointer y(BN_new()); |
618 |
|
|
|
619 |
|
70 |
EC_POINT_get_affine_coordinates(group, pub, x.get(), y.get(), nullptr); |
620 |
|
|
|
621 |
✗✓ |
210 |
if (target->Set( |
622 |
|
|
env->context(), |
623 |
|
|
env->jwk_kty_string(), |
624 |
|
350 |
env->jwk_ec_string()).IsNothing()) { |
625 |
|
|
return Nothing<bool>(); |
626 |
|
|
} |
627 |
|
|
|
628 |
✗✓ |
210 |
if (SetEncodedValue( |
629 |
|
|
env, |
630 |
|
|
target, |
631 |
|
|
env->jwk_x_string(), |
632 |
|
70 |
x.get(), |
633 |
✓✗✗✓
|
210 |
degree_bytes).IsNothing() || |
634 |
|
140 |
SetEncodedValue( |
635 |
|
|
env, |
636 |
|
|
target, |
637 |
|
|
env->jwk_y_string(), |
638 |
|
70 |
y.get(), |
639 |
|
140 |
degree_bytes).IsNothing()) { |
640 |
|
|
return Nothing<bool>(); |
641 |
|
|
} |
642 |
|
|
|
643 |
✓✓ |
70 |
if (key->GetKeyType() == kKeyTypePrivate) { |
644 |
|
33 |
const BIGNUM* pvt = EC_KEY_get0_private_key(ec); |
645 |
|
|
return SetEncodedValue( |
646 |
|
|
env, |
647 |
|
|
target, |
648 |
|
|
env->jwk_d_string(), |
649 |
|
|
pvt, |
650 |
|
33 |
degree_bytes); |
651 |
|
|
} |
652 |
|
|
|
653 |
|
37 |
return Just(true); |
654 |
|
|
} |
655 |
|
|
|
656 |
|
68 |
std::shared_ptr<KeyObjectData> ImportJWKEcKey( |
657 |
|
|
Environment* env, |
658 |
|
|
Local<Object> jwk, |
659 |
|
|
const FunctionCallbackInfo<Value>& args, |
660 |
|
|
unsigned int offset) { |
661 |
✗✓ |
272 |
CHECK(args[offset]->IsString()); // curve name |
662 |
|
272 |
Utf8Value curve(env->isolate(), args[offset].As<String>()); |
663 |
|
|
|
664 |
|
68 |
int nid = GetCurveFromName(*curve); |
665 |
✗✓ |
68 |
if (nid == NID_undef) { // Unknown curve |
666 |
|
|
THROW_ERR_CRYPTO_INVALID_CURVE(env); |
667 |
|
|
return std::shared_ptr<KeyObjectData>(); |
668 |
|
|
} |
669 |
|
|
|
670 |
|
|
Local<Value> x_value; |
671 |
|
|
Local<Value> y_value; |
672 |
|
|
Local<Value> d_value; |
673 |
|
|
|
674 |
✓✗✗✓
|
476 |
if (!jwk->Get(env->context(), env->jwk_x_string()).ToLocal(&x_value) || |
675 |
✓✗✗✓
|
408 |
!jwk->Get(env->context(), env->jwk_y_string()).ToLocal(&y_value) || |
676 |
|
340 |
!jwk->Get(env->context(), env->jwk_d_string()).ToLocal(&d_value)) { |
677 |
|
|
return std::shared_ptr<KeyObjectData>(); |
678 |
|
|
} |
679 |
|
|
|
680 |
✓✗✗✓
|
272 |
if (!x_value->IsString() || |
681 |
✓✗✓✓
|
272 |
!y_value->IsString() || |
682 |
✗✓ |
202 |
(!d_value->IsUndefined() && !d_value->IsString())) { |
683 |
|
|
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JSK EC key"); |
684 |
|
|
return std::shared_ptr<KeyObjectData>(); |
685 |
|
|
} |
686 |
|
|
|
687 |
✓✓ |
136 |
KeyType type = d_value->IsString() ? kKeyTypePrivate : kKeyTypePublic; |
688 |
|
|
|
689 |
|
136 |
ECKeyPointer ec(EC_KEY_new_by_curve_name(nid)); |
690 |
✗✓ |
68 |
if (!ec) { |
691 |
|
|
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JSK EC key"); |
692 |
|
|
return std::shared_ptr<KeyObjectData>(); |
693 |
|
|
} |
694 |
|
|
|
695 |
|
136 |
ByteSource x = ByteSource::FromEncodedString(env, x_value.As<String>()); |
696 |
|
136 |
ByteSource y = ByteSource::FromEncodedString(env, y_value.As<String>()); |
697 |
|
|
|
698 |
✗✓ |
204 |
if (!EC_KEY_set_public_key_affine_coordinates( |
699 |
|
|
ec.get(), |
700 |
|
136 |
x.ToBN().get(), |
701 |
|
136 |
y.ToBN().get())) { |
702 |
|
|
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JSK EC key"); |
703 |
|
|
return std::shared_ptr<KeyObjectData>(); |
704 |
|
|
} |
705 |
|
|
|
706 |
✓✓ |
68 |
if (type == kKeyTypePrivate) { |
707 |
|
66 |
ByteSource d = ByteSource::FromEncodedString(env, d_value.As<String>()); |
708 |
✗✓ |
33 |
if (!EC_KEY_set_private_key(ec.get(), d.ToBN().get())) { |
709 |
|
|
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JSK EC key"); |
710 |
|
|
return std::shared_ptr<KeyObjectData>(); |
711 |
|
|
} |
712 |
|
|
} |
713 |
|
|
|
714 |
|
136 |
EVPKeyPointer pkey(EVP_PKEY_new()); |
715 |
✗✓ |
68 |
CHECK_EQ(EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get()), 1); |
716 |
|
|
|
717 |
|
68 |
return KeyObjectData::CreateAsymmetric(type, ManagedEVPPKey(std::move(pkey))); |
718 |
|
|
} |
719 |
|
|
|
720 |
|
170 |
Maybe<bool> GetEcKeyDetail( |
721 |
|
|
Environment* env, |
722 |
|
|
std::shared_ptr<KeyObjectData> key, |
723 |
|
|
Local<Object> target) { |
724 |
|
340 |
ManagedEVPPKey pkey = key->GetAsymmetricKey(); |
725 |
✗✓ |
170 |
CHECK_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_EC); |
726 |
|
|
|
727 |
|
170 |
EC_KEY* ec = EVP_PKEY_get0_EC_KEY(pkey.get()); |
728 |
✗✓ |
170 |
CHECK_NOT_NULL(ec); |
729 |
|
|
|
730 |
|
170 |
const EC_GROUP* group = EC_KEY_get0_group(ec); |
731 |
|
170 |
int nid = EC_GROUP_get_curve_name(group); |
732 |
|
|
|
733 |
|
|
return target->Set( |
734 |
|
|
env->context(), |
735 |
|
|
env->named_curve_string(), |
736 |
|
850 |
OneByteString(env->isolate(), OBJ_nid2sn(nid))); |
737 |
|
|
} |
738 |
|
|
|
739 |
|
|
// WebCrypto requires a different format for ECDSA signatures than |
740 |
|
|
// what OpenSSL produces, so we need to convert between them. The |
741 |
|
|
// implementation here is a adapted from Chromium's impl here: |
742 |
|
|
// https://github.com/chromium/chromium/blob/7af6cfd/components/webcrypto/algorithms/ecdsa.cc |
743 |
|
|
|
744 |
|
82 |
size_t GroupOrderSize(ManagedEVPPKey key) { |
745 |
|
82 |
EC_KEY* ec = EVP_PKEY_get0_EC_KEY(key.get()); |
746 |
✗✓ |
82 |
CHECK_NOT_NULL(ec); |
747 |
|
82 |
const EC_GROUP* group = EC_KEY_get0_group(ec); |
748 |
|
164 |
BignumPointer order(BN_new()); |
749 |
✗✓ |
82 |
CHECK(EC_GROUP_get_order(group, order.get(), nullptr)); |
750 |
|
164 |
return BN_num_bytes(order.get()); |
751 |
|
|
} |
752 |
|
|
|
753 |
|
17 |
ByteSource ConvertToWebCryptoSignature( |
754 |
|
|
ManagedEVPPKey key, |
755 |
|
|
const ByteSource& signature) { |
756 |
|
|
const unsigned char* data = |
757 |
|
17 |
reinterpret_cast<const unsigned char*>(signature.get()); |
758 |
|
34 |
EcdsaSigPointer ecsig(d2i_ECDSA_SIG(nullptr, &data, signature.size())); |
759 |
|
|
|
760 |
✗✓ |
17 |
if (!ecsig) |
761 |
|
|
return ByteSource(); |
762 |
|
|
|
763 |
|
17 |
size_t order_size_bytes = GroupOrderSize(key); |
764 |
|
17 |
char* outdata = MallocOpenSSL<char>(order_size_bytes * 2); |
765 |
|
34 |
ByteSource out = ByteSource::Allocated(outdata, order_size_bytes * 2); |
766 |
|
17 |
unsigned char* ptr = reinterpret_cast<unsigned char*>(outdata); |
767 |
|
|
|
768 |
|
|
const BIGNUM* pr; |
769 |
|
|
const BIGNUM* ps; |
770 |
|
17 |
ECDSA_SIG_get0(ecsig.get(), &pr, &ps); |
771 |
|
|
|
772 |
✓✗✗✓ ✗✓ |
34 |
if (!BN_bn2binpad(pr, ptr, order_size_bytes) || |
773 |
|
17 |
!BN_bn2binpad(ps, ptr + order_size_bytes, order_size_bytes)) { |
774 |
|
|
return ByteSource(); |
775 |
|
|
} |
776 |
|
17 |
return out; |
777 |
|
|
} |
778 |
|
|
|
779 |
|
65 |
ByteSource ConvertFromWebCryptoSignature( |
780 |
|
|
ManagedEVPPKey key, |
781 |
|
|
const ByteSource& signature) { |
782 |
|
65 |
size_t order_size_bytes = GroupOrderSize(key); |
783 |
|
|
|
784 |
|
|
// If the size of the signature is incorrect, verification |
785 |
|
|
// will fail. |
786 |
✓✓ |
65 |
if (signature.size() != 2 * order_size_bytes) |
787 |
|
8 |
return ByteSource(); // Empty! |
788 |
|
|
|
789 |
|
114 |
EcdsaSigPointer ecsig(ECDSA_SIG_new()); |
790 |
✗✓ |
57 |
if (!ecsig) |
791 |
|
|
return ByteSource(); |
792 |
|
|
|
793 |
|
114 |
BignumPointer r(BN_new()); |
794 |
|
114 |
BignumPointer s(BN_new()); |
795 |
|
|
|
796 |
|
57 |
const unsigned char* sig = signature.data<unsigned char>(); |
797 |
|
|
|
798 |
✓✗✗✓
|
171 |
if (!BN_bin2bn(sig, order_size_bytes, r.get()) || |
799 |
✓✗✗✓
|
114 |
!BN_bin2bn(sig + order_size_bytes, order_size_bytes, s.get()) || |
800 |
|
57 |
!ECDSA_SIG_set0(ecsig.get(), r.release(), s.release())) { |
801 |
|
|
return ByteSource(); |
802 |
|
|
} |
803 |
|
|
|
804 |
|
57 |
int size = i2d_ECDSA_SIG(ecsig.get(), nullptr); |
805 |
|
57 |
char* data = MallocOpenSSL<char>(size); |
806 |
|
57 |
unsigned char* ptr = reinterpret_cast<unsigned char*>(data); |
807 |
✗✓ |
57 |
CHECK_EQ(i2d_ECDSA_SIG(ecsig.get(), &ptr), size); |
808 |
|
57 |
return ByteSource::Allocated(data, size); |
809 |
|
|
} |
810 |
|
|
|
811 |
|
|
} // namespace crypto |
812 |
✓✗✓✗
|
14034 |
} // namespace node |