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 GetSymmetricKeySize( 197 const v8::FunctionCallbackInfo<v8::Value>& args); 198 199 static void Export(const v8::FunctionCallbackInfo<v8::Value>& args); 200 201 v8::MaybeLocal<v8::Value> ExportSecretKey() const; 202 v8::MaybeLocal<v8::Value> ExportPublicKey( 203 const PublicKeyEncodingConfig& config) const; 204 v8::MaybeLocal<v8::Value> ExportPrivateKey( 205 const PrivateKeyEncodingConfig& config) const; 206 207 KeyObjectHandle(Environment* env, 208 v8::Local<v8::Object> wrap); 209 210 private: 211 std::shared_ptr<KeyObjectData> data_; 212 }; 213 214 class NativeKeyObject : public BaseObject { 215 public: 216 static void Initialize(Environment* env, v8::Local<v8::Object> target); 217 static void RegisterExternalReferences(ExternalReferenceRegistry* registry); 218 219 static void New(const v8::FunctionCallbackInfo<v8::Value>& args); 220 static void CreateNativeKeyObjectClass( 221 const v8::FunctionCallbackInfo<v8::Value>& args); 222 223 SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(NativeKeyObject)224 SET_MEMORY_INFO_NAME(NativeKeyObject) 225 SET_SELF_SIZE(NativeKeyObject) 226 227 class KeyObjectTransferData : public worker::TransferData { 228 public: 229 explicit KeyObjectTransferData(const std::shared_ptr<KeyObjectData>& data) 230 : data_(data) {} 231 232 BaseObjectPtr<BaseObject> Deserialize( 233 Environment* env, 234 v8::Local<v8::Context> context, 235 std::unique_ptr<worker::TransferData> self) override; 236 237 SET_MEMORY_INFO_NAME(KeyObjectTransferData) 238 SET_SELF_SIZE(KeyObjectTransferData) 239 SET_NO_MEMORY_INFO() 240 241 private: 242 std::shared_ptr<KeyObjectData> data_; 243 }; 244 245 BaseObject::TransferMode GetTransferMode() const override; 246 std::unique_ptr<worker::TransferData> CloneForMessaging() const override; 247 248 private: NativeKeyObject(Environment * env,v8::Local<v8::Object> wrap,const std::shared_ptr<KeyObjectData> & handle_data)249 NativeKeyObject(Environment* env, 250 v8::Local<v8::Object> wrap, 251 const std::shared_ptr<KeyObjectData>& handle_data) 252 : BaseObject(env, wrap), 253 handle_data_(handle_data) { 254 MakeWeak(); 255 } 256 257 std::shared_ptr<KeyObjectData> handle_data_; 258 }; 259 260 enum WebCryptoKeyFormat { 261 kWebCryptoKeyFormatRaw, 262 kWebCryptoKeyFormatPKCS8, 263 kWebCryptoKeyFormatSPKI, 264 kWebCryptoKeyFormatJWK 265 }; 266 267 enum class WebCryptoKeyExportStatus { 268 OK, 269 INVALID_KEY_TYPE, 270 FAILED 271 }; 272 273 template <typename KeyExportTraits> 274 class KeyExportJob final : public CryptoJob<KeyExportTraits> { 275 public: 276 using AdditionalParams = typename KeyExportTraits::AdditionalParameters; 277 New(const v8::FunctionCallbackInfo<v8::Value> & args)278 static void New(const v8::FunctionCallbackInfo<v8::Value>& args) { 279 Environment* env = Environment::GetCurrent(args); 280 CHECK(args.IsConstructCall()); 281 282 CryptoJobMode mode = GetCryptoJobMode(args[0]); 283 284 CHECK(args[1]->IsUint32()); // Export Type 285 CHECK(args[2]->IsObject()); // KeyObject 286 287 WebCryptoKeyFormat format = 288 static_cast<WebCryptoKeyFormat>(args[1].As<v8::Uint32>()->Value()); 289 290 KeyObjectHandle* key; 291 ASSIGN_OR_RETURN_UNWRAP(&key, args[2]); 292 293 CHECK_NOT_NULL(key); 294 295 AdditionalParams params; 296 if (KeyExportTraits::AdditionalConfig(args, 3, ¶ms).IsNothing()) { 297 // The KeyExportTraits::AdditionalConfig is responsible for 298 // calling an appropriate THROW_CRYPTO_* variant reporting 299 // whatever error caused initialization to fail. 300 return; 301 } 302 303 new KeyExportJob<KeyExportTraits>( 304 env, 305 args.This(), 306 mode, 307 key->Data(), 308 format, 309 std::move(params)); 310 } 311 Initialize(Environment * env,v8::Local<v8::Object> target)312 static void Initialize( 313 Environment* env, 314 v8::Local<v8::Object> target) { 315 CryptoJob<KeyExportTraits>::Initialize(New, env, target); 316 } 317 RegisterExternalReferences(ExternalReferenceRegistry * registry)318 static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { 319 CryptoJob<KeyExportTraits>::RegisterExternalReferences(New, registry); 320 } 321 KeyExportJob(Environment * env,v8::Local<v8::Object> object,CryptoJobMode mode,std::shared_ptr<KeyObjectData> key,WebCryptoKeyFormat format,AdditionalParams && params)322 KeyExportJob( 323 Environment* env, 324 v8::Local<v8::Object> object, 325 CryptoJobMode mode, 326 std::shared_ptr<KeyObjectData> key, 327 WebCryptoKeyFormat format, 328 AdditionalParams&& params) 329 : CryptoJob<KeyExportTraits>( 330 env, 331 object, 332 AsyncWrap::PROVIDER_KEYEXPORTREQUEST, 333 mode, 334 std::move(params)), 335 key_(key), 336 format_(format) {} 337 format()338 WebCryptoKeyFormat format() const { return format_; } 339 DoThreadPoolWork()340 void DoThreadPoolWork() override { 341 const WebCryptoKeyExportStatus status = 342 KeyExportTraits::DoExport( 343 key_, 344 format_, 345 *CryptoJob<KeyExportTraits>::params(), 346 &out_); 347 if (status == WebCryptoKeyExportStatus::OK) { 348 // Success! 349 return; 350 } 351 CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors(); 352 errors->Capture(); 353 if (errors->Empty()) { 354 switch (status) { 355 case WebCryptoKeyExportStatus::OK: 356 UNREACHABLE(); 357 break; 358 case WebCryptoKeyExportStatus::INVALID_KEY_TYPE: 359 errors->Insert(NodeCryptoError::INVALID_KEY_TYPE); 360 break; 361 case WebCryptoKeyExportStatus::FAILED: 362 errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED); 363 break; 364 } 365 } 366 } 367 ToResult(v8::Local<v8::Value> * err,v8::Local<v8::Value> * result)368 v8::Maybe<bool> ToResult( 369 v8::Local<v8::Value>* err, 370 v8::Local<v8::Value>* result) override { 371 Environment* env = AsyncWrap::env(); 372 CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors(); 373 if (out_.size() > 0) { 374 CHECK(errors->Empty()); 375 *err = v8::Undefined(env->isolate()); 376 *result = out_.ToArrayBuffer(env); 377 return v8::Just(!result->IsEmpty()); 378 } 379 380 if (errors->Empty()) 381 errors->Capture(); 382 CHECK(!errors->Empty()); 383 *result = v8::Undefined(env->isolate()); 384 return v8::Just(errors->ToException(env).ToLocal(err)); 385 } 386 SET_SELF_SIZE(KeyExportJob)387 SET_SELF_SIZE(KeyExportJob) 388 void MemoryInfo(MemoryTracker* tracker) const override { 389 tracker->TrackFieldWithSize("out", out_.size()); 390 CryptoJob<KeyExportTraits>::MemoryInfo(tracker); 391 } 392 393 private: 394 std::shared_ptr<KeyObjectData> key_; 395 WebCryptoKeyFormat format_; 396 ByteSource out_; 397 }; 398 399 WebCryptoKeyExportStatus PKEY_SPKI_Export( 400 KeyObjectData* key_data, 401 ByteSource* out); 402 403 WebCryptoKeyExportStatus PKEY_PKCS8_Export( 404 KeyObjectData* key_data, 405 ByteSource* out); 406 407 namespace Keys { 408 void Initialize(Environment* env, v8::Local<v8::Object> target); 409 void RegisterExternalReferences(ExternalReferenceRegistry* registry); 410 } // namespace Keys 411 412 } // namespace crypto 413 } // namespace node 414 415 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 416 #endif // SRC_CRYPTO_CRYPTO_KEYS_H_ 417