WebCryptoTask.h (7558B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_WebCryptoTask_h 8 #define mozilla_dom_WebCryptoTask_h 9 10 #include "ScopedNSSTypes.h" 11 #include "mozilla/dom/CryptoKey.h" 12 #include "mozilla/dom/DOMException.h" 13 #include "mozilla/dom/Promise.h" 14 #include "mozilla/dom/SubtleCryptoBinding.h" 15 #include "nsIGlobalObject.h" 16 17 namespace mozilla::dom { 18 19 class ThreadSafeWorkerRef; 20 21 typedef ArrayBufferViewOrArrayBuffer CryptoOperationData; 22 typedef ArrayBufferViewOrArrayBuffer KeyData; 23 24 /* 25 26 The execution of a WebCryptoTask happens in several phases 27 28 1. Constructor 29 2. BeforeCrypto 30 3. CalculateResult -> DoCrypto 31 4. AfterCrypto 32 5. Resolve or FailWithError 33 6. Cleanup 34 35 If any of these steps produces an error (setting mEarlyRv), then 36 subsequent steps will not proceed. If the constructor or BeforeCrypto 37 sets mEarlyComplete to true, then we will skip step 3, saving the 38 thread overhead. 39 40 In general, the constructor should handle any parsing steps that 41 require JS context, and otherwise just cache information for later 42 steps to use. 43 44 All steps besides step 3 occur on the main thread, so they should 45 avoid blocking operations. 46 47 Only step 3 is guarded to ensure that NSS has not been shutdown, 48 so all NSS interactions should occur in DoCrypto 49 50 Cleanup should execute regardless of what else happens. 51 52 */ 53 54 #define MAYBE_EARLY_FAIL(rv) \ 55 if (NS_FAILED(rv)) { \ 56 FailWithError(rv); \ 57 return; \ 58 } 59 60 class WebCryptoTask : public CancelableRunnable { 61 public: 62 virtual void DispatchWithPromise(Promise* aResultPromise); 63 64 protected: 65 static WebCryptoTask* CreateEncryptDecryptTask( 66 JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey, 67 const CryptoOperationData& aData, bool aEncrypt); 68 69 static WebCryptoTask* CreateSignVerifyTask( 70 JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey, 71 const CryptoOperationData& aSignature, const CryptoOperationData& aData, 72 bool aSign); 73 74 public: 75 static WebCryptoTask* CreateEncryptTask(JSContext* aCx, 76 const ObjectOrString& aAlgorithm, 77 CryptoKey& aKey, 78 const CryptoOperationData& aData) { 79 return CreateEncryptDecryptTask(aCx, aAlgorithm, aKey, aData, true); 80 } 81 82 static WebCryptoTask* CreateDecryptTask(JSContext* aCx, 83 const ObjectOrString& aAlgorithm, 84 CryptoKey& aKey, 85 const CryptoOperationData& aData) { 86 return CreateEncryptDecryptTask(aCx, aAlgorithm, aKey, aData, false); 87 } 88 89 static WebCryptoTask* CreateSignTask(JSContext* aCx, 90 const ObjectOrString& aAlgorithm, 91 CryptoKey& aKey, 92 const CryptoOperationData& aData) { 93 CryptoOperationData dummy; 94 (void)dummy.SetAsArrayBuffer(aCx); 95 return CreateSignVerifyTask(aCx, aAlgorithm, aKey, dummy, aData, true); 96 } 97 98 static WebCryptoTask* CreateVerifyTask(JSContext* aCx, 99 const ObjectOrString& aAlgorithm, 100 CryptoKey& aKey, 101 const CryptoOperationData& aSignature, 102 const CryptoOperationData& aData) { 103 return CreateSignVerifyTask(aCx, aAlgorithm, aKey, aSignature, aData, 104 false); 105 } 106 107 static WebCryptoTask* CreateDigestTask(JSContext* aCx, 108 const ObjectOrString& aAlgorithm, 109 const CryptoOperationData& aData); 110 111 static WebCryptoTask* CreateImportKeyTask( 112 nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat, 113 JS::Handle<JSObject*> aKeyData, const ObjectOrString& aAlgorithm, 114 bool aExtractable, const Sequence<nsString>& aKeyUsages); 115 static WebCryptoTask* CreateExportKeyTask(const nsAString& aFormat, 116 CryptoKey& aKey); 117 static WebCryptoTask* CreateGenerateKeyTask( 118 nsIGlobalObject* aGlobal, JSContext* aCx, 119 const ObjectOrString& aAlgorithm, bool aExtractable, 120 const Sequence<nsString>& aKeyUsages); 121 122 static WebCryptoTask* CreateDeriveKeyTask( 123 nsIGlobalObject* aGlobal, JSContext* aCx, 124 const ObjectOrString& aAlgorithm, CryptoKey& aBaseKey, 125 const ObjectOrString& aDerivedKeyType, bool extractable, 126 const Sequence<nsString>& aKeyUsages); 127 static WebCryptoTask* CreateDeriveBitsTask(JSContext* aCx, 128 const ObjectOrString& aAlgorithm, 129 CryptoKey& aKey, 130 const Nullable<uint32_t>& aLength); 131 132 static WebCryptoTask* CreateWrapKeyTask(JSContext* aCx, 133 const nsAString& aFormat, 134 CryptoKey& aKey, 135 CryptoKey& aWrappingKey, 136 const ObjectOrString& aWrapAlgorithm); 137 static WebCryptoTask* CreateUnwrapKeyTask( 138 nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat, 139 const ArrayBufferViewOrArrayBuffer& aWrappedKey, 140 CryptoKey& aUnwrappingKey, const ObjectOrString& aUnwrapAlgorithm, 141 const ObjectOrString& aUnwrappedKeyAlgorithm, bool aExtractable, 142 const Sequence<nsString>& aKeyUsages); 143 144 protected: 145 RefPtr<Promise> mResultPromise; 146 nsresult mEarlyRv; 147 bool mEarlyComplete; 148 149 WebCryptoTask(); 150 virtual ~WebCryptoTask(); 151 152 bool IsOnOriginalThread() { 153 return !mOriginalEventTarget || mOriginalEventTarget->IsOnCurrentThread(); 154 } 155 156 // For things that need to happen on the main thread 157 // either before or after CalculateResult 158 virtual nsresult BeforeCrypto() { return NS_OK; } 159 virtual nsresult DoCrypto() { return NS_OK; } 160 virtual nsresult AfterCrypto() { return NS_OK; } 161 virtual void Resolve() {} 162 virtual void Cleanup() {} 163 164 void FailWithError(nsresult aRv); 165 166 nsresult CalculateResult(); 167 168 void CallCallback(nsresult rv); 169 170 private: 171 NS_IMETHOD Run() final; 172 nsresult Cancel() final; 173 174 nsCOMPtr<nsISerialEventTarget> mOriginalEventTarget; 175 RefPtr<ThreadSafeWorkerRef> mWorkerRef; 176 nsresult mRv; 177 }; 178 179 // XXX This class is declared here (unlike others) to enable reuse by WebRTC. 180 class GenerateAsymmetricKeyTask : public WebCryptoTask { 181 public: 182 GenerateAsymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, 183 const ObjectOrString& aAlgorithm, bool aExtractable, 184 const Sequence<nsString>& aKeyUsages); 185 186 protected: 187 UniquePLArenaPool mArena; 188 UniquePtr<CryptoKeyPair> mKeyPair; 189 nsString mAlgName; 190 CK_MECHANISM_TYPE mMechanism; 191 PK11RSAGenParams mRsaParams; 192 SECKEYDHParams mDhParams; 193 nsString mNamedCurve; 194 195 virtual nsresult DoCrypto() override; 196 virtual void Resolve() override; 197 virtual void Cleanup() override; 198 199 private: 200 UniqueSECKEYPublicKey mPublicKey; 201 UniqueSECKEYPrivateKey mPrivateKey; 202 }; 203 204 } // namespace mozilla::dom 205 206 #endif // mozilla_dom_WebCryptoTask_h