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