GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
#include "crypto/crypto_keys.h" |
||
2 |
#include "crypto/crypto_common.h" |
||
3 |
#include "crypto/crypto_dsa.h" |
||
4 |
#include "crypto/crypto_ec.h" |
||
5 |
#include "crypto/crypto_dh.h" |
||
6 |
#include "crypto/crypto_rsa.h" |
||
7 |
#include "crypto/crypto_util.h" |
||
8 |
#include "async_wrap-inl.h" |
||
9 |
#include "base_object-inl.h" |
||
10 |
#include "env-inl.h" |
||
11 |
#include "memory_tracker-inl.h" |
||
12 |
#include "node.h" |
||
13 |
#include "node_buffer.h" |
||
14 |
#include "string_bytes.h" |
||
15 |
#include "threadpoolwork-inl.h" |
||
16 |
#include "util-inl.h" |
||
17 |
#include "v8.h" |
||
18 |
|||
19 |
namespace node { |
||
20 |
|||
21 |
using v8::Array; |
||
22 |
using v8::Context; |
||
23 |
using v8::Function; |
||
24 |
using v8::FunctionCallbackInfo; |
||
25 |
using v8::FunctionTemplate; |
||
26 |
using v8::Int32; |
||
27 |
using v8::Isolate; |
||
28 |
using v8::Just; |
||
29 |
using v8::Local; |
||
30 |
using v8::Maybe; |
||
31 |
using v8::MaybeLocal; |
||
32 |
using v8::NewStringType; |
||
33 |
using v8::Nothing; |
||
34 |
using v8::Number; |
||
35 |
using v8::Object; |
||
36 |
using v8::String; |
||
37 |
using v8::Uint32; |
||
38 |
using v8::Undefined; |
||
39 |
using v8::Value; |
||
40 |
|||
41 |
namespace crypto { |
||
42 |
namespace { |
||
43 |
5050 |
void GetKeyFormatAndTypeFromJs( |
|
44 |
AsymmetricKeyEncodingConfig* config, |
||
45 |
const FunctionCallbackInfo<Value>& args, |
||
46 |
unsigned int* offset, |
||
47 |
KeyEncodingContext context) { |
||
48 |
// During key pair generation, it is possible not to specify a key encoding, |
||
49 |
// which will lead to a key object being returned. |
||
50 |
✓✗✓✓ |
15150 |
if (args[*offset]->IsUndefined()) { |
51 |
✗✓ | 1488 |
CHECK_EQ(context, kKeyContextGenerate); |
52 |
✓✗✗✓ |
4464 |
CHECK(args[*offset + 1]->IsUndefined()); |
53 |
1488 |
config->output_key_object_ = true; |
|
54 |
} else { |
||
55 |
3562 |
config->output_key_object_ = false; |
|
56 |
|||
57 |
✓✗✗✓ |
7124 |
CHECK(args[*offset]->IsInt32()); |
58 |
3562 |
config->format_ = static_cast<PKFormatType>( |
|
59 |
✓✗ | 10686 |
args[*offset].As<Int32>()->Value()); |
60 |
|||
61 |
✓✗✓✓ |
7124 |
if (args[*offset + 1]->IsInt32()) { |
62 |
4138 |
config->type_ = Just<PKEncodingType>(static_cast<PKEncodingType>( |
|
63 |
✓✗ | 6207 |
args[*offset + 1].As<Int32>()->Value())); |
64 |
} else { |
||
65 |
✓✓✗✓ ✓✓✓✗ ✗✓✗✓ |
1493 |
CHECK( |
66 |
(context == kKeyContextInput && |
||
67 |
config->format_ == kKeyFormatPEM) || |
||
68 |
(context == kKeyContextGenerate && |
||
69 |
config->format_ == kKeyFormatJWK)); |
||
70 |
✓✗✗✓ |
4479 |
CHECK(args[*offset + 1]->IsNullOrUndefined()); |
71 |
1493 |
config->type_ = Nothing<PKEncodingType>(); |
|
72 |
} |
||
73 |
} |
||
74 |
|||
75 |
5050 |
*offset += 2; |
|
76 |
5050 |
} |
|
77 |
|||
78 |
3238 |
ParseKeyResult TryParsePublicKey( |
|
79 |
EVPKeyPointer* pkey, |
||
80 |
const BIOPointer& bp, |
||
81 |
const char* name, |
||
82 |
// NOLINTNEXTLINE(runtime/int) |
||
83 |
const std::function<EVP_PKEY*(const unsigned char** p, long l)>& parse) { |
||
84 |
unsigned char* der_data; |
||
85 |
long der_len; // NOLINT(runtime/int) |
||
86 |
|||
87 |
// This skips surrounding data and decodes PEM to DER. |
||
88 |
{ |
||
89 |
3238 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
|
90 |
3238 |
if (PEM_bytes_read_bio(&der_data, &der_len, nullptr, name, |
|
91 |
✓✓ | 3238 |
bp.get(), nullptr, nullptr) != 1) |
92 |
2271 |
return ParseKeyResult::kParseKeyNotRecognized; |
|
93 |
} |
||
94 |
|||
95 |
// OpenSSL might modify the pointer, so we need to make a copy before parsing. |
||
96 |
967 |
const unsigned char* p = der_data; |
|
97 |
967 |
pkey->reset(parse(&p, der_len)); |
|
98 |
967 |
OPENSSL_clear_free(der_data, der_len); |
|
99 |
|||
100 |
✓✗ | 967 |
return *pkey ? ParseKeyResult::kParseKeyOk : |
101 |
1934 |
ParseKeyResult::kParseKeyFailed; |
|
102 |
} |
||
103 |
|||
104 |
1229 |
ParseKeyResult ParsePublicKeyPEM(EVPKeyPointer* pkey, |
|
105 |
const char* key_pem, |
||
106 |
int key_pem_len) { |
||
107 |
2458 |
BIOPointer bp(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len)); |
|
108 |
✗✓ | 1229 |
if (!bp) |
109 |
return ParseKeyResult::kParseKeyFailed; |
||
110 |
|||
111 |
ParseKeyResult ret; |
||
112 |
|||
113 |
// Try parsing as a SubjectPublicKeyInfo first. |
||
114 |
1229 |
ret = TryParsePublicKey(pkey, bp, "PUBLIC KEY", |
|
115 |
217 |
[](const unsigned char** p, long l) { // NOLINT(runtime/int) |
|
116 |
217 |
return d2i_PUBKEY(nullptr, p, l); |
|
117 |
}); |
||
118 |
✓✓ | 1229 |
if (ret != ParseKeyResult::kParseKeyNotRecognized) |
119 |
217 |
return ret; |
|
120 |
|||
121 |
// Maybe it is PKCS#1. |
||
122 |
✗✓ | 1012 |
CHECK(BIO_reset(bp.get())); |
123 |
1012 |
ret = TryParsePublicKey(pkey, bp, "RSA PUBLIC KEY", |
|
124 |
15 |
[](const unsigned char** p, long l) { // NOLINT(runtime/int) |
|
125 |
15 |
return d2i_PublicKey(EVP_PKEY_RSA, nullptr, p, l); |
|
126 |
}); |
||
127 |
✓✓ | 1012 |
if (ret != ParseKeyResult::kParseKeyNotRecognized) |
128 |
15 |
return ret; |
|
129 |
|||
130 |
// X.509 fallback. |
||
131 |
✗✓ | 997 |
CHECK(BIO_reset(bp.get())); |
132 |
1994 |
return TryParsePublicKey(pkey, bp, "CERTIFICATE", |
|
133 |
735 |
[](const unsigned char** p, long l) { // NOLINT(runtime/int) |
|
134 |
735 |
X509Pointer x509(d2i_X509(nullptr, p, l)); |
|
135 |
✓✗ | 735 |
return x509 ? X509_get_pubkey(x509.get()) : nullptr; |
136 |
997 |
}); |
|
137 |
} |
||
138 |
|||
139 |
932 |
ParseKeyResult ParsePublicKey(EVPKeyPointer* pkey, |
|
140 |
const PublicKeyEncodingConfig& config, |
||
141 |
const char* key, |
||
142 |
size_t key_len) { |
||
143 |
✗✓ | 932 |
if (config.format_ == kKeyFormatPEM) { |
144 |
return ParsePublicKeyPEM(pkey, key, key_len); |
||
145 |
} else { |
||
146 |
✗✓ | 932 |
CHECK_EQ(config.format_, kKeyFormatDER); |
147 |
|||
148 |
932 |
const unsigned char* p = reinterpret_cast<const unsigned char*>(key); |
|
149 |
✓✓ | 1864 |
if (config.type_.ToChecked() == kKeyEncodingPKCS1) { |
150 |
22 |
pkey->reset(d2i_PublicKey(EVP_PKEY_RSA, nullptr, &p, key_len)); |
|
151 |
} else { |
||
152 |
✗✓ | 1820 |
CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSPKI); |
153 |
910 |
pkey->reset(d2i_PUBKEY(nullptr, &p, key_len)); |
|
154 |
} |
||
155 |
|||
156 |
✓✗ | 932 |
return *pkey ? ParseKeyResult::kParseKeyOk : |
157 |
1864 |
ParseKeyResult::kParseKeyFailed; |
|
158 |
} |
||
159 |
} |
||
160 |
|||
161 |
1021 |
bool IsASN1Sequence(const unsigned char* data, size_t size, |
|
162 |
size_t* data_offset, size_t* data_size) { |
||
163 |
✓✗✗✓ |
1021 |
if (size < 2 || data[0] != 0x30) |
164 |
return false; |
||
165 |
|||
166 |
✓✓ | 1021 |
if (data[1] & 0x80) { |
167 |
// Long form. |
||
168 |
930 |
size_t n_bytes = data[1] & ~0x80; |
|
169 |
✓✗✗✓ |
930 |
if (n_bytes + 2 > size || n_bytes > sizeof(size_t)) |
170 |
return false; |
||
171 |
930 |
size_t length = 0; |
|
172 |
✓✓ | 2528 |
for (size_t i = 0; i < n_bytes; i++) |
173 |
1598 |
length = (length << 8) | data[i + 2]; |
|
174 |
930 |
*data_offset = 2 + n_bytes; |
|
175 |
930 |
*data_size = std::min(size - 2 - n_bytes, length); |
|
176 |
} else { |
||
177 |
// Short form. |
||
178 |
91 |
*data_offset = 2; |
|
179 |
91 |
*data_size = std::min<size_t>(size - 2, data[1]); |
|
180 |
} |
||
181 |
|||
182 |
1021 |
return true; |
|
183 |
} |
||
184 |
|||
185 |
34 |
bool IsRSAPrivateKey(const unsigned char* data, size_t size) { |
|
186 |
// Both RSAPrivateKey and RSAPublicKey structures start with a SEQUENCE. |
||
187 |
size_t offset, len; |
||
188 |
✗✓ | 34 |
if (!IsASN1Sequence(data, size, &offset, &len)) |
189 |
return false; |
||
190 |
|||
191 |
// An RSAPrivateKey sequence always starts with a single-byte integer whose |
||
192 |
// value is either 0 or 1, whereas an RSAPublicKey starts with the modulus |
||
193 |
// (which is the product of two primes and therefore at least 4), so we can |
||
194 |
// decide the type of the structure based on the first three bytes of the |
||
195 |
// sequence. |
||
196 |
68 |
return len >= 3 && |
|
197 |
✓✗ | 34 |
data[offset] == 2 && |
198 |
✓✗✓✓ |
80 |
data[offset + 1] == 1 && |
199 |
✓✗ | 46 |
!(data[offset + 2] & 0xfe); |
200 |
} |
||
201 |
|||
202 |
987 |
bool IsEncryptedPrivateKeyInfo(const unsigned char* data, size_t size) { |
|
203 |
// Both PrivateKeyInfo and EncryptedPrivateKeyInfo start with a SEQUENCE. |
||
204 |
size_t offset, len; |
||
205 |
✗✓ | 987 |
if (!IsASN1Sequence(data, size, &offset, &len)) |
206 |
return false; |
||
207 |
|||
208 |
// A PrivateKeyInfo sequence always starts with an integer whereas an |
||
209 |
// EncryptedPrivateKeyInfo starts with an AlgorithmIdentifier. |
||
210 |
✓✗ | 1974 |
return len >= 1 && |
211 |
✓✓ | 1974 |
data[offset] != 2; |
212 |
} |
||
213 |
|||
214 |
1504 |
ParseKeyResult ParsePrivateKey(EVPKeyPointer* pkey, |
|
215 |
const PrivateKeyEncodingConfig& config, |
||
216 |
const char* key, |
||
217 |
size_t key_len) { |
||
218 |
1504 |
const ByteSource* passphrase = config.passphrase_.get(); |
|
219 |
|||
220 |
✓✓ | 1504 |
if (config.format_ == kKeyFormatPEM) { |
221 |
504 |
BIOPointer bio(BIO_new_mem_buf(key, key_len)); |
|
222 |
✗✓ | 504 |
if (!bio) |
223 |
return ParseKeyResult::kParseKeyFailed; |
||
224 |
|||
225 |
504 |
pkey->reset(PEM_read_bio_PrivateKey(bio.get(), |
|
226 |
nullptr, |
||
227 |
PasswordCallback, |
||
228 |
&passphrase)); |
||
229 |
} else { |
||
230 |
✗✓ | 1000 |
CHECK_EQ(config.format_, kKeyFormatDER); |
231 |
|||
232 |
✓✓ | 2000 |
if (config.type_.ToChecked() == kKeyEncodingPKCS1) { |
233 |
13 |
const unsigned char* p = reinterpret_cast<const unsigned char*>(key); |
|
234 |
13 |
pkey->reset(d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &p, key_len)); |
|
235 |
✓✗ | 1974 |
} else if (config.type_.ToChecked() == kKeyEncodingPKCS8) { |
236 |
987 |
BIOPointer bio(BIO_new_mem_buf(key, key_len)); |
|
237 |
✗✓ | 987 |
if (!bio) |
238 |
return ParseKeyResult::kParseKeyFailed; |
||
239 |
|||
240 |
✓✓ | 987 |
if (IsEncryptedPrivateKeyInfo( |
241 |
reinterpret_cast<const unsigned char*>(key), key_len)) { |
||
242 |
17 |
pkey->reset(d2i_PKCS8PrivateKey_bio(bio.get(), |
|
243 |
nullptr, |
||
244 |
PasswordCallback, |
||
245 |
&passphrase)); |
||
246 |
} else { |
||
247 |
1940 |
PKCS8Pointer p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr)); |
|
248 |
✓✗ | 970 |
if (p8inf) |
249 |
970 |
pkey->reset(EVP_PKCS82PKEY(p8inf.get())); |
|
250 |
} |
||
251 |
} else { |
||
252 |
CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSEC1); |
||
253 |
const unsigned char* p = reinterpret_cast<const unsigned char*>(key); |
||
254 |
pkey->reset(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &p, key_len)); |
||
255 |
} |
||
256 |
} |
||
257 |
|||
258 |
// OpenSSL can fail to parse the key but still return a non-null pointer. |
||
259 |
1504 |
unsigned long err = ERR_peek_error(); // NOLINT(runtime/int) |
|
260 |
✓✓ | 1504 |
if (err != 0) |
261 |
21 |
pkey->reset(); |
|
262 |
|||
263 |
✓✓ | 1504 |
if (*pkey) |
264 |
1483 |
return ParseKeyResult::kParseKeyOk; |
|
265 |
✓✓✓✗ ✓✓ |
23 |
if (ERR_GET_LIB(err) == ERR_LIB_PEM && |
266 |
2 |
ERR_GET_REASON(err) == PEM_R_BAD_PASSWORD_READ) { |
|
267 |
✓✗ | 2 |
if (config.passphrase_.IsEmpty()) |
268 |
2 |
return ParseKeyResult::kParseKeyNeedPassphrase; |
|
269 |
} |
||
270 |
19 |
return ParseKeyResult::kParseKeyFailed; |
|
271 |
} |
||
272 |
|||
273 |
130 |
MaybeLocal<Value> BIOToStringOrBuffer( |
|
274 |
Environment* env, |
||
275 |
BIO* bio, |
||
276 |
PKFormatType format) { |
||
277 |
BUF_MEM* bptr; |
||
278 |
130 |
BIO_get_mem_ptr(bio, &bptr); |
|
279 |
✓✓ | 130 |
if (format == kKeyFormatPEM) { |
280 |
// PEM is an ASCII format, so we will return it as a string. |
||
281 |
156 |
return String::NewFromUtf8(env->isolate(), bptr->data, |
|
282 |
NewStringType::kNormal, |
||
283 |
156 |
bptr->length).FromMaybe(Local<Value>()); |
|
284 |
} else { |
||
285 |
✗✓ | 52 |
CHECK_EQ(format, kKeyFormatDER); |
286 |
// DER is binary, return it as a buffer. |
||
287 |
52 |
return Buffer::Copy(env, bptr->data, bptr->length) |
|
288 |
52 |
.FromMaybe(Local<Value>()); |
|
289 |
} |
||
290 |
} |
||
291 |
|||
292 |
|||
293 |
62 |
MaybeLocal<Value> WritePrivateKey( |
|
294 |
Environment* env, |
||
295 |
EVP_PKEY* pkey, |
||
296 |
const PrivateKeyEncodingConfig& config) { |
||
297 |
124 |
BIOPointer bio(BIO_new(BIO_s_mem())); |
|
298 |
✗✓ | 62 |
CHECK(bio); |
299 |
|||
300 |
// If an empty string was passed as the passphrase, the ByteSource might |
||
301 |
// contain a null pointer, which OpenSSL will ignore, causing it to invoke its |
||
302 |
// default passphrase callback, which would block the thread until the user |
||
303 |
// manually enters a passphrase. We could supply our own passphrase callback |
||
304 |
// to handle this special case, but it is easier to avoid passing a null |
||
305 |
// pointer to OpenSSL. |
||
306 |
62 |
char* pass = nullptr; |
|
307 |
62 |
size_t pass_len = 0; |
|
308 |
✓✓ | 62 |
if (!config.passphrase_.IsEmpty()) { |
309 |
12 |
pass = const_cast<char*>(config.passphrase_->data<char>()); |
|
310 |
12 |
pass_len = config.passphrase_->size(); |
|
311 |
✓✓ | 12 |
if (pass == nullptr) { |
312 |
// OpenSSL will not actually dereference this pointer, so it can be any |
||
313 |
// non-null pointer. We cannot assert that directly, which is why we |
||
314 |
// intentionally use a pointer that will likely cause a segmentation fault |
||
315 |
// when dereferenced. |
||
316 |
✗✓ | 3 |
CHECK_EQ(pass_len, 0); |
317 |
3 |
pass = reinterpret_cast<char*>(-1); |
|
318 |
✗✓ | 3 |
CHECK_NE(pass, nullptr); |
319 |
} |
||
320 |
} |
||
321 |
|||
322 |
bool err; |
||
323 |
|||
324 |
62 |
PKEncodingType encoding_type = config.type_.ToChecked(); |
|
325 |
✓✓ | 62 |
if (encoding_type == kKeyEncodingPKCS1) { |
326 |
// PKCS#1 is only permitted for RSA keys. |
||
327 |
✗✓ | 12 |
CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_RSA); |
328 |
|||
329 |
24 |
RSAPointer rsa(EVP_PKEY_get1_RSA(pkey)); |
|
330 |
✓✓ | 12 |
if (config.format_ == kKeyFormatPEM) { |
331 |
// Encode PKCS#1 as PEM. |
||
332 |
11 |
err = PEM_write_bio_RSAPrivateKey( |
|
333 |
11 |
bio.get(), rsa.get(), |
|
334 |
11 |
config.cipher_, |
|
335 |
reinterpret_cast<unsigned char*>(pass), |
||
336 |
pass_len, |
||
337 |
nullptr, nullptr) != 1; |
||
338 |
} else { |
||
339 |
// Encode PKCS#1 as DER. This does not permit encryption. |
||
340 |
✗✓ | 1 |
CHECK_EQ(config.format_, kKeyFormatDER); |
341 |
✗✓ | 1 |
CHECK_NULL(config.cipher_); |
342 |
1 |
err = i2d_RSAPrivateKey_bio(bio.get(), rsa.get()) != 1; |
|
343 |
} |
||
344 |
✓✓ | 50 |
} else if (encoding_type == kKeyEncodingPKCS8) { |
345 |
✓✓ | 46 |
if (config.format_ == kKeyFormatPEM) { |
346 |
// Encode PKCS#8 as PEM. |
||
347 |
23 |
err = PEM_write_bio_PKCS8PrivateKey( |
|
348 |
bio.get(), pkey, |
||
349 |
23 |
config.cipher_, |
|
350 |
pass, |
||
351 |
pass_len, |
||
352 |
nullptr, nullptr) != 1; |
||
353 |
} else { |
||
354 |
// Encode PKCS#8 as DER. |
||
355 |
✗✓ | 23 |
CHECK_EQ(config.format_, kKeyFormatDER); |
356 |
23 |
err = i2d_PKCS8PrivateKey_bio( |
|
357 |
bio.get(), pkey, |
||
358 |
23 |
config.cipher_, |
|
359 |
pass, |
||
360 |
pass_len, |
||
361 |
nullptr, nullptr) != 1; |
||
362 |
} |
||
363 |
} else { |
||
364 |
✗✓ | 4 |
CHECK_EQ(encoding_type, kKeyEncodingSEC1); |
365 |
|||
366 |
// SEC1 is only permitted for EC keys. |
||
367 |
✗✓ | 4 |
CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_EC); |
368 |
|||
369 |
8 |
ECKeyPointer ec_key(EVP_PKEY_get1_EC_KEY(pkey)); |
|
370 |
✓✗ | 4 |
if (config.format_ == kKeyFormatPEM) { |
371 |
// Encode SEC1 as PEM. |
||
372 |
4 |
err = PEM_write_bio_ECPrivateKey( |
|
373 |
4 |
bio.get(), ec_key.get(), |
|
374 |
4 |
config.cipher_, |
|
375 |
reinterpret_cast<unsigned char*>(pass), |
||
376 |
pass_len, |
||
377 |
nullptr, nullptr) != 1; |
||
378 |
} else { |
||
379 |
// Encode SEC1 as DER. This does not permit encryption. |
||
380 |
CHECK_EQ(config.format_, kKeyFormatDER); |
||
381 |
CHECK_NULL(config.cipher_); |
||
382 |
err = i2d_ECPrivateKey_bio(bio.get(), ec_key.get()) != 1; |
||
383 |
} |
||
384 |
} |
||
385 |
|||
386 |
✗✓ | 62 |
if (err) { |
387 |
ThrowCryptoError(env, ERR_get_error(), "Failed to encode private key"); |
||
388 |
return MaybeLocal<Value>(); |
||
389 |
} |
||
390 |
62 |
return BIOToStringOrBuffer(env, bio.get(), config.format_); |
|
391 |
} |
||
392 |
|||
393 |
72 |
bool WritePublicKeyInner(EVP_PKEY* pkey, |
|
394 |
const BIOPointer& bio, |
||
395 |
const PublicKeyEncodingConfig& config) { |
||
396 |
✓✓ | 144 |
if (config.type_.ToChecked() == kKeyEncodingPKCS1) { |
397 |
// PKCS#1 is only valid for RSA keys. |
||
398 |
✗✓ | 13 |
CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_RSA); |
399 |
26 |
RSAPointer rsa(EVP_PKEY_get1_RSA(pkey)); |
|
400 |
✓✓ | 13 |
if (config.format_ == kKeyFormatPEM) { |
401 |
// Encode PKCS#1 as PEM. |
||
402 |
7 |
return PEM_write_bio_RSAPublicKey(bio.get(), rsa.get()) == 1; |
|
403 |
} else { |
||
404 |
// Encode PKCS#1 as DER. |
||
405 |
✗✓ | 6 |
CHECK_EQ(config.format_, kKeyFormatDER); |
406 |
6 |
return i2d_RSAPublicKey_bio(bio.get(), rsa.get()) == 1; |
|
407 |
} |
||
408 |
} else { |
||
409 |
✗✓ | 118 |
CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSPKI); |
410 |
✓✓ | 59 |
if (config.format_ == kKeyFormatPEM) { |
411 |
// Encode SPKI as PEM. |
||
412 |
33 |
return PEM_write_bio_PUBKEY(bio.get(), pkey) == 1; |
|
413 |
} else { |
||
414 |
// Encode SPKI as DER. |
||
415 |
✗✓ | 26 |
CHECK_EQ(config.format_, kKeyFormatDER); |
416 |
26 |
return i2d_PUBKEY_bio(bio.get(), pkey) == 1; |
|
417 |
} |
||
418 |
} |
||
419 |
} |
||
420 |
|||
421 |
72 |
MaybeLocal<Value> WritePublicKey(Environment* env, |
|
422 |
EVP_PKEY* pkey, |
||
423 |
const PublicKeyEncodingConfig& config) { |
||
424 |
144 |
BIOPointer bio(BIO_new(BIO_s_mem())); |
|
425 |
✗✓ | 72 |
CHECK(bio); |
426 |
|||
427 |
✓✓ | 72 |
if (!WritePublicKeyInner(pkey, bio, config)) { |
428 |
4 |
ThrowCryptoError(env, ERR_get_error(), "Failed to encode public key"); |
|
429 |
4 |
return MaybeLocal<Value>(); |
|
430 |
} |
||
431 |
68 |
return BIOToStringOrBuffer(env, bio.get(), config.format_); |
|
432 |
} |
||
433 |
|||
434 |
291 |
Maybe<bool> ExportJWKSecretKey( |
|
435 |
Environment* env, |
||
436 |
std::shared_ptr<KeyObjectData> key, |
||
437 |
Local<Object> target) { |
||
438 |
✗✓ | 291 |
CHECK_EQ(key->GetKeyType(), kKeyTypeSecret); |
439 |
|||
440 |
Local<Value> error; |
||
441 |
Local<Value> raw; |
||
442 |
MaybeLocal<Value> key_data = |
||
443 |
StringBytes::Encode( |
||
444 |
env->isolate(), |
||
445 |
key->GetSymmetricKey(), |
||
446 |
key->GetSymmetricKeySize(), |
||
447 |
BASE64URL, |
||
448 |
291 |
&error); |
|
449 |
✗✓ | 291 |
if (key_data.IsEmpty()) { |
450 |
CHECK(!error.IsEmpty()); |
||
451 |
env->isolate()->ThrowException(error); |
||
452 |
return Nothing<bool>(); |
||
453 |
} |
||
454 |
✗✓ | 291 |
if (!key_data.ToLocal(&raw)) |
455 |
return Nothing<bool>(); |
||
456 |
|||
457 |
582 |
if (target->Set( |
|
458 |
env->context(), |
||
459 |
env->jwk_kty_string(), |
||
460 |
✓✗ | 1455 |
env->jwk_oct_string()).IsNothing() || |
461 |
291 |
target->Set( |
|
462 |
env->context(), |
||
463 |
env->jwk_k_string(), |
||
464 |
✗✓✗✓ |
1164 |
raw).IsNothing()) { |
465 |
return Nothing<bool>(); |
||
466 |
} |
||
467 |
|||
468 |
291 |
return Just(true); |
|
469 |
} |
||
470 |
|||
471 |
270 |
std::shared_ptr<KeyObjectData> ImportJWKSecretKey( |
|
472 |
Environment* env, |
||
473 |
Local<Object> jwk) { |
||
474 |
Local<Value> key; |
||
475 |
✓✗✗✓ |
1080 |
if (!jwk->Get(env->context(), env->jwk_k_string()).ToLocal(&key) || |
476 |
✗✓ | 540 |
!key->IsString()) { |
477 |
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK secret key format"); |
||
478 |
return std::shared_ptr<KeyObjectData>(); |
||
479 |
} |
||
480 |
|||
481 |
540 |
ByteSource key_data = ByteSource::FromEncodedString(env, key.As<String>()); |
|
482 |
✗✓ | 270 |
if (key_data.size() > INT_MAX) { |
483 |
THROW_ERR_CRYPTO_INVALID_KEYLEN(env); |
||
484 |
return std::shared_ptr<KeyObjectData>(); |
||
485 |
} |
||
486 |
|||
487 |
270 |
return KeyObjectData::CreateSecret(std::move(key_data)); |
|
488 |
} |
||
489 |
|||
490 |
662 |
Maybe<bool> ExportJWKAsymmetricKey( |
|
491 |
Environment* env, |
||
492 |
std::shared_ptr<KeyObjectData> key, |
||
493 |
Local<Object> target, |
||
494 |
bool handleRsaPss) { |
||
495 |
✓✓✓✓ ✓ |
662 |
switch (EVP_PKEY_id(key->GetAsymmetricKey().get())) { |
496 |
2 |
case EVP_PKEY_RSA_PSS: { |
|
497 |
✗✓ | 2 |
if (handleRsaPss) return ExportJWKRsaKey(env, key, target); |
498 |
2 |
break; |
|
499 |
} |
||
500 |
409 |
case EVP_PKEY_RSA: return ExportJWKRsaKey(env, key, target); |
|
501 |
398 |
case EVP_PKEY_EC: return ExportJWKEcKey(env, key, target).IsJust() ? |
|
502 |
✓✓ | 199 |
Just(true) : Nothing<bool>(); |
503 |
48 |
case EVP_PKEY_ED25519: |
|
504 |
// Fall through |
||
505 |
case EVP_PKEY_ED448: |
||
506 |
// Fall through |
||
507 |
case EVP_PKEY_X25519: |
||
508 |
// Fall through |
||
509 |
48 |
case EVP_PKEY_X448: return ExportJWKEdKey(env, key, target); |
|
510 |
} |
||
511 |
6 |
THROW_ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE(env); |
|
512 |
6 |
return Just(false); |
|
513 |
} |
||
514 |
|||
515 |
658 |
std::shared_ptr<KeyObjectData> ImportJWKAsymmetricKey( |
|
516 |
Environment* env, |
||
517 |
Local<Object> jwk, |
||
518 |
const char* kty, |
||
519 |
const FunctionCallbackInfo<Value>& args, |
||
520 |
unsigned int offset) { |
||
521 |
✓✓ | 658 |
if (strcmp(kty, "RSA") == 0) { |
522 |
502 |
return ImportJWKRsaKey(env, jwk, args, offset); |
|
523 |
✓✗ | 156 |
} else if (strcmp(kty, "EC") == 0) { |
524 |
156 |
return ImportJWKEcKey(env, jwk, args, offset); |
|
525 |
} |
||
526 |
|||
527 |
THROW_ERR_CRYPTO_INVALID_JWK(env, "%s is not a supported JWK key type", kty); |
||
528 |
return std::shared_ptr<KeyObjectData>(); |
||
529 |
} |
||
530 |
|||
531 |
4015 |
Maybe<bool> GetSecretKeyDetail( |
|
532 |
Environment* env, |
||
533 |
std::shared_ptr<KeyObjectData> key, |
||
534 |
Local<Object> target) { |
||
535 |
// For the secret key detail, all we care about is the length, |
||
536 |
// converted to bits. |
||
537 |
|||
538 |
4015 |
size_t length = key->GetSymmetricKeySize() * CHAR_BIT; |
|
539 |
return target->Set(env->context(), |
||
540 |
env->length_string(), |
||
541 |
12045 |
Number::New(env->isolate(), static_cast<double>(length))); |
|
542 |
} |
||
543 |
|||
544 |
2355 |
Maybe<bool> GetAsymmetricKeyDetail( |
|
545 |
Environment* env, |
||
546 |
std::shared_ptr<KeyObjectData> key, |
||
547 |
Local<Object> target) { |
||
548 |
✓✓✓✗ ✗ |
2355 |
switch (EVP_PKEY_id(key->GetAsymmetricKey().get())) { |
549 |
1697 |
case EVP_PKEY_RSA: |
|
550 |
// Fall through |
||
551 |
1697 |
case EVP_PKEY_RSA_PSS: return GetRsaKeyDetail(env, key, target); |
|
552 |
2 |
case EVP_PKEY_DSA: return GetDsaKeyDetail(env, key, target); |
|
553 |
656 |
case EVP_PKEY_EC: return GetEcKeyDetail(env, key, target); |
|
554 |
case EVP_PKEY_DH: return GetDhKeyDetail(env, key, target); |
||
555 |
} |
||
556 |
THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); |
||
557 |
return Nothing<bool>(); |
||
558 |
} |
||
559 |
} // namespace |
||
560 |
|||
561 |
9646 |
ManagedEVPPKey::ManagedEVPPKey(EVPKeyPointer&& pkey) : pkey_(std::move(pkey)), |
|
562 |
4823 |
mutex_(std::make_shared<Mutex>()) {} |
|
563 |
|||
564 |
19534 |
ManagedEVPPKey::ManagedEVPPKey(const ManagedEVPPKey& that) { |
|
565 |
19534 |
*this = that; |
|
566 |
19534 |
} |
|
567 |
|||
568 |
25087 |
ManagedEVPPKey& ManagedEVPPKey::operator=(const ManagedEVPPKey& that) { |
|
569 |
25087 |
Mutex::ScopedLock lock(*that.mutex_); |
|
570 |
|||
571 |
25087 |
pkey_.reset(that.get()); |
|
572 |
|||
573 |
✓✓ | 25087 |
if (pkey_) |
574 |
24296 |
EVP_PKEY_up_ref(pkey_.get()); |
|
575 |
|||
576 |
25087 |
mutex_ = that.mutex_; |
|
577 |
|||
578 |
25087 |
return *this; |
|
579 |
} |
||
580 |
|||
581 |
9543 |
ManagedEVPPKey::operator bool() const { |
|
582 |
9543 |
return !!pkey_; |
|
583 |
} |
||
584 |
|||
585 |
48579 |
EVP_PKEY* ManagedEVPPKey::get() const { |
|
586 |
48579 |
return pkey_.get(); |
|
587 |
} |
||
588 |
|||
589 |
6819 |
Mutex* ManagedEVPPKey::mutex() const { |
|
590 |
6819 |
return mutex_.get(); |
|
591 |
} |
||
592 |
|||
593 |
void ManagedEVPPKey::MemoryInfo(MemoryTracker* tracker) const { |
||
594 |
tracker->TrackFieldWithSize("pkey", |
||
595 |
!pkey_ ? 0 : kSizeOf_EVP_PKEY + |
||
596 |
size_of_private_key() + |
||
597 |
size_of_public_key()); |
||
598 |
} |
||
599 |
|||
600 |
size_t ManagedEVPPKey::size_of_private_key() const { |
||
601 |
size_t len = 0; |
||
602 |
return (pkey_ && EVP_PKEY_get_raw_private_key( |
||
603 |
pkey_.get(), nullptr, &len) == 1) ? len : 0; |
||
604 |
} |
||
605 |
|||
606 |
size_t ManagedEVPPKey::size_of_public_key() const { |
||
607 |
size_t len = 0; |
||
608 |
return (pkey_ && EVP_PKEY_get_raw_public_key( |
||
609 |
pkey_.get(), nullptr, &len) == 1) ? len : 0; |
||
610 |
} |
||
611 |
|||
612 |
// This maps true to Just<bool>(true) and false to Nothing<bool>(). |
||
613 |
1332 |
static inline Maybe<bool> Tristate(bool b) { |
|
614 |
✓✓ | 1332 |
return b ? Just(true) : Nothing<bool>(); |
615 |
} |
||
616 |
|||
617 |
953 |
Maybe<bool> ExportJWKInner(Environment* env, |
|
618 |
std::shared_ptr<KeyObjectData> key, |
||
619 |
Local<Value> result, |
||
620 |
bool handleRsaPss) { |
||
621 |
✓✓✗ | 953 |
switch (key->GetKeyType()) { |
622 |
291 |
case kKeyTypeSecret: |
|
623 |
291 |
return ExportJWKSecretKey(env, key, result.As<Object>()); |
|
624 |
662 |
case kKeyTypePublic: |
|
625 |
// Fall through |
||
626 |
case kKeyTypePrivate: |
||
627 |
return ExportJWKAsymmetricKey( |
||
628 |
1324 |
env, key, result.As<Object>(), handleRsaPss); |
|
629 |
default: |
||
630 |
UNREACHABLE(); |
||
631 |
} |
||
632 |
} |
||
633 |
|||
634 |
679 |
Maybe<bool> ManagedEVPPKey::ToEncodedPublicKey( |
|
635 |
Environment* env, |
||
636 |
ManagedEVPPKey key, |
||
637 |
const PublicKeyEncodingConfig& config, |
||
638 |
Local<Value>* out) { |
||
639 |
✗✓ | 679 |
if (!key) return Nothing<bool>(); |
640 |
✓✓ | 679 |
if (config.output_key_object_) { |
641 |
// Note that this has the downside of containing sensitive data of the |
||
642 |
// private key. |
||
643 |
std::shared_ptr<KeyObjectData> data = |
||
644 |
648 |
KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key)); |
|
645 |
1296 |
return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out)); |
|
646 |
✓✓ | 31 |
} else if (config.format_ == kKeyFormatJWK) { |
647 |
std::shared_ptr<KeyObjectData> data = |
||
648 |
11 |
KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key)); |
|
649 |
11 |
*out = Object::New(env->isolate()); |
|
650 |
11 |
return ExportJWKInner(env, data, *out, false); |
|
651 |
} |
||
652 |
|||
653 |
40 |
return Tristate(WritePublicKey(env, key.get(), config).ToLocal(out)); |
|
654 |
} |
||
655 |
|||
656 |
674 |
Maybe<bool> ManagedEVPPKey::ToEncodedPrivateKey( |
|
657 |
Environment* env, |
||
658 |
ManagedEVPPKey key, |
||
659 |
const PrivateKeyEncodingConfig& config, |
||
660 |
Local<Value>* out) { |
||
661 |
✗✓ | 674 |
if (!key) return Nothing<bool>(); |
662 |
✓✓ | 674 |
if (config.output_key_object_) { |
663 |
std::shared_ptr<KeyObjectData> data = |
||
664 |
647 |
KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key)); |
|
665 |
1294 |
return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out)); |
|
666 |
✓✓ | 27 |
} else if (config.format_ == kKeyFormatJWK) { |
667 |
std::shared_ptr<KeyObjectData> data = |
||
668 |
10 |
KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key)); |
|
669 |
10 |
*out = Object::New(env->isolate()); |
|
670 |
10 |
return ExportJWKInner(env, data, *out, false); |
|
671 |
} |
||
672 |
|||
673 |
34 |
return Tristate(WritePrivateKey(env, key.get(), config).ToLocal(out)); |
|
674 |
} |
||
675 |
|||
676 |
NonCopyableMaybe<PrivateKeyEncodingConfig> |
||
677 |
4223 |
ManagedEVPPKey::GetPrivateKeyEncodingFromJs( |
|
678 |
const FunctionCallbackInfo<Value>& args, |
||
679 |
unsigned int* offset, |
||
680 |
KeyEncodingContext context) { |
||
681 |
4223 |
Environment* env = Environment::GetCurrent(args); |
|
682 |
|||
683 |
8446 |
PrivateKeyEncodingConfig result; |
|
684 |
4223 |
GetKeyFormatAndTypeFromJs(&result, args, offset, context); |
|
685 |
|||
686 |
✓✓ | 4223 |
if (result.output_key_object_) { |
687 |
✓✗ | 745 |
if (context != kKeyContextInput) |
688 |
745 |
(*offset)++; |
|
689 |
} else { |
||
690 |
3478 |
bool needs_passphrase = false; |
|
691 |
✓✓ | 3478 |
if (context != kKeyContextInput) { |
692 |
✓✗✓✓ |
225 |
if (args[*offset]->IsString()) { |
693 |
✓✗ | 26 |
Utf8Value cipher_name(env->isolate(), args[*offset]); |
694 |
13 |
result.cipher_ = EVP_get_cipherbyname(*cipher_name); |
|
695 |
✓✓ | 13 |
if (result.cipher_ == nullptr) { |
696 |
1 |
THROW_ERR_CRYPTO_UNKNOWN_CIPHER(env); |
|
697 |
1 |
return NonCopyableMaybe<PrivateKeyEncodingConfig>(); |
|
698 |
} |
||
699 |
12 |
needs_passphrase = true; |
|
700 |
} else { |
||
701 |
✓✗✗✓ |
186 |
CHECK(args[*offset]->IsNullOrUndefined()); |
702 |
62 |
result.cipher_ = nullptr; |
|
703 |
} |
||
704 |
74 |
(*offset)++; |
|
705 |
} |
||
706 |
|||
707 |
✓✗✓✓ |
6954 |
if (IsAnyByteSource(args[*offset])) { |
708 |
✓✓✗✓ |
95 |
CHECK_IMPLIES(context != kKeyContextInput, result.cipher_ != nullptr); |
709 |
✓✗ | 190 |
ArrayBufferOrViewContents<char> passphrase(args[*offset]); |
710 |
✗✓ | 95 |
if (UNLIKELY(!passphrase.CheckSizeInt32())) { |
711 |
THROW_ERR_OUT_OF_RANGE(env, "passphrase is too big"); |
||
712 |
return NonCopyableMaybe<PrivateKeyEncodingConfig>(); |
||
713 |
} |
||
714 |
190 |
result.passphrase_ = NonCopyableMaybe<ByteSource>( |
|
715 |
285 |
passphrase.ToNullTerminatedCopy()); |
|
716 |
} else { |
||
717 |
✓✗✓✗ ✗✓✗✓ |
10146 |
CHECK(args[*offset]->IsNullOrUndefined() && !needs_passphrase); |
718 |
} |
||
719 |
} |
||
720 |
|||
721 |
4222 |
(*offset)++; |
|
722 |
4222 |
return NonCopyableMaybe<PrivateKeyEncodingConfig>(std::move(result)); |
|
723 |
} |
||
724 |
|||
725 |
827 |
PublicKeyEncodingConfig ManagedEVPPKey::GetPublicKeyEncodingFromJs( |
|
726 |
const FunctionCallbackInfo<Value>& args, |
||
727 |
unsigned int* offset, |
||
728 |
KeyEncodingContext context) { |
||
729 |
827 |
PublicKeyEncodingConfig result; |
|
730 |
827 |
GetKeyFormatAndTypeFromJs(&result, args, offset, context); |
|
731 |
827 |
return result; |
|
732 |
} |
||
733 |
|||
734 |
1379 |
ManagedEVPPKey ManagedEVPPKey::GetPrivateKeyFromJs( |
|
735 |
const FunctionCallbackInfo<Value>& args, |
||
736 |
unsigned int* offset, |
||
737 |
bool allow_key_object) { |
||
738 |
✓✗✓✗ ✓✗✓✓ ✓✓ |
5516 |
if (args[*offset]->IsString() || IsAnyByteSource(args[*offset])) { |
739 |
1173 |
Environment* env = Environment::GetCurrent(args); |
|
740 |
✓✗ | 3519 |
ByteSource key = ByteSource::FromStringOrBuffer(env, args[(*offset)++]); |
741 |
NonCopyableMaybe<PrivateKeyEncodingConfig> config = |
||
742 |
2346 |
GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput); |
|
743 |
✗✓ | 1173 |
if (config.IsEmpty()) |
744 |
return ManagedEVPPKey(); |
||
745 |
|||
746 |
1173 |
EVPKeyPointer pkey; |
|
747 |
ParseKeyResult ret = |
||
748 |
1173 |
ParsePrivateKey(&pkey, config.Release(), key.data<char>(), key.size()); |
|
749 |
1173 |
return GetParsedKey(env, std::move(pkey), ret, |
|
750 |
1173 |
"Failed to read private key"); |
|
751 |
} else { |
||
752 |
✓✗✓✗ ✗✓✗✓ |
412 |
CHECK(args[*offset]->IsObject() && allow_key_object); |
753 |
KeyObjectHandle* key; |
||
754 |
✓✗✗✓ |
618 |
ASSIGN_OR_RETURN_UNWRAP(&key, args[*offset].As<Object>(), ManagedEVPPKey()); |
755 |
✗✓ | 206 |
CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePrivate); |
756 |
206 |
(*offset) += 4; |
|
757 |
206 |
return key->Data()->GetAsymmetricKey(); |
|
758 |
} |
||
759 |
} |
||
760 |
|||
761 |
2870 |
ManagedEVPPKey ManagedEVPPKey::GetPublicOrPrivateKeyFromJs( |
|
762 |
const FunctionCallbackInfo<Value>& args, |
||
763 |
unsigned int* offset) { |
||
764 |
✓✗✓✓ |
5740 |
if (IsAnyByteSource(args[*offset])) { |
765 |
2230 |
Environment* env = Environment::GetCurrent(args); |
|
766 |
✓✗ | 4460 |
ArrayBufferOrViewContents<char> data(args[(*offset)++]); |
767 |
✗✓ | 2230 |
if (UNLIKELY(!data.CheckSizeInt32())) { |
768 |
THROW_ERR_OUT_OF_RANGE(env, "keyData is too big"); |
||
769 |
return ManagedEVPPKey(); |
||
770 |
} |
||
771 |
NonCopyableMaybe<PrivateKeyEncodingConfig> config_ = |
||
772 |
4460 |
GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput); |
|
773 |
✗✓ | 2230 |
if (config_.IsEmpty()) |
774 |
return ManagedEVPPKey(); |
||
775 |
|||
776 |
ParseKeyResult ret; |
||
777 |
4460 |
PrivateKeyEncodingConfig config = config_.Release(); |
|
778 |
2230 |
EVPKeyPointer pkey; |
|
779 |
✓✓ | 2230 |
if (config.format_ == kKeyFormatPEM) { |
780 |
// For PEM, we can easily determine whether it is a public or private key |
||
781 |
// by looking for the respective PEM tags. |
||
782 |
1229 |
ret = ParsePublicKeyPEM(&pkey, data.data(), data.size()); |
|
783 |
✓✓ | 1229 |
if (ret == ParseKeyResult::kParseKeyNotRecognized) { |
784 |
262 |
ret = ParsePrivateKey(&pkey, config, data.data(), data.size()); |
|
785 |
} |
||
786 |
} else { |
||
787 |
// For DER, the type determines how to parse it. SPKI, PKCS#8 and SEC1 are |
||
788 |
// easy, but PKCS#1 can be a public key or a private key. |
||
789 |
bool is_public; |
||
790 |
✓✓✓✗ |
1001 |
switch (config.type_.ToChecked()) { |
791 |
34 |
case kKeyEncodingPKCS1: |
|
792 |
68 |
is_public = !IsRSAPrivateKey( |
|
793 |
34 |
reinterpret_cast<const unsigned char*>(data.data()), data.size()); |
|
794 |
34 |
break; |
|
795 |
910 |
case kKeyEncodingSPKI: |
|
796 |
910 |
is_public = true; |
|
797 |
910 |
break; |
|
798 |
57 |
case kKeyEncodingPKCS8: |
|
799 |
case kKeyEncodingSEC1: |
||
800 |
57 |
is_public = false; |
|
801 |
57 |
break; |
|
802 |
default: |
||
803 |
UNREACHABLE("Invalid key encoding type"); |
||
804 |
} |
||
805 |
|||
806 |
✓✓ | 1001 |
if (is_public) { |
807 |
932 |
ret = ParsePublicKey(&pkey, config, data.data(), data.size()); |
|
808 |
} else { |
||
809 |
69 |
ret = ParsePrivateKey(&pkey, config, data.data(), data.size()); |
|
810 |
} |
||
811 |
} |
||
812 |
|||
813 |
return ManagedEVPPKey::GetParsedKey( |
||
814 |
2230 |
env, std::move(pkey), ret, "Failed to read asymmetric key"); |
|
815 |
} else { |
||
816 |
✓✗✗✓ |
1280 |
CHECK(args[*offset]->IsObject()); |
817 |
✓✗ | 1920 |
KeyObjectHandle* key = Unwrap<KeyObjectHandle>(args[*offset].As<Object>()); |
818 |
✗✓ | 640 |
CHECK_NOT_NULL(key); |
819 |
✗✓ | 640 |
CHECK_NE(key->Data()->GetKeyType(), kKeyTypeSecret); |
820 |
640 |
(*offset) += 4; |
|
821 |
640 |
return key->Data()->GetAsymmetricKey(); |
|
822 |
} |
||
823 |
} |
||
824 |
|||
825 |
3403 |
ManagedEVPPKey ManagedEVPPKey::GetParsedKey(Environment* env, |
|
826 |
EVPKeyPointer&& pkey, |
||
827 |
ParseKeyResult ret, |
||
828 |
const char* default_msg) { |
||
829 |
✓✓✓ | 3403 |
switch (ret) { |
830 |
3382 |
case ParseKeyResult::kParseKeyOk: |
|
831 |
✗✓ | 3382 |
CHECK(pkey); |
832 |
3382 |
break; |
|
833 |
2 |
case ParseKeyResult::kParseKeyNeedPassphrase: |
|
834 |
2 |
THROW_ERR_MISSING_PASSPHRASE(env, |
|
835 |
"Passphrase required for encrypted key"); |
||
836 |
2 |
break; |
|
837 |
19 |
default: |
|
838 |
19 |
ThrowCryptoError(env, ERR_get_error(), default_msg); |
|
839 |
} |
||
840 |
|||
841 |
3403 |
return ManagedEVPPKey(std::move(pkey)); |
|
842 |
} |
||
843 |
|||
844 |
5375 |
KeyObjectData::KeyObjectData( |
|
845 |
5375 |
ByteSource symmetric_key) |
|
846 |
: key_type_(KeyType::kKeyTypeSecret), |
||
847 |
5375 |
symmetric_key_(std::move(symmetric_key)), |
|
848 |
5375 |
symmetric_key_len_(symmetric_key_.size()), |
|
849 |
10750 |
asymmetric_key_() {} |
|
850 |
|||
851 |
3941 |
KeyObjectData::KeyObjectData( |
|
852 |
KeyType type, |
||
853 |
3941 |
const ManagedEVPPKey& pkey) |
|
854 |
: key_type_(type), |
||
855 |
symmetric_key_(), |
||
856 |
symmetric_key_len_(0), |
||
857 |
3941 |
asymmetric_key_{pkey} {} |
|
858 |
|||
859 |
void KeyObjectData::MemoryInfo(MemoryTracker* tracker) const { |
||
860 |
switch (GetKeyType()) { |
||
861 |
case kKeyTypeSecret: |
||
862 |
tracker->TrackFieldWithSize("symmetric_key", symmetric_key_.size()); |
||
863 |
break; |
||
864 |
case kKeyTypePrivate: |
||
865 |
// Fall through |
||
866 |
case kKeyTypePublic: |
||
867 |
tracker->TrackFieldWithSize("key", asymmetric_key_); |
||
868 |
break; |
||
869 |
default: |
||
870 |
UNREACHABLE(); |
||
871 |
} |
||
872 |
} |
||
873 |
|||
874 |
5375 |
std::shared_ptr<KeyObjectData> KeyObjectData::CreateSecret(ByteSource key) { |
|
875 |
5375 |
return std::shared_ptr<KeyObjectData>(new KeyObjectData(std::move(key))); |
|
876 |
} |
||
877 |
|||
878 |
3941 |
std::shared_ptr<KeyObjectData> KeyObjectData::CreateAsymmetric( |
|
879 |
KeyType key_type, |
||
880 |
const ManagedEVPPKey& pkey) { |
||
881 |
✗✓ | 3941 |
CHECK(pkey); |
882 |
3941 |
return std::shared_ptr<KeyObjectData>(new KeyObjectData(key_type, pkey)); |
|
883 |
} |
||
884 |
|||
885 |
18824 |
KeyType KeyObjectData::GetKeyType() const { |
|
886 |
18824 |
return key_type_; |
|
887 |
} |
||
888 |
|||
889 |
10782 |
ManagedEVPPKey KeyObjectData::GetAsymmetricKey() const { |
|
890 |
✗✓ | 10782 |
CHECK_NE(key_type_, kKeyTypeSecret); |
891 |
10782 |
return asymmetric_key_; |
|
892 |
} |
||
893 |
|||
894 |
7770 |
const char* KeyObjectData::GetSymmetricKey() const { |
|
895 |
✗✓ | 7770 |
CHECK_EQ(key_type_, kKeyTypeSecret); |
896 |
7770 |
return symmetric_key_.data<char>(); |
|
897 |
} |
||
898 |
|||
899 |
12840 |
size_t KeyObjectData::GetSymmetricKeySize() const { |
|
900 |
✗✓ | 12840 |
CHECK_EQ(key_type_, kKeyTypeSecret); |
901 |
12840 |
return symmetric_key_len_; |
|
902 |
} |
||
903 |
|||
904 |
3270 |
v8::Local<v8::Function> KeyObjectHandle::Initialize(Environment* env) { |
|
905 |
3270 |
Local<Function> templ = env->crypto_key_object_handle_constructor(); |
|
906 |
✓✓ | 3270 |
if (!templ.IsEmpty()) { |
907 |
2500 |
return templ; |
|
908 |
} |
||
909 |
770 |
Isolate* isolate = env->isolate(); |
|
910 |
770 |
Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New); |
|
911 |
1540 |
t->InstanceTemplate()->SetInternalFieldCount( |
|
912 |
KeyObjectHandle::kInternalFieldCount); |
||
913 |
770 |
t->Inherit(BaseObject::GetConstructorTemplate(env)); |
|
914 |
|||
915 |
770 |
SetProtoMethod(isolate, t, "init", Init); |
|
916 |
770 |
SetProtoMethodNoSideEffect( |
|
917 |
isolate, t, "getSymmetricKeySize", GetSymmetricKeySize); |
||
918 |
770 |
SetProtoMethodNoSideEffect( |
|
919 |
isolate, t, "getAsymmetricKeyType", GetAsymmetricKeyType); |
||
920 |
770 |
SetProtoMethod(isolate, t, "export", Export); |
|
921 |
770 |
SetProtoMethod(isolate, t, "exportJwk", ExportJWK); |
|
922 |
770 |
SetProtoMethod(isolate, t, "initECRaw", InitECRaw); |
|
923 |
770 |
SetProtoMethod(isolate, t, "initEDRaw", InitEDRaw); |
|
924 |
770 |
SetProtoMethod(isolate, t, "initJwk", InitJWK); |
|
925 |
770 |
SetProtoMethod(isolate, t, "keyDetail", GetKeyDetail); |
|
926 |
770 |
SetProtoMethod(isolate, t, "equals", Equals); |
|
927 |
|||
928 |
770 |
auto function = t->GetFunction(env->context()).ToLocalChecked(); |
|
929 |
770 |
env->set_crypto_key_object_handle_constructor(function); |
|
930 |
770 |
return function; |
|
931 |
} |
||
932 |
|||
933 |
5338 |
void KeyObjectHandle::RegisterExternalReferences( |
|
934 |
ExternalReferenceRegistry* registry) { |
||
935 |
5338 |
registry->Register(New); |
|
936 |
5338 |
registry->Register(Init); |
|
937 |
5338 |
registry->Register(GetSymmetricKeySize); |
|
938 |
5338 |
registry->Register(GetAsymmetricKeyType); |
|
939 |
5338 |
registry->Register(Export); |
|
940 |
5338 |
registry->Register(ExportJWK); |
|
941 |
5338 |
registry->Register(InitECRaw); |
|
942 |
5338 |
registry->Register(InitEDRaw); |
|
943 |
5338 |
registry->Register(InitJWK); |
|
944 |
5338 |
registry->Register(GetKeyDetail); |
|
945 |
5338 |
registry->Register(Equals); |
|
946 |
5338 |
} |
|
947 |
|||
948 |
2500 |
MaybeLocal<Object> KeyObjectHandle::Create( |
|
949 |
Environment* env, |
||
950 |
std::shared_ptr<KeyObjectData> data) { |
||
951 |
Local<Object> obj; |
||
952 |
2500 |
Local<Function> ctor = KeyObjectHandle::Initialize(env); |
|
953 |
✗✓ | 5000 |
CHECK(!env->crypto_key_object_handle_constructor().IsEmpty()); |
954 |
✗✓ | 5000 |
if (!ctor->NewInstance(env->context(), 0, nullptr).ToLocal(&obj)) |
955 |
return MaybeLocal<Object>(); |
||
956 |
|||
957 |
2500 |
KeyObjectHandle* key = Unwrap<KeyObjectHandle>(obj); |
|
958 |
✗✓ | 2500 |
CHECK_NOT_NULL(key); |
959 |
2500 |
key->data_ = data; |
|
960 |
2500 |
return obj; |
|
961 |
} |
||
962 |
|||
963 |
27589 |
const std::shared_ptr<KeyObjectData>& KeyObjectHandle::Data() { |
|
964 |
27589 |
return data_; |
|
965 |
} |
||
966 |
|||
967 |
9308 |
void KeyObjectHandle::New(const FunctionCallbackInfo<Value>& args) { |
|
968 |
✗✓ | 9308 |
CHECK(args.IsConstructCall()); |
969 |
9308 |
Environment* env = Environment::GetCurrent(args); |
|
970 |
9308 |
new KeyObjectHandle(env, args.This()); |
|
971 |
9308 |
} |
|
972 |
|||
973 |
9308 |
KeyObjectHandle::KeyObjectHandle(Environment* env, |
|
974 |
9308 |
Local<Object> wrap) |
|
975 |
9308 |
: BaseObject(env, wrap) { |
|
976 |
9308 |
MakeWeak(); |
|
977 |
9308 |
} |
|
978 |
|||
979 |
5800 |
void KeyObjectHandle::Init(const FunctionCallbackInfo<Value>& args) { |
|
980 |
KeyObjectHandle* key; |
||
981 |
✗✓ | 5805 |
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); |
982 |
5800 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
|
983 |
|||
984 |
✗✓ | 5800 |
CHECK(args[0]->IsInt32()); |
985 |
11600 |
KeyType type = static_cast<KeyType>(args[0].As<Uint32>()->Value()); |
|
986 |
|||
987 |
unsigned int offset; |
||
988 |
5800 |
ManagedEVPPKey pkey; |
|
989 |
|||
990 |
✓✓✓✗ |
5800 |
switch (type) { |
991 |
3910 |
case kKeyTypeSecret: { |
|
992 |
✗✓ | 3910 |
CHECK_EQ(args.Length(), 2); |
993 |
3910 |
ArrayBufferOrViewContents<char> buf(args[1]); |
|
994 |
3910 |
key->data_ = KeyObjectData::CreateSecret(buf.ToCopy()); |
|
995 |
3910 |
break; |
|
996 |
} |
||
997 |
927 |
case kKeyTypePublic: { |
|
998 |
✗✓ | 927 |
CHECK_EQ(args.Length(), 5); |
999 |
|||
1000 |
927 |
offset = 1; |
|
1001 |
927 |
pkey = ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(args, &offset); |
|
1002 |
✗✓ | 927 |
if (!pkey) |
1003 |
return; |
||
1004 |
927 |
key->data_ = KeyObjectData::CreateAsymmetric(type, pkey); |
|
1005 |
927 |
break; |
|
1006 |
} |
||
1007 |
963 |
case kKeyTypePrivate: { |
|
1008 |
✗✓ | 963 |
CHECK_EQ(args.Length(), 5); |
1009 |
|||
1010 |
963 |
offset = 1; |
|
1011 |
963 |
pkey = ManagedEVPPKey::GetPrivateKeyFromJs(args, &offset, false); |
|
1012 |
✓✓ | 963 |
if (!pkey) |
1013 |
5 |
return; |
|
1014 |
958 |
key->data_ = KeyObjectData::CreateAsymmetric(type, pkey); |
|
1015 |
958 |
break; |
|
1016 |
} |
||
1017 |
default: |
||
1018 |
UNREACHABLE(); |
||
1019 |
} |
||
1020 |
} |
||
1021 |
|||
1022 |
928 |
void KeyObjectHandle::InitJWK(const FunctionCallbackInfo<Value>& args) { |
|
1023 |
928 |
Environment* env = Environment::GetCurrent(args); |
|
1024 |
KeyObjectHandle* key; |
||
1025 |
✗✓ | 928 |
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); |
1026 |
928 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
|
1027 |
|||
1028 |
// The argument must be a JavaScript object that we will inspect |
||
1029 |
// to get the JWK properties from. |
||
1030 |
✗✓ | 928 |
CHECK(args[0]->IsObject()); |
1031 |
|||
1032 |
// Step one, Secret key or not? |
||
1033 |
1856 |
Local<Object> input = args[0].As<Object>(); |
|
1034 |
|||
1035 |
Local<Value> kty; |
||
1036 |
✓✗✗✓ |
3712 |
if (!input->Get(env->context(), env->jwk_kty_string()).ToLocal(&kty) || |
1037 |
✗✓ | 1856 |
!kty->IsString()) { |
1038 |
return THROW_ERR_CRYPTO_INVALID_JWK(env); |
||
1039 |
} |
||
1040 |
|||
1041 |
928 |
Utf8Value kty_string(env->isolate(), kty); |
|
1042 |
|||
1043 |
✓✓ | 928 |
if (strcmp(*kty_string, "oct") == 0) { |
1044 |
// Secret key |
||
1045 |
270 |
key->data_ = ImportJWKSecretKey(env, input); |
|
1046 |
✗✓ | 270 |
if (!key->data_) { |
1047 |
// ImportJWKSecretKey is responsible for throwing an appropriate error |
||
1048 |
return; |
||
1049 |
} |
||
1050 |
} else { |
||
1051 |
658 |
key->data_ = ImportJWKAsymmetricKey(env, input, *kty_string, args, 1); |
|
1052 |
✗✓ | 658 |
if (!key->data_) { |
1053 |
// ImportJWKAsymmetricKey is responsible for throwing an appropriate error |
||
1054 |
return; |
||
1055 |
} |
||
1056 |
} |
||
1057 |
|||
1058 |
1856 |
args.GetReturnValue().Set(key->data_->GetKeyType()); |
|
1059 |
} |
||
1060 |
|||
1061 |
12 |
void KeyObjectHandle::InitECRaw(const FunctionCallbackInfo<Value>& args) { |
|
1062 |
12 |
Environment* env = Environment::GetCurrent(args); |
|
1063 |
KeyObjectHandle* key; |
||
1064 |
✗✓ | 12 |
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); |
1065 |
|||
1066 |
✗✓ | 24 |
CHECK(args[0]->IsString()); |
1067 |
12 |
Utf8Value name(env->isolate(), args[0]); |
|
1068 |
|||
1069 |
12 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
|
1070 |
|||
1071 |
12 |
int id = OBJ_txt2nid(*name); |
|
1072 |
12 |
ECKeyPointer eckey(EC_KEY_new_by_curve_name(id)); |
|
1073 |
✗✓ | 12 |
if (!eckey) |
1074 |
return args.GetReturnValue().Set(false); |
||
1075 |
|||
1076 |
12 |
const EC_GROUP* group = EC_KEY_get0_group(eckey.get()); |
|
1077 |
12 |
ECPointPointer pub(ECDH::BufferToPoint(env, group, args[1])); |
|
1078 |
|||
1079 |
12 |
if (!pub || |
|
1080 |
✓✗✓✗ ✗✓✗✓ |
24 |
!eckey || |
1081 |
12 |
!EC_KEY_set_public_key(eckey.get(), pub.get())) { |
|
1082 |
return args.GetReturnValue().Set(false); |
||
1083 |
} |
||
1084 |
|||
1085 |
12 |
EVPKeyPointer pkey(EVP_PKEY_new()); |
|
1086 |
✗✓ | 12 |
if (!EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get())) |
1087 |
args.GetReturnValue().Set(false); |
||
1088 |
|||
1089 |
12 |
eckey.release(); // Release ownership of the key |
|
1090 |
|||
1091 |
12 |
key->data_ = |
|
1092 |
24 |
KeyObjectData::CreateAsymmetric( |
|
1093 |
kKeyTypePublic, |
||
1094 |
36 |
ManagedEVPPKey(std::move(pkey))); |
|
1095 |
|||
1096 |
✓✗ | 24 |
args.GetReturnValue().Set(true); |
1097 |
} |
||
1098 |
|||
1099 |
68 |
void KeyObjectHandle::InitEDRaw(const FunctionCallbackInfo<Value>& args) { |
|
1100 |
68 |
Environment* env = Environment::GetCurrent(args); |
|
1101 |
KeyObjectHandle* key; |
||
1102 |
✗✓ | 68 |
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); |
1103 |
|||
1104 |
✗✓ | 136 |
CHECK(args[0]->IsString()); |
1105 |
68 |
Utf8Value name(env->isolate(), args[0]); |
|
1106 |
|||
1107 |
68 |
ArrayBufferOrViewContents<unsigned char> key_data(args[1]); |
|
1108 |
136 |
KeyType type = static_cast<KeyType>(args[2].As<Int32>()->Value()); |
|
1109 |
|||
1110 |
68 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
|
1111 |
|||
1112 |
typedef EVP_PKEY* (*new_key_fn)(int, ENGINE*, const unsigned char*, size_t); |
||
1113 |
68 |
new_key_fn fn = type == kKeyTypePrivate |
|
1114 |
✓✓ | 68 |
? EVP_PKEY_new_raw_private_key |
1115 |
: EVP_PKEY_new_raw_public_key; |
||
1116 |
|||
1117 |
68 |
int id = GetOKPCurveFromName(*name); |
|
1118 |
|||
1119 |
✓✗ | 68 |
switch (id) { |
1120 |
68 |
case EVP_PKEY_X25519: |
|
1121 |
case EVP_PKEY_X448: |
||
1122 |
case EVP_PKEY_ED25519: |
||
1123 |
case EVP_PKEY_ED448: { |
||
1124 |
68 |
EVPKeyPointer pkey(fn(id, nullptr, key_data.data(), key_data.size())); |
|
1125 |
✗✓ | 68 |
if (!pkey) |
1126 |
return args.GetReturnValue().Set(false); |
||
1127 |
68 |
key->data_ = |
|
1128 |
136 |
KeyObjectData::CreateAsymmetric( |
|
1129 |
type, |
||
1130 |
204 |
ManagedEVPPKey(std::move(pkey))); |
|
1131 |
✗✓ | 68 |
CHECK(key->data_); |
1132 |
68 |
break; |
|
1133 |
} |
||
1134 |
default: |
||
1135 |
UNREACHABLE(); |
||
1136 |
} |
||
1137 |
|||
1138 |
✓✗ | 136 |
args.GetReturnValue().Set(true); |
1139 |
} |
||
1140 |
|||
1141 |
15 |
void KeyObjectHandle::Equals(const FunctionCallbackInfo<Value>& args) { |
|
1142 |
KeyObjectHandle* self_handle; |
||
1143 |
KeyObjectHandle* arg_handle; |
||
1144 |
✗✓ | 15 |
ASSIGN_OR_RETURN_UNWRAP(&self_handle, args.Holder()); |
1145 |
✗✓ | 30 |
ASSIGN_OR_RETURN_UNWRAP(&arg_handle, args[0].As<Object>()); |
1146 |
15 |
std::shared_ptr<KeyObjectData> key = self_handle->Data(); |
|
1147 |
15 |
std::shared_ptr<KeyObjectData> key2 = arg_handle->Data(); |
|
1148 |
|||
1149 |
15 |
KeyType key_type = key->GetKeyType(); |
|
1150 |
✗✓ | 15 |
CHECK_EQ(key_type, key2->GetKeyType()); |
1151 |
|||
1152 |
bool ret; |
||
1153 |
✓✓✗ | 15 |
switch (key_type) { |
1154 |
7 |
case kKeyTypeSecret: { |
|
1155 |
7 |
size_t size = key->GetSymmetricKeySize(); |
|
1156 |
✓✓ | 7 |
if (size == key2->GetSymmetricKeySize()) { |
1157 |
5 |
ret = CRYPTO_memcmp( |
|
1158 |
5 |
key->GetSymmetricKey(), |
|
1159 |
5 |
key2->GetSymmetricKey(), |
|
1160 |
size) == 0; |
||
1161 |
} else { |
||
1162 |
2 |
ret = false; |
|
1163 |
} |
||
1164 |
7 |
break; |
|
1165 |
} |
||
1166 |
8 |
case kKeyTypePublic: |
|
1167 |
case kKeyTypePrivate: { |
||
1168 |
8 |
EVP_PKEY* pkey = key->GetAsymmetricKey().get(); |
|
1169 |
8 |
EVP_PKEY* pkey2 = key2->GetAsymmetricKey().get(); |
|
1170 |
#if OPENSSL_VERSION_MAJOR >= 3 |
||
1171 |
8 |
int ok = EVP_PKEY_eq(pkey, pkey2); |
|
1172 |
#else |
||
1173 |
int ok = EVP_PKEY_cmp(pkey, pkey2); |
||
1174 |
#endif |
||
1175 |
✗✓ | 8 |
if (ok == -2) { |
1176 |
Environment* env = Environment::GetCurrent(args); |
||
1177 |
return THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env); |
||
1178 |
} |
||
1179 |
8 |
ret = ok == 1; |
|
1180 |
8 |
break; |
|
1181 |
} |
||
1182 |
default: |
||
1183 |
UNREACHABLE("unsupported key type"); |
||
1184 |
} |
||
1185 |
|||
1186 |
✓✓ | 30 |
args.GetReturnValue().Set(ret); |
1187 |
} |
||
1188 |
|||
1189 |
6370 |
void KeyObjectHandle::GetKeyDetail(const FunctionCallbackInfo<Value>& args) { |
|
1190 |
6370 |
Environment* env = Environment::GetCurrent(args); |
|
1191 |
KeyObjectHandle* key; |
||
1192 |
✗✓ | 6370 |
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); |
1193 |
|||
1194 |
✗✓ | 6370 |
CHECK(args[0]->IsObject()); |
1195 |
|||
1196 |
6370 |
std::shared_ptr<KeyObjectData> data = key->Data(); |
|
1197 |
|||
1198 |
✓✓✗ | 6370 |
switch (data->GetKeyType()) { |
1199 |
✓✗ | 4015 |
case kKeyTypeSecret: |
1200 |
✗✓ | 12045 |
if (GetSecretKeyDetail(env, data, args[0].As<Object>()).IsNothing()) |
1201 |
return; |
||
1202 |
4015 |
break; |
|
1203 |
✓✗ | 2355 |
case kKeyTypePublic: |
1204 |
// Fall through |
||
1205 |
case kKeyTypePrivate: |
||
1206 |
✗✓ | 7065 |
if (GetAsymmetricKeyDetail(env, data, args[0].As<Object>()).IsNothing()) |
1207 |
return; |
||
1208 |
2355 |
break; |
|
1209 |
default: |
||
1210 |
UNREACHABLE(); |
||
1211 |
} |
||
1212 |
|||
1213 |
✓✗ | 12740 |
args.GetReturnValue().Set(args[0]); |
1214 |
} |
||
1215 |
|||
1216 |
2662 |
Local<Value> KeyObjectHandle::GetAsymmetricKeyType() const { |
|
1217 |
5324 |
const ManagedEVPPKey& key = data_->GetAsymmetricKey(); |
|
1218 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
2662 |
switch (EVP_PKEY_id(key.get())) { |
1219 |
1718 |
case EVP_PKEY_RSA: |
|
1220 |
3436 |
return env()->crypto_rsa_string(); |
|
1221 |
22 |
case EVP_PKEY_RSA_PSS: |
|
1222 |
44 |
return env()->crypto_rsa_pss_string(); |
|
1223 |
10 |
case EVP_PKEY_DSA: |
|
1224 |
20 |
return env()->crypto_dsa_string(); |
|
1225 |
18 |
case EVP_PKEY_DH: |
|
1226 |
36 |
return env()->crypto_dh_string(); |
|
1227 |
676 |
case EVP_PKEY_EC: |
|
1228 |
1352 |
return env()->crypto_ec_string(); |
|
1229 |
58 |
case EVP_PKEY_ED25519: |
|
1230 |
116 |
return env()->crypto_ed25519_string(); |
|
1231 |
58 |
case EVP_PKEY_ED448: |
|
1232 |
116 |
return env()->crypto_ed448_string(); |
|
1233 |
51 |
case EVP_PKEY_X25519: |
|
1234 |
102 |
return env()->crypto_x25519_string(); |
|
1235 |
51 |
case EVP_PKEY_X448: |
|
1236 |
102 |
return env()->crypto_x448_string(); |
|
1237 |
default: |
||
1238 |
return Undefined(env()->isolate()); |
||
1239 |
} |
||
1240 |
} |
||
1241 |
|||
1242 |
2662 |
void KeyObjectHandle::GetAsymmetricKeyType( |
|
1243 |
const FunctionCallbackInfo<Value>& args) { |
||
1244 |
KeyObjectHandle* key; |
||
1245 |
✗✓ | 2662 |
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); |
1246 |
|||
1247 |
5324 |
args.GetReturnValue().Set(key->GetAsymmetricKeyType()); |
|
1248 |
} |
||
1249 |
|||
1250 |
3 |
void KeyObjectHandle::GetSymmetricKeySize( |
|
1251 |
const FunctionCallbackInfo<Value>& args) { |
||
1252 |
KeyObjectHandle* key; |
||
1253 |
✗✓ | 3 |
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); |
1254 |
✓✗ | 6 |
args.GetReturnValue().Set( |
1255 |
3 |
static_cast<uint32_t>(key->Data()->GetSymmetricKeySize())); |
|
1256 |
} |
||
1257 |
|||
1258 |
5424 |
void KeyObjectHandle::Export(const FunctionCallbackInfo<Value>& args) { |
|
1259 |
KeyObjectHandle* key; |
||
1260 |
✗✓ | 5424 |
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); |
1261 |
|||
1262 |
✓✓ | 5424 |
KeyType type = key->Data()->GetKeyType(); |
1263 |
|||
1264 |
MaybeLocal<Value> result; |
||
1265 |
✓✓ | 5424 |
if (type == kKeyTypeSecret) { |
1266 |
5327 |
result = key->ExportSecretKey(); |
|
1267 |
✓✓ | 97 |
} else if (type == kKeyTypePublic) { |
1268 |
52 |
unsigned int offset = 0; |
|
1269 |
PublicKeyEncodingConfig config = |
||
1270 |
ManagedEVPPKey::GetPublicKeyEncodingFromJs( |
||
1271 |
52 |
args, &offset, kKeyContextExport); |
|
1272 |
✗✓ | 52 |
CHECK_EQ(offset, static_cast<unsigned int>(args.Length())); |
1273 |
52 |
result = key->ExportPublicKey(config); |
|
1274 |
} else { |
||
1275 |
✗✓ | 45 |
CHECK_EQ(type, kKeyTypePrivate); |
1276 |
45 |
unsigned int offset = 0; |
|
1277 |
NonCopyableMaybe<PrivateKeyEncodingConfig> config = |
||
1278 |
ManagedEVPPKey::GetPrivateKeyEncodingFromJs( |
||
1279 |
45 |
args, &offset, kKeyContextExport); |
|
1280 |
✗✓ | 45 |
if (config.IsEmpty()) |
1281 |
return; |
||
1282 |
✗✓ | 45 |
CHECK_EQ(offset, static_cast<unsigned int>(args.Length())); |
1283 |
45 |
result = key->ExportPrivateKey(config.Release()); |
|
1284 |
} |
||
1285 |
|||
1286 |
✓✗ | 5424 |
if (!result.IsEmpty()) |
1287 |
16272 |
args.GetReturnValue().Set(result.FromMaybe(Local<Value>())); |
|
1288 |
} |
||
1289 |
|||
1290 |
5327 |
MaybeLocal<Value> KeyObjectHandle::ExportSecretKey() const { |
|
1291 |
5327 |
const char* buf = data_->GetSymmetricKey(); |
|
1292 |
5327 |
unsigned int len = data_->GetSymmetricKeySize(); |
|
1293 |
10654 |
return Buffer::Copy(env(), buf, len).FromMaybe(Local<Value>()); |
|
1294 |
} |
||
1295 |
|||
1296 |
52 |
MaybeLocal<Value> KeyObjectHandle::ExportPublicKey( |
|
1297 |
const PublicKeyEncodingConfig& config) const { |
||
1298 |
52 |
return WritePublicKey(env(), data_->GetAsymmetricKey().get(), config); |
|
1299 |
} |
||
1300 |
|||
1301 |
45 |
MaybeLocal<Value> KeyObjectHandle::ExportPrivateKey( |
|
1302 |
const PrivateKeyEncodingConfig& config) const { |
||
1303 |
45 |
return WritePrivateKey(env(), data_->GetAsymmetricKey().get(), config); |
|
1304 |
} |
||
1305 |
|||
1306 |
932 |
void KeyObjectHandle::ExportJWK( |
|
1307 |
const v8::FunctionCallbackInfo<v8::Value>& args) { |
||
1308 |
932 |
Environment* env = Environment::GetCurrent(args); |
|
1309 |
KeyObjectHandle* key; |
||
1310 |
✗✓ | 932 |
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); |
1311 |
|||
1312 |
✗✓ | 932 |
CHECK(args[0]->IsObject()); |
1313 |
✗✓ | 932 |
CHECK(args[1]->IsBoolean()); |
1314 |
|||
1315 |
✓✗ | 1864 |
ExportJWKInner(env, key->Data(), args[0], args[1]->IsTrue()); |
1316 |
|||
1317 |
✓✗ | 1864 |
args.GetReturnValue().Set(args[0]); |
1318 |
} |
||
1319 |
|||
1320 |
770 |
void NativeKeyObject::Initialize(Environment* env, Local<Object> target) { |
|
1321 |
770 |
SetMethod(env->context(), |
|
1322 |
target, |
||
1323 |
"createNativeKeyObjectClass", |
||
1324 |
NativeKeyObject::CreateNativeKeyObjectClass); |
||
1325 |
770 |
} |
|
1326 |
|||
1327 |
5338 |
void NativeKeyObject::RegisterExternalReferences( |
|
1328 |
ExternalReferenceRegistry* registry) { |
||
1329 |
5338 |
registry->Register(NativeKeyObject::CreateNativeKeyObjectClass); |
|
1330 |
5338 |
registry->Register(NativeKeyObject::New); |
|
1331 |
5338 |
} |
|
1332 |
|||
1333 |
9289 |
void NativeKeyObject::New(const FunctionCallbackInfo<Value>& args) { |
|
1334 |
9289 |
Environment* env = Environment::GetCurrent(args); |
|
1335 |
✗✓ | 9289 |
CHECK_EQ(args.Length(), 1); |
1336 |
✗✓ | 9289 |
CHECK(args[0]->IsObject()); |
1337 |
18578 |
KeyObjectHandle* handle = Unwrap<KeyObjectHandle>(args[0].As<Object>()); |
|
1338 |
9289 |
new NativeKeyObject(env, args.This(), handle->Data()); |
|
1339 |
9289 |
} |
|
1340 |
|||
1341 |
770 |
void NativeKeyObject::CreateNativeKeyObjectClass( |
|
1342 |
const FunctionCallbackInfo<Value>& args) { |
||
1343 |
770 |
Environment* env = Environment::GetCurrent(args); |
|
1344 |
770 |
Isolate* isolate = env->isolate(); |
|
1345 |
|||
1346 |
✗✓ | 770 |
CHECK_EQ(args.Length(), 1); |
1347 |
770 |
Local<Value> callback = args[0]; |
|
1348 |
✗✓ | 770 |
CHECK(callback->IsFunction()); |
1349 |
|||
1350 |
Local<FunctionTemplate> t = |
||
1351 |
770 |
NewFunctionTemplate(isolate, NativeKeyObject::New); |
|
1352 |
1540 |
t->InstanceTemplate()->SetInternalFieldCount( |
|
1353 |
KeyObjectHandle::kInternalFieldCount); |
||
1354 |
770 |
t->Inherit(BaseObject::GetConstructorTemplate(env)); |
|
1355 |
|||
1356 |
Local<Value> ctor; |
||
1357 |
✗✓ | 1540 |
if (!t->GetFunction(env->context()).ToLocal(&ctor)) |
1358 |
return; |
||
1359 |
|||
1360 |
1540 |
Local<Value> recv = Undefined(env->isolate()); |
|
1361 |
Local<Value> ret_v; |
||
1362 |
770 |
if (!callback.As<Function>()->Call( |
|
1363 |
✗✓ | 1540 |
env->context(), recv, 1, &ctor).ToLocal(&ret_v)) { |
1364 |
return; |
||
1365 |
} |
||
1366 |
770 |
Local<Array> ret = ret_v.As<Array>(); |
|
1367 |
✗✓ | 1540 |
if (!ret->Get(env->context(), 1).ToLocal(&ctor)) return; |
1368 |
770 |
env->set_crypto_key_object_secret_constructor(ctor.As<Function>()); |
|
1369 |
✗✓ | 1540 |
if (!ret->Get(env->context(), 2).ToLocal(&ctor)) return; |
1370 |
770 |
env->set_crypto_key_object_public_constructor(ctor.As<Function>()); |
|
1371 |
✗✓ | 1540 |
if (!ret->Get(env->context(), 3).ToLocal(&ctor)) return; |
1372 |
770 |
env->set_crypto_key_object_private_constructor(ctor.As<Function>()); |
|
1373 |
1540 |
args.GetReturnValue().Set(ret); |
|
1374 |
} |
||
1375 |
|||
1376 |
11 |
BaseObjectPtr<BaseObject> NativeKeyObject::KeyObjectTransferData::Deserialize( |
|
1377 |
Environment* env, |
||
1378 |
Local<Context> context, |
||
1379 |
std::unique_ptr<worker::TransferData> self) { |
||
1380 |
✓✓ | 22 |
if (context != env->context()) { |
1381 |
3 |
THROW_ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE(env); |
|
1382 |
3 |
return {}; |
|
1383 |
} |
||
1384 |
|||
1385 |
Local<Value> handle; |
||
1386 |
✗✓ | 16 |
if (!KeyObjectHandle::Create(env, data_).ToLocal(&handle)) |
1387 |
return {}; |
||
1388 |
|||
1389 |
Local<Function> key_ctor; |
||
1390 |
Local<Value> arg = FIXED_ONE_BYTE_STRING(env->isolate(), |
||
1391 |
8 |
"internal/crypto/keys"); |
|
1392 |
8 |
if (env->builtin_module_require() |
|
1393 |
16 |
->Call(context, Null(env->isolate()), 1, &arg) |
|
1394 |
✗✓ | 8 |
.IsEmpty()) { |
1395 |
return {}; |
||
1396 |
} |
||
1397 |
✓✓✓✗ |
8 |
switch (data_->GetKeyType()) { |
1398 |
4 |
case kKeyTypeSecret: |
|
1399 |
4 |
key_ctor = env->crypto_key_object_secret_constructor(); |
|
1400 |
4 |
break; |
|
1401 |
2 |
case kKeyTypePublic: |
|
1402 |
2 |
key_ctor = env->crypto_key_object_public_constructor(); |
|
1403 |
2 |
break; |
|
1404 |
2 |
case kKeyTypePrivate: |
|
1405 |
2 |
key_ctor = env->crypto_key_object_private_constructor(); |
|
1406 |
2 |
break; |
|
1407 |
default: |
||
1408 |
CHECK(false); |
||
1409 |
} |
||
1410 |
|||
1411 |
Local<Value> key; |
||
1412 |
✗✓ | 16 |
if (!key_ctor->NewInstance(context, 1, &handle).ToLocal(&key)) |
1413 |
return {}; |
||
1414 |
|||
1415 |
8 |
return BaseObjectPtr<BaseObject>(Unwrap<KeyObjectHandle>(key.As<Object>())); |
|
1416 |
} |
||
1417 |
|||
1418 |
11 |
BaseObject::TransferMode NativeKeyObject::GetTransferMode() const { |
|
1419 |
11 |
return BaseObject::TransferMode::kCloneable; |
|
1420 |
} |
||
1421 |
|||
1422 |
11 |
std::unique_ptr<worker::TransferData> NativeKeyObject::CloneForMessaging() |
|
1423 |
const { |
||
1424 |
11 |
return std::make_unique<KeyObjectTransferData>(handle_data_); |
|
1425 |
} |
||
1426 |
|||
1427 |
252 |
WebCryptoKeyExportStatus PKEY_SPKI_Export( |
|
1428 |
KeyObjectData* key_data, |
||
1429 |
ByteSource* out) { |
||
1430 |
✗✓ | 252 |
CHECK_EQ(key_data->GetKeyType(), kKeyTypePublic); |
1431 |
504 |
ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey(); |
|
1432 |
504 |
Mutex::ScopedLock lock(*m_pkey.mutex()); |
|
1433 |
504 |
BIOPointer bio(BIO_new(BIO_s_mem())); |
|
1434 |
✗✓ | 252 |
CHECK(bio); |
1435 |
✗✓ | 252 |
if (!i2d_PUBKEY_bio(bio.get(), m_pkey.get())) |
1436 |
return WebCryptoKeyExportStatus::FAILED; |
||
1437 |
|||
1438 |
252 |
*out = ByteSource::FromBIO(bio); |
|
1439 |
252 |
return WebCryptoKeyExportStatus::OK; |
|
1440 |
} |
||
1441 |
|||
1442 |
263 |
WebCryptoKeyExportStatus PKEY_PKCS8_Export( |
|
1443 |
KeyObjectData* key_data, |
||
1444 |
ByteSource* out) { |
||
1445 |
✗✓ | 263 |
CHECK_EQ(key_data->GetKeyType(), kKeyTypePrivate); |
1446 |
526 |
ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey(); |
|
1447 |
526 |
Mutex::ScopedLock lock(*m_pkey.mutex()); |
|
1448 |
|||
1449 |
526 |
BIOPointer bio(BIO_new(BIO_s_mem())); |
|
1450 |
✗✓ | 263 |
CHECK(bio); |
1451 |
526 |
PKCS8Pointer p8inf(EVP_PKEY2PKCS8(m_pkey.get())); |
|
1452 |
✗✓ | 263 |
if (!i2d_PKCS8_PRIV_KEY_INFO_bio(bio.get(), p8inf.get())) |
1453 |
return WebCryptoKeyExportStatus::FAILED; |
||
1454 |
|||
1455 |
263 |
*out = ByteSource::FromBIO(bio); |
|
1456 |
263 |
return WebCryptoKeyExportStatus::OK; |
|
1457 |
} |
||
1458 |
|||
1459 |
namespace Keys { |
||
1460 |
770 |
void Initialize(Environment* env, Local<Object> target) { |
|
1461 |
770 |
target->Set(env->context(), |
|
1462 |
FIXED_ONE_BYTE_STRING(env->isolate(), "KeyObjectHandle"), |
||
1463 |
3080 |
KeyObjectHandle::Initialize(env)).Check(); |
|
1464 |
|||
1465 |
2310 |
NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatRaw); |
|
1466 |
2310 |
NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatPKCS8); |
|
1467 |
2310 |
NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatSPKI); |
|
1468 |
2310 |
NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatJWK); |
|
1469 |
|||
1470 |
2310 |
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ED25519); |
|
1471 |
2310 |
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ED448); |
|
1472 |
2310 |
NODE_DEFINE_CONSTANT(target, EVP_PKEY_X25519); |
|
1473 |
2310 |
NODE_DEFINE_CONSTANT(target, EVP_PKEY_X448); |
|
1474 |
2310 |
NODE_DEFINE_CONSTANT(target, kKeyEncodingPKCS1); |
|
1475 |
2310 |
NODE_DEFINE_CONSTANT(target, kKeyEncodingPKCS8); |
|
1476 |
2310 |
NODE_DEFINE_CONSTANT(target, kKeyEncodingSPKI); |
|
1477 |
2310 |
NODE_DEFINE_CONSTANT(target, kKeyEncodingSEC1); |
|
1478 |
2310 |
NODE_DEFINE_CONSTANT(target, kKeyFormatDER); |
|
1479 |
2310 |
NODE_DEFINE_CONSTANT(target, kKeyFormatPEM); |
|
1480 |
2310 |
NODE_DEFINE_CONSTANT(target, kKeyFormatJWK); |
|
1481 |
2310 |
NODE_DEFINE_CONSTANT(target, kKeyTypeSecret); |
|
1482 |
2310 |
NODE_DEFINE_CONSTANT(target, kKeyTypePublic); |
|
1483 |
2310 |
NODE_DEFINE_CONSTANT(target, kKeyTypePrivate); |
|
1484 |
2310 |
NODE_DEFINE_CONSTANT(target, kSigEncDER); |
|
1485 |
1540 |
NODE_DEFINE_CONSTANT(target, kSigEncP1363); |
|
1486 |
770 |
} |
|
1487 |
|||
1488 |
5338 |
void RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
|
1489 |
5338 |
KeyObjectHandle::RegisterExternalReferences(registry); |
|
1490 |
5338 |
} |
|
1491 |
} // namespace Keys |
||
1492 |
|||
1493 |
} // namespace crypto |
||
1494 |
} // namespace node |
Generated by: GCOVR (Version 4.2) |