1 #ifndef SRC_CRYPTO_CRYPTO_KEYS_H_ 2 #define SRC_CRYPTO_CRYPTO_KEYS_H_ 3 4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 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: ManagedEVPPKey()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) 89 SET_SELF_SIZE(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 v8::Maybe<bool> ToEncodedPublicKey(Environment* env, 116 const PublicKeyEncodingConfig& config, 117 v8::Local<v8::Value>* out); 118 119 v8::Maybe<bool> ToEncodedPrivateKey(Environment* env, 120 const PrivateKeyEncodingConfig& config, 121 v8::Local<v8::Value>* out); 122 123 private: 124 size_t size_of_private_key() const; 125 size_t size_of_public_key() const; 126 127 EVPKeyPointer pkey_; 128 std::shared_ptr<Mutex> mutex_; 129 }; 130 131 // Objects of this class can safely be shared among threads. 132 class KeyObjectData : public MemoryRetainer { 133 public: 134 static std::shared_ptr<KeyObjectData> CreateSecret(ByteSource key); 135 136 static std::shared_ptr<KeyObjectData> CreateAsymmetric( 137 KeyType type, 138 const ManagedEVPPKey& pkey); 139 140 KeyType GetKeyType() const; 141 142 // These functions allow unprotected access to the raw key material and should 143 // only be used to implement cryptographic operations requiring the key. 144 ManagedEVPPKey GetAsymmetricKey() const; 145 const char* GetSymmetricKey() const; 146 size_t GetSymmetricKeySize() const; 147 148 void MemoryInfo(MemoryTracker* tracker) const override; 149 SET_MEMORY_INFO_NAME(KeyObjectData) 150 SET_SELF_SIZE(KeyObjectData) 151 152 private: 153 explicit KeyObjectData(ByteSource symmetric_key); 154 155 KeyObjectData( 156 KeyType type, 157 const ManagedEVPPKey& pkey); 158 159 const KeyType key_type_; 160 const ByteSource symmetric_key_; 161 const ManagedEVPPKey asymmetric_key_; 162 }; 163 164 class KeyObjectHandle : public BaseObject { 165 public: 166 static bool HasInstance(Environment* env, v8::Local<v8::Value> value); 167 static v8::Local<v8::Function> Initialize(Environment* env); 168 static void RegisterExternalReferences(ExternalReferenceRegistry* registry); 169 170 static v8::MaybeLocal<v8::Object> Create(Environment* env, 171 std::shared_ptr<KeyObjectData> data); 172 173 // TODO(tniessen): track the memory used by OpenSSL types 174 SET_NO_MEMORY_INFO() 175 SET_MEMORY_INFO_NAME(KeyObjectHandle) 176 SET_SELF_SIZE(KeyObjectHandle) 177 178 const std::shared_ptr<KeyObjectData>& Data(); 179 180 protected: 181 static void New(const v8::FunctionCallbackInfo<v8::Value>& args); 182 183 static void Init(const v8::FunctionCallbackInfo<v8::Value>& args); 184 static void InitECRaw(const v8::FunctionCallbackInfo<v8::Value>& args); 185 static void InitEDRaw(const v8::FunctionCallbackInfo<v8::Value>& args); 186 static void InitJWK(const v8::FunctionCallbackInfo<v8::Value>& args); 187 static void GetKeyDetail(const v8::FunctionCallbackInfo<v8::Value>& args); 188 static void Equals(const v8::FunctionCallbackInfo<v8::Value>& args); 189 190 static void ExportJWK(const v8::FunctionCallbackInfo<v8::Value>& args); 191 192 static void GetAsymmetricKeyType( 193 const v8::FunctionCallbackInfo<v8::Value>& args); 194 v8::Local<v8::Value> GetAsymmetricKeyType() const; 195 196 static void CheckEcKeyData(const v8::FunctionCallbackInfo<v8::Value>& args); 197 bool CheckEcKeyData() const; 198 199 static void GetSymmetricKeySize( 200 const v8::FunctionCallbackInfo<v8::Value>& args); 201 202 static void Export(const v8::FunctionCallbackInfo<v8::Value>& args); 203 204 v8::MaybeLocal<v8::Value> ExportSecretKey() const; 205 v8::MaybeLocal<v8::Value> ExportPublicKey( 206 const PublicKeyEncodingConfig& config) const; 207 v8::MaybeLocal<v8::Value> ExportPrivateKey( 208 const PrivateKeyEncodingConfig& config) const; 209 210 KeyObjectHandle(Environment* env, 211 v8::Local<v8::Object> wrap); 212 213 private: 214 std::shared_ptr<KeyObjectData> data_; 215 }; 216 217 class NativeKeyObject : public BaseObject { 218 public: 219 static void Initialize(Environment* env, v8::Local<v8::Object> target); 220 static void RegisterExternalReferences(ExternalReferenceRegistry* registry); 221 222 static void New(const v8::FunctionCallbackInfo<v8::Value>& args); 223 static void CreateNativeKeyObjectClass( 224 const v8::FunctionCallbackInfo<v8::Value>& args); 225 226 SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(NativeKeyObject)227 SET_MEMORY_INFO_NAME(NativeKeyObject) 228 SET_SELF_SIZE(NativeKeyObject) 229 230 class KeyObjectTransferData : public worker::TransferData { 231 public: 232 explicit KeyObjectTransferData(const std::shared_ptr<KeyObjectData>& data) 233 : data_(data) {} 234 235 BaseObjectPtr<BaseObject> Deserialize( 236 Environment* env, 237 v8::Local<v8::Context> context, 238 std::unique_ptr<worker::TransferData> self) override; 239 240 SET_MEMORY_INFO_NAME(KeyObjectTransferData) 241 SET_SELF_SIZE(KeyObjectTransferData) 242 SET_NO_MEMORY_INFO() 243 244 private: 245 std::shared_ptr<KeyObjectData> data_; 246 }; 247 248 BaseObject::TransferMode GetTransferMode() const override; 249 std::unique_ptr<worker::TransferData> CloneForMessaging() const override; 250 251 private: NativeKeyObject(Environment * env,v8::Local<v8::Object> wrap,const std::shared_ptr<KeyObjectData> & handle_data)252 NativeKeyObject(Environment* env, 253 v8::Local<v8::Object> wrap, 254 const std::shared_ptr<KeyObjectData>& handle_data) 255 : BaseObject(env, wrap), 256 handle_data_(handle_data) { 257 MakeWeak(); 258 } 259 260 std::shared_ptr<KeyObjectData> handle_data_; 261 }; 262 263 enum WebCryptoKeyFormat { 264 kWebCryptoKeyFormatRaw, 265 kWebCryptoKeyFormatPKCS8, 266 kWebCryptoKeyFormatSPKI, 267 kWebCryptoKeyFormatJWK 268 }; 269 270 enum class WebCryptoKeyExportStatus { 271 OK, 272 INVALID_KEY_TYPE, 273 FAILED 274 }; 275 276 template <typename KeyExportTraits> 277 class KeyExportJob final : public CryptoJob<KeyExportTraits> { 278 public: 279 using AdditionalParams = typename KeyExportTraits::AdditionalParameters; 280 New(const v8::FunctionCallbackInfo<v8::Value> & args)281 static void New(const v8::FunctionCallbackInfo<v8::Value>& args) { 282 Environment* env = Environment::GetCurrent(args); 283 CHECK(args.IsConstructCall()); 284 285 CryptoJobMode mode = GetCryptoJobMode(args[0]); 286 287 CHECK(args[1]->IsUint32()); // Export Type 288 CHECK(args[2]->IsObject()); // KeyObject 289 290 WebCryptoKeyFormat format = 291 static_cast<WebCryptoKeyFormat>(args[1].As<v8::Uint32>()->Value()); 292 293 KeyObjectHandle* key; 294 ASSIGN_OR_RETURN_UNWRAP(&key, args[2]); 295 296 CHECK_NOT_NULL(key); 297 298 AdditionalParams params; 299 if (KeyExportTraits::AdditionalConfig(args, 3, ¶ms).IsNothing()) { 300 // The KeyExportTraits::AdditionalConfig is responsible for 301 // calling an appropriate THROW_CRYPTO_* variant reporting 302 // whatever error caused initialization to fail. 303 return; 304 } 305 306 new KeyExportJob<KeyExportTraits>( 307 env, 308 args.This(), 309 mode, 310 key->Data(), 311 format, 312 std::move(params)); 313 } 314 Initialize(Environment * env,v8::Local<v8::Object> target)315 static void Initialize( 316 Environment* env, 317 v8::Local<v8::Object> target) { 318 CryptoJob<KeyExportTraits>::Initialize(New, env, target); 319 } 320 RegisterExternalReferences(ExternalReferenceRegistry * registry)321 static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { 322 CryptoJob<KeyExportTraits>::RegisterExternalReferences(New, registry); 323 } 324 KeyExportJob(Environment * env,v8::Local<v8::Object> object,CryptoJobMode mode,std::shared_ptr<KeyObjectData> key,WebCryptoKeyFormat format,AdditionalParams && params)325 KeyExportJob( 326 Environment* env, 327 v8::Local<v8::Object> object, 328 CryptoJobMode mode, 329 std::shared_ptr<KeyObjectData> key, 330 WebCryptoKeyFormat format, 331 AdditionalParams&& params) 332 : CryptoJob<KeyExportTraits>( 333 env, 334 object, 335 AsyncWrap::PROVIDER_KEYEXPORTREQUEST, 336 mode, 337 std::move(params)), 338 key_(key), 339 format_(format) {} 340 format()341 WebCryptoKeyFormat format() const { return format_; } 342 DoThreadPoolWork()343 void DoThreadPoolWork() override { 344 const WebCryptoKeyExportStatus status = 345 KeyExportTraits::DoExport( 346 key_, 347 format_, 348 *CryptoJob<KeyExportTraits>::params(), 349 &out_); 350 if (status == WebCryptoKeyExportStatus::OK) { 351 // Success! 352 return; 353 } 354 CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors(); 355 errors->Capture(); 356 if (errors->Empty()) { 357 switch (status) { 358 case WebCryptoKeyExportStatus::OK: 359 UNREACHABLE(); 360 break; 361 case WebCryptoKeyExportStatus::INVALID_KEY_TYPE: 362 errors->Insert(NodeCryptoError::INVALID_KEY_TYPE); 363 break; 364 case WebCryptoKeyExportStatus::FAILED: 365 errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED); 366 break; 367 } 368 } 369 } 370 ToResult(v8::Local<v8::Value> * err,v8::Local<v8::Value> * result)371 v8::Maybe<bool> ToResult( 372 v8::Local<v8::Value>* err, 373 v8::Local<v8::Value>* result) override { 374 Environment* env = AsyncWrap::env(); 375 CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors(); 376 if (out_.size() > 0) { 377 CHECK(errors->Empty()); 378 *err = v8::Undefined(env->isolate()); 379 *result = out_.ToArrayBuffer(env); 380 return v8::Just(!result->IsEmpty()); 381 } 382 383 if (errors->Empty()) 384 errors->Capture(); 385 CHECK(!errors->Empty()); 386 *result = v8::Undefined(env->isolate()); 387 return v8::Just(errors->ToException(env).ToLocal(err)); 388 } 389 SET_SELF_SIZE(KeyExportJob)390 SET_SELF_SIZE(KeyExportJob) 391 void MemoryInfo(MemoryTracker* tracker) const override { 392 tracker->TrackFieldWithSize("out", out_.size()); 393 CryptoJob<KeyExportTraits>::MemoryInfo(tracker); 394 } 395 396 private: 397 std::shared_ptr<KeyObjectData> key_; 398 WebCryptoKeyFormat format_; 399 ByteSource out_; 400 }; 401 402 WebCryptoKeyExportStatus PKEY_SPKI_Export( 403 KeyObjectData* key_data, 404 ByteSource* out); 405 406 WebCryptoKeyExportStatus PKEY_PKCS8_Export( 407 KeyObjectData* key_data, 408 ByteSource* out); 409 410 namespace Keys { 411 void Initialize(Environment* env, v8::Local<v8::Object> target); 412 void RegisterExternalReferences(ExternalReferenceRegistry* registry); 413 } // namespace Keys 414 415 } // namespace crypto 416 } // namespace node 417 418 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 419 #endif // SRC_CRYPTO_CRYPTO_KEYS_H_ 420