| File: | out/../src/crypto/crypto_keys.h |
| Warning: | line 65, column 8 Value assigned to field 'cipher_' in implicit constructor is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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::Just; | ||||||
| 28 | using v8::Local; | ||||||
| 29 | using v8::Maybe; | ||||||
| 30 | using v8::MaybeLocal; | ||||||
| 31 | using v8::NewStringType; | ||||||
| 32 | using v8::Nothing; | ||||||
| 33 | using v8::Number; | ||||||
| 34 | using v8::Object; | ||||||
| 35 | using v8::String; | ||||||
| 36 | using v8::Uint32; | ||||||
| 37 | using v8::Undefined; | ||||||
| 38 | using v8::Value; | ||||||
| 39 | |||||||
| 40 | namespace crypto { | ||||||
| 41 | namespace { | ||||||
| 42 | void GetKeyFormatAndTypeFromJs( | ||||||
| 43 | AsymmetricKeyEncodingConfig* config, | ||||||
| 44 | const FunctionCallbackInfo<Value>& args, | ||||||
| 45 | unsigned int* offset, | ||||||
| 46 | KeyEncodingContext context) { | ||||||
| 47 | // During key pair generation, it is possible not to specify a key encoding, | ||||||
| 48 | // which will lead to a key object being returned. | ||||||
| 49 | if (args[*offset]->IsUndefined()) { | ||||||
| 50 | CHECK_EQ(context, kKeyContextGenerate)do { if (__builtin_expect(!!(!((context) == (kKeyContextGenerate ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "50", "(context) == (kKeyContextGenerate)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 51 | CHECK(args[*offset + 1]->IsUndefined())do { if (__builtin_expect(!!(!(args[*offset + 1]->IsUndefined ())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "51", "args[*offset + 1]->IsUndefined()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 52 | config->output_key_object_ = true; | ||||||
| 53 | } else { | ||||||
| 54 | config->output_key_object_ = false; | ||||||
| 55 | |||||||
| 56 | CHECK(args[*offset]->IsInt32())do { if (__builtin_expect(!!(!(args[*offset]->IsInt32())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "56", "args[*offset]->IsInt32()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 57 | config->format_ = static_cast<PKFormatType>( | ||||||
| 58 | args[*offset].As<Int32>()->Value()); | ||||||
| 59 | |||||||
| 60 | if (args[*offset + 1]->IsInt32()) { | ||||||
| 61 | config->type_ = Just<PKEncodingType>(static_cast<PKEncodingType>( | ||||||
| 62 | args[*offset + 1].As<Int32>()->Value())); | ||||||
| 63 | } else { | ||||||
| 64 | CHECK(do { if (__builtin_expect(!!(!((context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "68", "(context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) | ||||||
| 65 | (context == kKeyContextInput &&do { if (__builtin_expect(!!(!((context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "68", "(context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) | ||||||
| 66 | config->format_ == kKeyFormatPEM) ||do { if (__builtin_expect(!!(!((context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "68", "(context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) | ||||||
| 67 | (context == kKeyContextGenerate &&do { if (__builtin_expect(!!(!((context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "68", "(context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) | ||||||
| 68 | config->format_ == kKeyFormatJWK))do { if (__builtin_expect(!!(!((context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "68", "(context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 69 | CHECK(args[*offset + 1]->IsNullOrUndefined())do { if (__builtin_expect(!!(!(args[*offset + 1]->IsNullOrUndefined ())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "69", "args[*offset + 1]->IsNullOrUndefined()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 70 | config->type_ = Nothing<PKEncodingType>(); | ||||||
| 71 | } | ||||||
| 72 | } | ||||||
| 73 | |||||||
| 74 | *offset += 2; | ||||||
| 75 | } | ||||||
| 76 | |||||||
| 77 | ParseKeyResult TryParsePublicKey( | ||||||
| 78 | EVPKeyPointer* pkey, | ||||||
| 79 | const BIOPointer& bp, | ||||||
| 80 | const char* name, | ||||||
| 81 | // NOLINTNEXTLINE(runtime/int) | ||||||
| 82 | const std::function<EVP_PKEY*(const unsigned char** p, long l)>& parse) { | ||||||
| 83 | unsigned char* der_data; | ||||||
| 84 | long der_len; // NOLINT(runtime/int) | ||||||
| 85 | |||||||
| 86 | // This skips surrounding data and decodes PEM to DER. | ||||||
| 87 | { | ||||||
| 88 | MarkPopErrorOnReturn mark_pop_error_on_return; | ||||||
| 89 | if (PEM_bytes_read_bio(&der_data, &der_len, nullptr, name, | ||||||
| 90 | bp.get(), nullptr, nullptr) != 1) | ||||||
| 91 | return ParseKeyResult::kParseKeyNotRecognized; | ||||||
| 92 | } | ||||||
| 93 | |||||||
| 94 | // OpenSSL might modify the pointer, so we need to make a copy before parsing. | ||||||
| 95 | const unsigned char* p = der_data; | ||||||
| 96 | pkey->reset(parse(&p, der_len)); | ||||||
| 97 | OPENSSL_clear_free(der_data, der_len)CRYPTO_clear_free(der_data, der_len, "../src/crypto/crypto_keys.cc" , 97); | ||||||
| 98 | |||||||
| 99 | return *pkey ? ParseKeyResult::kParseKeyOk : | ||||||
| 100 | ParseKeyResult::kParseKeyFailed; | ||||||
| 101 | } | ||||||
| 102 | |||||||
| 103 | ParseKeyResult ParsePublicKeyPEM(EVPKeyPointer* pkey, | ||||||
| 104 | const char* key_pem, | ||||||
| 105 | int key_pem_len) { | ||||||
| 106 | BIOPointer bp(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len)); | ||||||
| 107 | if (!bp) | ||||||
| 108 | return ParseKeyResult::kParseKeyFailed; | ||||||
| 109 | |||||||
| 110 | ParseKeyResult ret; | ||||||
| 111 | |||||||
| 112 | // Try parsing as a SubjectPublicKeyInfo first. | ||||||
| 113 | ret = TryParsePublicKey(pkey, bp, "PUBLIC KEY", | ||||||
| 114 | [](const unsigned char** p, long l) { // NOLINT(runtime/int) | ||||||
| 115 | return d2i_PUBKEY(nullptr, p, l); | ||||||
| 116 | }); | ||||||
| 117 | if (ret != ParseKeyResult::kParseKeyNotRecognized) | ||||||
| 118 | return ret; | ||||||
| 119 | |||||||
| 120 | // Maybe it is PKCS#1. | ||||||
| 121 | CHECK(BIO_reset(bp.get()))do { if (__builtin_expect(!!(!((int)BIO_ctrl(bp.get(),1,0,__null ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "121", "(int)BIO_ctrl(bp.get(),1,0,__null)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 122 | ret = TryParsePublicKey(pkey, bp, "RSA PUBLIC KEY", | ||||||
| 123 | [](const unsigned char** p, long l) { // NOLINT(runtime/int) | ||||||
| 124 | return d2i_PublicKey(EVP_PKEY_RSA6, nullptr, p, l); | ||||||
| 125 | }); | ||||||
| 126 | if (ret != ParseKeyResult::kParseKeyNotRecognized) | ||||||
| 127 | return ret; | ||||||
| 128 | |||||||
| 129 | // X.509 fallback. | ||||||
| 130 | CHECK(BIO_reset(bp.get()))do { if (__builtin_expect(!!(!((int)BIO_ctrl(bp.get(),1,0,__null ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "130", "(int)BIO_ctrl(bp.get(),1,0,__null)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 131 | return TryParsePublicKey(pkey, bp, "CERTIFICATE", | ||||||
| 132 | [](const unsigned char** p, long l) { // NOLINT(runtime/int) | ||||||
| 133 | X509Pointer x509(d2i_X509(nullptr, p, l)); | ||||||
| 134 | return x509 ? X509_get_pubkey(x509.get()) : nullptr; | ||||||
| 135 | }); | ||||||
| 136 | } | ||||||
| 137 | |||||||
| 138 | ParseKeyResult ParsePublicKey(EVPKeyPointer* pkey, | ||||||
| 139 | const PublicKeyEncodingConfig& config, | ||||||
| 140 | const char* key, | ||||||
| 141 | size_t key_len) { | ||||||
| 142 | if (config.format_ == kKeyFormatPEM) { | ||||||
| 143 | return ParsePublicKeyPEM(pkey, key, key_len); | ||||||
| 144 | } else { | ||||||
| 145 | CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "145", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 146 | |||||||
| 147 | const unsigned char* p = reinterpret_cast<const unsigned char*>(key); | ||||||
| 148 | if (config.type_.ToChecked() == kKeyEncodingPKCS1) { | ||||||
| 149 | pkey->reset(d2i_PublicKey(EVP_PKEY_RSA6, nullptr, &p, key_len)); | ||||||
| 150 | } else { | ||||||
| 151 | CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSPKI)do { if (__builtin_expect(!!(!((config.type_.ToChecked()) == ( kKeyEncodingSPKI))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "151", "(config.type_.ToChecked()) == (kKeyEncodingSPKI)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 152 | pkey->reset(d2i_PUBKEY(nullptr, &p, key_len)); | ||||||
| 153 | } | ||||||
| 154 | |||||||
| 155 | return *pkey ? ParseKeyResult::kParseKeyOk : | ||||||
| 156 | ParseKeyResult::kParseKeyFailed; | ||||||
| 157 | } | ||||||
| 158 | } | ||||||
| 159 | |||||||
| 160 | bool IsASN1Sequence(const unsigned char* data, size_t size, | ||||||
| 161 | size_t* data_offset, size_t* data_size) { | ||||||
| 162 | if (size < 2 || data[0] != 0x30) | ||||||
| 163 | return false; | ||||||
| 164 | |||||||
| 165 | if (data[1] & 0x80) { | ||||||
| 166 | // Long form. | ||||||
| 167 | size_t n_bytes = data[1] & ~0x80; | ||||||
| 168 | if (n_bytes + 2 > size || n_bytes > sizeof(size_t)) | ||||||
| 169 | return false; | ||||||
| 170 | size_t length = 0; | ||||||
| 171 | for (size_t i = 0; i < n_bytes; i++) | ||||||
| 172 | length = (length << 8) | data[i + 2]; | ||||||
| 173 | *data_offset = 2 + n_bytes; | ||||||
| 174 | *data_size = std::min(size - 2 - n_bytes, length); | ||||||
| 175 | } else { | ||||||
| 176 | // Short form. | ||||||
| 177 | *data_offset = 2; | ||||||
| 178 | *data_size = std::min<size_t>(size - 2, data[1]); | ||||||
| 179 | } | ||||||
| 180 | |||||||
| 181 | return true; | ||||||
| 182 | } | ||||||
| 183 | |||||||
| 184 | bool IsRSAPrivateKey(const unsigned char* data, size_t size) { | ||||||
| 185 | // Both RSAPrivateKey and RSAPublicKey structures start with a SEQUENCE. | ||||||
| 186 | size_t offset, len; | ||||||
| 187 | if (!IsASN1Sequence(data, size, &offset, &len)) | ||||||
| 188 | return false; | ||||||
| 189 | |||||||
| 190 | // An RSAPrivateKey sequence always starts with a single-byte integer whose | ||||||
| 191 | // value is either 0 or 1, whereas an RSAPublicKey starts with the modulus | ||||||
| 192 | // (which is the product of two primes and therefore at least 4), so we can | ||||||
| 193 | // decide the type of the structure based on the first three bytes of the | ||||||
| 194 | // sequence. | ||||||
| 195 | return len >= 3 && | ||||||
| 196 | data[offset] == 2 && | ||||||
| 197 | data[offset + 1] == 1 && | ||||||
| 198 | !(data[offset + 2] & 0xfe); | ||||||
| 199 | } | ||||||
| 200 | |||||||
| 201 | bool IsEncryptedPrivateKeyInfo(const unsigned char* data, size_t size) { | ||||||
| 202 | // Both PrivateKeyInfo and EncryptedPrivateKeyInfo start with a SEQUENCE. | ||||||
| 203 | size_t offset, len; | ||||||
| 204 | if (!IsASN1Sequence(data, size, &offset, &len)) | ||||||
| 205 | return false; | ||||||
| 206 | |||||||
| 207 | // A PrivateKeyInfo sequence always starts with an integer whereas an | ||||||
| 208 | // EncryptedPrivateKeyInfo starts with an AlgorithmIdentifier. | ||||||
| 209 | return len >= 1 && | ||||||
| 210 | data[offset] != 2; | ||||||
| 211 | } | ||||||
| 212 | |||||||
| 213 | ParseKeyResult ParsePrivateKey(EVPKeyPointer* pkey, | ||||||
| 214 | const PrivateKeyEncodingConfig& config, | ||||||
| 215 | const char* key, | ||||||
| 216 | size_t key_len) { | ||||||
| 217 | const ByteSource* passphrase = config.passphrase_.get(); | ||||||
| 218 | |||||||
| 219 | if (config.format_ == kKeyFormatPEM) { | ||||||
| 220 | BIOPointer bio(BIO_new_mem_buf(key, key_len)); | ||||||
| 221 | if (!bio) | ||||||
| 222 | return ParseKeyResult::kParseKeyFailed; | ||||||
| 223 | |||||||
| 224 | pkey->reset(PEM_read_bio_PrivateKey(bio.get(), | ||||||
| 225 | nullptr, | ||||||
| 226 | PasswordCallback, | ||||||
| 227 | &passphrase)); | ||||||
| 228 | } else { | ||||||
| 229 | CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "229", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 230 | |||||||
| 231 | if (config.type_.ToChecked() == kKeyEncodingPKCS1) { | ||||||
| 232 | const unsigned char* p = reinterpret_cast<const unsigned char*>(key); | ||||||
| 233 | pkey->reset(d2i_PrivateKey(EVP_PKEY_RSA6, nullptr, &p, key_len)); | ||||||
| 234 | } else if (config.type_.ToChecked() == kKeyEncodingPKCS8) { | ||||||
| 235 | BIOPointer bio(BIO_new_mem_buf(key, key_len)); | ||||||
| 236 | if (!bio) | ||||||
| 237 | return ParseKeyResult::kParseKeyFailed; | ||||||
| 238 | |||||||
| 239 | if (IsEncryptedPrivateKeyInfo( | ||||||
| 240 | reinterpret_cast<const unsigned char*>(key), key_len)) { | ||||||
| 241 | pkey->reset(d2i_PKCS8PrivateKey_bio(bio.get(), | ||||||
| 242 | nullptr, | ||||||
| 243 | PasswordCallback, | ||||||
| 244 | &passphrase)); | ||||||
| 245 | } else { | ||||||
| 246 | PKCS8Pointer p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr)); | ||||||
| 247 | if (p8inf) | ||||||
| 248 | pkey->reset(EVP_PKCS82PKEY(p8inf.get())); | ||||||
| 249 | } | ||||||
| 250 | } else { | ||||||
| 251 | CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSEC1)do { if (__builtin_expect(!!(!((config.type_.ToChecked()) == ( kKeyEncodingSEC1))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "251", "(config.type_.ToChecked()) == (kKeyEncodingSEC1)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 252 | const unsigned char* p = reinterpret_cast<const unsigned char*>(key); | ||||||
| 253 | pkey->reset(d2i_PrivateKey(EVP_PKEY_EC408, nullptr, &p, key_len)); | ||||||
| 254 | } | ||||||
| 255 | } | ||||||
| 256 | |||||||
| 257 | // OpenSSL can fail to parse the key but still return a non-null pointer. | ||||||
| 258 | unsigned long err = ERR_peek_error(); // NOLINT(runtime/int) | ||||||
| 259 | if (err != 0) | ||||||
| 260 | pkey->reset(); | ||||||
| 261 | |||||||
| 262 | if (*pkey) | ||||||
| 263 | return ParseKeyResult::kParseKeyOk; | ||||||
| 264 | if (ERR_GET_LIB(err) == ERR_LIB_PEM9 && | ||||||
| 265 | ERR_GET_REASON(err) == PEM_R_BAD_PASSWORD_READ104) { | ||||||
| 266 | if (config.passphrase_.IsEmpty()) | ||||||
| 267 | return ParseKeyResult::kParseKeyNeedPassphrase; | ||||||
| 268 | } | ||||||
| 269 | return ParseKeyResult::kParseKeyFailed; | ||||||
| 270 | } | ||||||
| 271 | |||||||
| 272 | MaybeLocal<Value> BIOToStringOrBuffer( | ||||||
| 273 | Environment* env, | ||||||
| 274 | BIO* bio, | ||||||
| 275 | PKFormatType format) { | ||||||
| 276 | BUF_MEM* bptr; | ||||||
| 277 | BIO_get_mem_ptr(bio, &bptr)BIO_ctrl(bio,115,0, (char *)(&bptr)); | ||||||
| 278 | if (format == kKeyFormatPEM) { | ||||||
| 279 | // PEM is an ASCII format, so we will return it as a string. | ||||||
| 280 | return String::NewFromUtf8(env->isolate(), bptr->data, | ||||||
| 281 | NewStringType::kNormal, | ||||||
| 282 | bptr->length).FromMaybe(Local<Value>()); | ||||||
| 283 | } else { | ||||||
| 284 | CHECK_EQ(format, kKeyFormatDER)do { if (__builtin_expect(!!(!((format) == (kKeyFormatDER))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "284", "(format) == (kKeyFormatDER)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 285 | // DER is binary, return it as a buffer. | ||||||
| 286 | return Buffer::Copy(env, bptr->data, bptr->length) | ||||||
| 287 | .FromMaybe(Local<Value>()); | ||||||
| 288 | } | ||||||
| 289 | } | ||||||
| 290 | |||||||
| 291 | |||||||
| 292 | MaybeLocal<Value> WritePrivateKey( | ||||||
| 293 | Environment* env, | ||||||
| 294 | EVP_PKEY* pkey, | ||||||
| 295 | const PrivateKeyEncodingConfig& config) { | ||||||
| 296 | BIOPointer bio(BIO_new(BIO_s_mem())); | ||||||
| 297 | CHECK(bio)do { if (__builtin_expect(!!(!(bio)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "297", "bio", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 298 | |||||||
| 299 | // If an empty string was passed as the passphrase, the ByteSource might | ||||||
| 300 | // contain a null pointer, which OpenSSL will ignore, causing it to invoke its | ||||||
| 301 | // default passphrase callback, which would block the thread until the user | ||||||
| 302 | // manually enters a passphrase. We could supply our own passphrase callback | ||||||
| 303 | // to handle this special case, but it is easier to avoid passing a null | ||||||
| 304 | // pointer to OpenSSL. | ||||||
| 305 | char* pass = nullptr; | ||||||
| 306 | size_t pass_len = 0; | ||||||
| 307 | if (!config.passphrase_.IsEmpty()) { | ||||||
| 308 | pass = const_cast<char*>(config.passphrase_->data<char>()); | ||||||
| 309 | pass_len = config.passphrase_->size(); | ||||||
| 310 | if (pass == nullptr) { | ||||||
| 311 | // OpenSSL will not actually dereference this pointer, so it can be any | ||||||
| 312 | // non-null pointer. We cannot assert that directly, which is why we | ||||||
| 313 | // intentionally use a pointer that will likely cause a segmentation fault | ||||||
| 314 | // when dereferenced. | ||||||
| 315 | CHECK_EQ(pass_len, 0)do { if (__builtin_expect(!!(!((pass_len) == (0))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "315", "(pass_len) == (0)", __PRETTY_FUNCTION__ }; node:: Assert(args); } while (0); } } while (0); | ||||||
| 316 | pass = reinterpret_cast<char*>(-1); | ||||||
| 317 | CHECK_NE(pass, nullptr)do { if (__builtin_expect(!!(!((pass) != (nullptr))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "317", "(pass) != (nullptr)", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | ||||||
| 318 | } | ||||||
| 319 | } | ||||||
| 320 | |||||||
| 321 | bool err; | ||||||
| 322 | |||||||
| 323 | PKEncodingType encoding_type = config.type_.ToChecked(); | ||||||
| 324 | if (encoding_type == kKeyEncodingPKCS1) { | ||||||
| 325 | // PKCS#1 is only permitted for RSA keys. | ||||||
| 326 | CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_RSA)do { if (__builtin_expect(!!(!((EVP_PKEY_get_id(pkey)) == (6) )), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "326", "(EVP_PKEY_get_id(pkey)) == (6)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 327 | |||||||
| 328 | RSAPointer rsa(EVP_PKEY_get1_RSA(pkey)); | ||||||
| 329 | if (config.format_ == kKeyFormatPEM) { | ||||||
| 330 | // Encode PKCS#1 as PEM. | ||||||
| 331 | err = PEM_write_bio_RSAPrivateKey( | ||||||
| 332 | bio.get(), rsa.get(), | ||||||
| 333 | config.cipher_, | ||||||
| 334 | reinterpret_cast<unsigned char*>(pass), | ||||||
| 335 | pass_len, | ||||||
| 336 | nullptr, nullptr) != 1; | ||||||
| 337 | } else { | ||||||
| 338 | // Encode PKCS#1 as DER. This does not permit encryption. | ||||||
| 339 | CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "339", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 340 | CHECK_NULL(config.cipher_)do { if (__builtin_expect(!!(!((config.cipher_) == nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "340", "(config.cipher_) == nullptr", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 341 | err = i2d_RSAPrivateKey_bio(bio.get(), rsa.get()) != 1; | ||||||
| 342 | } | ||||||
| 343 | } else if (encoding_type == kKeyEncodingPKCS8) { | ||||||
| 344 | if (config.format_ == kKeyFormatPEM) { | ||||||
| 345 | // Encode PKCS#8 as PEM. | ||||||
| 346 | err = PEM_write_bio_PKCS8PrivateKey( | ||||||
| 347 | bio.get(), pkey, | ||||||
| 348 | config.cipher_, | ||||||
| 349 | pass, | ||||||
| 350 | pass_len, | ||||||
| 351 | nullptr, nullptr) != 1; | ||||||
| 352 | } else { | ||||||
| 353 | // Encode PKCS#8 as DER. | ||||||
| 354 | CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "354", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 355 | err = i2d_PKCS8PrivateKey_bio( | ||||||
| 356 | bio.get(), pkey, | ||||||
| 357 | config.cipher_, | ||||||
| 358 | pass, | ||||||
| 359 | pass_len, | ||||||
| 360 | nullptr, nullptr) != 1; | ||||||
| 361 | } | ||||||
| 362 | } else { | ||||||
| 363 | CHECK_EQ(encoding_type, kKeyEncodingSEC1)do { if (__builtin_expect(!!(!((encoding_type) == (kKeyEncodingSEC1 ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "363", "(encoding_type) == (kKeyEncodingSEC1)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 364 | |||||||
| 365 | // SEC1 is only permitted for EC keys. | ||||||
| 366 | CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_EC)do { if (__builtin_expect(!!(!((EVP_PKEY_get_id(pkey)) == (408 ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "366", "(EVP_PKEY_get_id(pkey)) == (408)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 367 | |||||||
| 368 | ECKeyPointer ec_key(EVP_PKEY_get1_EC_KEY(pkey)); | ||||||
| 369 | if (config.format_ == kKeyFormatPEM) { | ||||||
| 370 | // Encode SEC1 as PEM. | ||||||
| 371 | err = PEM_write_bio_ECPrivateKey( | ||||||
| 372 | bio.get(), ec_key.get(), | ||||||
| 373 | config.cipher_, | ||||||
| 374 | reinterpret_cast<unsigned char*>(pass), | ||||||
| 375 | pass_len, | ||||||
| 376 | nullptr, nullptr) != 1; | ||||||
| 377 | } else { | ||||||
| 378 | // Encode SEC1 as DER. This does not permit encryption. | ||||||
| 379 | CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "379", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 380 | CHECK_NULL(config.cipher_)do { if (__builtin_expect(!!(!((config.cipher_) == nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "380", "(config.cipher_) == nullptr", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 381 | err = i2d_ECPrivateKey_bio(bio.get(), ec_key.get()) != 1; | ||||||
| 382 | } | ||||||
| 383 | } | ||||||
| 384 | |||||||
| 385 | if (err) { | ||||||
| 386 | ThrowCryptoError(env, ERR_get_error(), "Failed to encode private key"); | ||||||
| 387 | return MaybeLocal<Value>(); | ||||||
| 388 | } | ||||||
| 389 | return BIOToStringOrBuffer(env, bio.get(), config.format_); | ||||||
| 390 | } | ||||||
| 391 | |||||||
| 392 | bool WritePublicKeyInner(EVP_PKEY* pkey, | ||||||
| 393 | const BIOPointer& bio, | ||||||
| 394 | const PublicKeyEncodingConfig& config) { | ||||||
| 395 | if (config.type_.ToChecked() == kKeyEncodingPKCS1) { | ||||||
| 396 | // PKCS#1 is only valid for RSA keys. | ||||||
| 397 | CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_RSA)do { if (__builtin_expect(!!(!((EVP_PKEY_get_id(pkey)) == (6) )), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "397", "(EVP_PKEY_get_id(pkey)) == (6)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 398 | RSAPointer rsa(EVP_PKEY_get1_RSA(pkey)); | ||||||
| 399 | if (config.format_ == kKeyFormatPEM) { | ||||||
| 400 | // Encode PKCS#1 as PEM. | ||||||
| 401 | return PEM_write_bio_RSAPublicKey(bio.get(), rsa.get()) == 1; | ||||||
| 402 | } else { | ||||||
| 403 | // Encode PKCS#1 as DER. | ||||||
| 404 | CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "404", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 405 | return i2d_RSAPublicKey_bio(bio.get(), rsa.get()) == 1; | ||||||
| 406 | } | ||||||
| 407 | } else { | ||||||
| 408 | CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSPKI)do { if (__builtin_expect(!!(!((config.type_.ToChecked()) == ( kKeyEncodingSPKI))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "408", "(config.type_.ToChecked()) == (kKeyEncodingSPKI)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 409 | if (config.format_ == kKeyFormatPEM) { | ||||||
| 410 | // Encode SPKI as PEM. | ||||||
| 411 | return PEM_write_bio_PUBKEY(bio.get(), pkey) == 1; | ||||||
| 412 | } else { | ||||||
| 413 | // Encode SPKI as DER. | ||||||
| 414 | CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "414", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 415 | return i2d_PUBKEY_bio(bio.get(), pkey) == 1; | ||||||
| 416 | } | ||||||
| 417 | } | ||||||
| 418 | } | ||||||
| 419 | |||||||
| 420 | MaybeLocal<Value> WritePublicKey(Environment* env, | ||||||
| 421 | EVP_PKEY* pkey, | ||||||
| 422 | const PublicKeyEncodingConfig& config) { | ||||||
| 423 | BIOPointer bio(BIO_new(BIO_s_mem())); | ||||||
| 424 | CHECK(bio)do { if (__builtin_expect(!!(!(bio)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "424", "bio", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 425 | |||||||
| 426 | if (!WritePublicKeyInner(pkey, bio, config)) { | ||||||
| 427 | ThrowCryptoError(env, ERR_get_error(), "Failed to encode public key"); | ||||||
| 428 | return MaybeLocal<Value>(); | ||||||
| 429 | } | ||||||
| 430 | return BIOToStringOrBuffer(env, bio.get(), config.format_); | ||||||
| 431 | } | ||||||
| 432 | |||||||
| 433 | Maybe<bool> ExportJWKSecretKey( | ||||||
| 434 | Environment* env, | ||||||
| 435 | std::shared_ptr<KeyObjectData> key, | ||||||
| 436 | Local<Object> target) { | ||||||
| 437 | CHECK_EQ(key->GetKeyType(), kKeyTypeSecret)do { if (__builtin_expect(!!(!((key->GetKeyType()) == (kKeyTypeSecret ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "437", "(key->GetKeyType()) == (kKeyTypeSecret)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 438 | |||||||
| 439 | Local<Value> error; | ||||||
| 440 | Local<Value> raw; | ||||||
| 441 | MaybeLocal<Value> key_data = | ||||||
| 442 | StringBytes::Encode( | ||||||
| 443 | env->isolate(), | ||||||
| 444 | key->GetSymmetricKey(), | ||||||
| 445 | key->GetSymmetricKeySize(), | ||||||
| 446 | BASE64URL, | ||||||
| 447 | &error); | ||||||
| 448 | if (key_data.IsEmpty()) { | ||||||
| 449 | CHECK(!error.IsEmpty())do { if (__builtin_expect(!!(!(!error.IsEmpty())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "449", "!error.IsEmpty()", __PRETTY_FUNCTION__ }; node:: Assert(args); } while (0); } } while (0); | ||||||
| 450 | env->isolate()->ThrowException(error); | ||||||
| 451 | return Nothing<bool>(); | ||||||
| 452 | } | ||||||
| 453 | if (!key_data.ToLocal(&raw)) | ||||||
| 454 | return Nothing<bool>(); | ||||||
| 455 | |||||||
| 456 | if (target->Set( | ||||||
| 457 | env->context(), | ||||||
| 458 | env->jwk_kty_string(), | ||||||
| 459 | env->jwk_oct_string()).IsNothing() || | ||||||
| 460 | target->Set( | ||||||
| 461 | env->context(), | ||||||
| 462 | env->jwk_k_string(), | ||||||
| 463 | raw).IsNothing()) { | ||||||
| 464 | return Nothing<bool>(); | ||||||
| 465 | } | ||||||
| 466 | |||||||
| 467 | return Just(true); | ||||||
| 468 | } | ||||||
| 469 | |||||||
| 470 | std::shared_ptr<KeyObjectData> ImportJWKSecretKey( | ||||||
| 471 | Environment* env, | ||||||
| 472 | Local<Object> jwk) { | ||||||
| 473 | Local<Value> key; | ||||||
| 474 | if (!jwk->Get(env->context(), env->jwk_k_string()).ToLocal(&key) || | ||||||
| 475 | !key->IsString()) { | ||||||
| 476 | THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK secret key format"); | ||||||
| 477 | return std::shared_ptr<KeyObjectData>(); | ||||||
| 478 | } | ||||||
| 479 | |||||||
| 480 | ByteSource key_data = ByteSource::FromEncodedString(env, key.As<String>()); | ||||||
| 481 | if (key_data.size() > INT_MAX2147483647) { | ||||||
| 482 | THROW_ERR_CRYPTO_INVALID_KEYLEN(env); | ||||||
| 483 | return std::shared_ptr<KeyObjectData>(); | ||||||
| 484 | } | ||||||
| 485 | |||||||
| 486 | return KeyObjectData::CreateSecret(std::move(key_data)); | ||||||
| 487 | } | ||||||
| 488 | |||||||
| 489 | Maybe<bool> ExportJWKAsymmetricKey( | ||||||
| 490 | Environment* env, | ||||||
| 491 | std::shared_ptr<KeyObjectData> key, | ||||||
| 492 | Local<Object> target, | ||||||
| 493 | bool handleRsaPss) { | ||||||
| 494 | switch (EVP_PKEY_idEVP_PKEY_get_id(key->GetAsymmetricKey().get())) { | ||||||
| 495 | case EVP_PKEY_RSA_PSS912: { | ||||||
| 496 | if (handleRsaPss) return ExportJWKRsaKey(env, key, target); | ||||||
| 497 | break; | ||||||
| 498 | } | ||||||
| 499 | case EVP_PKEY_RSA6: return ExportJWKRsaKey(env, key, target); | ||||||
| 500 | case EVP_PKEY_EC408: return ExportJWKEcKey(env, key, target).IsJust() ? | ||||||
| 501 | Just(true) : Nothing<bool>(); | ||||||
| 502 | case EVP_PKEY_ED255191087: | ||||||
| 503 | // Fall through | ||||||
| 504 | case EVP_PKEY_ED4481088: | ||||||
| 505 | // Fall through | ||||||
| 506 | case EVP_PKEY_X255191034: | ||||||
| 507 | // Fall through | ||||||
| 508 | case EVP_PKEY_X4481035: return ExportJWKEdKey(env, key, target); | ||||||
| 509 | } | ||||||
| 510 | THROW_ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE(env); | ||||||
| 511 | return Just(false); | ||||||
| 512 | } | ||||||
| 513 | |||||||
| 514 | std::shared_ptr<KeyObjectData> ImportJWKAsymmetricKey( | ||||||
| 515 | Environment* env, | ||||||
| 516 | Local<Object> jwk, | ||||||
| 517 | const char* kty, | ||||||
| 518 | const FunctionCallbackInfo<Value>& args, | ||||||
| 519 | unsigned int offset) { | ||||||
| 520 | if (strcmp(kty, "RSA") == 0) { | ||||||
| 521 | return ImportJWKRsaKey(env, jwk, args, offset); | ||||||
| 522 | } else if (strcmp(kty, "EC") == 0) { | ||||||
| 523 | return ImportJWKEcKey(env, jwk, args, offset); | ||||||
| 524 | } | ||||||
| 525 | |||||||
| 526 | THROW_ERR_CRYPTO_INVALID_JWK(env, "%s is not a supported JWK key type", kty); | ||||||
| 527 | return std::shared_ptr<KeyObjectData>(); | ||||||
| 528 | } | ||||||
| 529 | |||||||
| 530 | Maybe<bool> GetSecretKeyDetail( | ||||||
| 531 | Environment* env, | ||||||
| 532 | std::shared_ptr<KeyObjectData> key, | ||||||
| 533 | Local<Object> target) { | ||||||
| 534 | // For the secret key detail, all we care about is the length, | ||||||
| 535 | // converted to bits. | ||||||
| 536 | |||||||
| 537 | size_t length = key->GetSymmetricKeySize() * CHAR_BIT8; | ||||||
| 538 | return target->Set(env->context(), | ||||||
| 539 | env->length_string(), | ||||||
| 540 | Number::New(env->isolate(), static_cast<double>(length))); | ||||||
| 541 | } | ||||||
| 542 | |||||||
| 543 | Maybe<bool> GetAsymmetricKeyDetail( | ||||||
| 544 | Environment* env, | ||||||
| 545 | std::shared_ptr<KeyObjectData> key, | ||||||
| 546 | Local<Object> target) { | ||||||
| 547 | switch (EVP_PKEY_idEVP_PKEY_get_id(key->GetAsymmetricKey().get())) { | ||||||
| 548 | case EVP_PKEY_RSA6: | ||||||
| 549 | // Fall through | ||||||
| 550 | case EVP_PKEY_RSA_PSS912: return GetRsaKeyDetail(env, key, target); | ||||||
| 551 | case EVP_PKEY_DSA116: return GetDsaKeyDetail(env, key, target); | ||||||
| 552 | case EVP_PKEY_EC408: return GetEcKeyDetail(env, key, target); | ||||||
| 553 | case EVP_PKEY_DH28: return GetDhKeyDetail(env, key, target); | ||||||
| 554 | } | ||||||
| 555 | THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); | ||||||
| 556 | return Nothing<bool>(); | ||||||
| 557 | } | ||||||
| 558 | } // namespace | ||||||
| 559 | |||||||
| 560 | ManagedEVPPKey::ManagedEVPPKey(EVPKeyPointer&& pkey) : pkey_(std::move(pkey)), | ||||||
| 561 | mutex_(std::make_shared<Mutex>()) {} | ||||||
| 562 | |||||||
| 563 | ManagedEVPPKey::ManagedEVPPKey(const ManagedEVPPKey& that) { | ||||||
| 564 | *this = that; | ||||||
| 565 | } | ||||||
| 566 | |||||||
| 567 | ManagedEVPPKey& ManagedEVPPKey::operator=(const ManagedEVPPKey& that) { | ||||||
| 568 | Mutex::ScopedLock lock(*that.mutex_); | ||||||
| 569 | |||||||
| 570 | pkey_.reset(that.get()); | ||||||
| 571 | |||||||
| 572 | if (pkey_) | ||||||
| 573 | EVP_PKEY_up_ref(pkey_.get()); | ||||||
| 574 | |||||||
| 575 | mutex_ = that.mutex_; | ||||||
| 576 | |||||||
| 577 | return *this; | ||||||
| 578 | } | ||||||
| 579 | |||||||
| 580 | ManagedEVPPKey::operator bool() const { | ||||||
| 581 | return !!pkey_; | ||||||
| 582 | } | ||||||
| 583 | |||||||
| 584 | EVP_PKEY* ManagedEVPPKey::get() const { | ||||||
| 585 | return pkey_.get(); | ||||||
| 586 | } | ||||||
| 587 | |||||||
| 588 | Mutex* ManagedEVPPKey::mutex() const { | ||||||
| 589 | return mutex_.get(); | ||||||
| 590 | } | ||||||
| 591 | |||||||
| 592 | void ManagedEVPPKey::MemoryInfo(MemoryTracker* tracker) const { | ||||||
| 593 | tracker->TrackFieldWithSize("pkey", | ||||||
| 594 | !pkey_ ? 0 : kSizeOf_EVP_PKEY + | ||||||
| 595 | size_of_private_key() + | ||||||
| 596 | size_of_public_key()); | ||||||
| 597 | } | ||||||
| 598 | |||||||
| 599 | size_t ManagedEVPPKey::size_of_private_key() const { | ||||||
| 600 | size_t len = 0; | ||||||
| 601 | return (pkey_ && EVP_PKEY_get_raw_private_key( | ||||||
| 602 | pkey_.get(), nullptr, &len) == 1) ? len : 0; | ||||||
| 603 | } | ||||||
| 604 | |||||||
| 605 | size_t ManagedEVPPKey::size_of_public_key() const { | ||||||
| 606 | size_t len = 0; | ||||||
| 607 | return (pkey_ && EVP_PKEY_get_raw_public_key( | ||||||
| 608 | pkey_.get(), nullptr, &len) == 1) ? len : 0; | ||||||
| 609 | } | ||||||
| 610 | |||||||
| 611 | // This maps true to Just<bool>(true) and false to Nothing<bool>(). | ||||||
| 612 | static inline Maybe<bool> Tristate(bool b) { | ||||||
| 613 | return b ? Just(true) : Nothing<bool>(); | ||||||
| 614 | } | ||||||
| 615 | |||||||
| 616 | Maybe<bool> ExportJWKInner(Environment* env, | ||||||
| 617 | std::shared_ptr<KeyObjectData> key, | ||||||
| 618 | Local<Value> result, | ||||||
| 619 | bool handleRsaPss) { | ||||||
| 620 | switch (key->GetKeyType()) { | ||||||
| 621 | case kKeyTypeSecret: | ||||||
| 622 | return ExportJWKSecretKey(env, key, result.As<Object>()); | ||||||
| 623 | case kKeyTypePublic: | ||||||
| 624 | // Fall through | ||||||
| 625 | case kKeyTypePrivate: | ||||||
| 626 | return ExportJWKAsymmetricKey( | ||||||
| 627 | env, key, result.As<Object>(), handleRsaPss); | ||||||
| 628 | default: | ||||||
| 629 | UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "629", "\"Unreachable code reached\"", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); | ||||||
| 630 | } | ||||||
| 631 | } | ||||||
| 632 | |||||||
| 633 | Maybe<bool> ManagedEVPPKey::ToEncodedPublicKey( | ||||||
| 634 | Environment* env, | ||||||
| 635 | ManagedEVPPKey key, | ||||||
| 636 | const PublicKeyEncodingConfig& config, | ||||||
| 637 | Local<Value>* out) { | ||||||
| 638 | if (!key) return Nothing<bool>(); | ||||||
| 639 | if (config.output_key_object_) { | ||||||
| 640 | // Note that this has the downside of containing sensitive data of the | ||||||
| 641 | // private key. | ||||||
| 642 | std::shared_ptr<KeyObjectData> data = | ||||||
| 643 | KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key)); | ||||||
| 644 | return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out)); | ||||||
| 645 | } else if (config.format_ == kKeyFormatJWK) { | ||||||
| 646 | std::shared_ptr<KeyObjectData> data = | ||||||
| 647 | KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key)); | ||||||
| 648 | *out = Object::New(env->isolate()); | ||||||
| 649 | return ExportJWKInner(env, data, *out, false); | ||||||
| 650 | } | ||||||
| 651 | |||||||
| 652 | return Tristate(WritePublicKey(env, key.get(), config).ToLocal(out)); | ||||||
| 653 | } | ||||||
| 654 | |||||||
| 655 | Maybe<bool> ManagedEVPPKey::ToEncodedPrivateKey( | ||||||
| 656 | Environment* env, | ||||||
| 657 | ManagedEVPPKey key, | ||||||
| 658 | const PrivateKeyEncodingConfig& config, | ||||||
| 659 | Local<Value>* out) { | ||||||
| 660 | if (!key) return Nothing<bool>(); | ||||||
| 661 | if (config.output_key_object_) { | ||||||
| 662 | std::shared_ptr<KeyObjectData> data = | ||||||
| 663 | KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key)); | ||||||
| 664 | return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out)); | ||||||
| 665 | } else if (config.format_ == kKeyFormatJWK) { | ||||||
| 666 | std::shared_ptr<KeyObjectData> data = | ||||||
| 667 | KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key)); | ||||||
| 668 | *out = Object::New(env->isolate()); | ||||||
| 669 | return ExportJWKInner(env, data, *out, false); | ||||||
| 670 | } | ||||||
| 671 | |||||||
| 672 | return Tristate(WritePrivateKey(env, key.get(), config).ToLocal(out)); | ||||||
| 673 | } | ||||||
| 674 | |||||||
| 675 | NonCopyableMaybe<PrivateKeyEncodingConfig> | ||||||
| 676 | ManagedEVPPKey::GetPrivateKeyEncodingFromJs( | ||||||
| 677 | const FunctionCallbackInfo<Value>& args, | ||||||
| 678 | unsigned int* offset, | ||||||
| 679 | KeyEncodingContext context) { | ||||||
| 680 | Environment* env = Environment::GetCurrent(args); | ||||||
| 681 | |||||||
| 682 | PrivateKeyEncodingConfig result; | ||||||
| 683 | GetKeyFormatAndTypeFromJs(&result, args, offset, context); | ||||||
| 684 | |||||||
| 685 | if (result.output_key_object_
| ||||||
| 686 | if (context != kKeyContextInput) | ||||||
| 687 | (*offset)++; | ||||||
| 688 | } else { | ||||||
| 689 | bool needs_passphrase = false; | ||||||
| 690 | if (context
| ||||||
| 691 | if (args[*offset]->IsString()) { | ||||||
| 692 | Utf8Value cipher_name(env->isolate(), args[*offset]); | ||||||
| 693 | result.cipher_ = EVP_get_cipherbyname(*cipher_name); | ||||||
| 694 | if (result.cipher_ == nullptr) { | ||||||
| 695 | THROW_ERR_CRYPTO_UNKNOWN_CIPHER(env); | ||||||
| 696 | return NonCopyableMaybe<PrivateKeyEncodingConfig>(); | ||||||
| 697 | } | ||||||
| 698 | needs_passphrase = true; | ||||||
| 699 | } else { | ||||||
| 700 | CHECK(args[*offset]->IsNullOrUndefined())do { if (__builtin_expect(!!(!(args[*offset]->IsNullOrUndefined ())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "700", "args[*offset]->IsNullOrUndefined()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 701 | result.cipher_ = nullptr; | ||||||
| 702 | } | ||||||
| 703 | (*offset)++; | ||||||
| 704 | } | ||||||
| 705 | |||||||
| 706 | if (IsAnyByteSource(args[*offset])) { | ||||||
| 707 | CHECK_IMPLIES(context != kKeyContextInput, result.cipher_ != nullptr)do { if (__builtin_expect(!!(!(!(context != kKeyContextInput) || (result.cipher_ != nullptr))), 0)) { do { static const node ::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "707" , "!(context != kKeyContextInput) || (result.cipher_ != nullptr)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 708 | ArrayBufferOrViewContents<char> passphrase(args[*offset]); | ||||||
| 709 | if (UNLIKELY(!passphrase.CheckSizeInt32())__builtin_expect(!!(!passphrase.CheckSizeInt32()), 0)) { | ||||||
| 710 | THROW_ERR_OUT_OF_RANGE(env, "passphrase is too big"); | ||||||
| 711 | return NonCopyableMaybe<PrivateKeyEncodingConfig>(); | ||||||
| 712 | } | ||||||
| 713 | result.passphrase_ = NonCopyableMaybe<ByteSource>( | ||||||
| 714 | passphrase.ToNullTerminatedCopy()); | ||||||
| 715 | } else { | ||||||
| 716 | CHECK(args[*offset]->IsNullOrUndefined() && !needs_passphrase)do { if (__builtin_expect(!!(!(args[*offset]->IsNullOrUndefined () && !needs_passphrase)), 0)) { do { static const node ::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "716" , "args[*offset]->IsNullOrUndefined() && !needs_passphrase" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 717 | } | ||||||
| 718 | } | ||||||
| 719 | |||||||
| 720 | (*offset)++; | ||||||
| 721 | return NonCopyableMaybe<PrivateKeyEncodingConfig>(std::move(result)); | ||||||
| 722 | } | ||||||
| 723 | |||||||
| 724 | PublicKeyEncodingConfig ManagedEVPPKey::GetPublicKeyEncodingFromJs( | ||||||
| 725 | const FunctionCallbackInfo<Value>& args, | ||||||
| 726 | unsigned int* offset, | ||||||
| 727 | KeyEncodingContext context) { | ||||||
| 728 | PublicKeyEncodingConfig result; | ||||||
| 729 | GetKeyFormatAndTypeFromJs(&result, args, offset, context); | ||||||
| 730 | return result; | ||||||
| 731 | } | ||||||
| 732 | |||||||
| 733 | ManagedEVPPKey ManagedEVPPKey::GetPrivateKeyFromJs( | ||||||
| 734 | const FunctionCallbackInfo<Value>& args, | ||||||
| 735 | unsigned int* offset, | ||||||
| 736 | bool allow_key_object) { | ||||||
| 737 | if (args[*offset]->IsString() || IsAnyByteSource(args[*offset])) { | ||||||
| 738 | Environment* env = Environment::GetCurrent(args); | ||||||
| 739 | ByteSource key = ByteSource::FromStringOrBuffer(env, args[(*offset)++]); | ||||||
| 740 | NonCopyableMaybe<PrivateKeyEncodingConfig> config = | ||||||
| 741 | GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput); | ||||||
| 742 | if (config.IsEmpty()) | ||||||
| 743 | return ManagedEVPPKey(); | ||||||
| 744 | |||||||
| 745 | EVPKeyPointer pkey; | ||||||
| 746 | ParseKeyResult ret = | ||||||
| 747 | ParsePrivateKey(&pkey, config.Release(), key.data<char>(), key.size()); | ||||||
| 748 | return GetParsedKey(env, std::move(pkey), ret, | ||||||
| 749 | "Failed to read private key"); | ||||||
| 750 | } else { | ||||||
| 751 | CHECK(args[*offset]->IsObject() && allow_key_object)do { if (__builtin_expect(!!(!(args[*offset]->IsObject() && allow_key_object)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "751", "args[*offset]->IsObject() && allow_key_object" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 752 | KeyObjectHandle* key; | ||||||
| 753 | ASSIGN_OR_RETURN_UNWRAP(&key, args[*offset].As<Object>(), ManagedEVPPKey())do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args[*offset].As<Object>())); if (*&key == nullptr ) return ManagedEVPPKey(); } while (0); | ||||||
| 754 | CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePrivate)do { if (__builtin_expect(!!(!((key->Data()->GetKeyType ()) == (kKeyTypePrivate))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "754", "(key->Data()->GetKeyType()) == (kKeyTypePrivate)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 755 | (*offset) += 4; | ||||||
| 756 | return key->Data()->GetAsymmetricKey(); | ||||||
| 757 | } | ||||||
| 758 | } | ||||||
| 759 | |||||||
| 760 | ManagedEVPPKey ManagedEVPPKey::GetPublicOrPrivateKeyFromJs( | ||||||
| 761 | const FunctionCallbackInfo<Value>& args, | ||||||
| 762 | unsigned int* offset) { | ||||||
| 763 | if (IsAnyByteSource(args[*offset])) { | ||||||
| 764 | Environment* env = Environment::GetCurrent(args); | ||||||
| 765 | ArrayBufferOrViewContents<char> data(args[(*offset)++]); | ||||||
| 766 | if (UNLIKELY(!data.CheckSizeInt32())__builtin_expect(!!(!data.CheckSizeInt32()), 0)) { | ||||||
| 767 | THROW_ERR_OUT_OF_RANGE(env, "keyData is too big"); | ||||||
| 768 | return ManagedEVPPKey(); | ||||||
| 769 | } | ||||||
| 770 | NonCopyableMaybe<PrivateKeyEncodingConfig> config_ = | ||||||
| 771 | GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput); | ||||||
| 772 | if (config_.IsEmpty()) | ||||||
| 773 | return ManagedEVPPKey(); | ||||||
| 774 | |||||||
| 775 | ParseKeyResult ret; | ||||||
| 776 | PrivateKeyEncodingConfig config = config_.Release(); | ||||||
| 777 | EVPKeyPointer pkey; | ||||||
| 778 | if (config.format_ == kKeyFormatPEM) { | ||||||
| 779 | // For PEM, we can easily determine whether it is a public or private key | ||||||
| 780 | // by looking for the respective PEM tags. | ||||||
| 781 | ret = ParsePublicKeyPEM(&pkey, data.data(), data.size()); | ||||||
| 782 | if (ret == ParseKeyResult::kParseKeyNotRecognized) { | ||||||
| 783 | ret = ParsePrivateKey(&pkey, config, data.data(), data.size()); | ||||||
| 784 | } | ||||||
| 785 | } else { | ||||||
| 786 | // For DER, the type determines how to parse it. SPKI, PKCS#8 and SEC1 are | ||||||
| 787 | // easy, but PKCS#1 can be a public key or a private key. | ||||||
| 788 | bool is_public; | ||||||
| 789 | switch (config.type_.ToChecked()) { | ||||||
| 790 | case kKeyEncodingPKCS1: | ||||||
| 791 | is_public = !IsRSAPrivateKey( | ||||||
| 792 | reinterpret_cast<const unsigned char*>(data.data()), data.size()); | ||||||
| 793 | break; | ||||||
| 794 | case kKeyEncodingSPKI: | ||||||
| 795 | is_public = true; | ||||||
| 796 | break; | ||||||
| 797 | case kKeyEncodingPKCS8: | ||||||
| 798 | case kKeyEncodingSEC1: | ||||||
| 799 | is_public = false; | ||||||
| 800 | break; | ||||||
| 801 | default: | ||||||
| 802 | UNREACHABLE("Invalid key encoding type")do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "802", "\"Unreachable code reached\" \": \" \"Invalid key encoding type\"" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); | ||||||
| 803 | } | ||||||
| 804 | |||||||
| 805 | if (is_public) { | ||||||
| 806 | ret = ParsePublicKey(&pkey, config, data.data(), data.size()); | ||||||
| 807 | } else { | ||||||
| 808 | ret = ParsePrivateKey(&pkey, config, data.data(), data.size()); | ||||||
| 809 | } | ||||||
| 810 | } | ||||||
| 811 | |||||||
| 812 | return ManagedEVPPKey::GetParsedKey( | ||||||
| 813 | env, std::move(pkey), ret, "Failed to read asymmetric key"); | ||||||
| 814 | } else { | ||||||
| 815 | CHECK(args[*offset]->IsObject())do { if (__builtin_expect(!!(!(args[*offset]->IsObject())) , 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "815", "args[*offset]->IsObject()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 816 | KeyObjectHandle* key = Unwrap<KeyObjectHandle>(args[*offset].As<Object>()); | ||||||
| 817 | CHECK_NOT_NULL(key)do { if (__builtin_expect(!!(!((key) != nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "817", "(key) != nullptr", __PRETTY_FUNCTION__ }; node:: Assert(args); } while (0); } } while (0); | ||||||
| 818 | CHECK_NE(key->Data()->GetKeyType(), kKeyTypeSecret)do { if (__builtin_expect(!!(!((key->Data()->GetKeyType ()) != (kKeyTypeSecret))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "818", "(key->Data()->GetKeyType()) != (kKeyTypeSecret)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 819 | (*offset) += 4; | ||||||
| 820 | return key->Data()->GetAsymmetricKey(); | ||||||
| 821 | } | ||||||
| 822 | } | ||||||
| 823 | |||||||
| 824 | ManagedEVPPKey ManagedEVPPKey::GetParsedKey(Environment* env, | ||||||
| 825 | EVPKeyPointer&& pkey, | ||||||
| 826 | ParseKeyResult ret, | ||||||
| 827 | const char* default_msg) { | ||||||
| 828 | switch (ret) { | ||||||
| 829 | case ParseKeyResult::kParseKeyOk: | ||||||
| 830 | CHECK(pkey)do { if (__builtin_expect(!!(!(pkey)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "830", "pkey", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 831 | break; | ||||||
| 832 | case ParseKeyResult::kParseKeyNeedPassphrase: | ||||||
| 833 | THROW_ERR_MISSING_PASSPHRASE(env, | ||||||
| 834 | "Passphrase required for encrypted key"); | ||||||
| 835 | break; | ||||||
| 836 | default: | ||||||
| 837 | ThrowCryptoError(env, ERR_get_error(), default_msg); | ||||||
| 838 | } | ||||||
| 839 | |||||||
| 840 | return ManagedEVPPKey(std::move(pkey)); | ||||||
| 841 | } | ||||||
| 842 | |||||||
| 843 | KeyObjectData::KeyObjectData( | ||||||
| 844 | ByteSource symmetric_key) | ||||||
| 845 | : key_type_(KeyType::kKeyTypeSecret), | ||||||
| 846 | symmetric_key_(std::move(symmetric_key)), | ||||||
| 847 | symmetric_key_len_(symmetric_key_.size()), | ||||||
| 848 | asymmetric_key_() {} | ||||||
| 849 | |||||||
| 850 | KeyObjectData::KeyObjectData( | ||||||
| 851 | KeyType type, | ||||||
| 852 | const ManagedEVPPKey& pkey) | ||||||
| 853 | : key_type_(type), | ||||||
| 854 | symmetric_key_(), | ||||||
| 855 | symmetric_key_len_(0), | ||||||
| 856 | asymmetric_key_{pkey} {} | ||||||
| 857 | |||||||
| 858 | void KeyObjectData::MemoryInfo(MemoryTracker* tracker) const { | ||||||
| 859 | switch (GetKeyType()) { | ||||||
| 860 | case kKeyTypeSecret: | ||||||
| 861 | tracker->TrackFieldWithSize("symmetric_key", symmetric_key_.size()); | ||||||
| 862 | break; | ||||||
| 863 | case kKeyTypePrivate: | ||||||
| 864 | // Fall through | ||||||
| 865 | case kKeyTypePublic: | ||||||
| 866 | tracker->TrackFieldWithSize("key", asymmetric_key_); | ||||||
| 867 | break; | ||||||
| 868 | default: | ||||||
| 869 | UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "869", "\"Unreachable code reached\"", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); | ||||||
| 870 | } | ||||||
| 871 | } | ||||||
| 872 | |||||||
| 873 | std::shared_ptr<KeyObjectData> KeyObjectData::CreateSecret(ByteSource key) { | ||||||
| 874 | CHECK(key)do { if (__builtin_expect(!!(!(key)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "874", "key", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 875 | return std::shared_ptr<KeyObjectData>(new KeyObjectData(std::move(key))); | ||||||
| 876 | } | ||||||
| 877 | |||||||
| 878 | std::shared_ptr<KeyObjectData> KeyObjectData::CreateAsymmetric( | ||||||
| 879 | KeyType key_type, | ||||||
| 880 | const ManagedEVPPKey& pkey) { | ||||||
| 881 | CHECK(pkey)do { if (__builtin_expect(!!(!(pkey)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "881", "pkey", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 882 | return std::shared_ptr<KeyObjectData>(new KeyObjectData(key_type, pkey)); | ||||||
| 883 | } | ||||||
| 884 | |||||||
| 885 | KeyType KeyObjectData::GetKeyType() const { | ||||||
| 886 | return key_type_; | ||||||
| 887 | } | ||||||
| 888 | |||||||
| 889 | ManagedEVPPKey KeyObjectData::GetAsymmetricKey() const { | ||||||
| 890 | CHECK_NE(key_type_, kKeyTypeSecret)do { if (__builtin_expect(!!(!((key_type_) != (kKeyTypeSecret ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "890", "(key_type_) != (kKeyTypeSecret)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 891 | return asymmetric_key_; | ||||||
| 892 | } | ||||||
| 893 | |||||||
| 894 | const char* KeyObjectData::GetSymmetricKey() const { | ||||||
| 895 | CHECK_EQ(key_type_, kKeyTypeSecret)do { if (__builtin_expect(!!(!((key_type_) == (kKeyTypeSecret ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "895", "(key_type_) == (kKeyTypeSecret)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 896 | return symmetric_key_.data<char>(); | ||||||
| 897 | } | ||||||
| 898 | |||||||
| 899 | size_t KeyObjectData::GetSymmetricKeySize() const { | ||||||
| 900 | CHECK_EQ(key_type_, kKeyTypeSecret)do { if (__builtin_expect(!!(!((key_type_) == (kKeyTypeSecret ))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "900", "(key_type_) == (kKeyTypeSecret)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 901 | return symmetric_key_len_; | ||||||
| 902 | } | ||||||
| 903 | |||||||
| 904 | v8::Local<v8::Function> KeyObjectHandle::Initialize(Environment* env) { | ||||||
| 905 | Local<Function> templ = env->crypto_key_object_handle_constructor(); | ||||||
| 906 | if (!templ.IsEmpty()) { | ||||||
| 907 | return templ; | ||||||
| 908 | } | ||||||
| 909 | Local<FunctionTemplate> t = env->NewFunctionTemplate(New); | ||||||
| 910 | t->InstanceTemplate()->SetInternalFieldCount( | ||||||
| 911 | KeyObjectHandle::kInternalFieldCount); | ||||||
| 912 | t->Inherit(BaseObject::GetConstructorTemplate(env)); | ||||||
| 913 | |||||||
| 914 | env->SetProtoMethod(t, "init", Init); | ||||||
| 915 | env->SetProtoMethodNoSideEffect(t, "getSymmetricKeySize", | ||||||
| 916 | GetSymmetricKeySize); | ||||||
| 917 | env->SetProtoMethodNoSideEffect(t, "getAsymmetricKeyType", | ||||||
| 918 | GetAsymmetricKeyType); | ||||||
| 919 | env->SetProtoMethod(t, "export", Export); | ||||||
| 920 | env->SetProtoMethod(t, "exportJwk", ExportJWK); | ||||||
| 921 | env->SetProtoMethod(t, "initECRaw", InitECRaw); | ||||||
| 922 | env->SetProtoMethod(t, "initEDRaw", InitEDRaw); | ||||||
| 923 | env->SetProtoMethod(t, "initJwk", InitJWK); | ||||||
| 924 | env->SetProtoMethod(t, "keyDetail", GetKeyDetail); | ||||||
| 925 | env->SetProtoMethod(t, "equals", Equals); | ||||||
| 926 | |||||||
| 927 | auto function = t->GetFunction(env->context()).ToLocalChecked(); | ||||||
| 928 | env->set_crypto_key_object_handle_constructor(function); | ||||||
| 929 | return function; | ||||||
| 930 | } | ||||||
| 931 | |||||||
| 932 | void KeyObjectHandle::RegisterExternalReferences( | ||||||
| 933 | ExternalReferenceRegistry* registry) { | ||||||
| 934 | registry->Register(New); | ||||||
| 935 | registry->Register(Init); | ||||||
| 936 | registry->Register(GetSymmetricKeySize); | ||||||
| 937 | registry->Register(GetAsymmetricKeyType); | ||||||
| 938 | registry->Register(Export); | ||||||
| 939 | registry->Register(ExportJWK); | ||||||
| 940 | registry->Register(InitECRaw); | ||||||
| 941 | registry->Register(InitEDRaw); | ||||||
| 942 | registry->Register(InitJWK); | ||||||
| 943 | registry->Register(GetKeyDetail); | ||||||
| 944 | registry->Register(Equals); | ||||||
| 945 | } | ||||||
| 946 | |||||||
| 947 | MaybeLocal<Object> KeyObjectHandle::Create( | ||||||
| 948 | Environment* env, | ||||||
| 949 | std::shared_ptr<KeyObjectData> data) { | ||||||
| 950 | Local<Object> obj; | ||||||
| 951 | Local<Function> ctor = KeyObjectHandle::Initialize(env); | ||||||
| 952 | CHECK(!env->crypto_key_object_handle_constructor().IsEmpty())do { if (__builtin_expect(!!(!(!env->crypto_key_object_handle_constructor ().IsEmpty())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "952", "!env->crypto_key_object_handle_constructor().IsEmpty()" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 953 | if (!ctor->NewInstance(env->context(), 0, nullptr).ToLocal(&obj)) | ||||||
| 954 | return MaybeLocal<Object>(); | ||||||
| 955 | |||||||
| 956 | KeyObjectHandle* key = Unwrap<KeyObjectHandle>(obj); | ||||||
| 957 | CHECK_NOT_NULL(key)do { if (__builtin_expect(!!(!((key) != nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "957", "(key) != nullptr", __PRETTY_FUNCTION__ }; node:: Assert(args); } while (0); } } while (0); | ||||||
| 958 | key->data_ = data; | ||||||
| 959 | return obj; | ||||||
| 960 | } | ||||||
| 961 | |||||||
| 962 | const std::shared_ptr<KeyObjectData>& KeyObjectHandle::Data() { | ||||||
| 963 | return data_; | ||||||
| 964 | } | ||||||
| 965 | |||||||
| 966 | void KeyObjectHandle::New(const FunctionCallbackInfo<Value>& args) { | ||||||
| 967 | CHECK(args.IsConstructCall())do { if (__builtin_expect(!!(!(args.IsConstructCall())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "967", "args.IsConstructCall()", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | ||||||
| 968 | Environment* env = Environment::GetCurrent(args); | ||||||
| 969 | new KeyObjectHandle(env, args.This()); | ||||||
| 970 | } | ||||||
| 971 | |||||||
| 972 | KeyObjectHandle::KeyObjectHandle(Environment* env, | ||||||
| 973 | Local<Object> wrap) | ||||||
| 974 | : BaseObject(env, wrap) { | ||||||
| 975 | MakeWeak(); | ||||||
| 976 | } | ||||||
| 977 | |||||||
| 978 | void KeyObjectHandle::Init(const FunctionCallbackInfo<Value>& args) { | ||||||
| 979 | KeyObjectHandle* key; | ||||||
| 980 | ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args.Holder())); if (*&key == nullptr) return ; } while ( 0); | ||||||
| |||||||
| 981 | MarkPopErrorOnReturn mark_pop_error_on_return; | ||||||
| 982 | |||||||
| 983 | CHECK(args[0]->IsInt32())do { if (__builtin_expect(!!(!(args[0]->IsInt32())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "983", "args[0]->IsInt32()", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | ||||||
| 984 | KeyType type = static_cast<KeyType>(args[0].As<Uint32>()->Value()); | ||||||
| 985 | |||||||
| 986 | unsigned int offset; | ||||||
| 987 | ManagedEVPPKey pkey; | ||||||
| 988 | |||||||
| 989 | switch (type) { | ||||||
| 990 | case kKeyTypeSecret: { | ||||||
| 991 | CHECK_EQ(args.Length(), 2)do { if (__builtin_expect(!!(!((args.Length()) == (2))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "991", "(args.Length()) == (2)", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | ||||||
| 992 | ArrayBufferOrViewContents<char> buf(args[1]); | ||||||
| 993 | key->data_ = KeyObjectData::CreateSecret(buf.ToCopy()); | ||||||
| 994 | break; | ||||||
| 995 | } | ||||||
| 996 | case kKeyTypePublic: { | ||||||
| 997 | CHECK_EQ(args.Length(), 5)do { if (__builtin_expect(!!(!((args.Length()) == (5))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "997", "(args.Length()) == (5)", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | ||||||
| 998 | |||||||
| 999 | offset = 1; | ||||||
| 1000 | pkey = ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(args, &offset); | ||||||
| 1001 | if (!pkey) | ||||||
| 1002 | return; | ||||||
| 1003 | key->data_ = KeyObjectData::CreateAsymmetric(type, pkey); | ||||||
| 1004 | break; | ||||||
| 1005 | } | ||||||
| 1006 | case kKeyTypePrivate: { | ||||||
| 1007 | CHECK_EQ(args.Length(), 5)do { if (__builtin_expect(!!(!((args.Length()) == (5))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1007", "(args.Length()) == (5)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1008 | |||||||
| 1009 | offset = 1; | ||||||
| 1010 | pkey = ManagedEVPPKey::GetPrivateKeyFromJs(args, &offset, false); | ||||||
| 1011 | if (!pkey) | ||||||
| 1012 | return; | ||||||
| 1013 | key->data_ = KeyObjectData::CreateAsymmetric(type, pkey); | ||||||
| 1014 | break; | ||||||
| 1015 | } | ||||||
| 1016 | default: | ||||||
| 1017 | UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1017", "\"Unreachable code reached\"", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); | ||||||
| 1018 | } | ||||||
| 1019 | } | ||||||
| 1020 | |||||||
| 1021 | void KeyObjectHandle::InitJWK(const FunctionCallbackInfo<Value>& args) { | ||||||
| 1022 | Environment* env = Environment::GetCurrent(args); | ||||||
| 1023 | KeyObjectHandle* key; | ||||||
| 1024 | ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args.Holder())); if (*&key == nullptr) return ; } while ( 0); | ||||||
| 1025 | MarkPopErrorOnReturn mark_pop_error_on_return; | ||||||
| 1026 | |||||||
| 1027 | // The argument must be a JavaScript object that we will inspect | ||||||
| 1028 | // to get the JWK properties from. | ||||||
| 1029 | CHECK(args[0]->IsObject())do { if (__builtin_expect(!!(!(args[0]->IsObject())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1029", "args[0]->IsObject()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1030 | |||||||
| 1031 | // Step one, Secret key or not? | ||||||
| 1032 | Local<Object> input = args[0].As<Object>(); | ||||||
| 1033 | |||||||
| 1034 | Local<Value> kty; | ||||||
| 1035 | if (!input->Get(env->context(), env->jwk_kty_string()).ToLocal(&kty) || | ||||||
| 1036 | !kty->IsString()) { | ||||||
| 1037 | return THROW_ERR_CRYPTO_INVALID_JWK(env); | ||||||
| 1038 | } | ||||||
| 1039 | |||||||
| 1040 | Utf8Value kty_string(env->isolate(), kty); | ||||||
| 1041 | |||||||
| 1042 | if (strcmp(*kty_string, "oct") == 0) { | ||||||
| 1043 | // Secret key | ||||||
| 1044 | key->data_ = ImportJWKSecretKey(env, input); | ||||||
| 1045 | if (!key->data_) { | ||||||
| 1046 | // ImportJWKSecretKey is responsible for throwing an appropriate error | ||||||
| 1047 | return; | ||||||
| 1048 | } | ||||||
| 1049 | } else { | ||||||
| 1050 | key->data_ = ImportJWKAsymmetricKey(env, input, *kty_string, args, 1); | ||||||
| 1051 | if (!key->data_) { | ||||||
| 1052 | // ImportJWKAsymmetricKey is responsible for throwing an appropriate error | ||||||
| 1053 | return; | ||||||
| 1054 | } | ||||||
| 1055 | } | ||||||
| 1056 | |||||||
| 1057 | args.GetReturnValue().Set(key->data_->GetKeyType()); | ||||||
| 1058 | } | ||||||
| 1059 | |||||||
| 1060 | void KeyObjectHandle::InitECRaw(const FunctionCallbackInfo<Value>& args) { | ||||||
| 1061 | Environment* env = Environment::GetCurrent(args); | ||||||
| 1062 | KeyObjectHandle* key; | ||||||
| 1063 | ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args.Holder())); if (*&key == nullptr) return ; } while ( 0); | ||||||
| 1064 | |||||||
| 1065 | CHECK(args[0]->IsString())do { if (__builtin_expect(!!(!(args[0]->IsString())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1065", "args[0]->IsString()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1066 | Utf8Value name(env->isolate(), args[0]); | ||||||
| 1067 | |||||||
| 1068 | MarkPopErrorOnReturn mark_pop_error_on_return; | ||||||
| 1069 | |||||||
| 1070 | int id = OBJ_txt2nid(*name); | ||||||
| 1071 | ECKeyPointer eckey(EC_KEY_new_by_curve_name(id)); | ||||||
| 1072 | if (!eckey) | ||||||
| 1073 | return args.GetReturnValue().Set(false); | ||||||
| 1074 | |||||||
| 1075 | const EC_GROUP* group = EC_KEY_get0_group(eckey.get()); | ||||||
| 1076 | ECPointPointer pub(ECDH::BufferToPoint(env, group, args[1])); | ||||||
| 1077 | |||||||
| 1078 | if (!pub || | ||||||
| 1079 | !eckey || | ||||||
| 1080 | !EC_KEY_set_public_key(eckey.get(), pub.get())) { | ||||||
| 1081 | return args.GetReturnValue().Set(false); | ||||||
| 1082 | } | ||||||
| 1083 | |||||||
| 1084 | EVPKeyPointer pkey(EVP_PKEY_new()); | ||||||
| 1085 | if (!EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get())EVP_PKEY_assign((pkey.get()), 408, (eckey.get()))) | ||||||
| 1086 | args.GetReturnValue().Set(false); | ||||||
| 1087 | |||||||
| 1088 | eckey.release(); // Release ownership of the key | ||||||
| 1089 | |||||||
| 1090 | key->data_ = | ||||||
| 1091 | KeyObjectData::CreateAsymmetric( | ||||||
| 1092 | kKeyTypePublic, | ||||||
| 1093 | ManagedEVPPKey(std::move(pkey))); | ||||||
| 1094 | |||||||
| 1095 | args.GetReturnValue().Set(true); | ||||||
| 1096 | } | ||||||
| 1097 | |||||||
| 1098 | void KeyObjectHandle::InitEDRaw(const FunctionCallbackInfo<Value>& args) { | ||||||
| 1099 | Environment* env = Environment::GetCurrent(args); | ||||||
| 1100 | KeyObjectHandle* key; | ||||||
| 1101 | ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args.Holder())); if (*&key == nullptr) return ; } while ( 0); | ||||||
| 1102 | |||||||
| 1103 | CHECK(args[0]->IsString())do { if (__builtin_expect(!!(!(args[0]->IsString())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1103", "args[0]->IsString()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1104 | Utf8Value name(env->isolate(), args[0]); | ||||||
| 1105 | |||||||
| 1106 | ArrayBufferOrViewContents<unsigned char> key_data(args[1]); | ||||||
| 1107 | KeyType type = static_cast<KeyType>(args[2].As<Int32>()->Value()); | ||||||
| 1108 | |||||||
| 1109 | MarkPopErrorOnReturn mark_pop_error_on_return; | ||||||
| 1110 | |||||||
| 1111 | typedef EVP_PKEY* (*new_key_fn)(int, ENGINE*, const unsigned char*, size_t); | ||||||
| 1112 | new_key_fn fn = type == kKeyTypePrivate | ||||||
| 1113 | ? EVP_PKEY_new_raw_private_key | ||||||
| 1114 | : EVP_PKEY_new_raw_public_key; | ||||||
| 1115 | |||||||
| 1116 | int id = GetOKPCurveFromName(*name); | ||||||
| 1117 | |||||||
| 1118 | switch (id) { | ||||||
| 1119 | case EVP_PKEY_X255191034: | ||||||
| 1120 | case EVP_PKEY_X4481035: | ||||||
| 1121 | case EVP_PKEY_ED255191087: | ||||||
| 1122 | case EVP_PKEY_ED4481088: { | ||||||
| 1123 | EVPKeyPointer pkey(fn(id, nullptr, key_data.data(), key_data.size())); | ||||||
| 1124 | if (!pkey) | ||||||
| 1125 | return args.GetReturnValue().Set(false); | ||||||
| 1126 | key->data_ = | ||||||
| 1127 | KeyObjectData::CreateAsymmetric( | ||||||
| 1128 | type, | ||||||
| 1129 | ManagedEVPPKey(std::move(pkey))); | ||||||
| 1130 | CHECK(key->data_)do { if (__builtin_expect(!!(!(key->data_)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1130", "key->data_", __PRETTY_FUNCTION__ }; node::Assert (args); } while (0); } } while (0); | ||||||
| 1131 | break; | ||||||
| 1132 | } | ||||||
| 1133 | default: | ||||||
| 1134 | UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1134", "\"Unreachable code reached\"", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); | ||||||
| 1135 | } | ||||||
| 1136 | |||||||
| 1137 | args.GetReturnValue().Set(true); | ||||||
| 1138 | } | ||||||
| 1139 | |||||||
| 1140 | void KeyObjectHandle::Equals(const FunctionCallbackInfo<Value>& args) { | ||||||
| 1141 | KeyObjectHandle* self_handle; | ||||||
| 1142 | KeyObjectHandle* arg_handle; | ||||||
| 1143 | ASSIGN_OR_RETURN_UNWRAP(&self_handle, args.Holder())do { *&self_handle = static_cast<typename std::remove_reference <decltype(*&self_handle)>::type>( BaseObject::FromJSObject (args.Holder())); if (*&self_handle == nullptr) return ; } while (0); | ||||||
| 1144 | ASSIGN_OR_RETURN_UNWRAP(&arg_handle, args[0].As<Object>())do { *&arg_handle = static_cast<typename std::remove_reference <decltype(*&arg_handle)>::type>( BaseObject::FromJSObject (args[0].As<Object>())); if (*&arg_handle == nullptr ) return ; } while (0); | ||||||
| 1145 | std::shared_ptr<KeyObjectData> key = self_handle->Data(); | ||||||
| 1146 | std::shared_ptr<KeyObjectData> key2 = arg_handle->Data(); | ||||||
| 1147 | |||||||
| 1148 | KeyType key_type = key->GetKeyType(); | ||||||
| 1149 | CHECK_EQ(key_type, key2->GetKeyType())do { if (__builtin_expect(!!(!((key_type) == (key2->GetKeyType ()))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1149", "(key_type) == (key2->GetKeyType())", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1150 | |||||||
| 1151 | bool ret; | ||||||
| 1152 | switch (key_type) { | ||||||
| 1153 | case kKeyTypeSecret: { | ||||||
| 1154 | size_t size = key->GetSymmetricKeySize(); | ||||||
| 1155 | if (size == key2->GetSymmetricKeySize()) { | ||||||
| 1156 | ret = CRYPTO_memcmp( | ||||||
| 1157 | key->GetSymmetricKey(), | ||||||
| 1158 | key2->GetSymmetricKey(), | ||||||
| 1159 | size) == 0; | ||||||
| 1160 | } else { | ||||||
| 1161 | ret = false; | ||||||
| 1162 | } | ||||||
| 1163 | break; | ||||||
| 1164 | } | ||||||
| 1165 | case kKeyTypePublic: | ||||||
| 1166 | case kKeyTypePrivate: { | ||||||
| 1167 | EVP_PKEY* pkey = key->GetAsymmetricKey().get(); | ||||||
| 1168 | EVP_PKEY* pkey2 = key2->GetAsymmetricKey().get(); | ||||||
| 1169 | #if OPENSSL_VERSION_MAJOR3 >= 3 | ||||||
| 1170 | int ok = EVP_PKEY_eq(pkey, pkey2); | ||||||
| 1171 | #else | ||||||
| 1172 | int ok = EVP_PKEY_cmp(pkey, pkey2); | ||||||
| 1173 | #endif | ||||||
| 1174 | if (ok == -2) { | ||||||
| 1175 | Environment* env = Environment::GetCurrent(args); | ||||||
| 1176 | return THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env); | ||||||
| 1177 | } | ||||||
| 1178 | ret = ok == 1; | ||||||
| 1179 | break; | ||||||
| 1180 | } | ||||||
| 1181 | default: | ||||||
| 1182 | UNREACHABLE("unsupported key type")do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1182", "\"Unreachable code reached\" \": \" \"unsupported key type\"" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); | ||||||
| 1183 | } | ||||||
| 1184 | |||||||
| 1185 | args.GetReturnValue().Set(ret); | ||||||
| 1186 | } | ||||||
| 1187 | |||||||
| 1188 | void KeyObjectHandle::GetKeyDetail(const FunctionCallbackInfo<Value>& args) { | ||||||
| 1189 | Environment* env = Environment::GetCurrent(args); | ||||||
| 1190 | KeyObjectHandle* key; | ||||||
| 1191 | ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args.Holder())); if (*&key == nullptr) return ; } while ( 0); | ||||||
| 1192 | |||||||
| 1193 | CHECK(args[0]->IsObject())do { if (__builtin_expect(!!(!(args[0]->IsObject())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1193", "args[0]->IsObject()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1194 | |||||||
| 1195 | std::shared_ptr<KeyObjectData> data = key->Data(); | ||||||
| 1196 | |||||||
| 1197 | switch (data->GetKeyType()) { | ||||||
| 1198 | case kKeyTypeSecret: | ||||||
| 1199 | if (GetSecretKeyDetail(env, data, args[0].As<Object>()).IsNothing()) | ||||||
| 1200 | return; | ||||||
| 1201 | break; | ||||||
| 1202 | case kKeyTypePublic: | ||||||
| 1203 | // Fall through | ||||||
| 1204 | case kKeyTypePrivate: | ||||||
| 1205 | if (GetAsymmetricKeyDetail(env, data, args[0].As<Object>()).IsNothing()) | ||||||
| 1206 | return; | ||||||
| 1207 | break; | ||||||
| 1208 | default: | ||||||
| 1209 | UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1209", "\"Unreachable code reached\"", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); | ||||||
| 1210 | } | ||||||
| 1211 | |||||||
| 1212 | args.GetReturnValue().Set(args[0]); | ||||||
| 1213 | } | ||||||
| 1214 | |||||||
| 1215 | Local<Value> KeyObjectHandle::GetAsymmetricKeyType() const { | ||||||
| 1216 | const ManagedEVPPKey& key = data_->GetAsymmetricKey(); | ||||||
| 1217 | switch (EVP_PKEY_idEVP_PKEY_get_id(key.get())) { | ||||||
| 1218 | case EVP_PKEY_RSA6: | ||||||
| 1219 | return env()->crypto_rsa_string(); | ||||||
| 1220 | case EVP_PKEY_RSA_PSS912: | ||||||
| 1221 | return env()->crypto_rsa_pss_string(); | ||||||
| 1222 | case EVP_PKEY_DSA116: | ||||||
| 1223 | return env()->crypto_dsa_string(); | ||||||
| 1224 | case EVP_PKEY_DH28: | ||||||
| 1225 | return env()->crypto_dh_string(); | ||||||
| 1226 | case EVP_PKEY_EC408: | ||||||
| 1227 | return env()->crypto_ec_string(); | ||||||
| 1228 | case EVP_PKEY_ED255191087: | ||||||
| 1229 | return env()->crypto_ed25519_string(); | ||||||
| 1230 | case EVP_PKEY_ED4481088: | ||||||
| 1231 | return env()->crypto_ed448_string(); | ||||||
| 1232 | case EVP_PKEY_X255191034: | ||||||
| 1233 | return env()->crypto_x25519_string(); | ||||||
| 1234 | case EVP_PKEY_X4481035: | ||||||
| 1235 | return env()->crypto_x448_string(); | ||||||
| 1236 | default: | ||||||
| 1237 | return Undefined(env()->isolate()); | ||||||
| 1238 | } | ||||||
| 1239 | } | ||||||
| 1240 | |||||||
| 1241 | void KeyObjectHandle::GetAsymmetricKeyType( | ||||||
| 1242 | const FunctionCallbackInfo<Value>& args) { | ||||||
| 1243 | KeyObjectHandle* key; | ||||||
| 1244 | ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args.Holder())); if (*&key == nullptr) return ; } while ( 0); | ||||||
| 1245 | |||||||
| 1246 | args.GetReturnValue().Set(key->GetAsymmetricKeyType()); | ||||||
| 1247 | } | ||||||
| 1248 | |||||||
| 1249 | void KeyObjectHandle::GetSymmetricKeySize( | ||||||
| 1250 | const FunctionCallbackInfo<Value>& args) { | ||||||
| 1251 | KeyObjectHandle* key; | ||||||
| 1252 | ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args.Holder())); if (*&key == nullptr) return ; } while ( 0); | ||||||
| 1253 | args.GetReturnValue().Set( | ||||||
| 1254 | static_cast<uint32_t>(key->Data()->GetSymmetricKeySize())); | ||||||
| 1255 | } | ||||||
| 1256 | |||||||
| 1257 | void KeyObjectHandle::Export(const FunctionCallbackInfo<Value>& args) { | ||||||
| 1258 | KeyObjectHandle* key; | ||||||
| 1259 | ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args.Holder())); if (*&key == nullptr) return ; } while ( 0); | ||||||
| 1260 | |||||||
| 1261 | KeyType type = key->Data()->GetKeyType(); | ||||||
| 1262 | |||||||
| 1263 | MaybeLocal<Value> result; | ||||||
| 1264 | if (type == kKeyTypeSecret) { | ||||||
| 1265 | result = key->ExportSecretKey(); | ||||||
| 1266 | } else if (type == kKeyTypePublic) { | ||||||
| 1267 | unsigned int offset = 0; | ||||||
| 1268 | PublicKeyEncodingConfig config = | ||||||
| 1269 | ManagedEVPPKey::GetPublicKeyEncodingFromJs( | ||||||
| 1270 | args, &offset, kKeyContextExport); | ||||||
| 1271 | CHECK_EQ(offset, static_cast<unsigned int>(args.Length()))do { if (__builtin_expect(!!(!((offset) == (static_cast<unsigned int>(args.Length())))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1271", "(offset) == (static_cast<unsigned int>(args.Length()))" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1272 | result = key->ExportPublicKey(config); | ||||||
| 1273 | } else { | ||||||
| 1274 | CHECK_EQ(type, kKeyTypePrivate)do { if (__builtin_expect(!!(!((type) == (kKeyTypePrivate))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1274", "(type) == (kKeyTypePrivate)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1275 | unsigned int offset = 0; | ||||||
| 1276 | NonCopyableMaybe<PrivateKeyEncodingConfig> config = | ||||||
| 1277 | ManagedEVPPKey::GetPrivateKeyEncodingFromJs( | ||||||
| 1278 | args, &offset, kKeyContextExport); | ||||||
| 1279 | if (config.IsEmpty()) | ||||||
| 1280 | return; | ||||||
| 1281 | CHECK_EQ(offset, static_cast<unsigned int>(args.Length()))do { if (__builtin_expect(!!(!((offset) == (static_cast<unsigned int>(args.Length())))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1281", "(offset) == (static_cast<unsigned int>(args.Length()))" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1282 | result = key->ExportPrivateKey(config.Release()); | ||||||
| 1283 | } | ||||||
| 1284 | |||||||
| 1285 | if (!result.IsEmpty()) | ||||||
| 1286 | args.GetReturnValue().Set(result.FromMaybe(Local<Value>())); | ||||||
| 1287 | } | ||||||
| 1288 | |||||||
| 1289 | MaybeLocal<Value> KeyObjectHandle::ExportSecretKey() const { | ||||||
| 1290 | const char* buf = data_->GetSymmetricKey(); | ||||||
| 1291 | unsigned int len = data_->GetSymmetricKeySize(); | ||||||
| 1292 | return Buffer::Copy(env(), buf, len).FromMaybe(Local<Value>()); | ||||||
| 1293 | } | ||||||
| 1294 | |||||||
| 1295 | MaybeLocal<Value> KeyObjectHandle::ExportPublicKey( | ||||||
| 1296 | const PublicKeyEncodingConfig& config) const { | ||||||
| 1297 | return WritePublicKey(env(), data_->GetAsymmetricKey().get(), config); | ||||||
| 1298 | } | ||||||
| 1299 | |||||||
| 1300 | MaybeLocal<Value> KeyObjectHandle::ExportPrivateKey( | ||||||
| 1301 | const PrivateKeyEncodingConfig& config) const { | ||||||
| 1302 | return WritePrivateKey(env(), data_->GetAsymmetricKey().get(), config); | ||||||
| 1303 | } | ||||||
| 1304 | |||||||
| 1305 | void KeyObjectHandle::ExportJWK( | ||||||
| 1306 | const v8::FunctionCallbackInfo<v8::Value>& args) { | ||||||
| 1307 | Environment* env = Environment::GetCurrent(args); | ||||||
| 1308 | KeyObjectHandle* key; | ||||||
| 1309 | ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args.Holder())); if (*&key == nullptr) return ; } while ( 0); | ||||||
| 1310 | |||||||
| 1311 | CHECK(args[0]->IsObject())do { if (__builtin_expect(!!(!(args[0]->IsObject())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1311", "args[0]->IsObject()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1312 | CHECK(args[1]->IsBoolean())do { if (__builtin_expect(!!(!(args[1]->IsBoolean())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1312", "args[1]->IsBoolean()", __PRETTY_FUNCTION__ } ; node::Assert(args); } while (0); } } while (0); | ||||||
| 1313 | |||||||
| 1314 | ExportJWKInner(env, key->Data(), args[0], args[1]->IsTrue()); | ||||||
| 1315 | |||||||
| 1316 | args.GetReturnValue().Set(args[0]); | ||||||
| 1317 | } | ||||||
| 1318 | |||||||
| 1319 | void NativeKeyObject::Initialize(Environment* env, Local<Object> target) { | ||||||
| 1320 | env->SetMethod(target, "createNativeKeyObjectClass", | ||||||
| 1321 | NativeKeyObject::CreateNativeKeyObjectClass); | ||||||
| 1322 | } | ||||||
| 1323 | |||||||
| 1324 | void NativeKeyObject::RegisterExternalReferences( | ||||||
| 1325 | ExternalReferenceRegistry* registry) { | ||||||
| 1326 | registry->Register(NativeKeyObject::CreateNativeKeyObjectClass); | ||||||
| 1327 | registry->Register(NativeKeyObject::New); | ||||||
| 1328 | } | ||||||
| 1329 | |||||||
| 1330 | void NativeKeyObject::New(const FunctionCallbackInfo<Value>& args) { | ||||||
| 1331 | Environment* env = Environment::GetCurrent(args); | ||||||
| 1332 | CHECK_EQ(args.Length(), 1)do { if (__builtin_expect(!!(!((args.Length()) == (1))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1332", "(args.Length()) == (1)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1333 | CHECK(args[0]->IsObject())do { if (__builtin_expect(!!(!(args[0]->IsObject())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1333", "args[0]->IsObject()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1334 | KeyObjectHandle* handle = Unwrap<KeyObjectHandle>(args[0].As<Object>()); | ||||||
| 1335 | new NativeKeyObject(env, args.This(), handle->Data()); | ||||||
| 1336 | } | ||||||
| 1337 | |||||||
| 1338 | void NativeKeyObject::CreateNativeKeyObjectClass( | ||||||
| 1339 | const FunctionCallbackInfo<Value>& args) { | ||||||
| 1340 | Environment* env = Environment::GetCurrent(args); | ||||||
| 1341 | |||||||
| 1342 | CHECK_EQ(args.Length(), 1)do { if (__builtin_expect(!!(!((args.Length()) == (1))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1342", "(args.Length()) == (1)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1343 | Local<Value> callback = args[0]; | ||||||
| 1344 | CHECK(callback->IsFunction())do { if (__builtin_expect(!!(!(callback->IsFunction())), 0 )) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1344", "callback->IsFunction()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1345 | |||||||
| 1346 | Local<FunctionTemplate> t = env->NewFunctionTemplate(NativeKeyObject::New); | ||||||
| 1347 | t->InstanceTemplate()->SetInternalFieldCount( | ||||||
| 1348 | KeyObjectHandle::kInternalFieldCount); | ||||||
| 1349 | t->Inherit(BaseObject::GetConstructorTemplate(env)); | ||||||
| 1350 | |||||||
| 1351 | Local<Value> ctor; | ||||||
| 1352 | if (!t->GetFunction(env->context()).ToLocal(&ctor)) | ||||||
| 1353 | return; | ||||||
| 1354 | |||||||
| 1355 | Local<Value> recv = Undefined(env->isolate()); | ||||||
| 1356 | Local<Value> ret_v; | ||||||
| 1357 | if (!callback.As<Function>()->Call( | ||||||
| 1358 | env->context(), recv, 1, &ctor).ToLocal(&ret_v)) { | ||||||
| 1359 | return; | ||||||
| 1360 | } | ||||||
| 1361 | Local<Array> ret = ret_v.As<Array>(); | ||||||
| 1362 | if (!ret->Get(env->context(), 1).ToLocal(&ctor)) return; | ||||||
| 1363 | env->set_crypto_key_object_secret_constructor(ctor.As<Function>()); | ||||||
| 1364 | if (!ret->Get(env->context(), 2).ToLocal(&ctor)) return; | ||||||
| 1365 | env->set_crypto_key_object_public_constructor(ctor.As<Function>()); | ||||||
| 1366 | if (!ret->Get(env->context(), 3).ToLocal(&ctor)) return; | ||||||
| 1367 | env->set_crypto_key_object_private_constructor(ctor.As<Function>()); | ||||||
| 1368 | args.GetReturnValue().Set(ret); | ||||||
| 1369 | } | ||||||
| 1370 | |||||||
| 1371 | BaseObjectPtr<BaseObject> NativeKeyObject::KeyObjectTransferData::Deserialize( | ||||||
| 1372 | Environment* env, | ||||||
| 1373 | Local<Context> context, | ||||||
| 1374 | std::unique_ptr<worker::TransferData> self) { | ||||||
| 1375 | if (context != env->context()) { | ||||||
| 1376 | THROW_ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE(env); | ||||||
| 1377 | return {}; | ||||||
| 1378 | } | ||||||
| 1379 | |||||||
| 1380 | Local<Value> handle; | ||||||
| 1381 | if (!KeyObjectHandle::Create(env, data_).ToLocal(&handle)) | ||||||
| 1382 | return {}; | ||||||
| 1383 | |||||||
| 1384 | Local<Function> key_ctor; | ||||||
| 1385 | Local<Value> arg = FIXED_ONE_BYTE_STRING(env->isolate(), | ||||||
| 1386 | "internal/crypto/keys"); | ||||||
| 1387 | if (env->native_module_require()-> | ||||||
| 1388 | Call(context, Null(env->isolate()), 1, &arg).IsEmpty()) { | ||||||
| 1389 | return {}; | ||||||
| 1390 | } | ||||||
| 1391 | switch (data_->GetKeyType()) { | ||||||
| 1392 | case kKeyTypeSecret: | ||||||
| 1393 | key_ctor = env->crypto_key_object_secret_constructor(); | ||||||
| 1394 | break; | ||||||
| 1395 | case kKeyTypePublic: | ||||||
| 1396 | key_ctor = env->crypto_key_object_public_constructor(); | ||||||
| 1397 | break; | ||||||
| 1398 | case kKeyTypePrivate: | ||||||
| 1399 | key_ctor = env->crypto_key_object_private_constructor(); | ||||||
| 1400 | break; | ||||||
| 1401 | default: | ||||||
| 1402 | CHECK(false)do { if (__builtin_expect(!!(!(false)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1402", "false", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1403 | } | ||||||
| 1404 | |||||||
| 1405 | Local<Value> key; | ||||||
| 1406 | if (!key_ctor->NewInstance(context, 1, &handle).ToLocal(&key)) | ||||||
| 1407 | return {}; | ||||||
| 1408 | |||||||
| 1409 | return BaseObjectPtr<BaseObject>(Unwrap<KeyObjectHandle>(key.As<Object>())); | ||||||
| 1410 | } | ||||||
| 1411 | |||||||
| 1412 | BaseObject::TransferMode NativeKeyObject::GetTransferMode() const { | ||||||
| 1413 | return BaseObject::TransferMode::kCloneable; | ||||||
| 1414 | } | ||||||
| 1415 | |||||||
| 1416 | std::unique_ptr<worker::TransferData> NativeKeyObject::CloneForMessaging() | ||||||
| 1417 | const { | ||||||
| 1418 | return std::make_unique<KeyObjectTransferData>(handle_data_); | ||||||
| 1419 | } | ||||||
| 1420 | |||||||
| 1421 | WebCryptoKeyExportStatus PKEY_SPKI_Export( | ||||||
| 1422 | KeyObjectData* key_data, | ||||||
| 1423 | ByteSource* out) { | ||||||
| 1424 | CHECK_EQ(key_data->GetKeyType(), kKeyTypePublic)do { if (__builtin_expect(!!(!((key_data->GetKeyType()) == (kKeyTypePublic))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1424", "(key_data->GetKeyType()) == (kKeyTypePublic)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1425 | ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey(); | ||||||
| 1426 | Mutex::ScopedLock lock(*m_pkey.mutex()); | ||||||
| 1427 | BIOPointer bio(BIO_new(BIO_s_mem())); | ||||||
| 1428 | CHECK(bio)do { if (__builtin_expect(!!(!(bio)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1428", "bio", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1429 | if (!i2d_PUBKEY_bio(bio.get(), m_pkey.get())) | ||||||
| 1430 | return WebCryptoKeyExportStatus::FAILED; | ||||||
| 1431 | |||||||
| 1432 | *out = ByteSource::FromBIO(bio); | ||||||
| 1433 | return WebCryptoKeyExportStatus::OK; | ||||||
| 1434 | } | ||||||
| 1435 | |||||||
| 1436 | WebCryptoKeyExportStatus PKEY_PKCS8_Export( | ||||||
| 1437 | KeyObjectData* key_data, | ||||||
| 1438 | ByteSource* out) { | ||||||
| 1439 | CHECK_EQ(key_data->GetKeyType(), kKeyTypePrivate)do { if (__builtin_expect(!!(!((key_data->GetKeyType()) == (kKeyTypePrivate))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1439", "(key_data->GetKeyType()) == (kKeyTypePrivate)" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1440 | ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey(); | ||||||
| 1441 | Mutex::ScopedLock lock(*m_pkey.mutex()); | ||||||
| 1442 | |||||||
| 1443 | BIOPointer bio(BIO_new(BIO_s_mem())); | ||||||
| 1444 | CHECK(bio)do { if (__builtin_expect(!!(!(bio)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "1444", "bio", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | ||||||
| 1445 | PKCS8Pointer p8inf(EVP_PKEY2PKCS8(m_pkey.get())); | ||||||
| 1446 | if (!i2d_PKCS8_PRIV_KEY_INFO_bio(bio.get(), p8inf.get())) | ||||||
| 1447 | return WebCryptoKeyExportStatus::FAILED; | ||||||
| 1448 | |||||||
| 1449 | *out = ByteSource::FromBIO(bio); | ||||||
| 1450 | return WebCryptoKeyExportStatus::OK; | ||||||
| 1451 | } | ||||||
| 1452 | |||||||
| 1453 | namespace Keys { | ||||||
| 1454 | void Initialize(Environment* env, Local<Object> target) { | ||||||
| 1455 | target->Set(env->context(), | ||||||
| 1456 | FIXED_ONE_BYTE_STRING(env->isolate(), "KeyObjectHandle"), | ||||||
| 1457 | KeyObjectHandle::Initialize(env)).Check(); | ||||||
| 1458 | |||||||
| 1459 | NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatRaw)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kWebCryptoKeyFormatRaw", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kWebCryptoKeyFormatRaw )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1460 | NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatPKCS8)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kWebCryptoKeyFormatPKCS8", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kWebCryptoKeyFormatPKCS8 )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1461 | NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatSPKI)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kWebCryptoKeyFormatSPKI", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kWebCryptoKeyFormatSPKI )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1462 | NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatJWK)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kWebCryptoKeyFormatJWK", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kWebCryptoKeyFormatJWK )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1463 | |||||||
| 1464 | NODE_DEFINE_CONSTANT(target, EVP_PKEY_ED25519)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "EVP_PKEY_ED25519", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(1087)); v8::PropertyAttribute constant_attributes = static_cast<v8 ::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1465 | NODE_DEFINE_CONSTANT(target, EVP_PKEY_ED448)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "EVP_PKEY_ED448", v8::NewStringType::kInternalized) .ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(1088)); v8::PropertyAttribute constant_attributes = static_cast<v8 ::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1466 | NODE_DEFINE_CONSTANT(target, EVP_PKEY_X25519)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "EVP_PKEY_X25519", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(1034)); v8::PropertyAttribute constant_attributes = static_cast<v8 ::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1467 | NODE_DEFINE_CONSTANT(target, EVP_PKEY_X448)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "EVP_PKEY_X448", v8::NewStringType::kInternalized). ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(1035)); v8 ::PropertyAttribute constant_attributes = static_cast<v8:: PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1468 | NODE_DEFINE_CONSTANT(target, kKeyEncodingPKCS1)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kKeyEncodingPKCS1", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kKeyEncodingPKCS1 )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1469 | NODE_DEFINE_CONSTANT(target, kKeyEncodingPKCS8)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kKeyEncodingPKCS8", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kKeyEncodingPKCS8 )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1470 | NODE_DEFINE_CONSTANT(target, kKeyEncodingSPKI)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kKeyEncodingSPKI", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kKeyEncodingSPKI )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1471 | NODE_DEFINE_CONSTANT(target, kKeyEncodingSEC1)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kKeyEncodingSEC1", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kKeyEncodingSEC1 )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1472 | NODE_DEFINE_CONSTANT(target, kKeyFormatDER)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kKeyFormatDER", v8::NewStringType::kInternalized). ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kKeyFormatDER )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1473 | NODE_DEFINE_CONSTANT(target, kKeyFormatPEM)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kKeyFormatPEM", v8::NewStringType::kInternalized). ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kKeyFormatPEM )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1474 | NODE_DEFINE_CONSTANT(target, kKeyFormatJWK)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kKeyFormatJWK", v8::NewStringType::kInternalized). ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kKeyFormatJWK )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1475 | NODE_DEFINE_CONSTANT(target, kKeyTypeSecret)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kKeyTypeSecret", v8::NewStringType::kInternalized) .ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kKeyTypeSecret )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1476 | NODE_DEFINE_CONSTANT(target, kKeyTypePublic)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kKeyTypePublic", v8::NewStringType::kInternalized) .ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kKeyTypePublic )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1477 | NODE_DEFINE_CONSTANT(target, kKeyTypePrivate)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kKeyTypePrivate", v8::NewStringType::kInternalized ).ToLocalChecked(); v8::Local<v8::Number> constant_value = v8::Number::New(isolate, static_cast<double>(kKeyTypePrivate )); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target )->DefineOwnProperty(context, constant_name, constant_value , constant_attributes).Check(); } while (0); | ||||||
| 1478 | NODE_DEFINE_CONSTANT(target, kSigEncDER)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kSigEncDER", v8::NewStringType::kInternalized).ToLocalChecked (); v8::Local<v8::Number> constant_value = v8::Number:: New(isolate, static_cast<double>(kSigEncDER)); v8::PropertyAttribute constant_attributes = static_cast<v8::PropertyAttribute> (v8::ReadOnly | v8::DontDelete); (target)->DefineOwnProperty (context, constant_name, constant_value, constant_attributes) .Check(); } while (0); | ||||||
| 1479 | NODE_DEFINE_CONSTANT(target, kSigEncP1363)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::Context> context = isolate->GetCurrentContext() ; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8 (isolate, "kSigEncP1363", v8::NewStringType::kInternalized).ToLocalChecked (); v8::Local<v8::Number> constant_value = v8::Number:: New(isolate, static_cast<double>(kSigEncP1363)); v8::PropertyAttribute constant_attributes = static_cast<v8::PropertyAttribute> (v8::ReadOnly | v8::DontDelete); (target)->DefineOwnProperty (context, constant_name, constant_value, constant_attributes) .Check(); } while (0); | ||||||
| 1480 | } | ||||||
| 1481 | |||||||
| 1482 | void RegisterExternalReferences(ExternalReferenceRegistry* registry) { | ||||||
| 1483 | KeyObjectHandle::RegisterExternalReferences(registry); | ||||||
| 1484 | } | ||||||
| 1485 | } // namespace Keys | ||||||
| 1486 | |||||||
| 1487 | } // namespace crypto | ||||||
| 1488 | } // namespace node |
| 1 | // Copyright Joyent, Inc. and other Node contributors. |
| 2 | // |
| 3 | // Permission is hereby granted, free of charge, to any person obtaining a |
| 4 | // copy of this software and associated documentation files (the |
| 5 | // "Software"), to deal in the Software without restriction, including |
| 6 | // without limitation the rights to use, copy, modify, merge, publish, |
| 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit |
| 8 | // persons to whom the Software is furnished to do so, subject to the |
| 9 | // following conditions: |
| 10 | // |
| 11 | // The above copyright notice and this permission notice shall be included |
| 12 | // in all copies or substantial portions of the Software. |
| 13 | // |
| 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
| 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
| 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 21 | |
| 22 | #ifndef SRC_UTIL_H_ |
| 23 | #define SRC_UTIL_H_ |
| 24 | |
| 25 | #if defined(NODE_WANT_INTERNALS1) && NODE_WANT_INTERNALS1 |
| 26 | |
| 27 | #include "v8.h" |
| 28 | |
| 29 | #include "node.h" |
| 30 | |
| 31 | #include <climits> |
| 32 | #include <cstddef> |
| 33 | #include <cstdio> |
| 34 | #include <cstdlib> |
| 35 | #include <cstring> |
| 36 | |
| 37 | #include <array> |
| 38 | #include <limits> |
| 39 | #include <memory> |
| 40 | #include <string> |
| 41 | #include <string_view> |
| 42 | #include <type_traits> |
| 43 | #include <set> |
| 44 | #include <unordered_map> |
| 45 | #include <utility> |
| 46 | #include <vector> |
| 47 | |
| 48 | #ifdef __GNUC__4 |
| 49 | #define MUST_USE_RESULT__attribute__((warn_unused_result)) __attribute__((warn_unused_result)) |
| 50 | #else |
| 51 | #define MUST_USE_RESULT__attribute__((warn_unused_result)) |
| 52 | #endif |
| 53 | |
| 54 | namespace node { |
| 55 | |
| 56 | // Maybe remove kPathSeparator when cpp17 is ready |
| 57 | #ifdef _WIN32 |
| 58 | constexpr char kPathSeparator = '\\'; |
| 59 | /* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */ |
| 60 | #define PATH_MAX_BYTES(4096) (MAX_PATH * 4) |
| 61 | #else |
| 62 | constexpr char kPathSeparator = '/'; |
| 63 | #define PATH_MAX_BYTES(4096) (PATH_MAX4096) |
| 64 | #endif |
| 65 | |
| 66 | // These should be used in our code as opposed to the native |
| 67 | // versions as they abstract out some platform and or |
| 68 | // compiler version specific functionality |
| 69 | // malloc(0) and realloc(ptr, 0) have implementation-defined behavior in |
| 70 | // that the standard allows them to either return a unique pointer or a |
| 71 | // nullptr for zero-sized allocation requests. Normalize by always using |
| 72 | // a nullptr. |
| 73 | template <typename T> |
| 74 | inline T* UncheckedRealloc(T* pointer, size_t n); |
| 75 | template <typename T> |
| 76 | inline T* UncheckedMalloc(size_t n); |
| 77 | template <typename T> |
| 78 | inline T* UncheckedCalloc(size_t n); |
| 79 | |
| 80 | // Same things, but aborts immediately instead of returning nullptr when |
| 81 | // no memory is available. |
| 82 | template <typename T> |
| 83 | inline T* Realloc(T* pointer, size_t n); |
| 84 | template <typename T> |
| 85 | inline T* Malloc(size_t n); |
| 86 | template <typename T> |
| 87 | inline T* Calloc(size_t n); |
| 88 | |
| 89 | inline char* Malloc(size_t n); |
| 90 | inline char* Calloc(size_t n); |
| 91 | inline char* UncheckedMalloc(size_t n); |
| 92 | inline char* UncheckedCalloc(size_t n); |
| 93 | |
| 94 | template <typename T> |
| 95 | inline T MultiplyWithOverflowCheck(T a, T b); |
| 96 | |
| 97 | namespace per_process { |
| 98 | // Tells whether the per-process V8::Initialize() is called and |
| 99 | // if it is safe to call v8::Isolate::TryGetCurrent(). |
| 100 | extern bool v8_initialized; |
| 101 | } // namespace per_process |
| 102 | |
| 103 | // Used by the allocation functions when allocation fails. |
| 104 | // Thin wrapper around v8::Isolate::LowMemoryNotification() that checks |
| 105 | // whether V8 is initialized. |
| 106 | void LowMemoryNotification(); |
| 107 | |
| 108 | // The reason that Assert() takes a struct argument instead of individual |
| 109 | // const char*s is to ease instruction cache pressure in calls from CHECK. |
| 110 | struct AssertionInfo { |
| 111 | const char* file_line; // filename:line |
| 112 | const char* message; |
| 113 | const char* function; |
| 114 | }; |
| 115 | [[noreturn]] void NODE_EXTERN_PRIVATE Assert(const AssertionInfo& info); |
| 116 | [[noreturn]] void NODE_EXTERN_PRIVATE Abort(); |
| 117 | void DumpBacktrace(FILE* fp); |
| 118 | |
| 119 | // Windows 8+ does not like abort() in Release mode |
| 120 | #ifdef _WIN32 |
| 121 | #define ABORT_NO_BACKTRACE()abort() _exit(134) |
| 122 | #else |
| 123 | #define ABORT_NO_BACKTRACE()abort() abort() |
| 124 | #endif |
| 125 | |
| 126 | #define ABORT()node::Abort() node::Abort() |
| 127 | |
| 128 | #define ERROR_AND_ABORT(expr)do { static const node::AssertionInfo args = { "../src/util.h" ":" "128", "expr", __PRETTY_FUNCTION__ }; node::Assert(args) ; } while (0) \ |
| 129 | do { \ |
| 130 | /* Make sure that this struct does not end up in inline code, but */ \ |
| 131 | /* rather in a read-only data section when modifying this code. */ \ |
| 132 | static const node::AssertionInfo args = { \ |
| 133 | __FILE__"../src/util.h" ":" STRINGIFY(__LINE__)"133", #expr, PRETTY_FUNCTION_NAME__PRETTY_FUNCTION__ \ |
| 134 | }; \ |
| 135 | node::Assert(args); \ |
| 136 | } while (0) |
| 137 | |
| 138 | #ifdef __GNUC__4 |
| 139 | #define LIKELY(expr)__builtin_expect(!!(expr), 1) __builtin_expect(!!(expr), 1) |
| 140 | #define UNLIKELY(expr)__builtin_expect(!!(expr), 0) __builtin_expect(!!(expr), 0) |
| 141 | #define PRETTY_FUNCTION_NAME__PRETTY_FUNCTION__ __PRETTY_FUNCTION__ |
| 142 | #else |
| 143 | #define LIKELY(expr)__builtin_expect(!!(expr), 1) expr |
| 144 | #define UNLIKELY(expr)__builtin_expect(!!(expr), 0) expr |
| 145 | #define PRETTY_FUNCTION_NAME__PRETTY_FUNCTION__ "" |
| 146 | #endif |
| 147 | |
| 148 | #define STRINGIFY_(x)"x" #x |
| 149 | #define STRINGIFY(x)"x" STRINGIFY_(x)"x" |
| 150 | |
| 151 | #define CHECK(expr)do { if (__builtin_expect(!!(!(expr)), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "151", "expr" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) \ |
| 152 | do { \ |
| 153 | if (UNLIKELY(!(expr))__builtin_expect(!!(!(expr)), 0)) { \ |
| 154 | ERROR_AND_ABORT(expr)do { static const node::AssertionInfo args = { "../src/util.h" ":" "154", "expr", __PRETTY_FUNCTION__ }; node::Assert(args) ; } while (0); \ |
| 155 | } \ |
| 156 | } while (0) |
| 157 | |
| 158 | #define CHECK_EQ(a, b)do { if (__builtin_expect(!!(!((a) == (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "158" , "(a) == (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) CHECK((a) == (b))do { if (__builtin_expect(!!(!((a) == (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "158" , "(a) == (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 159 | #define CHECK_GE(a, b)do { if (__builtin_expect(!!(!((a) >= (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "159" , "(a) >= (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) CHECK((a) >= (b))do { if (__builtin_expect(!!(!((a) >= (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "159" , "(a) >= (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 160 | #define CHECK_GT(a, b)do { if (__builtin_expect(!!(!((a) > (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "160" , "(a) > (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) CHECK((a) > (b))do { if (__builtin_expect(!!(!((a) > (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "160" , "(a) > (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 161 | #define CHECK_LE(a, b)do { if (__builtin_expect(!!(!((a) <= (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "161" , "(a) <= (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) CHECK((a) <= (b))do { if (__builtin_expect(!!(!((a) <= (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "161" , "(a) <= (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 162 | #define CHECK_LT(a, b)do { if (__builtin_expect(!!(!((a) < (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "162" , "(a) < (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) CHECK((a) < (b))do { if (__builtin_expect(!!(!((a) < (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "162" , "(a) < (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 163 | #define CHECK_NE(a, b)do { if (__builtin_expect(!!(!((a) != (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "163" , "(a) != (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) CHECK((a) != (b))do { if (__builtin_expect(!!(!((a) != (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "163" , "(a) != (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 164 | #define CHECK_NULL(val)do { if (__builtin_expect(!!(!((val) == nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "164", "(val) == nullptr", __PRETTY_FUNCTION__ }; node::Assert (args); } while (0); } } while (0) CHECK((val) == nullptr)do { if (__builtin_expect(!!(!((val) == nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "164", "(val) == nullptr", __PRETTY_FUNCTION__ }; node::Assert (args); } while (0); } } while (0) |
| 165 | #define CHECK_NOT_NULL(val)do { if (__builtin_expect(!!(!((val) != nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "165", "(val) != nullptr", __PRETTY_FUNCTION__ }; node::Assert (args); } while (0); } } while (0) CHECK((val) != nullptr)do { if (__builtin_expect(!!(!((val) != nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "165", "(val) != nullptr", __PRETTY_FUNCTION__ }; node::Assert (args); } while (0); } } while (0) |
| 166 | #define CHECK_IMPLIES(a, b)do { if (__builtin_expect(!!(!(!(a) || (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "166" , "!(a) || (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) CHECK(!(a) || (b))do { if (__builtin_expect(!!(!(!(a) || (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "166" , "!(a) || (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 167 | |
| 168 | #ifdef DEBUG |
| 169 | #define DCHECK(expr) CHECK(expr)do { if (__builtin_expect(!!(!(expr)), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "169", "expr" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 170 | #define DCHECK_EQ(a, b) CHECK((a) == (b))do { if (__builtin_expect(!!(!((a) == (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "170" , "(a) == (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 171 | #define DCHECK_GE(a, b) CHECK((a) >= (b))do { if (__builtin_expect(!!(!((a) >= (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "171" , "(a) >= (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 172 | #define DCHECK_GT(a, b) CHECK((a) > (b))do { if (__builtin_expect(!!(!((a) > (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "172" , "(a) > (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 173 | #define DCHECK_LE(a, b) CHECK((a) <= (b))do { if (__builtin_expect(!!(!((a) <= (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "173" , "(a) <= (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 174 | #define DCHECK_LT(a, b) CHECK((a) < (b))do { if (__builtin_expect(!!(!((a) < (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "174" , "(a) < (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 175 | #define DCHECK_NE(a, b) CHECK((a) != (b))do { if (__builtin_expect(!!(!((a) != (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "175" , "(a) != (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 176 | #define DCHECK_NULL(val) CHECK((val) == nullptr)do { if (__builtin_expect(!!(!((val) == nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "176", "(val) == nullptr", __PRETTY_FUNCTION__ }; node::Assert (args); } while (0); } } while (0) |
| 177 | #define DCHECK_NOT_NULL(val) CHECK((val) != nullptr)do { if (__builtin_expect(!!(!((val) != nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "177", "(val) != nullptr", __PRETTY_FUNCTION__ }; node::Assert (args); } while (0); } } while (0) |
| 178 | #define DCHECK_IMPLIES(a, b) CHECK(!(a) || (b))do { if (__builtin_expect(!!(!(!(a) || (b))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "178" , "!(a) || (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) |
| 179 | #else |
| 180 | #define DCHECK(expr) |
| 181 | #define DCHECK_EQ(a, b) |
| 182 | #define DCHECK_GE(a, b) |
| 183 | #define DCHECK_GT(a, b) |
| 184 | #define DCHECK_LE(a, b) |
| 185 | #define DCHECK_LT(a, b) |
| 186 | #define DCHECK_NE(a, b) |
| 187 | #define DCHECK_NULL(val) |
| 188 | #define DCHECK_NOT_NULL(val) |
| 189 | #define DCHECK_IMPLIES(a, b) |
| 190 | #endif |
| 191 | |
| 192 | |
| 193 | #define UNREACHABLE(...)do { static const node::AssertionInfo args = { "../src/util.h" ":" "193", "\"Unreachable code reached\" \": \" ...", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0) \ |
| 194 | ERROR_AND_ABORT("Unreachable code reached" __VA_OPT__(": ") __VA_ARGS__)do { static const node::AssertionInfo args = { "../src/util.h" ":" "194", "\"Unreachable code reached\" __VA_OPT__(\": \") __VA_ARGS__" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0) |
| 195 | |
| 196 | // ECMA262 20.1.2.6 Number.MAX_SAFE_INTEGER (2^53-1) |
| 197 | constexpr int64_t kMaxSafeJsInteger = 9007199254740991; |
| 198 | |
| 199 | inline bool IsSafeJsInt(v8::Local<v8::Value> v); |
| 200 | |
| 201 | // TAILQ-style intrusive list node. |
| 202 | template <typename T> |
| 203 | class ListNode; |
| 204 | |
| 205 | // TAILQ-style intrusive list head. |
| 206 | template <typename T, ListNode<T> (T::*M)> |
| 207 | class ListHead; |
| 208 | |
| 209 | template <typename T> |
| 210 | class ListNode { |
| 211 | public: |
| 212 | inline ListNode(); |
| 213 | inline ~ListNode(); |
| 214 | inline void Remove(); |
| 215 | inline bool IsEmpty() const; |
| 216 | |
| 217 | ListNode(const ListNode&) = delete; |
| 218 | ListNode& operator=(const ListNode&) = delete; |
| 219 | |
| 220 | private: |
| 221 | template <typename U, ListNode<U> (U::*M)> friend class ListHead; |
| 222 | friend int GenDebugSymbols(); |
| 223 | ListNode* prev_; |
| 224 | ListNode* next_; |
| 225 | }; |
| 226 | |
| 227 | template <typename T, ListNode<T> (T::*M)> |
| 228 | class ListHead { |
| 229 | public: |
| 230 | class Iterator { |
| 231 | public: |
| 232 | inline T* operator*() const; |
| 233 | inline const Iterator& operator++(); |
| 234 | inline bool operator!=(const Iterator& that) const; |
| 235 | |
| 236 | private: |
| 237 | friend class ListHead; |
| 238 | inline explicit Iterator(ListNode<T>* node); |
| 239 | ListNode<T>* node_; |
| 240 | }; |
| 241 | |
| 242 | inline ListHead() = default; |
| 243 | inline ~ListHead(); |
| 244 | inline void PushBack(T* element); |
| 245 | inline void PushFront(T* element); |
| 246 | inline bool IsEmpty() const; |
| 247 | inline T* PopFront(); |
| 248 | inline Iterator begin() const; |
| 249 | inline Iterator end() const; |
| 250 | |
| 251 | ListHead(const ListHead&) = delete; |
| 252 | ListHead& operator=(const ListHead&) = delete; |
| 253 | |
| 254 | private: |
| 255 | friend int GenDebugSymbols(); |
| 256 | ListNode<T> head_; |
| 257 | }; |
| 258 | |
| 259 | // The helper is for doing safe downcasts from base types to derived types. |
| 260 | template <typename Inner, typename Outer> |
| 261 | class ContainerOfHelper { |
| 262 | public: |
| 263 | inline ContainerOfHelper(Inner Outer::*field, Inner* pointer); |
| 264 | template <typename TypeName> |
| 265 | inline operator TypeName*() const; |
| 266 | private: |
| 267 | Outer* const pointer_; |
| 268 | }; |
| 269 | |
| 270 | // Calculate the address of the outer (i.e. embedding) struct from |
| 271 | // the interior pointer to a data member. |
| 272 | template <typename Inner, typename Outer> |
| 273 | constexpr ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field, |
| 274 | Inner* pointer); |
| 275 | |
| 276 | // Convenience wrapper around v8::String::NewFromOneByte(). |
| 277 | inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate, |
| 278 | const char* data, |
| 279 | int length = -1); |
| 280 | |
| 281 | // For the people that compile with -funsigned-char. |
| 282 | inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate, |
| 283 | const signed char* data, |
| 284 | int length = -1); |
| 285 | |
| 286 | inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate, |
| 287 | const unsigned char* data, |
| 288 | int length = -1); |
| 289 | |
| 290 | // Used to be a macro, hence the uppercase name. |
| 291 | template <int N> |
| 292 | inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING( |
| 293 | v8::Isolate* isolate, |
| 294 | const char(&data)[N]) { |
| 295 | return OneByteString(isolate, data, N - 1); |
| 296 | } |
| 297 | |
| 298 | template <std::size_t N> |
| 299 | inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING( |
| 300 | v8::Isolate* isolate, |
| 301 | const std::array<char, N>& arr) { |
| 302 | return OneByteString(isolate, arr.data(), N - 1); |
| 303 | } |
| 304 | |
| 305 | |
| 306 | |
| 307 | // Swaps bytes in place. nbytes is the number of bytes to swap and must be a |
| 308 | // multiple of the word size (checked by function). |
| 309 | inline void SwapBytes16(char* data, size_t nbytes); |
| 310 | inline void SwapBytes32(char* data, size_t nbytes); |
| 311 | inline void SwapBytes64(char* data, size_t nbytes); |
| 312 | |
| 313 | // tolower() is locale-sensitive. Use ToLower() instead. |
| 314 | inline char ToLower(char c); |
| 315 | inline std::string ToLower(const std::string& in); |
| 316 | |
| 317 | // toupper() is locale-sensitive. Use ToUpper() instead. |
| 318 | inline char ToUpper(char c); |
| 319 | inline std::string ToUpper(const std::string& in); |
| 320 | |
| 321 | // strcasecmp() is locale-sensitive. Use StringEqualNoCase() instead. |
| 322 | inline bool StringEqualNoCase(const char* a, const char* b); |
| 323 | |
| 324 | // strncasecmp() is locale-sensitive. Use StringEqualNoCaseN() instead. |
| 325 | inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length); |
| 326 | |
| 327 | template <typename T, size_t N> |
| 328 | constexpr size_t arraysize(const T (&)[N]) { |
| 329 | return N; |
| 330 | } |
| 331 | |
| 332 | template <typename T, size_t N> |
| 333 | constexpr size_t strsize(const T (&)[N]) { |
| 334 | return N - 1; |
| 335 | } |
| 336 | |
| 337 | // Allocates an array of member type T. For up to kStackStorageSize items, |
| 338 | // the stack is used, otherwise malloc(). |
| 339 | template <typename T, size_t kStackStorageSize = 1024> |
| 340 | class MaybeStackBuffer { |
| 341 | public: |
| 342 | const T* out() const { |
| 343 | return buf_; |
| 344 | } |
| 345 | |
| 346 | T* out() { |
| 347 | return buf_; |
| 348 | } |
| 349 | |
| 350 | // operator* for compatibility with `v8::String::(Utf8)Value` |
| 351 | T* operator*() { |
| 352 | return buf_; |
| 353 | } |
| 354 | |
| 355 | const T* operator*() const { |
| 356 | return buf_; |
| 357 | } |
| 358 | |
| 359 | T& operator[](size_t index) { |
| 360 | CHECK_LT(index, length())do { if (__builtin_expect(!!(!((index) < (length()))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "360", "(index) < (length())", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); |
| 361 | return buf_[index]; |
| 362 | } |
| 363 | |
| 364 | const T& operator[](size_t index) const { |
| 365 | CHECK_LT(index, length())do { if (__builtin_expect(!!(!((index) < (length()))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "365", "(index) < (length())", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); |
| 366 | return buf_[index]; |
| 367 | } |
| 368 | |
| 369 | size_t length() const { |
| 370 | return length_; |
| 371 | } |
| 372 | |
| 373 | // Current maximum capacity of the buffer with which SetLength() can be used |
| 374 | // without first calling AllocateSufficientStorage(). |
| 375 | size_t capacity() const { |
| 376 | return capacity_; |
| 377 | } |
| 378 | |
| 379 | // Make sure enough space for `storage` entries is available. |
| 380 | // This method can be called multiple times throughout the lifetime of the |
| 381 | // buffer, but once this has been called Invalidate() cannot be used. |
| 382 | // Content of the buffer in the range [0, length()) is preserved. |
| 383 | void AllocateSufficientStorage(size_t storage) { |
| 384 | CHECK(!IsInvalidated())do { if (__builtin_expect(!!(!(!IsInvalidated())), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "384", "!IsInvalidated()", __PRETTY_FUNCTION__ }; node::Assert (args); } while (0); } } while (0); |
| 385 | if (storage > capacity()) { |
| 386 | bool was_allocated = IsAllocated(); |
| 387 | T* allocated_ptr = was_allocated ? buf_ : nullptr; |
| 388 | buf_ = Realloc(allocated_ptr, storage); |
| 389 | capacity_ = storage; |
| 390 | if (!was_allocated && length_ > 0) |
| 391 | memcpy(buf_, buf_st_, length_ * sizeof(buf_[0])); |
| 392 | } |
| 393 | |
| 394 | length_ = storage; |
| 395 | } |
| 396 | |
| 397 | void SetLength(size_t length) { |
| 398 | // capacity() returns how much memory is actually available. |
| 399 | CHECK_LE(length, capacity())do { if (__builtin_expect(!!(!((length) <= (capacity()))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "399", "(length) <= (capacity())", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); |
| 400 | length_ = length; |
| 401 | } |
| 402 | |
| 403 | void SetLengthAndZeroTerminate(size_t length) { |
| 404 | // capacity() returns how much memory is actually available. |
| 405 | CHECK_LE(length + 1, capacity())do { if (__builtin_expect(!!(!((length + 1) <= (capacity() ))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "405", "(length + 1) <= (capacity())", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); |
| 406 | SetLength(length); |
| 407 | |
| 408 | // T() is 0 for integer types, nullptr for pointers, etc. |
| 409 | buf_[length] = T(); |
| 410 | } |
| 411 | |
| 412 | // Make dereferencing this object return nullptr. |
| 413 | // This method can be called multiple times throughout the lifetime of the |
| 414 | // buffer, but once this has been called AllocateSufficientStorage() cannot |
| 415 | // be used. |
| 416 | void Invalidate() { |
| 417 | CHECK(!IsAllocated())do { if (__builtin_expect(!!(!(!IsAllocated())), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "417" , "!IsAllocated()", __PRETTY_FUNCTION__ }; node::Assert(args) ; } while (0); } } while (0); |
| 418 | capacity_ = 0; |
| 419 | length_ = 0; |
| 420 | buf_ = nullptr; |
| 421 | } |
| 422 | |
| 423 | // If the buffer is stored in the heap rather than on the stack. |
| 424 | bool IsAllocated() const { |
| 425 | return !IsInvalidated() && buf_ != buf_st_; |
| 426 | } |
| 427 | |
| 428 | // If Invalidate() has been called. |
| 429 | bool IsInvalidated() const { |
| 430 | return buf_ == nullptr; |
| 431 | } |
| 432 | |
| 433 | // Release ownership of the malloc'd buffer. |
| 434 | // Note: This does not free the buffer. |
| 435 | void Release() { |
| 436 | CHECK(IsAllocated())do { if (__builtin_expect(!!(!(IsAllocated())), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "436" , "IsAllocated()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); |
| 437 | buf_ = buf_st_; |
| 438 | length_ = 0; |
| 439 | capacity_ = arraysize(buf_st_); |
| 440 | } |
| 441 | |
| 442 | MaybeStackBuffer() |
| 443 | : length_(0), capacity_(arraysize(buf_st_)), buf_(buf_st_) { |
| 444 | // Default to a zero-length, null-terminated buffer. |
| 445 | buf_[0] = T(); |
| 446 | } |
| 447 | |
| 448 | explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() { |
| 449 | AllocateSufficientStorage(storage); |
| 450 | } |
| 451 | |
| 452 | ~MaybeStackBuffer() { |
| 453 | if (IsAllocated()) |
| 454 | free(buf_); |
| 455 | } |
| 456 | |
| 457 | private: |
| 458 | size_t length_; |
| 459 | // capacity of the malloc'ed buf_ |
| 460 | size_t capacity_; |
| 461 | T* buf_; |
| 462 | T buf_st_[kStackStorageSize]; |
| 463 | }; |
| 464 | |
| 465 | // Provides access to an ArrayBufferView's storage, either the original, |
| 466 | // or for small data, a copy of it. This object's lifetime is bound to the |
| 467 | // original ArrayBufferView's lifetime. |
| 468 | template <typename T, size_t kStackStorageSize = 64> |
| 469 | class ArrayBufferViewContents { |
| 470 | public: |
| 471 | ArrayBufferViewContents() = default; |
| 472 | |
| 473 | explicit inline ArrayBufferViewContents(v8::Local<v8::Value> value); |
| 474 | explicit inline ArrayBufferViewContents(v8::Local<v8::Object> value); |
| 475 | explicit inline ArrayBufferViewContents(v8::Local<v8::ArrayBufferView> abv); |
| 476 | inline void Read(v8::Local<v8::ArrayBufferView> abv); |
| 477 | |
| 478 | inline const T* data() const { return data_; } |
| 479 | inline size_t length() const { return length_; } |
| 480 | |
| 481 | private: |
| 482 | T stack_storage_[kStackStorageSize]; |
| 483 | T* data_ = nullptr; |
| 484 | size_t length_ = 0; |
| 485 | }; |
| 486 | |
| 487 | class Utf8Value : public MaybeStackBuffer<char> { |
| 488 | public: |
| 489 | explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value); |
| 490 | |
| 491 | inline std::string ToString() const { return std::string(out(), length()); } |
| 492 | |
| 493 | inline bool operator==(const char* a) const { |
| 494 | return strcmp(out(), a) == 0; |
| 495 | } |
| 496 | }; |
| 497 | |
| 498 | class TwoByteValue : public MaybeStackBuffer<uint16_t> { |
| 499 | public: |
| 500 | explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value); |
| 501 | }; |
| 502 | |
| 503 | class BufferValue : public MaybeStackBuffer<char> { |
| 504 | public: |
| 505 | explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value); |
| 506 | |
| 507 | inline std::string ToString() const { return std::string(out(), length()); } |
| 508 | }; |
| 509 | |
| 510 | #define SPREAD_BUFFER_ARG(val, name)do { if (__builtin_expect(!!(!((val)->IsArrayBufferView()) ), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "510", "(val)->IsArrayBufferView()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); v8::Local <v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView >(); std::shared_ptr<v8::BackingStore> name_bs = name ->Buffer()->GetBackingStore(); const size_t name_offset = name->ByteOffset(); const size_t name_length = name-> ByteLength(); char* const name_data = static_cast<char*> (name_bs->Data()) + name_offset; if (name_length > 0) do { if (__builtin_expect(!!(!((name_data) != (nullptr))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "510", "(name_data) != (nullptr)", __PRETTY_FUNCTION__ } ; node::Assert(args); } while (0); } } while (0); \ |
| 511 | CHECK((val)->IsArrayBufferView())do { if (__builtin_expect(!!(!((val)->IsArrayBufferView()) ), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "511", "(val)->IsArrayBufferView()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); \ |
| 512 | v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>(); \ |
| 513 | std::shared_ptr<v8::BackingStore> name##_bs = \ |
| 514 | name->Buffer()->GetBackingStore(); \ |
| 515 | const size_t name##_offset = name->ByteOffset(); \ |
| 516 | const size_t name##_length = name->ByteLength(); \ |
| 517 | char* const name##_data = \ |
| 518 | static_cast<char*>(name##_bs->Data()) + name##_offset; \ |
| 519 | if (name##_length > 0) \ |
| 520 | CHECK_NE(name##_data, nullptr)do { if (__builtin_expect(!!(!((name##_data) != (nullptr))), 0 )) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "520", "(name##_data) != (nullptr)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); |
| 521 | |
| 522 | // Use this when a variable or parameter is unused in order to explicitly |
| 523 | // silence a compiler warning about that. |
| 524 | template <typename T> inline void USE(T&&) {} |
| 525 | |
| 526 | template <typename Fn> |
| 527 | struct OnScopeLeaveImpl { |
| 528 | Fn fn_; |
| 529 | bool active_; |
| 530 | |
| 531 | explicit OnScopeLeaveImpl(Fn&& fn) : fn_(std::move(fn)), active_(true) {} |
| 532 | ~OnScopeLeaveImpl() { if (active_) fn_(); } |
| 533 | |
| 534 | OnScopeLeaveImpl(const OnScopeLeaveImpl& other) = delete; |
| 535 | OnScopeLeaveImpl& operator=(const OnScopeLeaveImpl& other) = delete; |
| 536 | OnScopeLeaveImpl(OnScopeLeaveImpl&& other) |
| 537 | : fn_(std::move(other.fn_)), active_(other.active_) { |
| 538 | other.active_ = false; |
| 539 | } |
| 540 | OnScopeLeaveImpl& operator=(OnScopeLeaveImpl&& other) { |
| 541 | if (this == &other) return *this; |
| 542 | this->~OnScopeLeave(); |
| 543 | new (this)OnScopeLeaveImpl(std::move(other)); |
| 544 | return *this; |
| 545 | } |
| 546 | }; |
| 547 | |
| 548 | // Run a function when exiting the current scope. Used like this: |
| 549 | // auto on_scope_leave = OnScopeLeave([&] { |
| 550 | // // ... run some code ... |
| 551 | // }); |
| 552 | template <typename Fn> |
| 553 | inline MUST_USE_RESULT__attribute__((warn_unused_result)) OnScopeLeaveImpl<Fn> OnScopeLeave(Fn&& fn) { |
| 554 | return OnScopeLeaveImpl<Fn>{std::move(fn)}; |
| 555 | } |
| 556 | |
| 557 | // Simple RAII wrapper for contiguous data that uses malloc()/free(). |
| 558 | template <typename T> |
| 559 | struct MallocedBuffer { |
| 560 | T* data; |
| 561 | size_t size; |
| 562 | |
| 563 | T* release() { |
| 564 | T* ret = data; |
| 565 | data = nullptr; |
| 566 | return ret; |
| 567 | } |
| 568 | |
| 569 | void Truncate(size_t new_size) { |
| 570 | CHECK(new_size <= size)do { if (__builtin_expect(!!(!(new_size <= size)), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "570", "new_size <= size", __PRETTY_FUNCTION__ }; node::Assert (args); } while (0); } } while (0); |
| 571 | size = new_size; |
| 572 | } |
| 573 | |
| 574 | void Realloc(size_t new_size) { |
| 575 | Truncate(new_size); |
| 576 | data = UncheckedRealloc(data, new_size); |
| 577 | } |
| 578 | |
| 579 | inline bool is_empty() const { return data == nullptr; } |
| 580 | |
| 581 | MallocedBuffer() : data(nullptr), size(0) {} |
| 582 | explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {} |
| 583 | MallocedBuffer(T* data, size_t size) : data(data), size(size) {} |
| 584 | MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) { |
| 585 | other.data = nullptr; |
| 586 | } |
| 587 | MallocedBuffer& operator=(MallocedBuffer&& other) { |
| 588 | this->~MallocedBuffer(); |
| 589 | return *new(this) MallocedBuffer(std::move(other)); |
| 590 | } |
| 591 | ~MallocedBuffer() { |
| 592 | free(data); |
| 593 | } |
| 594 | MallocedBuffer(const MallocedBuffer&) = delete; |
| 595 | MallocedBuffer& operator=(const MallocedBuffer&) = delete; |
| 596 | }; |
| 597 | |
| 598 | template <typename T> |
| 599 | class NonCopyableMaybe { |
| 600 | public: |
| 601 | NonCopyableMaybe() : empty_(true) {} |
| 602 | explicit NonCopyableMaybe(T&& value) |
| 603 | : empty_(false), |
| 604 | value_(std::move(value)) {} |
| 605 | |
| 606 | bool IsEmpty() const { |
| 607 | return empty_; |
| 608 | } |
| 609 | |
| 610 | const T* get() const { |
| 611 | return empty_ ? nullptr : &value_; |
| 612 | } |
| 613 | |
| 614 | const T* operator->() const { |
| 615 | CHECK(!empty_)do { if (__builtin_expect(!!(!(!empty_)), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "615", "!empty_" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); |
| 616 | return &value_; |
| 617 | } |
| 618 | |
| 619 | T&& Release() { |
| 620 | CHECK_EQ(empty_, false)do { if (__builtin_expect(!!(!((empty_) == (false))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h" ":" "620", "(empty_) == (false)", __PRETTY_FUNCTION__ }; node::Assert (args); } while (0); } } while (0); |
| 621 | empty_ = true; |
| 622 | return std::move(value_); |
| 623 | } |
| 624 | |
| 625 | private: |
| 626 | bool empty_; |
| 627 | T value_; |
| 628 | }; |
| 629 | |
| 630 | // Test whether some value can be called with (). |
| 631 | template <typename T, typename = void> |
| 632 | struct is_callable : std::is_function<T> { }; |
| 633 | |
| 634 | template <typename T> |
| 635 | struct is_callable<T, typename std::enable_if< |
| 636 | std::is_same<decltype(void(&T::operator())), void>::value |
| 637 | >::type> : std::true_type { }; |
| 638 | |
| 639 | template <typename T, void (*function)(T*)> |
| 640 | struct FunctionDeleter { |
| 641 | void operator()(T* pointer) const { function(pointer); } |
| 642 | typedef std::unique_ptr<T, FunctionDeleter> Pointer; |
| 643 | }; |
| 644 | |
| 645 | template <typename T, void (*function)(T*)> |
| 646 | using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer; |
| 647 | |
| 648 | std::vector<std::string> SplitString(const std::string& in, |
| 649 | char delim, |
| 650 | bool skipEmpty = true); |
| 651 | |
| 652 | inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
| 653 | std::string_view str, |
| 654 | v8::Isolate* isolate = nullptr); |
| 655 | template <typename T, typename test_for_number = |
| 656 | typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type> |
| 657 | inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
| 658 | const T& number, |
| 659 | v8::Isolate* isolate = nullptr); |
| 660 | template <typename T> |
| 661 | inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
| 662 | const std::vector<T>& vec, |
| 663 | v8::Isolate* isolate = nullptr); |
| 664 | template <typename T> |
| 665 | inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
| 666 | const std::set<T>& set, |
| 667 | v8::Isolate* isolate = nullptr); |
| 668 | template <typename T, typename U> |
| 669 | inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
| 670 | const std::unordered_map<T, U>& map, |
| 671 | v8::Isolate* isolate = nullptr); |
| 672 | |
| 673 | // These macros expects a `Isolate* isolate` and a `Local<Context> context` |
| 674 | // to be in the scope. |
| 675 | #define READONLY_PROPERTY(obj, name, value)do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING (isolate, name), value, v8::ReadOnly) .Check(); } while (0) \ |
| 676 | do { \ |
| 677 | obj->DefineOwnProperty( \ |
| 678 | context, FIXED_ONE_BYTE_STRING(isolate, name), value, v8::ReadOnly) \ |
| 679 | .Check(); \ |
| 680 | } while (0) |
| 681 | |
| 682 | #define READONLY_DONT_ENUM_PROPERTY(obj, name, var)do { obj->DefineOwnProperty( context, OneByteString(isolate , name), var, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum)) .Check(); } while (0) \ |
| 683 | do { \ |
| 684 | obj->DefineOwnProperty( \ |
| 685 | context, \ |
| 686 | OneByteString(isolate, name), \ |
| 687 | var, \ |
| 688 | static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum)) \ |
| 689 | .Check(); \ |
| 690 | } while (0) |
| 691 | |
| 692 | #define READONLY_FALSE_PROPERTY(obj, name)do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING (isolate, name), v8::False(isolate), v8::ReadOnly) .Check(); } while (0) \ |
| 693 | READONLY_PROPERTY(obj, name, v8::False(isolate))do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING (isolate, name), v8::False(isolate), v8::ReadOnly) .Check(); } while (0) |
| 694 | |
| 695 | #define READONLY_TRUE_PROPERTY(obj, name)do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING (isolate, name), v8::True(isolate), v8::ReadOnly) .Check(); } while (0) \ |
| 696 | READONLY_PROPERTY(obj, name, v8::True(isolate))do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING (isolate, name), v8::True(isolate), v8::ReadOnly) .Check(); } while (0) |
| 697 | |
| 698 | #define READONLY_STRING_PROPERTY(obj, name, str)do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING (isolate, name), ToV8Value(context, str).ToLocalChecked(), v8 ::ReadOnly) .Check(); } while (0) \ |
| 699 | READONLY_PROPERTY(obj, name, ToV8Value(context, str).ToLocalChecked())do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING (isolate, name), ToV8Value(context, str).ToLocalChecked(), v8 ::ReadOnly) .Check(); } while (0) |
| 700 | |
| 701 | // Variation on NODE_DEFINE_CONSTANT that sets a String value. |
| 702 | #define NODE_DEFINE_STRING_CONSTANT(target, name, constant)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local <v8::String> constant_name = v8::String::NewFromUtf8(isolate , name).ToLocalChecked(); v8::Local<v8::String> constant_value = v8::String::NewFromUtf8(isolate, constant).ToLocalChecked( ); v8::PropertyAttribute constant_attributes = static_cast< v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); target ->DefineOwnProperty(isolate->GetCurrentContext(), constant_name , constant_value, constant_attributes) .Check(); } while (0) \ |
| 703 | do { \ |
| 704 | v8::Isolate* isolate = target->GetIsolate(); \ |
| 705 | v8::Local<v8::String> constant_name = \ |
| 706 | v8::String::NewFromUtf8(isolate, name).ToLocalChecked(); \ |
| 707 | v8::Local<v8::String> constant_value = \ |
| 708 | v8::String::NewFromUtf8(isolate, constant).ToLocalChecked(); \ |
| 709 | v8::PropertyAttribute constant_attributes = \ |
| 710 | static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); \ |
| 711 | target \ |
| 712 | ->DefineOwnProperty(isolate->GetCurrentContext(), \ |
| 713 | constant_name, \ |
| 714 | constant_value, \ |
| 715 | constant_attributes) \ |
| 716 | .Check(); \ |
| 717 | } while (0) |
| 718 | |
| 719 | enum Endianness { |
| 720 | kLittleEndian, // _Not_ LITTLE_ENDIAN, clashes with endian.h. |
| 721 | kBigEndian |
| 722 | }; |
| 723 | |
| 724 | inline enum Endianness GetEndianness() { |
| 725 | // Constant-folded by the compiler. |
| 726 | const union { |
| 727 | uint8_t u8[2]; |
| 728 | uint16_t u16; |
| 729 | } u = {{1, 0}}; |
| 730 | return u.u16 == 1 ? kLittleEndian : kBigEndian; |
| 731 | } |
| 732 | |
| 733 | inline bool IsLittleEndian() { |
| 734 | return GetEndianness() == kLittleEndian; |
| 735 | } |
| 736 | |
| 737 | inline bool IsBigEndian() { |
| 738 | return GetEndianness() == kBigEndian; |
| 739 | } |
| 740 | |
| 741 | // Round up a to the next highest multiple of b. |
| 742 | template <typename T> |
| 743 | constexpr T RoundUp(T a, T b) { |
| 744 | return a % b != 0 ? a + b - (a % b) : a; |
| 745 | } |
| 746 | |
| 747 | // Align ptr to an `alignment`-bytes boundary. |
| 748 | template <typename T, typename U> |
| 749 | constexpr T* AlignUp(T* ptr, U alignment) { |
| 750 | return reinterpret_cast<T*>( |
| 751 | RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment)); |
| 752 | } |
| 753 | |
| 754 | class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> { |
| 755 | public: |
| 756 | inline explicit SlicedArguments( |
| 757 | const v8::FunctionCallbackInfo<v8::Value>& args, size_t start = 0); |
| 758 | }; |
| 759 | |
| 760 | // Convert a v8::PersistentBase, e.g. v8::Global, to a Local, with an extra |
| 761 | // optimization for strong persistent handles. |
| 762 | class PersistentToLocal { |
| 763 | public: |
| 764 | // If persistent.IsWeak() == false, then do not call persistent.Reset() |
| 765 | // while the returned Local<T> is still in scope, it will destroy the |
| 766 | // reference to the object. |
| 767 | template <class TypeName> |
| 768 | static inline v8::Local<TypeName> Default( |
| 769 | v8::Isolate* isolate, |
| 770 | const v8::PersistentBase<TypeName>& persistent) { |
| 771 | if (persistent.IsWeak()) { |
| 772 | return PersistentToLocal::Weak(isolate, persistent); |
| 773 | } else { |
| 774 | return PersistentToLocal::Strong(persistent); |
| 775 | } |
| 776 | } |
| 777 | |
| 778 | // Unchecked conversion from a non-weak Persistent<T> to Local<T>, |
| 779 | // use with care! |
| 780 | // |
| 781 | // Do not call persistent.Reset() while the returned Local<T> is still in |
| 782 | // scope, it will destroy the reference to the object. |
| 783 | template <class TypeName> |
| 784 | static inline v8::Local<TypeName> Strong( |
| 785 | const v8::PersistentBase<TypeName>& persistent) { |
| 786 | DCHECK(!persistent.IsWeak()); |
| 787 | return *reinterpret_cast<v8::Local<TypeName>*>( |
| 788 | const_cast<v8::PersistentBase<TypeName>*>(&persistent)); |
| 789 | } |
| 790 | |
| 791 | template <class TypeName> |
| 792 | static inline v8::Local<TypeName> Weak( |
| 793 | v8::Isolate* isolate, |
| 794 | const v8::PersistentBase<TypeName>& persistent) { |
| 795 | return v8::Local<TypeName>::New(isolate, persistent); |
| 796 | } |
| 797 | }; |
| 798 | |
| 799 | // Can be used as a key for std::unordered_map when lookup performance is more |
| 800 | // important than size and the keys are statically used to avoid redundant hash |
| 801 | // computations. |
| 802 | class FastStringKey { |
| 803 | public: |
| 804 | constexpr explicit FastStringKey(const char* name); |
| 805 | |
| 806 | struct Hash { |
| 807 | constexpr size_t operator()(const FastStringKey& key) const; |
| 808 | }; |
| 809 | constexpr bool operator==(const FastStringKey& other) const; |
| 810 | |
| 811 | constexpr const char* c_str() const; |
| 812 | |
| 813 | private: |
| 814 | static constexpr size_t HashImpl(const char* str); |
| 815 | |
| 816 | const char* name_; |
| 817 | size_t cached_hash_; |
| 818 | }; |
| 819 | |
| 820 | // Like std::static_pointer_cast but for unique_ptr with the default deleter. |
| 821 | template <typename T, typename U> |
| 822 | std::unique_ptr<T> static_unique_pointer_cast(std::unique_ptr<U>&& ptr) { |
| 823 | return std::unique_ptr<T>(static_cast<T*>(ptr.release())); |
| 824 | } |
| 825 | |
| 826 | #define MAYBE_FIELD_PTR(ptr, field)ptr == nullptr ? nullptr : &(ptr->field) ptr == nullptr ? nullptr : &(ptr->field) |
| 827 | |
| 828 | // Returns a non-zero code if it fails to open or read the file, |
| 829 | // aborts if it fails to close the file. |
| 830 | int ReadFileSync(std::string* result, const char* path); |
| 831 | } // namespace node |
| 832 | |
| 833 | #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
| 834 | |
| 835 | #endif // SRC_UTIL_H_ |
| 1 | #ifndef SRC_CRYPTO_CRYPTO_KEYS_H_ | |||
| 2 | #define SRC_CRYPTO_CRYPTO_KEYS_H_ | |||
| 3 | ||||
| 4 | #if defined(NODE_WANT_INTERNALS1) && NODE_WANT_INTERNALS1 | |||
| 5 | ||||
| 6 | #include "crypto/crypto_util.h" | |||
| 7 | #include "base_object.h" | |||
| 8 | #include "env.h" | |||
| 9 | #include "memory_tracker.h" | |||
| 10 | #include "node_buffer.h" | |||
| 11 | #include "node_worker.h" | |||
| 12 | #include "v8.h" | |||
| 13 | ||||
| 14 | #include <openssl/evp.h> | |||
| 15 | ||||
| 16 | #include <memory> | |||
| 17 | #include <string> | |||
| 18 | ||||
| 19 | namespace node { | |||
| 20 | namespace crypto { | |||
| 21 | enum PKEncodingType { | |||
| 22 | // RSAPublicKey / RSAPrivateKey according to PKCS#1. | |||
| 23 | kKeyEncodingPKCS1, | |||
| 24 | // PrivateKeyInfo or EncryptedPrivateKeyInfo according to PKCS#8. | |||
| 25 | kKeyEncodingPKCS8, | |||
| 26 | // SubjectPublicKeyInfo according to X.509. | |||
| 27 | kKeyEncodingSPKI, | |||
| 28 | // ECPrivateKey according to SEC1. | |||
| 29 | kKeyEncodingSEC1 | |||
| 30 | }; | |||
| 31 | ||||
| 32 | enum PKFormatType { | |||
| 33 | kKeyFormatDER, | |||
| 34 | kKeyFormatPEM, | |||
| 35 | kKeyFormatJWK | |||
| 36 | }; | |||
| 37 | ||||
| 38 | enum KeyType { | |||
| 39 | kKeyTypeSecret, | |||
| 40 | kKeyTypePublic, | |||
| 41 | kKeyTypePrivate | |||
| 42 | }; | |||
| 43 | ||||
| 44 | enum KeyEncodingContext { | |||
| 45 | kKeyContextInput, | |||
| 46 | kKeyContextExport, | |||
| 47 | kKeyContextGenerate | |||
| 48 | }; | |||
| 49 | ||||
| 50 | enum class ParseKeyResult { | |||
| 51 | kParseKeyOk, | |||
| 52 | kParseKeyNotRecognized, | |||
| 53 | kParseKeyNeedPassphrase, | |||
| 54 | kParseKeyFailed | |||
| 55 | }; | |||
| 56 | ||||
| 57 | struct AsymmetricKeyEncodingConfig { | |||
| 58 | bool output_key_object_ = false; | |||
| 59 | PKFormatType format_ = kKeyFormatDER; | |||
| 60 | v8::Maybe<PKEncodingType> type_ = v8::Nothing<PKEncodingType>(); | |||
| 61 | }; | |||
| 62 | ||||
| 63 | using PublicKeyEncodingConfig = AsymmetricKeyEncodingConfig; | |||
| 64 | ||||
| 65 | struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig { | |||
| ||||
| 66 | const EVP_CIPHER* cipher_; | |||
| 67 | // The ByteSource alone is not enough to distinguish between "no passphrase" | |||
| 68 | // and a zero-length passphrase (which can be a null pointer), therefore, we | |||
| 69 | // use a NonCopyableMaybe. | |||
| 70 | NonCopyableMaybe<ByteSource> passphrase_; | |||
| 71 | }; | |||
| 72 | ||||
| 73 | // This uses the built-in reference counter of OpenSSL to manage an EVP_PKEY | |||
| 74 | // which is slightly more efficient than using a shared pointer and easier to | |||
| 75 | // use. | |||
| 76 | class ManagedEVPPKey : public MemoryRetainer { | |||
| 77 | public: | |||
| 78 | ManagedEVPPKey() : mutex_(std::make_shared<Mutex>()) {} | |||
| 79 | explicit ManagedEVPPKey(EVPKeyPointer&& pkey); | |||
| 80 | ManagedEVPPKey(const ManagedEVPPKey& that); | |||
| 81 | ManagedEVPPKey& operator=(const ManagedEVPPKey& that); | |||
| 82 | ||||
| 83 | operator bool() const; | |||
| 84 | EVP_PKEY* get() const; | |||
| 85 | Mutex* mutex() const; | |||
| 86 | ||||
| 87 | void MemoryInfo(MemoryTracker* tracker) const override; | |||
| 88 | SET_MEMORY_INFO_NAME(ManagedEVPPKey)inline std::string MemoryInfoName() const override { return "ManagedEVPPKey" ; } | |||
| 89 | SET_SELF_SIZE(ManagedEVPPKey)inline size_t SelfSize() const override { return sizeof(ManagedEVPPKey ); } | |||
| 90 | ||||
| 91 | static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs( | |||
| 92 | const v8::FunctionCallbackInfo<v8::Value>& args, | |||
| 93 | unsigned int* offset, | |||
| 94 | KeyEncodingContext context); | |||
| 95 | ||||
| 96 | static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs( | |||
| 97 | const v8::FunctionCallbackInfo<v8::Value>& args, | |||
| 98 | unsigned int* offset, | |||
| 99 | KeyEncodingContext context); | |||
| 100 | ||||
| 101 | static ManagedEVPPKey GetParsedKey(Environment* env, | |||
| 102 | EVPKeyPointer&& pkey, | |||
| 103 | ParseKeyResult ret, | |||
| 104 | const char* default_msg); | |||
| 105 | ||||
| 106 | static ManagedEVPPKey GetPublicOrPrivateKeyFromJs( | |||
| 107 | const v8::FunctionCallbackInfo<v8::Value>& args, | |||
| 108 | unsigned int* offset); | |||
| 109 | ||||
| 110 | static ManagedEVPPKey GetPrivateKeyFromJs( | |||
| 111 | const v8::FunctionCallbackInfo<v8::Value>& args, | |||
| 112 | unsigned int* offset, | |||
| 113 | bool allow_key_object); | |||
| 114 | ||||
| 115 | static v8::Maybe<bool> ToEncodedPublicKey( | |||
| 116 | Environment* env, | |||
| 117 | ManagedEVPPKey key, | |||
| 118 | const PublicKeyEncodingConfig& config, | |||
| 119 | v8::Local<v8::Value>* out); | |||
| 120 | ||||
| 121 | static v8::Maybe<bool> ToEncodedPrivateKey( | |||
| 122 | Environment* env, | |||
| 123 | ManagedEVPPKey key, | |||
| 124 | const PrivateKeyEncodingConfig& config, | |||
| 125 | v8::Local<v8::Value>* out); | |||
| 126 | ||||
| 127 | private: | |||
| 128 | size_t size_of_private_key() const; | |||
| 129 | size_t size_of_public_key() const; | |||
| 130 | ||||
| 131 | EVPKeyPointer pkey_; | |||
| 132 | std::shared_ptr<Mutex> mutex_; | |||
| 133 | }; | |||
| 134 | ||||
| 135 | // Objects of this class can safely be shared among threads. | |||
| 136 | class KeyObjectData : public MemoryRetainer { | |||
| 137 | public: | |||
| 138 | static std::shared_ptr<KeyObjectData> CreateSecret(ByteSource key); | |||
| 139 | ||||
| 140 | static std::shared_ptr<KeyObjectData> CreateAsymmetric( | |||
| 141 | KeyType type, | |||
| 142 | const ManagedEVPPKey& pkey); | |||
| 143 | ||||
| 144 | KeyType GetKeyType() const; | |||
| 145 | ||||
| 146 | // These functions allow unprotected access to the raw key material and should | |||
| 147 | // only be used to implement cryptographic operations requiring the key. | |||
| 148 | ManagedEVPPKey GetAsymmetricKey() const; | |||
| 149 | const char* GetSymmetricKey() const; | |||
| 150 | size_t GetSymmetricKeySize() const; | |||
| 151 | ||||
| 152 | void MemoryInfo(MemoryTracker* tracker) const override; | |||
| 153 | SET_MEMORY_INFO_NAME(KeyObjectData)inline std::string MemoryInfoName() const override { return "KeyObjectData" ; } | |||
| 154 | SET_SELF_SIZE(KeyObjectData)inline size_t SelfSize() const override { return sizeof(KeyObjectData ); } | |||
| 155 | ||||
| 156 | private: | |||
| 157 | explicit KeyObjectData(ByteSource symmetric_key); | |||
| 158 | ||||
| 159 | KeyObjectData( | |||
| 160 | KeyType type, | |||
| 161 | const ManagedEVPPKey& pkey); | |||
| 162 | ||||
| 163 | const KeyType key_type_; | |||
| 164 | const ByteSource symmetric_key_; | |||
| 165 | const unsigned int symmetric_key_len_; | |||
| 166 | const ManagedEVPPKey asymmetric_key_; | |||
| 167 | }; | |||
| 168 | ||||
| 169 | class KeyObjectHandle : public BaseObject { | |||
| 170 | public: | |||
| 171 | static v8::Local<v8::Function> Initialize(Environment* env); | |||
| 172 | static void RegisterExternalReferences(ExternalReferenceRegistry* registry); | |||
| 173 | ||||
| 174 | static v8::MaybeLocal<v8::Object> Create(Environment* env, | |||
| 175 | std::shared_ptr<KeyObjectData> data); | |||
| 176 | ||||
| 177 | // TODO(tniessen): track the memory used by OpenSSL types | |||
| 178 | SET_NO_MEMORY_INFO()inline void MemoryInfo(node::MemoryTracker* tracker) const override {} | |||
| 179 | SET_MEMORY_INFO_NAME(KeyObjectHandle)inline std::string MemoryInfoName() const override { return "KeyObjectHandle" ; } | |||
| 180 | SET_SELF_SIZE(KeyObjectHandle)inline size_t SelfSize() const override { return sizeof(KeyObjectHandle ); } | |||
| 181 | ||||
| 182 | const std::shared_ptr<KeyObjectData>& Data(); | |||
| 183 | ||||
| 184 | protected: | |||
| 185 | static void New(const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 186 | ||||
| 187 | static void Init(const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 188 | static void InitECRaw(const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 189 | static void InitEDRaw(const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 190 | static void InitJWK(const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 191 | static void GetKeyDetail(const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 192 | static void Equals(const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 193 | ||||
| 194 | static void ExportJWK(const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 195 | ||||
| 196 | static void GetAsymmetricKeyType( | |||
| 197 | const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 198 | v8::Local<v8::Value> GetAsymmetricKeyType() const; | |||
| 199 | ||||
| 200 | static void GetSymmetricKeySize( | |||
| 201 | const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 202 | ||||
| 203 | static void Export(const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 204 | ||||
| 205 | v8::MaybeLocal<v8::Value> ExportSecretKey() const; | |||
| 206 | v8::MaybeLocal<v8::Value> ExportPublicKey( | |||
| 207 | const PublicKeyEncodingConfig& config) const; | |||
| 208 | v8::MaybeLocal<v8::Value> ExportPrivateKey( | |||
| 209 | const PrivateKeyEncodingConfig& config) const; | |||
| 210 | ||||
| 211 | KeyObjectHandle(Environment* env, | |||
| 212 | v8::Local<v8::Object> wrap); | |||
| 213 | ||||
| 214 | private: | |||
| 215 | std::shared_ptr<KeyObjectData> data_; | |||
| 216 | }; | |||
| 217 | ||||
| 218 | class NativeKeyObject : public BaseObject { | |||
| 219 | public: | |||
| 220 | static void Initialize(Environment* env, v8::Local<v8::Object> target); | |||
| 221 | static void RegisterExternalReferences(ExternalReferenceRegistry* registry); | |||
| 222 | ||||
| 223 | static void New(const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 224 | static void CreateNativeKeyObjectClass( | |||
| 225 | const v8::FunctionCallbackInfo<v8::Value>& args); | |||
| 226 | ||||
| 227 | SET_NO_MEMORY_INFO()inline void MemoryInfo(node::MemoryTracker* tracker) const override {} | |||
| 228 | SET_MEMORY_INFO_NAME(NativeKeyObject)inline std::string MemoryInfoName() const override { return "NativeKeyObject" ; } | |||
| 229 | SET_SELF_SIZE(NativeKeyObject)inline size_t SelfSize() const override { return sizeof(NativeKeyObject ); } | |||
| 230 | ||||
| 231 | class KeyObjectTransferData : public worker::TransferData { | |||
| 232 | public: | |||
| 233 | explicit KeyObjectTransferData(const std::shared_ptr<KeyObjectData>& data) | |||
| 234 | : data_(data) {} | |||
| 235 | ||||
| 236 | BaseObjectPtr<BaseObject> Deserialize( | |||
| 237 | Environment* env, | |||
| 238 | v8::Local<v8::Context> context, | |||
| 239 | std::unique_ptr<worker::TransferData> self) override; | |||
| 240 | ||||
| 241 | SET_MEMORY_INFO_NAME(KeyObjectTransferData)inline std::string MemoryInfoName() const override { return "KeyObjectTransferData" ; } | |||
| 242 | SET_SELF_SIZE(KeyObjectTransferData)inline size_t SelfSize() const override { return sizeof(KeyObjectTransferData ); } | |||
| 243 | SET_NO_MEMORY_INFO()inline void MemoryInfo(node::MemoryTracker* tracker) const override {} | |||
| 244 | ||||
| 245 | private: | |||
| 246 | std::shared_ptr<KeyObjectData> data_; | |||
| 247 | }; | |||
| 248 | ||||
| 249 | BaseObject::TransferMode GetTransferMode() const override; | |||
| 250 | std::unique_ptr<worker::TransferData> CloneForMessaging() const override; | |||
| 251 | ||||
| 252 | private: | |||
| 253 | NativeKeyObject(Environment* env, | |||
| 254 | v8::Local<v8::Object> wrap, | |||
| 255 | const std::shared_ptr<KeyObjectData>& handle_data) | |||
| 256 | : BaseObject(env, wrap), | |||
| 257 | handle_data_(handle_data) { | |||
| 258 | MakeWeak(); | |||
| 259 | } | |||
| 260 | ||||
| 261 | std::shared_ptr<KeyObjectData> handle_data_; | |||
| 262 | }; | |||
| 263 | ||||
| 264 | enum WebCryptoKeyFormat { | |||
| 265 | kWebCryptoKeyFormatRaw, | |||
| 266 | kWebCryptoKeyFormatPKCS8, | |||
| 267 | kWebCryptoKeyFormatSPKI, | |||
| 268 | kWebCryptoKeyFormatJWK | |||
| 269 | }; | |||
| 270 | ||||
| 271 | enum class WebCryptoKeyExportStatus { | |||
| 272 | OK, | |||
| 273 | INVALID_KEY_TYPE, | |||
| 274 | FAILED | |||
| 275 | }; | |||
| 276 | ||||
| 277 | template <typename KeyExportTraits> | |||
| 278 | class KeyExportJob final : public CryptoJob<KeyExportTraits> { | |||
| 279 | public: | |||
| 280 | using AdditionalParams = typename KeyExportTraits::AdditionalParameters; | |||
| 281 | ||||
| 282 | static void New(const v8::FunctionCallbackInfo<v8::Value>& args) { | |||
| 283 | Environment* env = Environment::GetCurrent(args); | |||
| 284 | CHECK(args.IsConstructCall())do { if (__builtin_expect(!!(!(args.IsConstructCall())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h" ":" "284", "args.IsConstructCall()", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | |||
| 285 | ||||
| 286 | CryptoJobMode mode = GetCryptoJobMode(args[0]); | |||
| 287 | ||||
| 288 | CHECK(args[1]->IsUint32())do { if (__builtin_expect(!!(!(args[1]->IsUint32())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h" ":" "288", "args[1]->IsUint32()", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); // Export Type | |||
| 289 | CHECK(args[2]->IsObject())do { if (__builtin_expect(!!(!(args[2]->IsObject())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h" ":" "289", "args[2]->IsObject()", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); // KeyObject | |||
| 290 | ||||
| 291 | WebCryptoKeyFormat format = | |||
| 292 | static_cast<WebCryptoKeyFormat>(args[1].As<v8::Uint32>()->Value()); | |||
| 293 | ||||
| 294 | KeyObjectHandle* key; | |||
| 295 | ASSIGN_OR_RETURN_UNWRAP(&key, args[2])do { *&key = static_cast<typename std::remove_reference <decltype(*&key)>::type>( BaseObject::FromJSObject (args[2])); if (*&key == nullptr) return ; } while (0); | |||
| 296 | ||||
| 297 | CHECK_NOT_NULL(key)do { if (__builtin_expect(!!(!((key) != nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h" ":" "297", "(key) != nullptr", __PRETTY_FUNCTION__ }; node:: Assert(args); } while (0); } } while (0); | |||
| 298 | ||||
| 299 | AdditionalParams params; | |||
| 300 | if (KeyExportTraits::AdditionalConfig(args, 3, ¶ms).IsNothing()) { | |||
| 301 | // The KeyExportTraits::AdditionalConfig is responsible for | |||
| 302 | // calling an appropriate THROW_CRYPTO_* variant reporting | |||
| 303 | // whatever error caused initialization to fail. | |||
| 304 | return; | |||
| 305 | } | |||
| 306 | ||||
| 307 | new KeyExportJob<KeyExportTraits>( | |||
| 308 | env, | |||
| 309 | args.This(), | |||
| 310 | mode, | |||
| 311 | key->Data(), | |||
| 312 | format, | |||
| 313 | std::move(params)); | |||
| 314 | } | |||
| 315 | ||||
| 316 | static void Initialize( | |||
| 317 | Environment* env, | |||
| 318 | v8::Local<v8::Object> target) { | |||
| 319 | CryptoJob<KeyExportTraits>::Initialize(New, env, target); | |||
| 320 | } | |||
| 321 | ||||
| 322 | static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { | |||
| 323 | CryptoJob<KeyExportTraits>::RegisterExternalReferences(New, registry); | |||
| 324 | } | |||
| 325 | ||||
| 326 | KeyExportJob( | |||
| 327 | Environment* env, | |||
| 328 | v8::Local<v8::Object> object, | |||
| 329 | CryptoJobMode mode, | |||
| 330 | std::shared_ptr<KeyObjectData> key, | |||
| 331 | WebCryptoKeyFormat format, | |||
| 332 | AdditionalParams&& params) | |||
| 333 | : CryptoJob<KeyExportTraits>( | |||
| 334 | env, | |||
| 335 | object, | |||
| 336 | AsyncWrap::PROVIDER_KEYEXPORTREQUEST, | |||
| 337 | mode, | |||
| 338 | std::move(params)), | |||
| 339 | key_(key), | |||
| 340 | format_(format) {} | |||
| 341 | ||||
| 342 | WebCryptoKeyFormat format() const { return format_; } | |||
| 343 | ||||
| 344 | void DoThreadPoolWork() override { | |||
| 345 | const WebCryptoKeyExportStatus status = | |||
| 346 | KeyExportTraits::DoExport( | |||
| 347 | key_, | |||
| 348 | format_, | |||
| 349 | *CryptoJob<KeyExportTraits>::params(), | |||
| 350 | &out_); | |||
| 351 | if (status == WebCryptoKeyExportStatus::OK) { | |||
| 352 | // Success! | |||
| 353 | return; | |||
| 354 | } | |||
| 355 | CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors(); | |||
| 356 | errors->Capture(); | |||
| 357 | if (errors->Empty()) { | |||
| 358 | switch (status) { | |||
| 359 | case WebCryptoKeyExportStatus::OK: | |||
| 360 | UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h" ":" "360", "\"Unreachable code reached\"", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); | |||
| 361 | break; | |||
| 362 | case WebCryptoKeyExportStatus::INVALID_KEY_TYPE: | |||
| 363 | errors->Insert(NodeCryptoError::INVALID_KEY_TYPE); | |||
| 364 | break; | |||
| 365 | case WebCryptoKeyExportStatus::FAILED: | |||
| 366 | errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED); | |||
| 367 | break; | |||
| 368 | } | |||
| 369 | } | |||
| 370 | } | |||
| 371 | ||||
| 372 | v8::Maybe<bool> ToResult( | |||
| 373 | v8::Local<v8::Value>* err, | |||
| 374 | v8::Local<v8::Value>* result) override { | |||
| 375 | Environment* env = AsyncWrap::env(); | |||
| 376 | CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors(); | |||
| 377 | if (out_.size() > 0) { | |||
| 378 | CHECK(errors->Empty())do { if (__builtin_expect(!!(!(errors->Empty())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h" ":" "378", "errors->Empty()", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | |||
| 379 | *err = v8::Undefined(env->isolate()); | |||
| 380 | *result = out_.ToArrayBuffer(env); | |||
| 381 | return v8::Just(!result->IsEmpty()); | |||
| 382 | } | |||
| 383 | ||||
| 384 | if (errors->Empty()) | |||
| 385 | errors->Capture(); | |||
| 386 | CHECK(!errors->Empty())do { if (__builtin_expect(!!(!(!errors->Empty())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h" ":" "386", "!errors->Empty()", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | |||
| 387 | *result = v8::Undefined(env->isolate()); | |||
| 388 | return v8::Just(errors->ToException(env).ToLocal(err)); | |||
| 389 | } | |||
| 390 | ||||
| 391 | SET_SELF_SIZE(KeyExportJob)inline size_t SelfSize() const override { return sizeof(KeyExportJob ); } | |||
| 392 | void MemoryInfo(MemoryTracker* tracker) const override { | |||
| 393 | tracker->TrackFieldWithSize("out", out_.size()); | |||
| 394 | CryptoJob<KeyExportTraits>::MemoryInfo(tracker); | |||
| 395 | } | |||
| 396 | ||||
| 397 | private: | |||
| 398 | std::shared_ptr<KeyObjectData> key_; | |||
| 399 | WebCryptoKeyFormat format_; | |||
| 400 | ByteSource out_; | |||
| 401 | }; | |||
| 402 | ||||
| 403 | WebCryptoKeyExportStatus PKEY_SPKI_Export( | |||
| 404 | KeyObjectData* key_data, | |||
| 405 | ByteSource* out); | |||
| 406 | ||||
| 407 | WebCryptoKeyExportStatus PKEY_PKCS8_Export( | |||
| 408 | KeyObjectData* key_data, | |||
| 409 | ByteSource* out); | |||
| 410 | ||||
| 411 | namespace Keys { | |||
| 412 | void Initialize(Environment* env, v8::Local<v8::Object> target); | |||
| 413 | void RegisterExternalReferences(ExternalReferenceRegistry* registry); | |||
| 414 | } // namespace Keys | |||
| 415 | ||||
| 416 | } // namespace crypto | |||
| 417 | } // namespace node | |||
| 418 | ||||
| 419 | #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | |||
| 420 | #endif // SRC_CRYPTO_CRYPTO_KEYS_H_ |