Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/crypto/WebCryptoTask.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "pk11pub.h"
8
#include "cryptohi.h"
9
#include "secerr.h"
10
#include "nsNSSComponent.h"
11
#include "nsProxyRelease.h"
12
13
#include "jsapi.h"
14
#include "mozilla/Telemetry.h"
15
#include "mozilla/dom/CryptoBuffer.h"
16
#include "mozilla/dom/CryptoKey.h"
17
#include "mozilla/dom/KeyAlgorithmProxy.h"
18
#include "mozilla/dom/TypedArray.h"
19
#include "mozilla/dom/WebCryptoCommon.h"
20
#include "mozilla/dom/WebCryptoTask.h"
21
#include "mozilla/dom/WebCryptoThreadPool.h"
22
#include "mozilla/dom/WorkerRef.h"
23
#include "mozilla/dom/WorkerPrivate.h"
24
25
// Template taken from security/nss/lib/util/templates.c
26
// This (or SGN_EncodeDigestInfo) would ideally be exported
27
// by NSS and until that happens we have to keep our own copy.
28
const SEC_ASN1Template SGN_DigestInfoTemplate[] = {
29
    { SEC_ASN1_SEQUENCE,
30
      0, NULL, sizeof(SGNDigestInfo) },
31
    { SEC_ASN1_INLINE,
32
      offsetof(SGNDigestInfo,digestAlgorithm),
33
      SEC_ASN1_GET(SECOID_AlgorithmIDTemplate) },
34
    { SEC_ASN1_OCTET_STRING,
35
      offsetof(SGNDigestInfo,digest) },
36
    { 0, }
37
};
38
39
namespace mozilla {
40
namespace dom {
41
42
// Pre-defined identifiers for telemetry histograms
43
44
enum TelemetryMethod {
45
  TM_ENCRYPT      = 0,
46
  TM_DECRYPT      = 1,
47
  TM_SIGN         = 2,
48
  TM_VERIFY       = 3,
49
  TM_DIGEST       = 4,
50
  TM_GENERATEKEY  = 5,
51
  TM_DERIVEKEY    = 6,
52
  TM_DERIVEBITS   = 7,
53
  TM_IMPORTKEY    = 8,
54
  TM_EXPORTKEY    = 9,
55
  TM_WRAPKEY      = 10,
56
  TM_UNWRAPKEY    = 11
57
};
58
59
enum TelemetryAlgorithm {
60
  // Please make additions at the end of the list,
61
  // to preserve comparability of histograms over time
62
  TA_UNKNOWN         = 0,
63
  // encrypt / decrypt
64
  TA_AES_CBC         = 1,
65
  TA_AES_CFB         = 2,
66
  TA_AES_CTR         = 3,
67
  TA_AES_GCM         = 4,
68
  TA_RSAES_PKCS1     = 5, // NB: This algorithm has been removed
69
  TA_RSA_OAEP        = 6,
70
  // sign/verify
71
  TA_RSASSA_PKCS1    = 7,
72
  TA_RSA_PSS         = 8,
73
  TA_HMAC_SHA_1      = 9,
74
  TA_HMAC_SHA_224    = 10,
75
  TA_HMAC_SHA_256    = 11,
76
  TA_HMAC_SHA_384    = 12,
77
  TA_HMAC_SHA_512    = 13,
78
  // digest
79
  TA_SHA_1           = 14,
80
  TA_SHA_224         = 15,
81
  TA_SHA_256         = 16,
82
  TA_SHA_384         = 17,
83
  TA_SHA_512         = 18,
84
  // Later additions
85
  TA_AES_KW          = 19,
86
  TA_ECDH            = 20,
87
  TA_PBKDF2          = 21,
88
  TA_ECDSA           = 22,
89
  TA_HKDF            = 23,
90
};
91
92
// Convenience functions for extracting / converting information
93
94
// OOM-safe CryptoBuffer initialization, suitable for constructors
95
#define ATTEMPT_BUFFER_INIT(dst, src) \
96
0
  if (!dst.Assign(src)) { \
97
0
    mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; \
98
0
    return; \
99
0
  }
100
101
// OOM-safe CryptoBuffer-to-SECItem copy, suitable for DoCrypto
102
#define ATTEMPT_BUFFER_TO_SECITEM(arena, dst, src) \
103
0
  if (!src.ToSECItem(arena, dst)) { \
104
0
    return NS_ERROR_DOM_UNKNOWN_ERR; \
105
0
  }
106
107
// OOM-safe CryptoBuffer copy, suitable for DoCrypto
108
#define ATTEMPT_BUFFER_ASSIGN(dst, src) \
109
0
  if (!dst.Assign(src)) { \
110
0
    return NS_ERROR_DOM_UNKNOWN_ERR; \
111
0
  }
112
113
// Safety check for algorithms that use keys, suitable for constructors
114
#define CHECK_KEY_ALGORITHM(keyAlg, algName) \
115
0
  { \
116
0
    if (!NORMALIZED_EQUALS(keyAlg.mName, algName)) { \
117
0
      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; \
118
0
      return; \
119
0
    } \
120
0
  }
121
122
class ClearException
123
{
124
public:
125
  explicit ClearException(JSContext* aCx)
126
    : mCx(aCx)
127
0
  {}
128
129
  ~ClearException()
130
0
  {
131
0
    JS_ClearPendingException(mCx);
132
0
  }
133
134
private:
135
  JSContext* mCx;
136
};
137
138
template<class OOS>
139
static nsresult
140
GetAlgorithmName(JSContext* aCx, const OOS& aAlgorithm, nsString& aName)
141
0
{
142
0
  ClearException ce(aCx);
143
0
144
0
  if (aAlgorithm.IsString()) {
145
0
    // If string, then treat as algorithm name
146
0
    aName.Assign(aAlgorithm.GetAsString());
147
0
  } else {
148
0
    // Coerce to algorithm and extract name
149
0
    JS::RootedValue value(aCx, JS::ObjectValue(*aAlgorithm.GetAsObject()));
150
0
    Algorithm alg;
151
0
152
0
    if (!alg.Init(aCx, value)) {
153
0
      return NS_ERROR_DOM_SYNTAX_ERR;
154
0
    }
155
0
156
0
    aName = alg.mName;
157
0
  }
158
0
159
0
  if (!NormalizeToken(aName, aName)) {
160
0
    return NS_ERROR_DOM_SYNTAX_ERR;
161
0
  }
162
0
163
0
  return NS_OK;
164
0
}
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::GetAlgorithmName<mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::ObjectOrString const&, nsTString<char16_t>&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::GetAlgorithmName<mozilla::dom::OwningObjectOrString>(JSContext*, mozilla::dom::OwningObjectOrString const&, nsTString<char16_t>&)
165
166
template<class T, class OOS>
167
static nsresult
168
Coerce(JSContext* aCx, T& aTarget, const OOS& aAlgorithm)
169
0
{
170
0
  ClearException ce(aCx);
171
0
172
0
  if (!aAlgorithm.IsObject()) {
173
0
    return NS_ERROR_DOM_SYNTAX_ERR;
174
0
  }
175
0
176
0
  JS::RootedValue value(aCx, JS::ObjectValue(*aAlgorithm.GetAsObject()));
177
0
  if (!aTarget.Init(aCx, value)) {
178
0
    return NS_ERROR_DOM_SYNTAX_ERR;
179
0
  }
180
0
181
0
  return NS_OK;
182
0
}
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::AesCbcParams, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::AesCbcParams&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::AesCtrParams, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::AesCtrParams&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::AesGcmParams, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::AesGcmParams&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::RsaOaepParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::RsaOaepParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::RsaPssParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::RsaPssParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::EcdsaParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::EcdsaParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::HmacImportParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::HmacImportParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::RsaHashedImportParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::RsaHashedImportParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::EcKeyImportParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::EcKeyImportParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::DhImportKeyParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::DhImportKeyParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::AesDerivedKeyParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::AesDerivedKeyParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::HmacDerivedKeyParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::HmacDerivedKeyParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::HmacKeyGenParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::HmacKeyGenParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::Pbkdf2Params>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::Pbkdf2Params>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::EcdhKeyDeriveParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::EcdhKeyDeriveParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::DhKeyDeriveParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::DhKeyDeriveParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::HkdfParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::HkdfParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::RsaHashedKeyGenParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::RsaHashedKeyGenParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::EcKeyGenParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::EcKeyGenParams>&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: Unified_cpp_dom_crypto0.cpp:nsresult mozilla::dom::Coerce<mozilla::dom::RootedDictionary<mozilla::dom::DhKeyGenParams>, mozilla::dom::ObjectOrString>(JSContext*, mozilla::dom::RootedDictionary<mozilla::dom::DhKeyGenParams>&, mozilla::dom::ObjectOrString const&)
183
184
inline size_t
185
MapHashAlgorithmNameToBlockSize(const nsString& aName)
186
0
{
187
0
  if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1) ||
188
0
      aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
189
0
    return 512;
190
0
  }
191
0
192
0
  if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384) ||
193
0
      aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
194
0
    return 1024;
195
0
  }
196
0
197
0
  return 0;
198
0
}
199
200
inline nsresult
201
GetKeyLengthForAlgorithm(JSContext* aCx, const ObjectOrString& aAlgorithm,
202
                         size_t& aLength)
203
0
{
204
0
  aLength = 0;
205
0
206
0
  // Extract algorithm name
207
0
  nsString algName;
208
0
  if (NS_FAILED(GetAlgorithmName(aCx, aAlgorithm, algName))) {
209
0
    return NS_ERROR_DOM_SYNTAX_ERR;
210
0
  }
211
0
212
0
  // Read AES key length from given algorithm object.
213
0
  if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
214
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
215
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
216
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
217
0
    RootedDictionary<AesDerivedKeyParams> params(aCx);
218
0
    if (NS_FAILED(Coerce(aCx, params, aAlgorithm))) {
219
0
      return NS_ERROR_DOM_SYNTAX_ERR;
220
0
    }
221
0
222
0
    if (params.mLength != 128 &&
223
0
        params.mLength != 192 &&
224
0
        params.mLength != 256) {
225
0
      return NS_ERROR_DOM_DATA_ERR;
226
0
    }
227
0
228
0
    aLength = params.mLength;
229
0
    return NS_OK;
230
0
  }
231
0
232
0
  // Read HMAC key length from given algorithm object or
233
0
  // determine key length as the block size of the given hash.
234
0
  if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
235
0
    RootedDictionary<HmacDerivedKeyParams> params(aCx);
236
0
    if (NS_FAILED(Coerce(aCx, params, aAlgorithm))) {
237
0
      return NS_ERROR_DOM_SYNTAX_ERR;
238
0
    }
239
0
240
0
    // Return the passed length, if any.
241
0
    if (params.mLength.WasPassed()) {
242
0
      aLength = params.mLength.Value();
243
0
      return NS_OK;
244
0
    }
245
0
246
0
    nsString hashName;
247
0
    if (NS_FAILED(GetAlgorithmName(aCx, params.mHash, hashName))) {
248
0
      return NS_ERROR_DOM_SYNTAX_ERR;
249
0
    }
250
0
251
0
    // Return the given hash algorithm's block size as the key length.
252
0
    size_t length = MapHashAlgorithmNameToBlockSize(hashName);
253
0
    if (length == 0) {
254
0
      return NS_ERROR_DOM_SYNTAX_ERR;
255
0
    }
256
0
257
0
    aLength = length;
258
0
    return NS_OK;
259
0
  }
260
0
261
0
  return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
262
0
}
263
264
inline bool
265
MapOIDTagToNamedCurve(SECOidTag aOIDTag, nsString& aResult)
266
0
{
267
0
  switch (aOIDTag) {
268
0
    case SEC_OID_SECG_EC_SECP256R1:
269
0
      aResult.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256);
270
0
      break;
271
0
    case SEC_OID_SECG_EC_SECP384R1:
272
0
      aResult.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384);
273
0
      break;
274
0
    case SEC_OID_SECG_EC_SECP521R1:
275
0
      aResult.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521);
276
0
      break;
277
0
    default:
278
0
      return false;
279
0
  }
280
0
281
0
  return true;
282
0
}
283
284
inline SECOidTag
285
MapHashAlgorithmNameToOID(const nsString& aName)
286
0
{
287
0
  SECOidTag hashOID(SEC_OID_UNKNOWN);
288
0
289
0
  if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
290
0
    hashOID = SEC_OID_SHA1;
291
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
292
0
    hashOID = SEC_OID_SHA256;
293
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
294
0
    hashOID = SEC_OID_SHA384;
295
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
296
0
    hashOID = SEC_OID_SHA512;
297
0
  }
298
0
299
0
  return hashOID;
300
0
}
301
302
inline CK_MECHANISM_TYPE
303
0
MapHashAlgorithmNameToMgfMechanism(const nsString& aName) {
304
0
  CK_MECHANISM_TYPE mech(UNKNOWN_CK_MECHANISM);
305
0
306
0
  if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
307
0
    mech = CKG_MGF1_SHA1;
308
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
309
0
    mech = CKG_MGF1_SHA256;
310
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
311
0
    mech = CKG_MGF1_SHA384;
312
0
  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
313
0
    mech = CKG_MGF1_SHA512;
314
0
  }
315
0
316
0
  return mech;
317
0
}
318
319
// Implementation of WebCryptoTask methods
320
321
void
322
WebCryptoTask::DispatchWithPromise(Promise* aResultPromise)
323
0
{
324
0
  mResultPromise = aResultPromise;
325
0
326
0
  // Fail if an error was set during the constructor
327
0
  MAYBE_EARLY_FAIL(mEarlyRv)
328
0
329
0
  // Perform pre-NSS operations, and fail if they fail
330
0
  mEarlyRv = BeforeCrypto();
331
0
  MAYBE_EARLY_FAIL(mEarlyRv)
332
0
333
0
  // Skip dispatch if we're already done. Otherwise launch a CryptoTask
334
0
  if (mEarlyComplete) {
335
0
    CallCallback(mEarlyRv);
336
0
    return;
337
0
  }
338
0
339
0
  // Store calling thread
340
0
  mOriginalEventTarget = GetCurrentThreadSerialEventTarget();
341
0
342
0
  // If we are running on a worker thread we must hold the worker
343
0
  // alive while we work on the thread pool.  Otherwise the worker
344
0
  // private may get torn down before we dispatch back to complete
345
0
  // the transaction.
346
0
  if (!NS_IsMainThread()) {
347
0
    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
348
0
    MOZ_ASSERT(workerPrivate);
349
0
350
0
    RefPtr<StrongWorkerRef> workerRef =
351
0
      StrongWorkerRef::Create(workerPrivate, "WebCryptoTask");
352
0
    if (NS_WARN_IF(!workerRef)) {
353
0
      mEarlyRv = NS_BINDING_ABORTED;
354
0
    } else {
355
0
      mWorkerRef = new ThreadSafeWorkerRef(workerRef);
356
0
    }
357
0
  }
358
0
  MAYBE_EARLY_FAIL(mEarlyRv);
359
0
360
0
  // dispatch to thread pool
361
0
  mEarlyRv = WebCryptoThreadPool::Dispatch(this);
362
0
  MAYBE_EARLY_FAIL(mEarlyRv)
363
0
}
364
365
NS_IMETHODIMP
366
WebCryptoTask::Run()
367
0
{
368
0
  // Run heavy crypto operations on the thread pool, off the original thread.
369
0
  if (!IsOnOriginalThread()) {
370
0
    mRv = CalculateResult();
371
0
372
0
    // Back to the original thread, i.e. continue below.
373
0
    mOriginalEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
374
0
    return NS_OK;
375
0
  }
376
0
377
0
  // We're now back on the calling thread.
378
0
  CallCallback(mRv);
379
0
380
0
  // Stop holding the worker thread alive now that the async work has
381
0
  // been completed.
382
0
  mWorkerRef = nullptr;
383
0
384
0
  return NS_OK;
385
0
}
386
387
nsresult
388
WebCryptoTask::Cancel()
389
0
{
390
0
  MOZ_ASSERT(IsOnOriginalThread());
391
0
  FailWithError(NS_BINDING_ABORTED);
392
0
  return NS_OK;
393
0
}
394
395
void
396
WebCryptoTask::FailWithError(nsresult aRv)
397
0
{
398
0
  MOZ_ASSERT(IsOnOriginalThread());
399
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, false);
400
0
401
0
  // Blindly convert nsresult to DOMException
402
0
  // Individual tasks must ensure they pass the right values
403
0
  mResultPromise->MaybeReject(aRv);
404
0
  // Manually release mResultPromise while we're on the main thread
405
0
  mResultPromise = nullptr;
406
0
  mWorkerRef = nullptr;
407
0
  Cleanup();
408
0
}
409
410
nsresult
411
WebCryptoTask::CalculateResult()
412
0
{
413
0
  MOZ_ASSERT(!IsOnOriginalThread());
414
0
415
0
  return DoCrypto();
416
0
}
417
418
void
419
WebCryptoTask::CallCallback(nsresult rv)
420
0
{
421
0
  MOZ_ASSERT(IsOnOriginalThread());
422
0
  if (NS_FAILED(rv)) {
423
0
    FailWithError(rv);
424
0
    return;
425
0
  }
426
0
427
0
  nsresult rv2 = AfterCrypto();
428
0
  if (NS_FAILED(rv2)) {
429
0
    FailWithError(rv2);
430
0
    return;
431
0
  }
432
0
433
0
  Resolve();
434
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, true);
435
0
436
0
  // Manually release mResultPromise while we're on the main thread
437
0
  mResultPromise = nullptr;
438
0
  Cleanup();
439
0
}
440
441
// Some generic utility classes
442
443
class FailureTask : public WebCryptoTask
444
{
445
public:
446
0
  explicit FailureTask(nsresult aRv) {
447
0
    mEarlyRv = aRv;
448
0
  }
449
};
450
451
class ReturnArrayBufferViewTask : public WebCryptoTask
452
{
453
protected:
454
  CryptoBuffer mResult;
455
456
private:
457
  // Returns mResult as an ArrayBufferView, or an error
458
  virtual void Resolve() override
459
0
  {
460
0
    TypedArrayCreator<ArrayBuffer> ret(mResult);
461
0
    mResultPromise->MaybeResolve(ret);
462
0
  }
463
};
464
465
class DeferredData
466
{
467
public:
468
  template<class T>
469
0
  void SetData(const T& aData) {
470
0
    mDataIsSet = mData.Assign(aData);
471
0
  }
Unexecuted instantiation: void mozilla::dom::DeferredData::SetData<mozilla::dom::ArrayBufferViewOrArrayBuffer>(mozilla::dom::ArrayBufferViewOrArrayBuffer const&)
Unexecuted instantiation: void mozilla::dom::DeferredData::SetData<mozilla::dom::CryptoBuffer>(mozilla::dom::CryptoBuffer const&)
472
473
protected:
474
  DeferredData()
475
    : mDataIsSet(false)
476
0
  {}
477
478
  CryptoBuffer mData;
479
  bool mDataIsSet;
480
};
481
482
class AesTask : public ReturnArrayBufferViewTask,
483
                public DeferredData
484
{
485
public:
486
  AesTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
487
          CryptoKey& aKey, bool aEncrypt)
488
    : mMechanism(CKM_INVALID_MECHANISM)
489
    , mSymKey(aKey.GetSymKey())
490
    , mTagLength(0)
491
    , mCounterLength(0)
492
    , mEncrypt(aEncrypt)
493
0
  {
494
0
    Init(aCx, aAlgorithm, aKey, aEncrypt);
495
0
  }
496
497
  AesTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
498
          CryptoKey& aKey, const CryptoOperationData& aData,
499
          bool aEncrypt)
500
    : mMechanism(CKM_INVALID_MECHANISM)
501
    , mSymKey(aKey.GetSymKey())
502
    , mTagLength(0)
503
    , mCounterLength(0)
504
    , mEncrypt(aEncrypt)
505
0
  {
506
0
    Init(aCx, aAlgorithm, aKey, aEncrypt);
507
0
    SetData(aData);
508
0
  }
509
510
  void Init(JSContext* aCx, const ObjectOrString& aAlgorithm,
511
            CryptoKey& aKey, bool aEncrypt)
512
0
  {
513
0
    nsString algName;
514
0
    mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
515
0
    if (NS_FAILED(mEarlyRv)) {
516
0
      return;
517
0
    }
518
0
519
0
    // Check that we got a reasonable key
520
0
    if ((mSymKey.Length() != 16) &&
521
0
        (mSymKey.Length() != 24) &&
522
0
        (mSymKey.Length() != 32))
523
0
    {
524
0
      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
525
0
      return;
526
0
    }
527
0
528
0
    // Cache parameters depending on the specific algorithm
529
0
    TelemetryAlgorithm telemetryAlg;
530
0
    if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) {
531
0
      CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_CBC);
532
0
533
0
      mMechanism = CKM_AES_CBC_PAD;
534
0
      telemetryAlg = TA_AES_CBC;
535
0
      AesCbcParams params;
536
0
      nsresult rv = Coerce(aCx, params, aAlgorithm);
537
0
      if (NS_FAILED(rv)) {
538
0
        mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
539
0
        return;
540
0
      }
541
0
542
0
      ATTEMPT_BUFFER_INIT(mIv, params.mIv)
543
0
      if (mIv.Length() != 16) {
544
0
        mEarlyRv = NS_ERROR_DOM_DATA_ERR;
545
0
        return;
546
0
      }
547
0
    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) {
548
0
      CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_CTR);
549
0
550
0
      mMechanism = CKM_AES_CTR;
551
0
      telemetryAlg = TA_AES_CTR;
552
0
      AesCtrParams params;
553
0
      nsresult rv = Coerce(aCx, params, aAlgorithm);
554
0
      if (NS_FAILED(rv)) {
555
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
556
0
        return;
557
0
      }
558
0
559
0
      ATTEMPT_BUFFER_INIT(mIv, params.mCounter)
560
0
      if (mIv.Length() != 16) {
561
0
        mEarlyRv = NS_ERROR_DOM_DATA_ERR;
562
0
        return;
563
0
      }
564
0
565
0
      mCounterLength = params.mLength;
566
0
    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
567
0
      CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_GCM);
568
0
569
0
      mMechanism = CKM_AES_GCM;
570
0
      telemetryAlg = TA_AES_GCM;
571
0
      AesGcmParams params;
572
0
      nsresult rv = Coerce(aCx, params, aAlgorithm);
573
0
      if (NS_FAILED(rv)) {
574
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
575
0
        return;
576
0
      }
577
0
578
0
      ATTEMPT_BUFFER_INIT(mIv, params.mIv)
579
0
580
0
      if (params.mAdditionalData.WasPassed()) {
581
0
        ATTEMPT_BUFFER_INIT(mAad, params.mAdditionalData.Value())
582
0
      }
583
0
584
0
      // 32, 64, 96, 104, 112, 120 or 128
585
0
      mTagLength = 128;
586
0
      if (params.mTagLength.WasPassed()) {
587
0
        mTagLength = params.mTagLength.Value();
588
0
        if ((mTagLength > 128) ||
589
0
            !(mTagLength == 32 || mTagLength == 64 ||
590
0
              (mTagLength >= 96 && mTagLength % 8 == 0))) {
591
0
          mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
592
0
          return;
593
0
        }
594
0
      }
595
0
    } else {
596
0
      mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
597
0
      return;
598
0
    }
599
0
    Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg);
600
0
  }
601
602
private:
603
  CK_MECHANISM_TYPE mMechanism;
604
  CryptoBuffer mSymKey;
605
  CryptoBuffer mIv;   // Initialization vector
606
  CryptoBuffer mAad;  // Additional Authenticated Data
607
  uint8_t mTagLength;
608
  uint8_t mCounterLength;
609
  bool mEncrypt;
610
611
  virtual nsresult DoCrypto() override
612
0
  {
613
0
    nsresult rv;
614
0
615
0
    if (!mDataIsSet) {
616
0
      return NS_ERROR_DOM_OPERATION_ERR;
617
0
    }
618
0
619
0
    UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
620
0
    if (!arena) {
621
0
      return NS_ERROR_DOM_OPERATION_ERR;
622
0
    }
623
0
624
0
    // Construct the parameters object depending on algorithm
625
0
    SECItem param = { siBuffer, nullptr, 0 };
626
0
    CK_AES_CTR_PARAMS ctrParams;
627
0
    CK_GCM_PARAMS gcmParams;
628
0
    switch (mMechanism) {
629
0
      case CKM_AES_CBC_PAD:
630
0
        ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &param, mIv);
631
0
        break;
632
0
      case CKM_AES_CTR:
633
0
        ctrParams.ulCounterBits = mCounterLength;
634
0
        MOZ_ASSERT(mIv.Length() == 16);
635
0
        memcpy(&ctrParams.cb, mIv.Elements(), 16);
636
0
        param.type = siBuffer;
637
0
        param.data = (unsigned char*) &ctrParams;
638
0
        param.len  = sizeof(ctrParams);
639
0
        break;
640
0
      case CKM_AES_GCM:
641
0
        gcmParams.pIv = mIv.Elements();
642
0
        gcmParams.ulIvLen = mIv.Length();
643
0
        gcmParams.pAAD = mAad.Elements();
644
0
        gcmParams.ulAADLen = mAad.Length();
645
0
        gcmParams.ulTagBits = mTagLength;
646
0
        param.type = siBuffer;
647
0
        param.data = (unsigned char*) &gcmParams;
648
0
        param.len  = sizeof(gcmParams);
649
0
        break;
650
0
      default:
651
0
        return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
652
0
    }
653
0
654
0
    // Import the key
655
0
    SECItem keyItem = { siBuffer, nullptr, 0 };
656
0
    ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
657
0
    UniquePK11SlotInfo slot(PK11_GetInternalSlot());
658
0
    MOZ_ASSERT(slot.get());
659
0
    UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism,
660
0
                                              PK11_OriginUnwrap, CKA_ENCRYPT,
661
0
                                              &keyItem, nullptr));
662
0
    if (!symKey) {
663
0
      return NS_ERROR_DOM_INVALID_ACCESS_ERR;
664
0
    }
665
0
666
0
    // Check whether the integer addition would overflow.
667
0
    if (std::numeric_limits<CryptoBuffer::size_type>::max() - 16 < mData.Length()) {
668
0
      return NS_ERROR_DOM_DATA_ERR;
669
0
    }
670
0
671
0
    // Initialize the output buffer (enough space for padding / a full tag)
672
0
    if (!mResult.SetLength(mData.Length() + 16, fallible)) {
673
0
      return NS_ERROR_DOM_UNKNOWN_ERR;
674
0
    }
675
0
676
0
    uint32_t outLen = 0;
677
0
678
0
    // Perform the encryption/decryption
679
0
    if (mEncrypt) {
680
0
      rv = MapSECStatus(PK11_Encrypt(symKey.get(), mMechanism, &param,
681
0
                                     mResult.Elements(), &outLen,
682
0
                                     mResult.Length(), mData.Elements(),
683
0
                                     mData.Length()));
684
0
    } else {
685
0
      rv = MapSECStatus(PK11_Decrypt(symKey.get(), mMechanism, &param,
686
0
                                     mResult.Elements(), &outLen,
687
0
                                     mResult.Length(), mData.Elements(),
688
0
                                     mData.Length()));
689
0
    }
690
0
    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
691
0
692
0
    mResult.TruncateLength(outLen);
693
0
    return rv;
694
0
  }
695
};
696
697
// This class looks like an encrypt/decrypt task, like AesTask,
698
// but it is only exposed to wrapKey/unwrapKey, not encrypt/decrypt
699
class AesKwTask : public ReturnArrayBufferViewTask,
700
                  public DeferredData
701
{
702
public:
703
  AesKwTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
704
            CryptoKey& aKey, bool aEncrypt)
705
    : mMechanism(CKM_NSS_AES_KEY_WRAP)
706
    , mSymKey(aKey.GetSymKey())
707
    , mEncrypt(aEncrypt)
708
0
  {
709
0
    Init(aCx, aAlgorithm, aKey, aEncrypt);
710
0
  }
711
712
  AesKwTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
713
            CryptoKey& aKey, const CryptoOperationData& aData,
714
            bool aEncrypt)
715
    : mMechanism(CKM_NSS_AES_KEY_WRAP)
716
    , mSymKey(aKey.GetSymKey())
717
    , mEncrypt(aEncrypt)
718
0
  {
719
0
    Init(aCx, aAlgorithm, aKey, aEncrypt);
720
0
    SetData(aData);
721
0
  }
722
723
  void Init(JSContext* aCx, const ObjectOrString& aAlgorithm,
724
            CryptoKey& aKey, bool aEncrypt)
725
0
  {
726
0
    CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_KW);
727
0
728
0
    nsString algName;
729
0
    mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
730
0
    if (NS_FAILED(mEarlyRv)) {
731
0
      return;
732
0
    }
733
0
734
0
    // Check that we got a reasonable key
735
0
    if ((mSymKey.Length() != 16) &&
736
0
        (mSymKey.Length() != 24) &&
737
0
        (mSymKey.Length() != 32))
738
0
    {
739
0
      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
740
0
      return;
741
0
    }
742
0
743
0
    Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_AES_KW);
744
0
  }
745
746
private:
747
  CK_MECHANISM_TYPE mMechanism;
748
  CryptoBuffer mSymKey;
749
  bool mEncrypt;
750
751
  virtual nsresult DoCrypto() override
752
0
  {
753
0
    nsresult rv;
754
0
755
0
    if (!mDataIsSet) {
756
0
      return NS_ERROR_DOM_OPERATION_ERR;
757
0
    }
758
0
759
0
    // Check that the input is a multiple of 64 bits long
760
0
    if (mData.Length() == 0 || mData.Length() % 8 != 0) {
761
0
      return NS_ERROR_DOM_DATA_ERR;
762
0
    }
763
0
764
0
    UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
765
0
    if (!arena) {
766
0
      return NS_ERROR_DOM_OPERATION_ERR;
767
0
    }
768
0
769
0
    // Import the key
770
0
    SECItem keyItem = { siBuffer, nullptr, 0 };
771
0
    ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
772
0
    UniquePK11SlotInfo slot(PK11_GetInternalSlot());
773
0
    MOZ_ASSERT(slot.get());
774
0
    UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism,
775
0
                                              PK11_OriginUnwrap, CKA_WRAP,
776
0
                                              &keyItem, nullptr));
777
0
    if (!symKey) {
778
0
      return NS_ERROR_DOM_INVALID_ACCESS_ERR;
779
0
    }
780
0
781
0
    // Import the data to a SECItem
782
0
    SECItem dataItem = { siBuffer, nullptr, 0 };
783
0
    ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &dataItem, mData);
784
0
785
0
    // Parameters for the fake keys
786
0
    CK_MECHANISM_TYPE fakeMechanism = CKM_SHA_1_HMAC;
787
0
    CK_ATTRIBUTE_TYPE fakeOperation = CKA_SIGN;
788
0
789
0
    if (mEncrypt) {
790
0
      // Import the data into a fake PK11SymKey structure
791
0
      UniquePK11SymKey keyToWrap(PK11_ImportSymKey(slot.get(), fakeMechanism,
792
0
                                                   PK11_OriginUnwrap, fakeOperation,
793
0
                                                   &dataItem, nullptr));
794
0
      if (!keyToWrap) {
795
0
        return NS_ERROR_DOM_OPERATION_ERR;
796
0
      }
797
0
798
0
      // Encrypt and return the wrapped key
799
0
      // AES-KW encryption results in a wrapped key 64 bits longer
800
0
      if (!mResult.SetLength(mData.Length() + 8, fallible)) {
801
0
        return NS_ERROR_DOM_OPERATION_ERR;
802
0
      }
803
0
      SECItem resultItem = {siBuffer, mResult.Elements(),
804
0
                            (unsigned int) mResult.Length()};
805
0
      rv = MapSECStatus(PK11_WrapSymKey(mMechanism, nullptr, symKey.get(),
806
0
                                        keyToWrap.get(), &resultItem));
807
0
      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
808
0
    } else {
809
0
      // Decrypt the ciphertext into a temporary PK11SymKey
810
0
      // Unwrapped key should be 64 bits shorter
811
0
      int keySize = mData.Length() - 8;
812
0
      UniquePK11SymKey unwrappedKey(
813
0
        PK11_UnwrapSymKey(symKey.get(), mMechanism, nullptr, &dataItem,
814
0
                          fakeMechanism, fakeOperation, keySize));
815
0
      if (!unwrappedKey) {
816
0
        return NS_ERROR_DOM_OPERATION_ERR;
817
0
      }
818
0
819
0
      // Export the key to get the cleartext
820
0
      rv = MapSECStatus(PK11_ExtractKeyValue(unwrappedKey.get()));
821
0
      if (NS_FAILED(rv)) {
822
0
        return NS_ERROR_DOM_UNKNOWN_ERR;
823
0
      }
824
0
      ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(unwrappedKey.get()));
825
0
    }
826
0
827
0
    return rv;
828
0
  }
829
};
830
831
class RsaOaepTask : public ReturnArrayBufferViewTask,
832
                    public DeferredData
833
{
834
public:
835
  RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
836
              CryptoKey& aKey, bool aEncrypt)
837
    : mPrivKey(aKey.GetPrivateKey())
838
    , mPubKey(aKey.GetPublicKey())
839
    , mEncrypt(aEncrypt)
840
0
  {
841
0
    Init(aCx, aAlgorithm, aKey, aEncrypt);
842
0
  }
843
844
  RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
845
              CryptoKey& aKey, const CryptoOperationData& aData,
846
              bool aEncrypt)
847
    : mPrivKey(aKey.GetPrivateKey())
848
    , mPubKey(aKey.GetPublicKey())
849
    , mEncrypt(aEncrypt)
850
0
  {
851
0
    Init(aCx, aAlgorithm, aKey, aEncrypt);
852
0
    SetData(aData);
853
0
  }
854
855
  void Init(JSContext* aCx, const ObjectOrString& aAlgorithm,
856
            CryptoKey& aKey, bool aEncrypt)
857
0
  {
858
0
    Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_OAEP);
859
0
860
0
    CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_OAEP);
861
0
862
0
    if (mEncrypt) {
863
0
      if (!mPubKey) {
864
0
        mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
865
0
        return;
866
0
      }
867
0
      mStrength = SECKEY_PublicKeyStrength(mPubKey.get());
868
0
    } else {
869
0
      if (!mPrivKey) {
870
0
        mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
871
0
        return;
872
0
      }
873
0
      mStrength = PK11_GetPrivateModulusLen(mPrivKey.get());
874
0
    }
875
0
876
0
    // The algorithm could just be given as a string
877
0
    // in which case there would be no label specified.
878
0
    if (!aAlgorithm.IsString()) {
879
0
      RootedDictionary<RsaOaepParams> params(aCx);
880
0
      mEarlyRv = Coerce(aCx, params, aAlgorithm);
881
0
      if (NS_FAILED(mEarlyRv)) {
882
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
883
0
        return;
884
0
      }
885
0
886
0
      if (params.mLabel.WasPassed()) {
887
0
        ATTEMPT_BUFFER_INIT(mLabel, params.mLabel.Value());
888
0
      }
889
0
    }
890
0
    // Otherwise mLabel remains the empty octet string, as intended
891
0
892
0
    KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash;
893
0
    mHashMechanism = KeyAlgorithmProxy::GetMechanism(hashAlg);
894
0
    mMgfMechanism = MapHashAlgorithmNameToMgfMechanism(hashAlg.mName);
895
0
896
0
    // Check we found appropriate mechanisms.
897
0
    if (mHashMechanism == UNKNOWN_CK_MECHANISM ||
898
0
        mMgfMechanism == UNKNOWN_CK_MECHANISM) {
899
0
      mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
900
0
      return;
901
0
    }
902
0
  }
903
904
private:
905
  CK_MECHANISM_TYPE mHashMechanism;
906
  CK_MECHANISM_TYPE mMgfMechanism;
907
  UniqueSECKEYPrivateKey mPrivKey;
908
  UniqueSECKEYPublicKey mPubKey;
909
  CryptoBuffer mLabel;
910
  uint32_t mStrength;
911
  bool mEncrypt;
912
913
  virtual nsresult DoCrypto() override
914
0
  {
915
0
    nsresult rv;
916
0
917
0
    if (!mDataIsSet) {
918
0
      return NS_ERROR_DOM_OPERATION_ERR;
919
0
    }
920
0
921
0
    // Ciphertext is an integer mod the modulus, so it will be
922
0
    // no longer than mStrength octets
923
0
    if (!mResult.SetLength(mStrength, fallible)) {
924
0
      return NS_ERROR_DOM_UNKNOWN_ERR;
925
0
    }
926
0
927
0
    CK_RSA_PKCS_OAEP_PARAMS oaepParams;
928
0
    oaepParams.source = CKZ_DATA_SPECIFIED;
929
0
930
0
    oaepParams.pSourceData = mLabel.Length() ? mLabel.Elements() : nullptr;
931
0
    oaepParams.ulSourceDataLen = mLabel.Length();
932
0
933
0
    oaepParams.mgf = mMgfMechanism;
934
0
    oaepParams.hashAlg = mHashMechanism;
935
0
936
0
    SECItem param;
937
0
    param.type = siBuffer;
938
0
    param.data = (unsigned char*) &oaepParams;
939
0
    param.len = sizeof(oaepParams);
940
0
941
0
    uint32_t outLen = 0;
942
0
    if (mEncrypt) {
943
0
      // PK11_PubEncrypt() checks the plaintext's length and fails if it is too
944
0
      // long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
945
0
      // being the length in octets of the RSA modulus n and 'hLen' being the
946
0
      // output length in octets of the chosen hash function.
947
0
      // <https://tools.ietf.org/html/rfc3447#section-7.1>
948
0
      rv = MapSECStatus(PK11_PubEncrypt(
949
0
             mPubKey.get(), CKM_RSA_PKCS_OAEP, &param,
950
0
             mResult.Elements(), &outLen, mResult.Length(),
951
0
             mData.Elements(), mData.Length(), nullptr));
952
0
    } else {
953
0
      rv = MapSECStatus(PK11_PrivDecrypt(
954
0
             mPrivKey.get(), CKM_RSA_PKCS_OAEP, &param,
955
0
             mResult.Elements(), &outLen, mResult.Length(),
956
0
             mData.Elements(), mData.Length()));
957
0
    }
958
0
    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
959
0
960
0
    mResult.TruncateLength(outLen);
961
0
    return NS_OK;
962
0
  }
963
};
964
965
class HmacTask : public WebCryptoTask
966
{
967
public:
968
  HmacTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
969
           CryptoKey& aKey,
970
           const CryptoOperationData& aSignature,
971
           const CryptoOperationData& aData,
972
           bool aSign)
973
    : mMechanism(aKey.Algorithm().Mechanism())
974
    , mSymKey(aKey.GetSymKey())
975
    , mSign(aSign)
976
0
  {
977
0
    CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_HMAC);
978
0
979
0
    ATTEMPT_BUFFER_INIT(mData, aData);
980
0
    if (!aSign) {
981
0
      ATTEMPT_BUFFER_INIT(mSignature, aSignature);
982
0
    }
983
0
984
0
    // Check that we got a symmetric key
985
0
    if (mSymKey.Length() == 0) {
986
0
      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
987
0
      return;
988
0
    }
989
0
990
0
    TelemetryAlgorithm telemetryAlg;
991
0
    switch (mMechanism) {
992
0
      case CKM_SHA_1_HMAC:  telemetryAlg = TA_HMAC_SHA_1; break;
993
0
      case CKM_SHA224_HMAC: telemetryAlg = TA_HMAC_SHA_224; break;
994
0
      case CKM_SHA256_HMAC: telemetryAlg = TA_HMAC_SHA_256; break;
995
0
      case CKM_SHA384_HMAC: telemetryAlg = TA_HMAC_SHA_384; break;
996
0
      case CKM_SHA512_HMAC: telemetryAlg = TA_HMAC_SHA_512; break;
997
0
      default:              telemetryAlg = TA_UNKNOWN;
998
0
    }
999
0
    Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg);
1000
0
  }
1001
1002
private:
1003
  CK_MECHANISM_TYPE mMechanism;
1004
  CryptoBuffer mSymKey;
1005
  CryptoBuffer mData;
1006
  CryptoBuffer mSignature;
1007
  CryptoBuffer mResult;
1008
  bool mSign;
1009
1010
  virtual nsresult DoCrypto() override
1011
0
  {
1012
0
    // Initialize the output buffer
1013
0
    if (!mResult.SetLength(HASH_LENGTH_MAX, fallible)) {
1014
0
      return NS_ERROR_DOM_UNKNOWN_ERR;
1015
0
    }
1016
0
1017
0
    UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
1018
0
    if (!arena) {
1019
0
      return NS_ERROR_DOM_OPERATION_ERR;
1020
0
    }
1021
0
1022
0
    // Import the key
1023
0
    uint32_t outLen;
1024
0
    SECItem keyItem = { siBuffer, nullptr, 0 };
1025
0
    ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
1026
0
    UniquePK11SlotInfo slot(PK11_GetInternalSlot());
1027
0
    MOZ_ASSERT(slot.get());
1028
0
    UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism,
1029
0
                                              PK11_OriginUnwrap, CKA_SIGN,
1030
0
                                              &keyItem, nullptr));
1031
0
    if (!symKey) {
1032
0
      return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1033
0
    }
1034
0
1035
0
    // Compute the MAC
1036
0
    SECItem param = { siBuffer, nullptr, 0 };
1037
0
    UniquePK11Context ctx(PK11_CreateContextBySymKey(mMechanism, CKA_SIGN,
1038
0
                                                     symKey.get(), &param));
1039
0
    if (!ctx.get()) {
1040
0
      return NS_ERROR_DOM_OPERATION_ERR;
1041
0
    }
1042
0
    nsresult rv = MapSECStatus(PK11_DigestBegin(ctx.get()));
1043
0
    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
1044
0
    rv = MapSECStatus(PK11_DigestOp(ctx.get(), mData.Elements(), mData.Length()));
1045
0
    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
1046
0
    rv = MapSECStatus(PK11_DigestFinal(ctx.get(), mResult.Elements(),
1047
0
                                       &outLen, mResult.Length()));
1048
0
    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
1049
0
1050
0
    mResult.TruncateLength(outLen);
1051
0
    return rv;
1052
0
  }
1053
1054
  // Returns mResult as an ArrayBufferView, or an error
1055
  virtual void Resolve() override
1056
0
  {
1057
0
    if (mSign) {
1058
0
      // Return the computed MAC
1059
0
      TypedArrayCreator<ArrayBuffer> ret(mResult);
1060
0
      mResultPromise->MaybeResolve(ret);
1061
0
    } else {
1062
0
      // Compare the MAC to the provided signature
1063
0
      // No truncation allowed
1064
0
      bool equal = (mResult.Length() == mSignature.Length());
1065
0
      if (equal) {
1066
0
        int cmp = NSS_SecureMemcmp(mSignature.Elements(),
1067
0
                                   mResult.Elements(),
1068
0
                                   mSignature.Length());
1069
0
        equal = (cmp == 0);
1070
0
      }
1071
0
      mResultPromise->MaybeResolve(equal);
1072
0
    }
1073
0
  }
1074
};
1075
1076
class AsymmetricSignVerifyTask : public WebCryptoTask
1077
{
1078
public:
1079
  AsymmetricSignVerifyTask(JSContext* aCx,
1080
                           const ObjectOrString& aAlgorithm,
1081
                           CryptoKey& aKey,
1082
                           const CryptoOperationData& aSignature,
1083
                           const CryptoOperationData& aData,
1084
                           bool aSign)
1085
    : mOidTag(SEC_OID_UNKNOWN)
1086
    , mHashMechanism(UNKNOWN_CK_MECHANISM)
1087
    , mMgfMechanism(UNKNOWN_CK_MECHANISM)
1088
    , mPrivKey(aKey.GetPrivateKey())
1089
    , mPubKey(aKey.GetPublicKey())
1090
    , mSaltLength(0)
1091
    , mSign(aSign)
1092
    , mVerified(false)
1093
    , mAlgorithm(Algorithm::UNKNOWN)
1094
0
  {
1095
0
    ATTEMPT_BUFFER_INIT(mData, aData);
1096
0
    if (!aSign) {
1097
0
      ATTEMPT_BUFFER_INIT(mSignature, aSignature);
1098
0
    }
1099
0
1100
0
    nsString algName;
1101
0
    nsString hashAlgName;
1102
0
    mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
1103
0
    if (NS_FAILED(mEarlyRv)) {
1104
0
      return;
1105
0
    }
1106
0
1107
0
    if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
1108
0
      mAlgorithm = Algorithm::RSA_PKCS1;
1109
0
      Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1);
1110
0
      CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1);
1111
0
      hashAlgName = aKey.Algorithm().mRsa.mHash.mName;
1112
0
    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
1113
0
      mAlgorithm = Algorithm::RSA_PSS;
1114
0
      Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_PSS);
1115
0
      CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_PSS);
1116
0
1117
0
      KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash;
1118
0
      hashAlgName = hashAlg.mName;
1119
0
      mHashMechanism = KeyAlgorithmProxy::GetMechanism(hashAlg);
1120
0
      mMgfMechanism = MapHashAlgorithmNameToMgfMechanism(hashAlgName);
1121
0
1122
0
      // Check we found appropriate mechanisms.
1123
0
      if (mHashMechanism == UNKNOWN_CK_MECHANISM ||
1124
0
          mMgfMechanism == UNKNOWN_CK_MECHANISM) {
1125
0
        mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1126
0
        return;
1127
0
      }
1128
0
1129
0
      RootedDictionary<RsaPssParams> params(aCx);
1130
0
      mEarlyRv = Coerce(aCx, params, aAlgorithm);
1131
0
      if (NS_FAILED(mEarlyRv)) {
1132
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1133
0
        return;
1134
0
      }
1135
0
1136
0
      mSaltLength = params.mSaltLength;
1137
0
    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
1138
0
      mAlgorithm = Algorithm::ECDSA;
1139
0
      Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDSA);
1140
0
      CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDSA);
1141
0
1142
0
      // For ECDSA, the hash name comes from the algorithm parameter
1143
0
      RootedDictionary<EcdsaParams> params(aCx);
1144
0
      mEarlyRv = Coerce(aCx, params, aAlgorithm);
1145
0
      if (NS_FAILED(mEarlyRv)) {
1146
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1147
0
        return;
1148
0
      }
1149
0
1150
0
      mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashAlgName);
1151
0
      if (NS_FAILED(mEarlyRv)) {
1152
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1153
0
        return;
1154
0
      }
1155
0
    } else {
1156
0
      // This shouldn't happen; CreateSignVerifyTask shouldn't create
1157
0
      // one of these unless it's for the above algorithms.
1158
0
      MOZ_ASSERT(false);
1159
0
    }
1160
0
1161
0
    // Must have a valid algorithm by now.
1162
0
    MOZ_ASSERT(mAlgorithm != Algorithm::UNKNOWN);
1163
0
1164
0
    // Determine hash algorithm to use.
1165
0
    mOidTag = MapHashAlgorithmNameToOID(hashAlgName);
1166
0
    if (mOidTag == SEC_OID_UNKNOWN) {
1167
0
      mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1168
0
      return;
1169
0
    }
1170
0
1171
0
    // Check that we have the appropriate key
1172
0
    if ((mSign && !mPrivKey) || (!mSign && !mPubKey)) {
1173
0
      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
1174
0
      return;
1175
0
    }
1176
0
  }
1177
1178
private:
1179
  SECOidTag mOidTag;
1180
  CK_MECHANISM_TYPE mHashMechanism;
1181
  CK_MECHANISM_TYPE mMgfMechanism;
1182
  UniqueSECKEYPrivateKey mPrivKey;
1183
  UniqueSECKEYPublicKey mPubKey;
1184
  CryptoBuffer mSignature;
1185
  CryptoBuffer mData;
1186
  uint32_t mSaltLength;
1187
  bool mSign;
1188
  bool mVerified;
1189
1190
  // The signature algorithm to use.
1191
  enum class Algorithm: uint8_t {ECDSA, RSA_PKCS1, RSA_PSS, UNKNOWN};
1192
  Algorithm mAlgorithm;
1193
1194
  virtual nsresult DoCrypto() override
1195
0
  {
1196
0
    SECStatus rv;
1197
0
    UniqueSECItem hash(::SECITEM_AllocItem(nullptr, nullptr,
1198
0
                                           HASH_ResultLenByOidTag(mOidTag)));
1199
0
    if (!hash) {
1200
0
      return NS_ERROR_DOM_OPERATION_ERR;
1201
0
    }
1202
0
1203
0
    // Compute digest over given data.
1204
0
    rv = PK11_HashBuf(mOidTag, hash->data, mData.Elements(), mData.Length());
1205
0
    NS_ENSURE_SUCCESS(MapSECStatus(rv), NS_ERROR_DOM_OPERATION_ERR);
1206
0
1207
0
    // Wrap hash in a digest info template (RSA-PKCS1 only).
1208
0
    if (mAlgorithm == Algorithm::RSA_PKCS1) {
1209
0
      UniqueSGNDigestInfo di(SGN_CreateDigestInfo(mOidTag, hash->data,
1210
0
                                                  hash->len));
1211
0
      if (!di) {
1212
0
        return NS_ERROR_DOM_OPERATION_ERR;
1213
0
      }
1214
0
1215
0
      // Reuse |hash|.
1216
0
      SECITEM_FreeItem(hash.get(), false);
1217
0
      if (!SEC_ASN1EncodeItem(nullptr, hash.get(), di.get(),
1218
0
                              SGN_DigestInfoTemplate)) {
1219
0
        return NS_ERROR_DOM_OPERATION_ERR;
1220
0
      }
1221
0
    }
1222
0
1223
0
    SECItem* params = nullptr;
1224
0
    CK_MECHANISM_TYPE mech = PK11_MapSignKeyType((mSign ? mPrivKey->keyType :
1225
0
                                                          mPubKey->keyType));
1226
0
1227
0
    CK_RSA_PKCS_PSS_PARAMS rsaPssParams;
1228
0
    SECItem rsaPssParamsItem = { siBuffer, };
1229
0
1230
0
    // Set up parameters for RSA-PSS.
1231
0
    if (mAlgorithm == Algorithm::RSA_PSS) {
1232
0
      rsaPssParams.hashAlg = mHashMechanism;
1233
0
      rsaPssParams.mgf = mMgfMechanism;
1234
0
      rsaPssParams.sLen = mSaltLength;
1235
0
1236
0
      rsaPssParamsItem.data = (unsigned char*)&rsaPssParams;
1237
0
      rsaPssParamsItem.len = sizeof(rsaPssParams);
1238
0
      params = &rsaPssParamsItem;
1239
0
1240
0
      mech = CKM_RSA_PKCS_PSS;
1241
0
    }
1242
0
1243
0
    // Allocate SECItem to hold the signature.
1244
0
    uint32_t len = mSign ? PK11_SignatureLen(mPrivKey.get()) : 0;
1245
0
    UniqueSECItem sig(::SECITEM_AllocItem(nullptr, nullptr, len));
1246
0
    if (!sig) {
1247
0
      return NS_ERROR_DOM_OPERATION_ERR;
1248
0
    }
1249
0
1250
0
    if (mSign) {
1251
0
      // Sign the hash.
1252
0
      rv = PK11_SignWithMechanism(mPrivKey.get(), mech, params, sig.get(),
1253
0
                                  hash.get());
1254
0
      NS_ENSURE_SUCCESS(MapSECStatus(rv), NS_ERROR_DOM_OPERATION_ERR);
1255
0
      ATTEMPT_BUFFER_ASSIGN(mSignature, sig.get());
1256
0
    } else {
1257
0
      // Copy the given signature to the SECItem.
1258
0
      if (!mSignature.ToSECItem(nullptr, sig.get())) {
1259
0
        return NS_ERROR_DOM_OPERATION_ERR;
1260
0
      }
1261
0
1262
0
      // Verify the signature.
1263
0
      rv = PK11_VerifyWithMechanism(mPubKey.get(), mech, params, sig.get(),
1264
0
                                    hash.get(), nullptr);
1265
0
      mVerified = NS_SUCCEEDED(MapSECStatus(rv));
1266
0
    }
1267
0
1268
0
    return NS_OK;
1269
0
  }
1270
1271
  virtual void Resolve() override
1272
0
  {
1273
0
    if (mSign) {
1274
0
      TypedArrayCreator<ArrayBuffer> ret(mSignature);
1275
0
      mResultPromise->MaybeResolve(ret);
1276
0
    } else {
1277
0
      mResultPromise->MaybeResolve(mVerified);
1278
0
    }
1279
0
  }
1280
};
1281
1282
class DigestTask : public ReturnArrayBufferViewTask
1283
{
1284
public:
1285
  DigestTask(JSContext* aCx,
1286
                   const ObjectOrString& aAlgorithm,
1287
                   const CryptoOperationData& aData)
1288
0
  {
1289
0
    ATTEMPT_BUFFER_INIT(mData, aData);
1290
0
1291
0
    nsString algName;
1292
0
    mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
1293
0
    if (NS_FAILED(mEarlyRv)) {
1294
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1295
0
      return;
1296
0
    }
1297
0
1298
0
    TelemetryAlgorithm telemetryAlg;
1299
0
    if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA1))   {
1300
0
      telemetryAlg = TA_SHA_1;
1301
0
    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
1302
0
      telemetryAlg = TA_SHA_224;
1303
0
    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
1304
0
      telemetryAlg = TA_SHA_256;
1305
0
    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
1306
0
      telemetryAlg = TA_SHA_384;
1307
0
    } else {
1308
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1309
0
      return;
1310
0
    }
1311
0
    Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg);
1312
0
    mOidTag = MapHashAlgorithmNameToOID(algName);
1313
0
  }
1314
1315
private:
1316
  SECOidTag mOidTag;
1317
  CryptoBuffer mData;
1318
1319
  virtual nsresult DoCrypto() override
1320
0
  {
1321
0
    // Resize the result buffer
1322
0
    uint32_t hashLen = HASH_ResultLenByOidTag(mOidTag);
1323
0
    if (!mResult.SetLength(hashLen, fallible)) {
1324
0
      return NS_ERROR_DOM_UNKNOWN_ERR;
1325
0
    }
1326
0
1327
0
    // Compute the hash
1328
0
    nsresult rv = MapSECStatus(PK11_HashBuf(mOidTag, mResult.Elements(),
1329
0
                                            mData.Elements(), mData.Length()));
1330
0
    if (NS_FAILED(rv)) {
1331
0
      return NS_ERROR_DOM_UNKNOWN_ERR;
1332
0
    }
1333
0
1334
0
    return rv;
1335
0
  }
1336
};
1337
1338
class ImportKeyTask : public WebCryptoTask
1339
{
1340
public:
1341
  void Init(nsIGlobalObject* aGlobal, JSContext* aCx,
1342
      const nsAString& aFormat, const ObjectOrString& aAlgorithm,
1343
      bool aExtractable, const Sequence<nsString>& aKeyUsages)
1344
0
  {
1345
0
    mFormat = aFormat;
1346
0
    mDataIsSet = false;
1347
0
    mDataIsJwk = false;
1348
0
1349
0
    // This stuff pretty much always happens, so we'll do it here
1350
0
    mKey = new CryptoKey(aGlobal);
1351
0
    mKey->SetExtractable(aExtractable);
1352
0
    mKey->ClearUsages();
1353
0
    for (uint32_t i = 0; i < aKeyUsages.Length(); ++i) {
1354
0
      mEarlyRv = mKey->AddUsage(aKeyUsages[i]);
1355
0
      if (NS_FAILED(mEarlyRv)) {
1356
0
        return;
1357
0
      }
1358
0
    }
1359
0
1360
0
    mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, mAlgName);
1361
0
    if (NS_FAILED(mEarlyRv)) {
1362
0
      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1363
0
      return;
1364
0
    }
1365
0
  }
1366
1367
  static bool JwkCompatible(const JsonWebKey& aJwk, const CryptoKey* aKey)
1368
0
  {
1369
0
    // Check 'ext'
1370
0
    if (aKey->Extractable() &&
1371
0
        aJwk.mExt.WasPassed() && !aJwk.mExt.Value()) {
1372
0
      return false;
1373
0
    }
1374
0
1375
0
    // Check 'alg'
1376
0
    if (aJwk.mAlg.WasPassed() &&
1377
0
        aJwk.mAlg.Value() != aKey->Algorithm().JwkAlg()) {
1378
0
      return false;
1379
0
    }
1380
0
1381
0
    // Check 'key_ops'
1382
0
    if (aJwk.mKey_ops.WasPassed()) {
1383
0
      nsTArray<nsString> usages;
1384
0
      aKey->GetUsages(usages);
1385
0
      for (size_t i = 0; i < usages.Length(); ++i) {
1386
0
        if (!aJwk.mKey_ops.Value().Contains(usages[i])) {
1387
0
          return false;
1388
0
        }
1389
0
      }
1390
0
    }
1391
0
1392
0
    // Individual algorithms may still have to check 'use'
1393
0
    return true;
1394
0
  }
1395
1396
  void SetKeyData(JSContext* aCx, JS::Handle<JSObject*> aKeyData)
1397
0
  {
1398
0
    mDataIsJwk = false;
1399
0
1400
0
    // Try ArrayBuffer
1401
0
    RootedSpiderMonkeyInterface<ArrayBuffer> ab(aCx);
1402
0
    if (ab.Init(aKeyData)) {
1403
0
      if (!mKeyData.Assign(ab)) {
1404
0
        mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1405
0
      }
1406
0
      return;
1407
0
    }
1408
0
1409
0
    // Try ArrayBufferView
1410
0
    RootedSpiderMonkeyInterface<ArrayBufferView> abv(aCx);
1411
0
    if (abv.Init(aKeyData)) {
1412
0
      if (!mKeyData.Assign(abv)) {
1413
0
        mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1414
0
      }
1415
0
      return;
1416
0
    }
1417
0
1418
0
    // Try JWK
1419
0
    ClearException ce(aCx);
1420
0
    JS::RootedValue value(aCx, JS::ObjectValue(*aKeyData));
1421
0
    if (!mJwk.Init(aCx, value)) {
1422
0
      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1423
0
      return;
1424
0
    }
1425
0
1426
0
    mDataIsJwk = true;
1427
0
  }
1428
1429
  void SetKeyDataMaybeParseJWK(const CryptoBuffer& aKeyData)
1430
0
  {
1431
0
    if (!mKeyData.Assign(aKeyData)) {
1432
0
      mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1433
0
      return;
1434
0
    }
1435
0
1436
0
    mDataIsJwk = false;
1437
0
1438
0
    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1439
0
      nsDependentCSubstring utf8((const char*) mKeyData.Elements(),
1440
0
                                 (const char*) (mKeyData.Elements() +
1441
0
                                                mKeyData.Length()));
1442
0
      if (!IsUTF8(utf8)) {
1443
0
        mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1444
0
        return;
1445
0
      }
1446
0
1447
0
      nsString json = NS_ConvertUTF8toUTF16(utf8);
1448
0
      if (!mJwk.Init(json)) {
1449
0
        mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1450
0
        return;
1451
0
      }
1452
0
1453
0
      mDataIsJwk = true;
1454
0
    }
1455
0
  }
1456
1457
  void SetRawKeyData(const CryptoBuffer& aKeyData)
1458
0
  {
1459
0
    if (!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1460
0
      mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1461
0
      return;
1462
0
    }
1463
0
1464
0
    if (!mKeyData.Assign(aKeyData)) {
1465
0
      mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1466
0
      return;
1467
0
    }
1468
0
1469
0
    mDataIsJwk = false;
1470
0
  }
1471
1472
protected:
1473
  nsString mFormat;
1474
  RefPtr<CryptoKey> mKey;
1475
  CryptoBuffer mKeyData;
1476
  bool mDataIsSet;
1477
  bool mDataIsJwk;
1478
  JsonWebKey mJwk;
1479
  nsString mAlgName;
1480
1481
private:
1482
  virtual void Resolve() override
1483
0
  {
1484
0
    mResultPromise->MaybeResolve(mKey);
1485
0
  }
1486
1487
  virtual void Cleanup() override
1488
0
  {
1489
0
    mKey = nullptr;
1490
0
  }
1491
};
1492
1493
1494
class ImportSymmetricKeyTask : public ImportKeyTask
1495
{
1496
public:
1497
  ImportSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1498
      const nsAString& aFormat,
1499
      const ObjectOrString& aAlgorithm, bool aExtractable,
1500
      const Sequence<nsString>& aKeyUsages)
1501
0
  {
1502
0
    Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1503
0
  }
1504
1505
  ImportSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1506
      const nsAString& aFormat, const JS::Handle<JSObject*> aKeyData,
1507
      const ObjectOrString& aAlgorithm, bool aExtractable,
1508
      const Sequence<nsString>& aKeyUsages)
1509
0
  {
1510
0
    Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1511
0
    if (NS_FAILED(mEarlyRv)) {
1512
0
      return;
1513
0
    }
1514
0
1515
0
    SetKeyData(aCx, aKeyData);
1516
0
    NS_ENSURE_SUCCESS_VOID(mEarlyRv);
1517
0
    if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1518
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1519
0
      return;
1520
0
    }
1521
0
  }
1522
1523
  void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1524
      const ObjectOrString& aAlgorithm, bool aExtractable,
1525
      const Sequence<nsString>& aKeyUsages)
1526
0
  {
1527
0
    ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1528
0
    if (NS_FAILED(mEarlyRv)) {
1529
0
      return;
1530
0
    }
1531
0
1532
0
    // This task only supports raw and JWK format.
1533
0
    if (!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1534
0
        !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1535
0
      mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1536
0
      return;
1537
0
    }
1538
0
1539
0
    // If this is an HMAC key, import the hash name
1540
0
    if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
1541
0
      RootedDictionary<HmacImportParams> params(aCx);
1542
0
      mEarlyRv = Coerce(aCx, params, aAlgorithm);
1543
0
      if (NS_FAILED(mEarlyRv)) {
1544
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1545
0
        return;
1546
0
      }
1547
0
      mEarlyRv = GetAlgorithmName(aCx, params.mHash, mHashName);
1548
0
      if (NS_FAILED(mEarlyRv)) {
1549
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1550
0
        return;
1551
0
      }
1552
0
    }
1553
0
  }
1554
1555
  virtual nsresult BeforeCrypto() override
1556
0
  {
1557
0
    nsresult rv;
1558
0
1559
0
    // If we're doing a JWK import, import the key data
1560
0
    if (mDataIsJwk) {
1561
0
      if (!mJwk.mK.WasPassed()) {
1562
0
        return NS_ERROR_DOM_DATA_ERR;
1563
0
      }
1564
0
1565
0
      // Import the key material
1566
0
      rv = mKeyData.FromJwkBase64(mJwk.mK.Value());
1567
0
      if (NS_FAILED(rv)) {
1568
0
        return NS_ERROR_DOM_DATA_ERR;
1569
0
      }
1570
0
    }
1571
0
1572
0
    // Check that we have valid key data.
1573
0
    if (mKeyData.Length() == 0) {
1574
0
      return NS_ERROR_DOM_DATA_ERR;
1575
0
    }
1576
0
1577
0
    // Construct an appropriate KeyAlorithm,
1578
0
    // and verify that usages are appropriate
1579
0
    uint32_t length = 8 * mKeyData.Length(); // bytes to bits
1580
0
    if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
1581
0
        mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
1582
0
        mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
1583
0
        mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
1584
0
      if (mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::DECRYPT |
1585
0
                                  CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) {
1586
0
        return NS_ERROR_DOM_DATA_ERR;
1587
0
      }
1588
0
1589
0
      if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) &&
1590
0
          mKey->HasUsageOtherThan(CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) {
1591
0
        return NS_ERROR_DOM_DATA_ERR;
1592
0
      }
1593
0
1594
0
      if ( (length != 128) && (length != 192) && (length != 256) ) {
1595
0
        return NS_ERROR_DOM_DATA_ERR;
1596
0
      }
1597
0
      mKey->Algorithm().MakeAes(mAlgName, length);
1598
0
1599
0
      if (mDataIsJwk && mJwk.mUse.WasPassed() &&
1600
0
          !mJwk.mUse.Value().EqualsLiteral(JWK_USE_ENC)) {
1601
0
        return NS_ERROR_DOM_DATA_ERR;
1602
0
      }
1603
0
    } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HKDF) ||
1604
0
               mAlgName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
1605
0
      if (mKey->HasUsageOtherThan(CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS)) {
1606
0
        return NS_ERROR_DOM_DATA_ERR;
1607
0
      }
1608
0
      mKey->Algorithm().MakeAes(mAlgName, length);
1609
0
1610
0
      if (mDataIsJwk && mJwk.mUse.WasPassed()) {
1611
0
        // There is not a 'use' value consistent with PBKDF or HKDF
1612
0
        return NS_ERROR_DOM_DATA_ERR;
1613
0
      };
1614
0
    } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
1615
0
      if (mKey->HasUsageOtherThan(CryptoKey::SIGN | CryptoKey::VERIFY)) {
1616
0
        return NS_ERROR_DOM_DATA_ERR;
1617
0
      }
1618
0
1619
0
      mKey->Algorithm().MakeHmac(length, mHashName);
1620
0
1621
0
      if (mKey->Algorithm().Mechanism() == UNKNOWN_CK_MECHANISM) {
1622
0
        return NS_ERROR_DOM_SYNTAX_ERR;
1623
0
      }
1624
0
1625
0
      if (mDataIsJwk && mJwk.mUse.WasPassed() &&
1626
0
          !mJwk.mUse.Value().EqualsLiteral(JWK_USE_SIG)) {
1627
0
        return NS_ERROR_DOM_DATA_ERR;
1628
0
      }
1629
0
    } else {
1630
0
      return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1631
0
    }
1632
0
1633
0
    if (NS_FAILED(mKey->SetSymKey(mKeyData))) {
1634
0
      return NS_ERROR_DOM_OPERATION_ERR;
1635
0
    }
1636
0
1637
0
    mKey->SetType(CryptoKey::SECRET);
1638
0
1639
0
    if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) {
1640
0
      return NS_ERROR_DOM_DATA_ERR;
1641
0
    }
1642
0
1643
0
    mEarlyComplete = true;
1644
0
    return NS_OK;
1645
0
  }
1646
1647
private:
1648
  nsString mHashName;
1649
};
1650
1651
class ImportRsaKeyTask : public ImportKeyTask
1652
{
1653
public:
1654
  ImportRsaKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1655
      const nsAString& aFormat,
1656
      const ObjectOrString& aAlgorithm, bool aExtractable,
1657
      const Sequence<nsString>& aKeyUsages)
1658
    : mModulusLength(0)
1659
0
  {
1660
0
    Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1661
0
  }
1662
1663
  ImportRsaKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1664
      const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
1665
      const ObjectOrString& aAlgorithm, bool aExtractable,
1666
      const Sequence<nsString>& aKeyUsages)
1667
    : mModulusLength(0)
1668
0
  {
1669
0
    Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1670
0
    if (NS_FAILED(mEarlyRv)) {
1671
0
      return;
1672
0
    }
1673
0
1674
0
    SetKeyData(aCx, aKeyData);
1675
0
    NS_ENSURE_SUCCESS_VOID(mEarlyRv);
1676
0
    if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1677
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1678
0
      return;
1679
0
    }
1680
0
  }
1681
1682
  void Init(nsIGlobalObject* aGlobal, JSContext* aCx,
1683
      const nsAString& aFormat,
1684
      const ObjectOrString& aAlgorithm, bool aExtractable,
1685
      const Sequence<nsString>& aKeyUsages)
1686
0
  {
1687
0
    ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1688
0
    if (NS_FAILED(mEarlyRv)) {
1689
0
      return;
1690
0
    }
1691
0
1692
0
    // If this is RSA with a hash, cache the hash name
1693
0
    if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
1694
0
        mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
1695
0
        mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
1696
0
      RootedDictionary<RsaHashedImportParams> params(aCx);
1697
0
      mEarlyRv = Coerce(aCx, params, aAlgorithm);
1698
0
      if (NS_FAILED(mEarlyRv)) {
1699
0
        mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1700
0
        return;
1701
0
      }
1702
0
1703
0
      mEarlyRv = GetAlgorithmName(aCx, params.mHash, mHashName);
1704
0
      if (NS_FAILED(mEarlyRv)) {
1705
0
        mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1706
0
        return;
1707
0
      }
1708
0
    }
1709
0
1710
0
    // Check support for the algorithm and hash names
1711
0
    CK_MECHANISM_TYPE mech1 = MapAlgorithmNameToMechanism(mAlgName);
1712
0
    CK_MECHANISM_TYPE mech2 = MapAlgorithmNameToMechanism(mHashName);
1713
0
    if ((mech1 == UNKNOWN_CK_MECHANISM) || (mech2 == UNKNOWN_CK_MECHANISM)) {
1714
0
      mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1715
0
      return;
1716
0
    }
1717
0
  }
1718
1719
private:
1720
  nsString mHashName;
1721
  uint32_t mModulusLength;
1722
  CryptoBuffer mPublicExponent;
1723
1724
  virtual nsresult DoCrypto() override
1725
0
  {
1726
0
    // Import the key data itself
1727
0
    UniqueSECKEYPublicKey pubKey;
1728
0
    UniqueSECKEYPrivateKey privKey;
1729
0
    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) ||
1730
0
        (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1731
0
         !mJwk.mD.WasPassed())) {
1732
0
      // Public key import
1733
0
      if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
1734
0
        pubKey = CryptoKey::PublicKeyFromSpki(mKeyData);
1735
0
      } else {
1736
0
        pubKey = CryptoKey::PublicKeyFromJwk(mJwk);
1737
0
      }
1738
0
1739
0
      if (!pubKey) {
1740
0
        return NS_ERROR_DOM_DATA_ERR;
1741
0
      }
1742
0
1743
0
      if (NS_FAILED(mKey->SetPublicKey(pubKey.get()))) {
1744
0
        return NS_ERROR_DOM_OPERATION_ERR;
1745
0
      }
1746
0
1747
0
      mKey->SetType(CryptoKey::PUBLIC);
1748
0
    } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) ||
1749
0
        (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1750
0
         mJwk.mD.WasPassed())) {
1751
0
      // Private key import
1752
0
      if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8)) {
1753
0
        privKey = CryptoKey::PrivateKeyFromPkcs8(mKeyData);
1754
0
      } else {
1755
0
        privKey = CryptoKey::PrivateKeyFromJwk(mJwk);
1756
0
      }
1757
0
1758
0
      if (!privKey) {
1759
0
        return NS_ERROR_DOM_DATA_ERR;
1760
0
      }
1761
0
1762
0
      if (NS_FAILED(mKey->SetPrivateKey(privKey.get()))) {
1763
0
        return NS_ERROR_DOM_OPERATION_ERR;
1764
0
      }
1765
0
1766
0
      mKey->SetType(CryptoKey::PRIVATE);
1767
0
      pubKey = UniqueSECKEYPublicKey(SECKEY_ConvertToPublicKey(privKey.get()));
1768
0
      if (!pubKey) {
1769
0
        return NS_ERROR_DOM_UNKNOWN_ERR;
1770
0
      }
1771
0
    } else {
1772
0
      // Invalid key format
1773
0
      return NS_ERROR_DOM_SYNTAX_ERR;
1774
0
    }
1775
0
1776
0
    // Extract relevant information from the public key
1777
0
    mModulusLength = 8 * pubKey->u.rsa.modulus.len;
1778
0
    if (!mPublicExponent.Assign(&pubKey->u.rsa.publicExponent)) {
1779
0
      return NS_ERROR_DOM_OPERATION_ERR;
1780
0
    }
1781
0
1782
0
    return NS_OK;
1783
0
  }
1784
1785
  virtual nsresult AfterCrypto() override
1786
0
  {
1787
0
    // Check permissions for the requested operation
1788
0
    if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
1789
0
      if ((mKey->GetKeyType() == CryptoKey::PUBLIC &&
1790
0
           mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::WRAPKEY)) ||
1791
0
          (mKey->GetKeyType() == CryptoKey::PRIVATE &&
1792
0
           mKey->HasUsageOtherThan(CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY))) {
1793
0
        return NS_ERROR_DOM_DATA_ERR;
1794
0
      }
1795
0
    } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
1796
0
               mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
1797
0
      if ((mKey->GetKeyType() == CryptoKey::PUBLIC &&
1798
0
           mKey->HasUsageOtherThan(CryptoKey::VERIFY)) ||
1799
0
          (mKey->GetKeyType() == CryptoKey::PRIVATE &&
1800
0
           mKey->HasUsageOtherThan(CryptoKey::SIGN))) {
1801
0
        return NS_ERROR_DOM_DATA_ERR;
1802
0
      }
1803
0
    }
1804
0
1805
0
    // Set an appropriate KeyAlgorithm
1806
0
    if (!mKey->Algorithm().MakeRsa(mAlgName, mModulusLength,
1807
0
                                   mPublicExponent, mHashName)) {
1808
0
      return NS_ERROR_DOM_OPERATION_ERR;
1809
0
    }
1810
0
1811
0
    if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) {
1812
0
      return NS_ERROR_DOM_DATA_ERR;
1813
0
    }
1814
0
1815
0
    return NS_OK;
1816
0
  }
1817
};
1818
1819
class ImportEcKeyTask : public ImportKeyTask
1820
{
1821
public:
1822
  ImportEcKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1823
                  const nsAString& aFormat, const ObjectOrString& aAlgorithm,
1824
                  bool aExtractable, const Sequence<nsString>& aKeyUsages)
1825
0
  {
1826
0
    Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1827
0
  }
1828
1829
  ImportEcKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1830
                  const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
1831
                  const ObjectOrString& aAlgorithm, bool aExtractable,
1832
                  const Sequence<nsString>& aKeyUsages)
1833
0
  {
1834
0
    Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1835
0
    if (NS_FAILED(mEarlyRv)) {
1836
0
      return;
1837
0
    }
1838
0
1839
0
    SetKeyData(aCx, aKeyData);
1840
0
    NS_ENSURE_SUCCESS_VOID(mEarlyRv);
1841
0
  }
1842
1843
  void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1844
            const ObjectOrString& aAlgorithm, bool aExtractable,
1845
            const Sequence<nsString>& aKeyUsages)
1846
0
  {
1847
0
    ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1848
0
    if (NS_FAILED(mEarlyRv)) {
1849
0
      return;
1850
0
    }
1851
0
1852
0
    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1853
0
      RootedDictionary<EcKeyImportParams> params(aCx);
1854
0
      mEarlyRv = Coerce(aCx, params, aAlgorithm);
1855
0
      if (NS_FAILED(mEarlyRv) || !params.mNamedCurve.WasPassed()) {
1856
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1857
0
        return;
1858
0
      }
1859
0
1860
0
      if (!NormalizeToken(params.mNamedCurve.Value(), mNamedCurve)) {
1861
0
        mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1862
0
        return;
1863
0
      }
1864
0
    }
1865
0
  }
1866
1867
private:
1868
  nsString mNamedCurve;
1869
1870
  virtual nsresult DoCrypto() override
1871
0
  {
1872
0
    // Import the key data itself
1873
0
    UniqueSECKEYPublicKey pubKey;
1874
0
    UniqueSECKEYPrivateKey privKey;
1875
0
1876
0
    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) && mJwk.mD.WasPassed()) {
1877
0
      // Private key import
1878
0
      privKey = CryptoKey::PrivateKeyFromJwk(mJwk);
1879
0
      if (!privKey) {
1880
0
        return NS_ERROR_DOM_DATA_ERR;
1881
0
      }
1882
0
1883
0
      if (NS_FAILED(mKey->SetPrivateKey(privKey.get()))) {
1884
0
        return NS_ERROR_DOM_OPERATION_ERR;
1885
0
      }
1886
0
1887
0
      mKey->SetType(CryptoKey::PRIVATE);
1888
0
    } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) ||
1889
0
               mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) ||
1890
0
               (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1891
0
                !mJwk.mD.WasPassed())) {
1892
0
      // Public key import
1893
0
      if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1894
0
        pubKey = CryptoKey::PublicECKeyFromRaw(mKeyData, mNamedCurve);
1895
0
      } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
1896
0
        pubKey = CryptoKey::PublicKeyFromSpki(mKeyData);
1897
0
      } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1898
0
        pubKey = CryptoKey::PublicKeyFromJwk(mJwk);
1899
0
      } else {
1900
0
        MOZ_ASSERT(false);
1901
0
      }
1902
0
1903
0
      if (!pubKey) {
1904
0
        return NS_ERROR_DOM_DATA_ERR;
1905
0
      }
1906
0
1907
0
      if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
1908
0
        if (!CheckEncodedECParameters(&pubKey->u.ec.DEREncodedParams)) {
1909
0
          return NS_ERROR_DOM_OPERATION_ERR;
1910
0
        }
1911
0
1912
0
        // Construct the OID tag.
1913
0
        SECItem oid = { siBuffer, nullptr, 0 };
1914
0
        oid.len = pubKey->u.ec.DEREncodedParams.data[1];
1915
0
        oid.data = pubKey->u.ec.DEREncodedParams.data + 2;
1916
0
1917
0
        // Find a matching and supported named curve.
1918
0
        if (!MapOIDTagToNamedCurve(SECOID_FindOIDTag(&oid), mNamedCurve)) {
1919
0
          return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1920
0
        }
1921
0
      }
1922
0
1923
0
      if (NS_FAILED(mKey->SetPublicKey(pubKey.get()))) {
1924
0
        return NS_ERROR_DOM_OPERATION_ERR;
1925
0
      }
1926
0
1927
0
      mKey->SetType(CryptoKey::PUBLIC);
1928
0
    } else {
1929
0
      return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1930
0
    }
1931
0
1932
0
    // Extract 'crv' parameter from JWKs.
1933
0
    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1934
0
      if (!NormalizeToken(mJwk.mCrv.Value(), mNamedCurve)) {
1935
0
        return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1936
0
      }
1937
0
    }
1938
0
1939
0
    return NS_OK;
1940
0
  }
1941
1942
  virtual nsresult AfterCrypto() override
1943
0
  {
1944
0
    uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0;
1945
0
    if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
1946
0
      privateAllowedUsages = CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY;
1947
0
      publicAllowedUsages = CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY;
1948
0
    } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
1949
0
      privateAllowedUsages = CryptoKey::SIGN;
1950
0
      publicAllowedUsages = CryptoKey::VERIFY;
1951
0
    }
1952
0
1953
0
    // Check permissions for the requested operation
1954
0
    if ((mKey->GetKeyType() == CryptoKey::PRIVATE &&
1955
0
         mKey->HasUsageOtherThan(privateAllowedUsages)) ||
1956
0
        (mKey->GetKeyType() == CryptoKey::PUBLIC &&
1957
0
         mKey->HasUsageOtherThan(publicAllowedUsages))) {
1958
0
       return NS_ERROR_DOM_DATA_ERR;
1959
0
     }
1960
0
1961
0
    mKey->Algorithm().MakeEc(mAlgName, mNamedCurve);
1962
0
1963
0
    if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) {
1964
0
      return NS_ERROR_DOM_DATA_ERR;
1965
0
    }
1966
0
1967
0
    return NS_OK;
1968
0
  }
1969
};
1970
1971
class ImportDhKeyTask : public ImportKeyTask
1972
{
1973
public:
1974
  ImportDhKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1975
                  const nsAString& aFormat, const ObjectOrString& aAlgorithm,
1976
                  bool aExtractable, const Sequence<nsString>& aKeyUsages)
1977
0
  {
1978
0
    Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1979
0
  }
1980
1981
  ImportDhKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1982
                  const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
1983
                  const ObjectOrString& aAlgorithm, bool aExtractable,
1984
                  const Sequence<nsString>& aKeyUsages)
1985
0
  {
1986
0
    Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1987
0
    if (NS_SUCCEEDED(mEarlyRv)) {
1988
0
      SetKeyData(aCx, aKeyData);
1989
0
      NS_ENSURE_SUCCESS_VOID(mEarlyRv);
1990
0
    }
1991
0
  }
1992
1993
  void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1994
            const ObjectOrString& aAlgorithm, bool aExtractable,
1995
            const Sequence<nsString>& aKeyUsages)
1996
0
  {
1997
0
    ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1998
0
    if (NS_FAILED(mEarlyRv)) {
1999
0
      return;
2000
0
    }
2001
0
2002
0
    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
2003
0
      RootedDictionary<DhImportKeyParams> params(aCx);
2004
0
      mEarlyRv = Coerce(aCx, params, aAlgorithm);
2005
0
      if (NS_FAILED(mEarlyRv)) {
2006
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2007
0
        return;
2008
0
      }
2009
0
2010
0
      CryptoBuffer prime;
2011
0
      ATTEMPT_BUFFER_INIT(mPrime, params.mPrime);
2012
0
2013
0
      CryptoBuffer generator;
2014
0
      ATTEMPT_BUFFER_INIT(mGenerator, params.mGenerator);
2015
0
    }
2016
0
  }
2017
2018
private:
2019
  CryptoBuffer mPrime;
2020
  CryptoBuffer mGenerator;
2021
2022
  virtual nsresult DoCrypto() override
2023
0
  {
2024
0
    // Import the key data itself
2025
0
    UniqueSECKEYPublicKey pubKey;
2026
0
2027
0
    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) ||
2028
0
        mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
2029
0
      // Public key import
2030
0
      if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
2031
0
        pubKey = CryptoKey::PublicDhKeyFromRaw(mKeyData, mPrime, mGenerator);
2032
0
      } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
2033
0
        pubKey = CryptoKey::PublicKeyFromSpki(mKeyData);
2034
0
      } else {
2035
0
        MOZ_ASSERT(false);
2036
0
      }
2037
0
2038
0
      if (!pubKey) {
2039
0
        return NS_ERROR_DOM_DATA_ERR;
2040
0
      }
2041
0
2042
0
      if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
2043
0
        ATTEMPT_BUFFER_ASSIGN(mPrime, &pubKey->u.dh.prime);
2044
0
        ATTEMPT_BUFFER_ASSIGN(mGenerator, &pubKey->u.dh.base);
2045
0
      }
2046
0
2047
0
      if (NS_FAILED(mKey->SetPublicKey(pubKey.get()))) {
2048
0
        return NS_ERROR_DOM_OPERATION_ERR;
2049
0
      }
2050
0
2051
0
      mKey->SetType(CryptoKey::PUBLIC);
2052
0
    } else {
2053
0
      return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2054
0
    }
2055
0
2056
0
    return NS_OK;
2057
0
  }
2058
2059
  virtual nsresult AfterCrypto() override
2060
0
  {
2061
0
    // Check permissions for the requested operation
2062
0
    if (mKey->HasUsageOtherThan(CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY)) {
2063
0
      return NS_ERROR_DOM_DATA_ERR;
2064
0
    }
2065
0
2066
0
    if (!mKey->Algorithm().MakeDh(mAlgName, mPrime, mGenerator)) {
2067
0
      return NS_ERROR_DOM_OPERATION_ERR;
2068
0
    }
2069
0
    return NS_OK;
2070
0
  }
2071
};
2072
2073
class ExportKeyTask : public WebCryptoTask
2074
{
2075
public:
2076
  ExportKeyTask(const nsAString& aFormat, CryptoKey& aKey)
2077
    : mFormat(aFormat)
2078
    , mSymKey(aKey.GetSymKey())
2079
    , mPrivateKey(aKey.GetPrivateKey())
2080
    , mPublicKey(aKey.GetPublicKey())
2081
    , mKeyType(aKey.GetKeyType())
2082
    , mExtractable(aKey.Extractable())
2083
    , mAlg(aKey.Algorithm().JwkAlg())
2084
0
  {
2085
0
    aKey.GetUsages(mKeyUsages);
2086
0
  }
2087
2088
2089
protected:
2090
  nsString mFormat;
2091
  CryptoBuffer mSymKey;
2092
  UniqueSECKEYPrivateKey mPrivateKey;
2093
  UniqueSECKEYPublicKey mPublicKey;
2094
  CryptoKey::KeyType mKeyType;
2095
  bool mExtractable;
2096
  nsString mAlg;
2097
  nsTArray<nsString> mKeyUsages;
2098
  CryptoBuffer mResult;
2099
  JsonWebKey mJwk;
2100
2101
private:
2102
  virtual nsresult DoCrypto() override
2103
0
  {
2104
0
    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
2105
0
      if (mPublicKey && mPublicKey->keyType == dhKey) {
2106
0
        nsresult rv = CryptoKey::PublicDhKeyToRaw(mPublicKey.get(), mResult);
2107
0
        if (NS_FAILED(rv)) {
2108
0
          return NS_ERROR_DOM_OPERATION_ERR;
2109
0
        }
2110
0
        return NS_OK;
2111
0
      }
2112
0
2113
0
      if (mPublicKey && mPublicKey->keyType == ecKey) {
2114
0
        nsresult rv = CryptoKey::PublicECKeyToRaw(mPublicKey.get(), mResult);
2115
0
        if (NS_FAILED(rv)) {
2116
0
          return NS_ERROR_DOM_OPERATION_ERR;
2117
0
        }
2118
0
        return NS_OK;
2119
0
      }
2120
0
2121
0
      mResult = mSymKey;
2122
0
      if (mResult.Length() == 0) {
2123
0
        return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2124
0
      }
2125
0
2126
0
      return NS_OK;
2127
0
    } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8)) {
2128
0
      if (!mPrivateKey) {
2129
0
        return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2130
0
      }
2131
0
2132
0
      switch (mPrivateKey->keyType) {
2133
0
        case rsaKey: {
2134
0
          nsresult rv = CryptoKey::PrivateKeyToPkcs8(mPrivateKey.get(), mResult);
2135
0
          if (NS_FAILED(rv)) {
2136
0
            return NS_ERROR_DOM_OPERATION_ERR;
2137
0
          }
2138
0
          return NS_OK;
2139
0
        }
2140
0
        default:
2141
0
          return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2142
0
      }
2143
0
    } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
2144
0
      if (!mPublicKey) {
2145
0
        return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2146
0
      }
2147
0
2148
0
      return CryptoKey::PublicKeyToSpki(mPublicKey.get(), mResult);
2149
0
    } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
2150
0
      if (mKeyType == CryptoKey::SECRET) {
2151
0
        nsString k;
2152
0
        nsresult rv = mSymKey.ToJwkBase64(k);
2153
0
        if (NS_FAILED(rv)) {
2154
0
          return NS_ERROR_DOM_OPERATION_ERR;
2155
0
        }
2156
0
        mJwk.mK.Construct(k);
2157
0
        mJwk.mKty = NS_LITERAL_STRING(JWK_TYPE_SYMMETRIC);
2158
0
      } else if (mKeyType == CryptoKey::PUBLIC) {
2159
0
        if (!mPublicKey) {
2160
0
          return NS_ERROR_DOM_UNKNOWN_ERR;
2161
0
        }
2162
0
2163
0
        nsresult rv = CryptoKey::PublicKeyToJwk(mPublicKey.get(), mJwk);
2164
0
        if (NS_FAILED(rv)) {
2165
0
          return NS_ERROR_DOM_OPERATION_ERR;
2166
0
        }
2167
0
      } else if (mKeyType == CryptoKey::PRIVATE) {
2168
0
        if (!mPrivateKey) {
2169
0
          return NS_ERROR_DOM_UNKNOWN_ERR;
2170
0
        }
2171
0
2172
0
        nsresult rv = CryptoKey::PrivateKeyToJwk(mPrivateKey.get(), mJwk);
2173
0
        if (NS_FAILED(rv)) {
2174
0
          return NS_ERROR_DOM_OPERATION_ERR;
2175
0
        }
2176
0
      }
2177
0
2178
0
      if (!mAlg.IsEmpty()) {
2179
0
        mJwk.mAlg.Construct(mAlg);
2180
0
      }
2181
0
2182
0
      mJwk.mExt.Construct(mExtractable);
2183
0
2184
0
      mJwk.mKey_ops.Construct();
2185
0
      if (!mJwk.mKey_ops.Value().AppendElements(mKeyUsages, fallible)) {
2186
0
        return NS_ERROR_OUT_OF_MEMORY;
2187
0
      }
2188
0
2189
0
      return NS_OK;
2190
0
    }
2191
0
2192
0
    return NS_ERROR_DOM_SYNTAX_ERR;
2193
0
  }
2194
2195
  // Returns mResult as an ArrayBufferView or JWK, as appropriate
2196
  virtual void Resolve() override
2197
0
  {
2198
0
    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
2199
0
      mResultPromise->MaybeResolve(mJwk);
2200
0
      return;
2201
0
    }
2202
0
2203
0
    TypedArrayCreator<ArrayBuffer> ret(mResult);
2204
0
    mResultPromise->MaybeResolve(ret);
2205
0
  }
2206
};
2207
2208
class GenerateSymmetricKeyTask : public WebCryptoTask
2209
{
2210
public:
2211
  GenerateSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
2212
      const ObjectOrString& aAlgorithm, bool aExtractable,
2213
      const Sequence<nsString>& aKeyUsages)
2214
0
  {
2215
0
    // Create an empty key and set easy attributes
2216
0
    mKey = new CryptoKey(aGlobal);
2217
0
    mKey->SetExtractable(aExtractable);
2218
0
    mKey->SetType(CryptoKey::SECRET);
2219
0
2220
0
    // Extract algorithm name
2221
0
    nsString algName;
2222
0
    mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
2223
0
    if (NS_FAILED(mEarlyRv)) {
2224
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2225
0
      return;
2226
0
    }
2227
0
2228
0
    // Construct an appropriate KeyAlorithm
2229
0
    uint32_t allowedUsages = 0;
2230
0
    if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
2231
0
        algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
2232
0
        algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
2233
0
        algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
2234
0
      mEarlyRv = GetKeyLengthForAlgorithm(aCx, aAlgorithm, mLength);
2235
0
      if (NS_FAILED(mEarlyRv)) {
2236
0
        return;
2237
0
      }
2238
0
      mKey->Algorithm().MakeAes(algName, mLength);
2239
0
2240
0
      allowedUsages = CryptoKey::ENCRYPT | CryptoKey::DECRYPT |
2241
0
                      CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY;
2242
0
    } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
2243
0
      RootedDictionary<HmacKeyGenParams> params(aCx);
2244
0
      mEarlyRv = Coerce(aCx, params, aAlgorithm);
2245
0
      if (NS_FAILED(mEarlyRv)) {
2246
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2247
0
        return;
2248
0
      }
2249
0
2250
0
      nsString hashName;
2251
0
      mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName);
2252
0
      if (NS_FAILED(mEarlyRv)) {
2253
0
        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2254
0
        return;
2255
0
      }
2256
0
2257
0
      if (params.mLength.WasPassed()) {
2258
0
        mLength = params.mLength.Value();
2259
0
      } else {
2260
0
        mLength = MapHashAlgorithmNameToBlockSize(hashName);
2261
0
      }
2262
0
2263
0
      if (mLength == 0) {
2264
0
        mEarlyRv = NS_ERROR_DOM_DATA_ERR;
2265
0
        return;
2266
0
      }
2267
0
2268
0
      mKey->Algorithm().MakeHmac(mLength, hashName);
2269
0
      allowedUsages = CryptoKey::SIGN | CryptoKey::VERIFY;
2270
0
    } else {
2271
0
      mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2272
0
      return;
2273
0
    }
2274
0
2275
0
    // Add key usages
2276
0
    mKey->ClearUsages();
2277
0
    for (uint32_t i = 0; i < aKeyUsages.Length(); ++i) {
2278
0
      mEarlyRv = mKey->AddUsageIntersecting(aKeyUsages[i], allowedUsages);
2279
0
      if (NS_FAILED(mEarlyRv)) {
2280
0
        return;
2281
0
      }
2282
0
    }
2283
0
2284
0
    mLength = mLength >> 3; // bits to bytes
2285
0
    mMechanism = mKey->Algorithm().Mechanism();
2286
0
    // SetSymKey done in Resolve, after we've done the keygen
2287
0
  }
2288
2289
private:
2290
  RefPtr<CryptoKey> mKey;
2291
  size_t mLength;
2292
  CK_MECHANISM_TYPE mMechanism;
2293
  CryptoBuffer mKeyData;
2294
2295
  virtual nsresult DoCrypto() override
2296
0
  {
2297
0
    UniquePK11SlotInfo slot(PK11_GetInternalSlot());
2298
0
    MOZ_ASSERT(slot.get());
2299
0
2300
0
    UniquePK11SymKey symKey(PK11_KeyGen(slot.get(), mMechanism, nullptr,
2301
0
                                        mLength, nullptr));
2302
0
    if (!symKey) {
2303
0
      return NS_ERROR_DOM_UNKNOWN_ERR;
2304
0
    }
2305
0
2306
0
    nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get()));
2307
0
    if (NS_FAILED(rv)) {
2308
0
      return NS_ERROR_DOM_UNKNOWN_ERR;
2309
0
    }
2310
0
2311
0
    // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2312
0
    // just refers to a buffer managed by symKey.  The assignment copies the
2313
0
    // data, so mKeyData manages one copy, while symKey manages another.
2314
0
    ATTEMPT_BUFFER_ASSIGN(mKeyData, PK11_GetKeyData(symKey.get()));
2315
0
    return NS_OK;
2316
0
  }
2317
2318
  virtual void Resolve() override
2319
0
  {
2320
0
    if (NS_SUCCEEDED(mKey->SetSymKey(mKeyData))) {
2321
0
      mResultPromise->MaybeResolve(mKey);
2322
0
    } else {
2323
0
      mResultPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
2324
0
    }
2325
0
  }
2326
2327
  virtual void Cleanup() override
2328
0
  {
2329
0
    mKey = nullptr;
2330
0
  }
2331
};
2332
2333
GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask(
2334
    nsIGlobalObject* aGlobal, JSContext* aCx, const ObjectOrString& aAlgorithm,
2335
    bool aExtractable, const Sequence<nsString>& aKeyUsages)
2336
  : mKeyPair(new CryptoKeyPair())
2337
  , mMechanism(CKM_INVALID_MECHANISM)
2338
  , mRsaParams()
2339
  , mDhParams()
2340
0
{
2341
0
  mArena = UniquePLArenaPool(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
2342
0
  if (!mArena) {
2343
0
    mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
2344
0
    return;
2345
0
  }
2346
0
2347
0
  // Create an empty key pair and set easy attributes
2348
0
  mKeyPair->mPrivateKey = new CryptoKey(aGlobal);
2349
0
  mKeyPair->mPublicKey = new CryptoKey(aGlobal);
2350
0
2351
0
  // Extract algorithm name
2352
0
  mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, mAlgName);
2353
0
  if (NS_FAILED(mEarlyRv)) {
2354
0
    mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2355
0
    return;
2356
0
  }
2357
0
2358
0
  // Construct an appropriate KeyAlorithm
2359
0
  uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0;
2360
0
  if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
2361
0
      mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
2362
0
      mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
2363
0
    RootedDictionary<RsaHashedKeyGenParams> params(aCx);
2364
0
    mEarlyRv = Coerce(aCx, params, aAlgorithm);
2365
0
    if (NS_FAILED(mEarlyRv)) {
2366
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2367
0
      return;
2368
0
    }
2369
0
2370
0
    // Pull relevant info
2371
0
    uint32_t modulusLength = params.mModulusLength;
2372
0
    CryptoBuffer publicExponent;
2373
0
    ATTEMPT_BUFFER_INIT(publicExponent, params.mPublicExponent);
2374
0
    nsString hashName;
2375
0
    mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName);
2376
0
    if (NS_FAILED(mEarlyRv)) {
2377
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2378
0
      return;
2379
0
    }
2380
0
2381
0
    // Create algorithm
2382
0
    if (!mKeyPair->mPublicKey.get()->Algorithm().MakeRsa(mAlgName,
2383
0
                                                         modulusLength,
2384
0
                                                         publicExponent,
2385
0
                                                         hashName)) {
2386
0
      mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
2387
0
      return;
2388
0
    }
2389
0
    if (!mKeyPair->mPrivateKey.get()->Algorithm().MakeRsa(mAlgName,
2390
0
                                                          modulusLength,
2391
0
                                                          publicExponent,
2392
0
                                                          hashName)) {
2393
0
      mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
2394
0
      return;
2395
0
    }
2396
0
    mMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
2397
0
2398
0
    // Set up params struct
2399
0
    mRsaParams.keySizeInBits = modulusLength;
2400
0
    bool converted = publicExponent.GetBigIntValue(mRsaParams.pe);
2401
0
    if (!converted) {
2402
0
      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
2403
0
      return;
2404
0
    }
2405
0
  } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
2406
0
             mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
2407
0
    RootedDictionary<EcKeyGenParams> params(aCx);
2408
0
    mEarlyRv = Coerce(aCx, params, aAlgorithm);
2409
0
    if (NS_FAILED(mEarlyRv)) {
2410
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2411
0
      return;
2412
0
    }
2413
0
2414
0
    if (!NormalizeToken(params.mNamedCurve, mNamedCurve)) {
2415
0
      mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2416
0
      return;
2417
0
    }
2418
0
2419
0
    // Create algorithm.
2420
0
    mKeyPair->mPublicKey.get()->Algorithm().MakeEc(mAlgName, mNamedCurve);
2421
0
    mKeyPair->mPrivateKey.get()->Algorithm().MakeEc(mAlgName, mNamedCurve);
2422
0
    mMechanism = CKM_EC_KEY_PAIR_GEN;
2423
0
  } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
2424
0
    RootedDictionary<DhKeyGenParams> params(aCx);
2425
0
    mEarlyRv = Coerce(aCx, params, aAlgorithm);
2426
0
    if (NS_FAILED(mEarlyRv)) {
2427
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2428
0
      return;
2429
0
    }
2430
0
2431
0
    CryptoBuffer prime;
2432
0
    ATTEMPT_BUFFER_INIT(prime, params.mPrime);
2433
0
2434
0
    CryptoBuffer generator;
2435
0
    ATTEMPT_BUFFER_INIT(generator, params.mGenerator);
2436
0
2437
0
    // Set up params.
2438
0
    if (!prime.ToSECItem(mArena.get(), &mDhParams.prime) ||
2439
0
        !generator.ToSECItem(mArena.get(), &mDhParams.base)) {
2440
0
      mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
2441
0
      return;
2442
0
    }
2443
0
2444
0
    // Create algorithm.
2445
0
    if (!mKeyPair->mPublicKey.get()->Algorithm().MakeDh(mAlgName,
2446
0
                                                        prime,
2447
0
                                                        generator)) {
2448
0
      mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
2449
0
      return;
2450
0
    }
2451
0
    if (!mKeyPair->mPrivateKey.get()->Algorithm().MakeDh(mAlgName,
2452
0
                                                         prime,
2453
0
                                                         generator)) {
2454
0
      mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
2455
0
      return;
2456
0
    }
2457
0
    mMechanism = CKM_DH_PKCS_KEY_PAIR_GEN;
2458
0
  } else {
2459
0
    mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2460
0
    return;
2461
0
  }
2462
0
2463
0
  // Set key usages.
2464
0
  if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
2465
0
      mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS) ||
2466
0
      mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
2467
0
    privateAllowedUsages = CryptoKey::SIGN;
2468
0
    publicAllowedUsages = CryptoKey::VERIFY;
2469
0
  } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
2470
0
    privateAllowedUsages = CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY;
2471
0
    publicAllowedUsages = CryptoKey::ENCRYPT | CryptoKey::WRAPKEY;
2472
0
  } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
2473
0
             mAlgName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
2474
0
    privateAllowedUsages = CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS;
2475
0
    publicAllowedUsages = 0;
2476
0
  } else {
2477
0
    MOZ_ASSERT(false); // This shouldn't happen.
2478
0
  }
2479
0
2480
0
  mKeyPair->mPrivateKey.get()->SetExtractable(aExtractable);
2481
0
  mKeyPair->mPrivateKey.get()->SetType(CryptoKey::PRIVATE);
2482
0
2483
0
  mKeyPair->mPublicKey.get()->SetExtractable(true);
2484
0
  mKeyPair->mPublicKey.get()->SetType(CryptoKey::PUBLIC);
2485
0
2486
0
  mKeyPair->mPrivateKey.get()->ClearUsages();
2487
0
  mKeyPair->mPublicKey.get()->ClearUsages();
2488
0
  for (uint32_t i=0; i < aKeyUsages.Length(); ++i) {
2489
0
    mEarlyRv = mKeyPair->mPrivateKey.get()->AddUsageIntersecting(aKeyUsages[i],
2490
0
                                                                 privateAllowedUsages);
2491
0
    if (NS_FAILED(mEarlyRv)) {
2492
0
      return;
2493
0
    }
2494
0
2495
0
    mEarlyRv = mKeyPair->mPublicKey.get()->AddUsageIntersecting(aKeyUsages[i],
2496
0
                                                                publicAllowedUsages);
2497
0
    if (NS_FAILED(mEarlyRv)) {
2498
0
      return;
2499
0
    }
2500
0
  }
2501
0
2502
0
  // If no usages ended up being allowed, DataError
2503
0
  if (!mKeyPair->mPublicKey.get()->HasAnyUsage() &&
2504
0
      !mKeyPair->mPrivateKey.get()->HasAnyUsage()) {
2505
0
    mEarlyRv = NS_ERROR_DOM_DATA_ERR;
2506
0
    return;
2507
0
  }
2508
0
}
2509
2510
nsresult
2511
GenerateAsymmetricKeyTask::DoCrypto()
2512
0
{
2513
0
  MOZ_ASSERT(mKeyPair);
2514
0
2515
0
  UniquePK11SlotInfo slot(PK11_GetInternalSlot());
2516
0
  MOZ_ASSERT(slot.get());
2517
0
2518
0
  void* param;
2519
0
  switch (mMechanism) {
2520
0
    case CKM_RSA_PKCS_KEY_PAIR_GEN:
2521
0
      param = &mRsaParams;
2522
0
      break;
2523
0
    case CKM_DH_PKCS_KEY_PAIR_GEN:
2524
0
      param = &mDhParams;
2525
0
      break;
2526
0
    case CKM_EC_KEY_PAIR_GEN: {
2527
0
      param = CreateECParamsForCurve(mNamedCurve, mArena.get());
2528
0
      if (!param) {
2529
0
        return NS_ERROR_DOM_UNKNOWN_ERR;
2530
0
      }
2531
0
      break;
2532
0
    }
2533
0
    default:
2534
0
      return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2535
0
  }
2536
0
2537
0
  SECKEYPublicKey* pubKey = nullptr;
2538
0
  mPrivateKey = UniqueSECKEYPrivateKey(
2539
0
    PK11_GenerateKeyPair(slot.get(), mMechanism, param, &pubKey, PR_FALSE,
2540
0
                         PR_FALSE, nullptr));
2541
0
  mPublicKey = UniqueSECKEYPublicKey(pubKey);
2542
0
  pubKey = nullptr;
2543
0
  if (!mPrivateKey.get() || !mPublicKey.get()) {
2544
0
    return NS_ERROR_DOM_UNKNOWN_ERR;
2545
0
  }
2546
0
2547
0
  nsresult rv = mKeyPair->mPrivateKey.get()->SetPrivateKey(mPrivateKey.get());
2548
0
  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
2549
0
  rv = mKeyPair->mPublicKey.get()->SetPublicKey(mPublicKey.get());
2550
0
  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
2551
0
2552
0
  // PK11_GenerateKeyPair() does not set a CKA_EC_POINT attribute on the
2553
0
  // private key, we need this later when exporting to PKCS8 and JWK though.
2554
0
  if (mMechanism == CKM_EC_KEY_PAIR_GEN) {
2555
0
    rv = mKeyPair->mPrivateKey->AddPublicKeyData(mPublicKey.get());
2556
0
    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
2557
0
  }
2558
0
2559
0
  return NS_OK;
2560
0
}
2561
2562
void
2563
GenerateAsymmetricKeyTask::Resolve()
2564
0
{
2565
0
  mResultPromise->MaybeResolve(*mKeyPair);
2566
0
}
2567
2568
void
2569
GenerateAsymmetricKeyTask::Cleanup()
2570
0
{
2571
0
  mKeyPair = nullptr;
2572
0
}
2573
2574
class DeriveHkdfBitsTask : public ReturnArrayBufferViewTask
2575
{
2576
public:
2577
  DeriveHkdfBitsTask(JSContext* aCx,
2578
      const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength)
2579
    : mSymKey(aKey.GetSymKey())
2580
    , mMechanism(CKM_INVALID_MECHANISM)
2581
0
  {
2582
0
    Init(aCx, aAlgorithm, aKey, aLength);
2583
0
  }
2584
2585
  DeriveHkdfBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
2586
                      CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm)
2587
    : mLengthInBits(0)
2588
    , mLengthInBytes(0)
2589
    , mSymKey(aKey.GetSymKey())
2590
    , mMechanism(CKM_INVALID_MECHANISM)
2591
0
  {
2592
0
    size_t length;
2593
0
    mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, length);
2594
0
2595
0
    if (NS_SUCCEEDED(mEarlyRv)) {
2596
0
      Init(aCx, aAlgorithm, aKey, length);
2597
0
    }
2598
0
  }
2599
2600
  void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
2601
            uint32_t aLength)
2602
0
  {
2603
0
    Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_HKDF);
2604
0
    CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_HKDF);
2605
0
2606
0
    // Check that we have a key.
2607
0
    if (mSymKey.Length() == 0) {
2608
0
      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
2609
0
      return;
2610
0
    }
2611
0
2612
0
    RootedDictionary<HkdfParams> params(aCx);
2613
0
    mEarlyRv = Coerce(aCx, params, aAlgorithm);
2614
0
    if (NS_FAILED(mEarlyRv)) {
2615
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2616
0
      return;
2617
0
    }
2618
0
2619
0
    // length must be greater than zero.
2620
0
    if (aLength == 0) {
2621
0
      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
2622
0
      return;
2623
0
    }
2624
0
2625
0
    // Extract the hash algorithm.
2626
0
    nsString hashName;
2627
0
    mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName);
2628
0
    if (NS_FAILED(mEarlyRv)) {
2629
0
      return;
2630
0
    }
2631
0
2632
0
    // Check the given hash algorithm.
2633
0
    switch (MapAlgorithmNameToMechanism(hashName)) {
2634
0
      case CKM_SHA_1: mMechanism = CKM_NSS_HKDF_SHA1; break;
2635
0
      case CKM_SHA256: mMechanism = CKM_NSS_HKDF_SHA256; break;
2636
0
      case CKM_SHA384: mMechanism = CKM_NSS_HKDF_SHA384; break;
2637
0
      case CKM_SHA512: mMechanism = CKM_NSS_HKDF_SHA512; break;
2638
0
      default:
2639
0
        mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2640
0
        return;
2641
0
    }
2642
0
2643
0
    ATTEMPT_BUFFER_INIT(mSalt, params.mSalt)
2644
0
    ATTEMPT_BUFFER_INIT(mInfo, params.mInfo)
2645
0
    mLengthInBytes = ceil((double)aLength / 8);
2646
0
    mLengthInBits = aLength;
2647
0
  }
2648
2649
private:
2650
  size_t mLengthInBits;
2651
  size_t mLengthInBytes;
2652
  CryptoBuffer mSalt;
2653
  CryptoBuffer mInfo;
2654
  CryptoBuffer mSymKey;
2655
  CK_MECHANISM_TYPE mMechanism;
2656
2657
  virtual nsresult DoCrypto() override
2658
0
  {
2659
0
    UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
2660
0
    if (!arena) {
2661
0
      return NS_ERROR_DOM_OPERATION_ERR;
2662
0
    }
2663
0
2664
0
    // Import the key
2665
0
    SECItem keyItem = { siBuffer, nullptr, 0 };
2666
0
    ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
2667
0
2668
0
    UniquePK11SlotInfo slot(PK11_GetInternalSlot());
2669
0
    if (!slot.get()) {
2670
0
      return NS_ERROR_DOM_OPERATION_ERR;
2671
0
    }
2672
0
2673
0
    UniquePK11SymKey baseKey(PK11_ImportSymKey(slot.get(), mMechanism,
2674
0
                                               PK11_OriginUnwrap, CKA_WRAP,
2675
0
                                               &keyItem, nullptr));
2676
0
    if (!baseKey) {
2677
0
      return NS_ERROR_DOM_INVALID_ACCESS_ERR;
2678
0
    }
2679
0
2680
0
    SECItem salt = { siBuffer, nullptr, 0 };
2681
0
    SECItem info = { siBuffer, nullptr, 0 };
2682
0
    ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &salt, mSalt);
2683
0
    ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &info, mInfo);
2684
0
2685
0
    CK_NSS_HKDFParams hkdfParams = { true, salt.data, salt.len,
2686
0
                                     true, info.data, info.len };
2687
0
    SECItem params = { siBuffer, (unsigned char*)&hkdfParams,
2688
0
                       sizeof(hkdfParams) };
2689
0
2690
0
    // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
2691
0
    // derived symmetric key and don't matter because we ignore them anyway.
2692
0
    UniquePK11SymKey symKey(PK11_Derive(baseKey.get(), mMechanism, &params,
2693
0
                                        CKM_SHA512_HMAC, CKA_SIGN,
2694
0
                                        mLengthInBytes));
2695
0
2696
0
    if (!symKey.get()) {
2697
0
      return NS_ERROR_DOM_OPERATION_ERR;
2698
0
    }
2699
0
2700
0
    nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get()));
2701
0
    if (NS_FAILED(rv)) {
2702
0
      return NS_ERROR_DOM_OPERATION_ERR;
2703
0
    }
2704
0
2705
0
    // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2706
0
    // just refers to a buffer managed by symKey. The assignment copies the
2707
0
    // data, so mResult manages one copy, while symKey manages another.
2708
0
    ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey.get()));
2709
0
2710
0
    if (mLengthInBytes > mResult.Length()) {
2711
0
      return NS_ERROR_DOM_DATA_ERR;
2712
0
    }
2713
0
2714
0
    if (!mResult.SetLength(mLengthInBytes, fallible)) {
2715
0
      return NS_ERROR_DOM_UNKNOWN_ERR;
2716
0
    }
2717
0
2718
0
    // If the number of bits to derive is not a multiple of 8 we need to
2719
0
    // zero out the remaining bits that were derived but not requested.
2720
0
    if (mLengthInBits % 8) {
2721
0
      mResult[mResult.Length() - 1] &= 0xff << (mLengthInBits % 8);
2722
0
    }
2723
0
2724
0
    return NS_OK;
2725
0
  }
2726
};
2727
2728
class DerivePbkdfBitsTask : public ReturnArrayBufferViewTask
2729
{
2730
public:
2731
  DerivePbkdfBitsTask(JSContext* aCx,
2732
      const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength)
2733
    : mSymKey(aKey.GetSymKey())
2734
    , mHashOidTag(SEC_OID_UNKNOWN)
2735
0
  {
2736
0
    Init(aCx, aAlgorithm, aKey, aLength);
2737
0
  }
2738
2739
  DerivePbkdfBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
2740
                      CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm)
2741
    : mLength(0)
2742
    , mIterations(0)
2743
    , mSymKey(aKey.GetSymKey())
2744
    , mHashOidTag(SEC_OID_UNKNOWN)
2745
0
  {
2746
0
    size_t length;
2747
0
    mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, length);
2748
0
2749
0
    if (NS_SUCCEEDED(mEarlyRv)) {
2750
0
      Init(aCx, aAlgorithm, aKey, length);
2751
0
    }
2752
0
  }
2753
2754
  void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
2755
            uint32_t aLength)
2756
0
  {
2757
0
    Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_PBKDF2);
2758
0
    CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_PBKDF2);
2759
0
2760
0
    // Check that we got a symmetric key
2761
0
    if (mSymKey.Length() == 0) {
2762
0
      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
2763
0
      return;
2764
0
    }
2765
0
2766
0
    RootedDictionary<Pbkdf2Params> params(aCx);
2767
0
    mEarlyRv = Coerce(aCx, params, aAlgorithm);
2768
0
    if (NS_FAILED(mEarlyRv)) {
2769
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2770
0
      return;
2771
0
    }
2772
0
2773
0
    // length must be a multiple of 8 bigger than zero.
2774
0
    if (aLength == 0 || aLength % 8) {
2775
0
      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
2776
0
      return;
2777
0
    }
2778
0
2779
0
    // Extract the hash algorithm.
2780
0
    nsString hashName;
2781
0
    mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName);
2782
0
    if (NS_FAILED(mEarlyRv)) {
2783
0
      return;
2784
0
    }
2785
0
2786
0
    // Check the given hash algorithm.
2787
0
    switch (MapAlgorithmNameToMechanism(hashName)) {
2788
0
      case CKM_SHA_1: mHashOidTag = SEC_OID_HMAC_SHA1; break;
2789
0
      case CKM_SHA256: mHashOidTag = SEC_OID_HMAC_SHA256; break;
2790
0
      case CKM_SHA384: mHashOidTag = SEC_OID_HMAC_SHA384; break;
2791
0
      case CKM_SHA512: mHashOidTag = SEC_OID_HMAC_SHA512; break;
2792
0
      default:
2793
0
        mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
2794
0
        return;
2795
0
    }
2796
0
2797
0
    ATTEMPT_BUFFER_INIT(mSalt, params.mSalt)
2798
0
    mLength = aLength >> 3; // bits to bytes
2799
0
    mIterations = params.mIterations;
2800
0
  }
2801
2802
private:
2803
  size_t mLength;
2804
  size_t mIterations;
2805
  CryptoBuffer mSalt;
2806
  CryptoBuffer mSymKey;
2807
  SECOidTag mHashOidTag;
2808
2809
  virtual nsresult DoCrypto() override
2810
0
  {
2811
0
    UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
2812
0
    if (!arena) {
2813
0
      return NS_ERROR_DOM_OPERATION_ERR;
2814
0
    }
2815
0
2816
0
    SECItem salt = { siBuffer, nullptr, 0 };
2817
0
    ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &salt, mSalt);
2818
0
    // PK11_CreatePBEV2AlgorithmID will "helpfully" create PBKDF2 parameters
2819
0
    // with a random salt if given a SECItem* that is either null or has a null
2820
0
    // data pointer. This obviously isn't what we want, so we have to fake it
2821
0
    // out by passing in a SECItem* with a non-null data pointer but with zero
2822
0
    // length.
2823
0
    if (!salt.data) {
2824
0
      MOZ_ASSERT(salt.len == 0);
2825
0
      salt.data =
2826
0
        reinterpret_cast<unsigned char*>(PORT_ArenaAlloc(arena.get(), 1));
2827
0
      if (!salt.data) {
2828
0
        return NS_ERROR_DOM_UNKNOWN_ERR;
2829
0
      }
2830
0
    }
2831
0
2832
0
    // Always pass in cipherAlg=SEC_OID_HMAC_SHA1 (i.e. PBMAC1) as this
2833
0
    // parameter is unused for key generation. It is currently only used
2834
0
    // for PBKDF2 authentication or key (un)wrapping when specifying an
2835
0
    // encryption algorithm (PBES2).
2836
0
    UniqueSECAlgorithmID algID(PK11_CreatePBEV2AlgorithmID(
2837
0
      SEC_OID_PKCS5_PBKDF2, SEC_OID_HMAC_SHA1, mHashOidTag,
2838
0
      mLength, mIterations, &salt));
2839
0
2840
0
    if (!algID) {
2841
0
      return NS_ERROR_DOM_OPERATION_ERR;
2842
0
    }
2843
0
2844
0
    UniquePK11SlotInfo slot(PK11_GetInternalSlot());
2845
0
    if (!slot.get()) {
2846
0
      return NS_ERROR_DOM_OPERATION_ERR;
2847
0
    }
2848
0
2849
0
    SECItem keyItem = { siBuffer, nullptr, 0 };
2850
0
    ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
2851
0
2852
0
    UniquePK11SymKey symKey(PK11_PBEKeyGen(slot.get(), algID.get(), &keyItem,
2853
0
                                           false, nullptr));
2854
0
    if (!symKey.get()) {
2855
0
      return NS_ERROR_DOM_OPERATION_ERR;
2856
0
    }
2857
0
2858
0
    nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get()));
2859
0
    if (NS_FAILED(rv)) {
2860
0
      return NS_ERROR_DOM_OPERATION_ERR;
2861
0
    }
2862
0
2863
0
    // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2864
0
    // just refers to a buffer managed by symKey. The assignment copies the
2865
0
    // data, so mResult manages one copy, while symKey manages another.
2866
0
    ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey.get()));
2867
0
    return NS_OK;
2868
0
  }
2869
};
2870
2871
template<class DeriveBitsTask>
2872
class DeriveKeyTask : public DeriveBitsTask
2873
{
2874
public:
2875
  DeriveKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
2876
                const ObjectOrString& aAlgorithm, CryptoKey& aBaseKey,
2877
                const ObjectOrString& aDerivedKeyType, bool aExtractable,
2878
                const Sequence<nsString>& aKeyUsages)
2879
    : DeriveBitsTask(aCx, aAlgorithm, aBaseKey, aDerivedKeyType)
2880
0
  {
2881
0
    if (NS_FAILED(this->mEarlyRv)) {
2882
0
      return;
2883
0
    }
2884
0
2885
0
    NS_NAMED_LITERAL_STRING(format, WEBCRYPTO_KEY_FORMAT_RAW);
2886
0
    mTask = new ImportSymmetricKeyTask(aGlobal, aCx, format, aDerivedKeyType,
2887
0
                                       aExtractable, aKeyUsages);
2888
0
  }
Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveHkdfBitsTask>::DeriveKeyTask(nsIGlobalObject*, JSContext*, mozilla::dom::ObjectOrString const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, bool, mozilla::dom::Sequence<nsTString<char16_t> > const&)
Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DerivePbkdfBitsTask>::DeriveKeyTask(nsIGlobalObject*, JSContext*, mozilla::dom::ObjectOrString const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, bool, mozilla::dom::Sequence<nsTString<char16_t> > const&)
Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveEcdhBitsTask>::DeriveKeyTask(nsIGlobalObject*, JSContext*, mozilla::dom::ObjectOrString const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, bool, mozilla::dom::Sequence<nsTString<char16_t> > const&)
2889
2890
protected:
2891
  RefPtr<ImportSymmetricKeyTask> mTask;
2892
2893
private:
2894
0
  virtual void Resolve() override {
2895
0
    mTask->SetRawKeyData(this->mResult);
2896
0
    mTask->DispatchWithPromise(this->mResultPromise);
2897
0
  }
Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveHkdfBitsTask>::Resolve()
Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DerivePbkdfBitsTask>::Resolve()
Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveEcdhBitsTask>::Resolve()
2898
2899
  virtual void Cleanup() override
2900
0
  {
2901
0
    mTask = nullptr;
2902
0
  }
Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveHkdfBitsTask>::Cleanup()
Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DerivePbkdfBitsTask>::Cleanup()
Unexecuted instantiation: mozilla::dom::DeriveKeyTask<mozilla::dom::DeriveEcdhBitsTask>::Cleanup()
2903
};
2904
2905
class DeriveEcdhBitsTask : public ReturnArrayBufferViewTask
2906
{
2907
public:
2908
  DeriveEcdhBitsTask(JSContext* aCx,
2909
      const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength)
2910
    : mLength(aLength),
2911
      mPrivKey(aKey.GetPrivateKey())
2912
0
  {
2913
0
    Init(aCx, aAlgorithm, aKey);
2914
0
  }
2915
2916
  DeriveEcdhBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
2917
                     CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm)
2918
    : mPrivKey(aKey.GetPrivateKey())
2919
0
  {
2920
0
    mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, mLength);
2921
0
    if (NS_SUCCEEDED(mEarlyRv)) {
2922
0
      Init(aCx, aAlgorithm, aKey);
2923
0
    }
2924
0
  }
2925
2926
  void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey)
2927
0
  {
2928
0
    Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDH);
2929
0
    CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDH);
2930
0
2931
0
    // Check that we have a private key.
2932
0
    if (!mPrivKey) {
2933
0
      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
2934
0
      return;
2935
0
    }
2936
0
2937
0
    // Length must be a multiple of 8 bigger than zero.
2938
0
    if (mLength == 0 || mLength % 8) {
2939
0
      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
2940
0
      return;
2941
0
    }
2942
0
2943
0
    mLength = mLength >> 3; // bits to bytes
2944
0
2945
0
    // Retrieve the peer's public key.
2946
0
    RootedDictionary<EcdhKeyDeriveParams> params(aCx);
2947
0
    mEarlyRv = Coerce(aCx, params, aAlgorithm);
2948
0
    if (NS_FAILED(mEarlyRv)) {
2949
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
2950
0
      return;
2951
0
    }
2952
0
2953
0
    CryptoKey* publicKey = params.mPublic;
2954
0
    mPubKey = publicKey->GetPublicKey();
2955
0
    if (!mPubKey) {
2956
0
      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
2957
0
      return;
2958
0
    }
2959
0
2960
0
    CHECK_KEY_ALGORITHM(publicKey->Algorithm(), WEBCRYPTO_ALG_ECDH);
2961
0
2962
0
    // Both keys must use the same named curve.
2963
0
    nsString curve1 = aKey.Algorithm().mEc.mNamedCurve;
2964
0
    nsString curve2 = publicKey->Algorithm().mEc.mNamedCurve;
2965
0
2966
0
    if (!curve1.Equals(curve2)) {
2967
0
      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
2968
0
      return;
2969
0
    }
2970
0
  }
2971
2972
private:
2973
  size_t mLength;
2974
  UniqueSECKEYPrivateKey mPrivKey;
2975
  UniqueSECKEYPublicKey mPubKey;
2976
2977
  virtual nsresult DoCrypto() override
2978
0
  {
2979
0
    // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
2980
0
    // derived symmetric key and don't matter because we ignore them anyway.
2981
0
    UniquePK11SymKey symKey(PK11_PubDeriveWithKDF(
2982
0
      mPrivKey.get(), mPubKey.get(), PR_FALSE, nullptr, nullptr,
2983
0
      CKM_ECDH1_DERIVE, CKM_SHA512_HMAC, CKA_SIGN, 0, CKD_NULL, nullptr,
2984
0
      nullptr));
2985
0
2986
0
    if (!symKey.get()) {
2987
0
      return NS_ERROR_DOM_OPERATION_ERR;
2988
0
    }
2989
0
2990
0
    nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get()));
2991
0
    if (NS_FAILED(rv)) {
2992
0
      return NS_ERROR_DOM_OPERATION_ERR;
2993
0
    }
2994
0
2995
0
    // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
2996
0
    // just refers to a buffer managed by symKey. The assignment copies the
2997
0
    // data, so mResult manages one copy, while symKey manages another.
2998
0
    ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey.get()));
2999
0
3000
0
    if (mLength > mResult.Length()) {
3001
0
      return NS_ERROR_DOM_DATA_ERR;
3002
0
    }
3003
0
3004
0
    if (!mResult.SetLength(mLength, fallible)) {
3005
0
      return NS_ERROR_DOM_UNKNOWN_ERR;
3006
0
    }
3007
0
3008
0
    return NS_OK;
3009
0
  }
3010
};
3011
3012
class DeriveDhBitsTask : public ReturnArrayBufferViewTask
3013
{
3014
public:
3015
  DeriveDhBitsTask(JSContext* aCx,
3016
      const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength)
3017
    : mLength(aLength),
3018
      mPrivKey(aKey.GetPrivateKey())
3019
0
  {
3020
0
    Init(aCx, aAlgorithm, aKey);
3021
0
  }
3022
3023
  DeriveDhBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
3024
                   CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm)
3025
    : mPrivKey(aKey.GetPrivateKey())
3026
0
  {
3027
0
    mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, mLength);
3028
0
    if (NS_SUCCEEDED(mEarlyRv)) {
3029
0
      Init(aCx, aAlgorithm, aKey);
3030
0
    }
3031
0
  }
3032
3033
  void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey)
3034
0
  {
3035
0
    CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_DH);
3036
0
3037
0
    // Check that we have a private key.
3038
0
    if (!mPrivKey) {
3039
0
      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
3040
0
      return;
3041
0
    }
3042
0
3043
0
    mLength = mLength >> 3; // bits to bytes
3044
0
3045
0
    // Retrieve the peer's public key.
3046
0
    RootedDictionary<DhKeyDeriveParams> params(aCx);
3047
0
    mEarlyRv = Coerce(aCx, params, aAlgorithm);
3048
0
    if (NS_FAILED(mEarlyRv)) {
3049
0
      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
3050
0
      return;
3051
0
    }
3052
0
3053
0
    CryptoKey* publicKey = params.mPublic;
3054
0
    mPubKey = publicKey->GetPublicKey();
3055
0
    if (!mPubKey) {
3056
0
      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
3057
0
      return;
3058
0
    }
3059
0
3060
0
    KeyAlgorithmProxy alg1 = publicKey->Algorithm();
3061
0
    CHECK_KEY_ALGORITHM(alg1, WEBCRYPTO_ALG_DH);
3062
0
3063
0
    // Both keys must use the same prime and generator.
3064
0
    KeyAlgorithmProxy alg2 = aKey.Algorithm();
3065
0
    if (alg1.mDh.mPrime != alg2.mDh.mPrime ||
3066
0
        alg1.mDh.mGenerator != alg2.mDh.mGenerator) {
3067
0
      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
3068
0
      return;
3069
0
    }
3070
0
  }
3071
3072
private:
3073
  size_t mLength;
3074
  UniqueSECKEYPrivateKey mPrivKey;
3075
  UniqueSECKEYPublicKey mPubKey;
3076
3077
  virtual nsresult DoCrypto() override
3078
0
  {
3079
0
    // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
3080
0
    // derived symmetric key and don't matter because we ignore them anyway.
3081
0
    UniquePK11SymKey symKey(PK11_PubDeriveWithKDF(
3082
0
      mPrivKey.get(), mPubKey.get(), PR_FALSE, nullptr, nullptr,
3083
0
      CKM_DH_PKCS_DERIVE, CKM_SHA512_HMAC, CKA_SIGN, 0, CKD_NULL, nullptr,
3084
0
      nullptr));
3085
0
3086
0
    if (!symKey.get()) {
3087
0
      return NS_ERROR_DOM_OPERATION_ERR;
3088
0
    }
3089
0
3090
0
    nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get()));
3091
0
    if (NS_FAILED(rv)) {
3092
0
      return NS_ERROR_DOM_OPERATION_ERR;
3093
0
    }
3094
0
3095
0
    // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
3096
0
    // just refers to a buffer managed by symKey. The assignment copies the
3097
0
    // data, so mResult manages one copy, while symKey manages another.
3098
0
    ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey.get()));
3099
0
3100
0
    if (mLength > mResult.Length()) {
3101
0
      return NS_ERROR_DOM_DATA_ERR;
3102
0
    }
3103
0
3104
0
    if (!mResult.SetLength(mLength, fallible)) {
3105
0
      return NS_ERROR_DOM_UNKNOWN_ERR;
3106
0
    }
3107
0
3108
0
    return NS_OK;
3109
0
  }
3110
};
3111
3112
template<class KeyEncryptTask>
3113
class WrapKeyTask : public ExportKeyTask
3114
{
3115
public:
3116
  WrapKeyTask(JSContext* aCx,
3117
              const nsAString& aFormat,
3118
              CryptoKey& aKey,
3119
              CryptoKey& aWrappingKey,
3120
              const ObjectOrString& aWrapAlgorithm)
3121
    : ExportKeyTask(aFormat, aKey)
3122
0
  {
3123
0
    if (NS_FAILED(mEarlyRv)) {
3124
0
      return;
3125
0
    }
3126
0
3127
0
    mTask = new KeyEncryptTask(aCx, aWrapAlgorithm, aWrappingKey, true);
3128
0
  }
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesTask>::WrapKeyTask(JSContext*, nsTSubstring<char16_t> const&, mozilla::dom::CryptoKey&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesKwTask>::WrapKeyTask(JSContext*, nsTSubstring<char16_t> const&, mozilla::dom::CryptoKey&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&)
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::RsaOaepTask>::WrapKeyTask(JSContext*, nsTSubstring<char16_t> const&, mozilla::dom::CryptoKey&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&)
3129
3130
private:
3131
  RefPtr<KeyEncryptTask> mTask;
3132
3133
0
  virtual nsresult AfterCrypto() override {
3134
0
    // If wrapping JWK, stringify the JSON
3135
0
    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
3136
0
      nsAutoString json;
3137
0
      if (!mJwk.ToJSON(json)) {
3138
0
        return NS_ERROR_DOM_OPERATION_ERR;
3139
0
      }
3140
0
3141
0
      NS_ConvertUTF16toUTF8 utf8(json);
3142
0
      if (!mResult.Assign((const uint8_t*) utf8.BeginReading(), utf8.Length())) {
3143
0
        return NS_ERROR_DOM_OPERATION_ERR;
3144
0
      }
3145
0
    }
3146
0
3147
0
    return NS_OK;
3148
0
  }
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesTask>::AfterCrypto()
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesKwTask>::AfterCrypto()
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::RsaOaepTask>::AfterCrypto()
3149
3150
  virtual void Resolve() override
3151
0
  {
3152
0
    mTask->SetData(mResult);
3153
0
    mTask->DispatchWithPromise(mResultPromise);
3154
0
  }
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesTask>::Resolve()
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesKwTask>::Resolve()
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::RsaOaepTask>::Resolve()
3155
3156
  virtual void Cleanup() override
3157
0
  {
3158
0
    mTask = nullptr;
3159
0
  }
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesTask>::Cleanup()
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::AesKwTask>::Cleanup()
Unexecuted instantiation: mozilla::dom::WrapKeyTask<mozilla::dom::RsaOaepTask>::Cleanup()
3160
};
3161
3162
template<class KeyEncryptTask>
3163
class UnwrapKeyTask : public KeyEncryptTask
3164
{
3165
public:
3166
  UnwrapKeyTask(JSContext* aCx,
3167
                const ArrayBufferViewOrArrayBuffer& aWrappedKey,
3168
                CryptoKey& aUnwrappingKey,
3169
                const ObjectOrString& aUnwrapAlgorithm,
3170
                ImportKeyTask* aTask)
3171
    : KeyEncryptTask(aCx, aUnwrapAlgorithm, aUnwrappingKey, aWrappedKey, false)
3172
    , mTask(aTask)
3173
0
  {}
Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesTask>::UnwrapKeyTask(JSContext*, mozilla::dom::ArrayBufferViewOrArrayBuffer const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, mozilla::dom::ImportKeyTask*)
Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesKwTask>::UnwrapKeyTask(JSContext*, mozilla::dom::ArrayBufferViewOrArrayBuffer const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, mozilla::dom::ImportKeyTask*)
Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::RsaOaepTask>::UnwrapKeyTask(JSContext*, mozilla::dom::ArrayBufferViewOrArrayBuffer const&, mozilla::dom::CryptoKey&, mozilla::dom::ObjectOrString const&, mozilla::dom::ImportKeyTask*)
3174
3175
private:
3176
  RefPtr<ImportKeyTask> mTask;
3177
3178
  virtual void Resolve() override
3179
0
  {
3180
0
    mTask->SetKeyDataMaybeParseJWK(KeyEncryptTask::mResult);
3181
0
    mTask->DispatchWithPromise(KeyEncryptTask::mResultPromise);
3182
0
  }
Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesTask>::Resolve()
Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesKwTask>::Resolve()
Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::RsaOaepTask>::Resolve()
3183
3184
  virtual void Cleanup() override
3185
0
  {
3186
0
    mTask = nullptr;
3187
0
  }
Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesTask>::Cleanup()
Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::AesKwTask>::Cleanup()
Unexecuted instantiation: mozilla::dom::UnwrapKeyTask<mozilla::dom::RsaOaepTask>::Cleanup()
3188
};
3189
3190
// Task creation methods for WebCryptoTask
3191
3192
// Note: We do not perform algorithm normalization as a monolithic process,
3193
// as described in the spec.  Instead:
3194
// * Each method handles its slice of the supportedAlgorithms structure
3195
// * Task constructors take care of:
3196
//    * Coercing the algorithm to the proper concrete type
3197
//    * Cloning subordinate data items
3198
//    * Cloning input data as needed
3199
//
3200
// Thus, support for different algorithms is determined by the if-statements
3201
// below, rather than a data structure.
3202
//
3203
// This results in algorithm normalization coming after some other checks,
3204
// and thus slightly more steps being done synchronously than the spec calls
3205
// for.  But none of these steps is especially time-consuming.
3206
3207
WebCryptoTask*
3208
WebCryptoTask::CreateEncryptDecryptTask(JSContext* aCx,
3209
                                        const ObjectOrString& aAlgorithm,
3210
                                        CryptoKey& aKey,
3211
                                        const CryptoOperationData& aData,
3212
                                        bool aEncrypt)
3213
0
{
3214
0
  TelemetryMethod method = (aEncrypt)? TM_ENCRYPT : TM_DECRYPT;
3215
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, method);
3216
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_ENC, aKey.Extractable());
3217
0
3218
0
  // Ensure key is usable for this operation
3219
0
  if ((aEncrypt  && !aKey.HasUsage(CryptoKey::ENCRYPT)) ||
3220
0
      (!aEncrypt && !aKey.HasUsage(CryptoKey::DECRYPT))) {
3221
0
    return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
3222
0
  }
3223
0
3224
0
  nsString algName;
3225
0
  nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
3226
0
  if (NS_FAILED(rv)) {
3227
0
    return new FailureTask(rv);
3228
0
  }
3229
0
3230
0
  if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
3231
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
3232
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
3233
0
    return new AesTask(aCx, aAlgorithm, aKey, aData, aEncrypt);
3234
0
  } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
3235
0
    return new RsaOaepTask(aCx, aAlgorithm, aKey, aData, aEncrypt);
3236
0
  }
3237
0
3238
0
  return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3239
0
}
3240
3241
WebCryptoTask*
3242
WebCryptoTask::CreateSignVerifyTask(JSContext* aCx,
3243
                                    const ObjectOrString& aAlgorithm,
3244
                                    CryptoKey& aKey,
3245
                                    const CryptoOperationData& aSignature,
3246
                                    const CryptoOperationData& aData,
3247
                                    bool aSign)
3248
0
{
3249
0
  TelemetryMethod method = (aSign)? TM_SIGN : TM_VERIFY;
3250
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, method);
3251
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_SIG, aKey.Extractable());
3252
0
3253
0
  // Ensure key is usable for this operation
3254
0
  if ((aSign  && !aKey.HasUsage(CryptoKey::SIGN)) ||
3255
0
      (!aSign && !aKey.HasUsage(CryptoKey::VERIFY))) {
3256
0
    return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
3257
0
  }
3258
0
3259
0
  nsString algName;
3260
0
  nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
3261
0
  if (NS_FAILED(rv)) {
3262
0
    return new FailureTask(rv);
3263
0
  }
3264
0
3265
0
  if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
3266
0
    return new HmacTask(aCx, aAlgorithm, aKey, aSignature, aData, aSign);
3267
0
  } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
3268
0
             algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS) ||
3269
0
             algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
3270
0
    return new AsymmetricSignVerifyTask(aCx, aAlgorithm, aKey, aSignature,
3271
0
                                        aData, aSign);
3272
0
  }
3273
0
3274
0
  return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3275
0
}
3276
3277
WebCryptoTask*
3278
WebCryptoTask::CreateDigestTask(JSContext* aCx,
3279
                                const ObjectOrString& aAlgorithm,
3280
                                const CryptoOperationData& aData)
3281
0
{
3282
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DIGEST);
3283
0
3284
0
  nsString algName;
3285
0
  nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
3286
0
  if (NS_FAILED(rv)) {
3287
0
    return new FailureTask(rv);
3288
0
  }
3289
0
3290
0
  if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA1) ||
3291
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_SHA256) ||
3292
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_SHA384) ||
3293
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
3294
0
    return new DigestTask(aCx, aAlgorithm, aData);
3295
0
  }
3296
0
3297
0
  return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3298
0
}
3299
3300
WebCryptoTask*
3301
WebCryptoTask::CreateImportKeyTask(nsIGlobalObject* aGlobal,
3302
                                   JSContext* aCx,
3303
                                   const nsAString& aFormat,
3304
                                   JS::Handle<JSObject*> aKeyData,
3305
                                   const ObjectOrString& aAlgorithm,
3306
                                   bool aExtractable,
3307
                                   const Sequence<nsString>& aKeyUsages)
3308
0
{
3309
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_IMPORTKEY);
3310
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_IMPORT, aExtractable);
3311
0
3312
0
  // Verify that the format is recognized
3313
0
  if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) &&
3314
0
      !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) &&
3315
0
      !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) &&
3316
0
      !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
3317
0
    return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR);
3318
0
  }
3319
0
3320
0
  // Verify that aKeyUsages does not contain an unrecognized value
3321
0
  if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) {
3322
0
    return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR);
3323
0
  }
3324
0
3325
0
  nsString algName;
3326
0
  nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
3327
0
  if (NS_FAILED(rv)) {
3328
0
    return new FailureTask(rv);
3329
0
  }
3330
0
3331
0
  // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation.
3332
0
  // However, the spec should be updated to allow it.
3333
0
  if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
3334
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
3335
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
3336
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) ||
3337
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2) ||
3338
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_HKDF) ||
3339
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
3340
0
    return new ImportSymmetricKeyTask(aGlobal, aCx, aFormat, aKeyData,
3341
0
                                      aAlgorithm, aExtractable, aKeyUsages);
3342
0
  } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
3343
0
             algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
3344
0
             algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
3345
0
    return new ImportRsaKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm,
3346
0
                                aExtractable, aKeyUsages);
3347
0
  } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
3348
0
             algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
3349
0
    return new ImportEcKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm,
3350
0
                               aExtractable, aKeyUsages);
3351
0
  } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
3352
0
    return new ImportDhKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm,
3353
0
                               aExtractable, aKeyUsages);
3354
0
  } else {
3355
0
    return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3356
0
  }
3357
0
}
3358
3359
WebCryptoTask*
3360
WebCryptoTask::CreateExportKeyTask(const nsAString& aFormat,
3361
                                   CryptoKey& aKey)
3362
0
{
3363
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_EXPORTKEY);
3364
0
3365
0
  // Verify that the format is recognized
3366
0
  if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) &&
3367
0
      !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) &&
3368
0
      !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) &&
3369
0
      !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
3370
0
    return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR);
3371
0
  }
3372
0
3373
0
  // Verify that the key is extractable
3374
0
  if (!aKey.Extractable()) {
3375
0
    return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
3376
0
  }
3377
0
3378
0
  // Verify that the algorithm supports export
3379
0
  // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation.
3380
0
  // However, the spec should be updated to allow it.
3381
0
  nsString algName = aKey.Algorithm().mName;
3382
0
  if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
3383
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
3384
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
3385
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) ||
3386
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2) ||
3387
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC) ||
3388
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
3389
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
3390
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS) ||
3391
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA) ||
3392
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
3393
0
      algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
3394
0
    return new ExportKeyTask(aFormat, aKey);
3395
0
  }
3396
0
3397
0
  return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3398
0
}
3399
3400
WebCryptoTask*
3401
WebCryptoTask::CreateGenerateKeyTask(nsIGlobalObject* aGlobal,
3402
                                     JSContext* aCx,
3403
                                     const ObjectOrString& aAlgorithm,
3404
                                     bool aExtractable,
3405
                                     const Sequence<nsString>& aKeyUsages)
3406
0
{
3407
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_GENERATEKEY);
3408
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_GENERATE, aExtractable);
3409
0
3410
0
  // Verify that aKeyUsages does not contain an unrecognized value
3411
0
  // SPEC-BUG: Spec says that this should be InvalidAccessError, but that
3412
0
  // is inconsistent with other analogous points in the spec
3413
0
  if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) {
3414
0
    return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR);
3415
0
  }
3416
0
3417
0
  nsString algName;
3418
0
  nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
3419
0
  if (NS_FAILED(rv)) {
3420
0
    return new FailureTask(rv);
3421
0
  }
3422
0
3423
0
  if (algName.EqualsASCII(WEBCRYPTO_ALG_AES_CBC) ||
3424
0
      algName.EqualsASCII(WEBCRYPTO_ALG_AES_CTR) ||
3425
0
      algName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) ||
3426
0
      algName.EqualsASCII(WEBCRYPTO_ALG_AES_KW) ||
3427
0
      algName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
3428
0
    return new GenerateSymmetricKeyTask(aGlobal, aCx, aAlgorithm, aExtractable,
3429
0
                                        aKeyUsages);
3430
0
  } else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
3431
0
             algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) ||
3432
0
             algName.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS) ||
3433
0
             algName.EqualsASCII(WEBCRYPTO_ALG_ECDH) ||
3434
0
             algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA) ||
3435
0
             algName.EqualsASCII(WEBCRYPTO_ALG_DH)) {
3436
0
    return new GenerateAsymmetricKeyTask(aGlobal, aCx, aAlgorithm, aExtractable,
3437
0
                                         aKeyUsages);
3438
0
  } else {
3439
0
    return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3440
0
  }
3441
0
}
3442
3443
WebCryptoTask*
3444
WebCryptoTask::CreateDeriveKeyTask(nsIGlobalObject* aGlobal,
3445
                                   JSContext* aCx,
3446
                                   const ObjectOrString& aAlgorithm,
3447
                                   CryptoKey& aBaseKey,
3448
                                   const ObjectOrString& aDerivedKeyType,
3449
                                   bool aExtractable,
3450
                                   const Sequence<nsString>& aKeyUsages)
3451
0
{
3452
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DERIVEKEY);
3453
0
3454
0
  // Ensure baseKey is usable for this operation
3455
0
  if (!aBaseKey.HasUsage(CryptoKey::DERIVEKEY)) {
3456
0
    return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
3457
0
  }
3458
0
3459
0
  // Verify that aKeyUsages does not contain an unrecognized value
3460
0
  if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) {
3461
0
    return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR);
3462
0
  }
3463
0
3464
0
  nsString algName;
3465
0
  nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
3466
0
  if (NS_FAILED(rv)) {
3467
0
    return new FailureTask(rv);
3468
0
  }
3469
0
3470
0
  if (algName.EqualsASCII(WEBCRYPTO_ALG_HKDF)) {
3471
0
    return new DeriveKeyTask<DeriveHkdfBitsTask>(aGlobal, aCx, aAlgorithm,
3472
0
                                                 aBaseKey, aDerivedKeyType,
3473
0
                                                 aExtractable, aKeyUsages);
3474
0
  }
3475
0
3476
0
  if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) {
3477
0
    return new DeriveKeyTask<DerivePbkdfBitsTask>(aGlobal, aCx, aAlgorithm,
3478
0
                                                  aBaseKey, aDerivedKeyType,
3479
0
                                                  aExtractable, aKeyUsages);
3480
0
  }
3481
0
3482
0
  if (algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) {
3483
0
    return new DeriveKeyTask<DeriveEcdhBitsTask>(aGlobal, aCx, aAlgorithm,
3484
0
                                                 aBaseKey, aDerivedKeyType,
3485
0
                                                 aExtractable, aKeyUsages);
3486
0
  }
3487
0
3488
0
  return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3489
0
}
3490
3491
WebCryptoTask*
3492
WebCryptoTask::CreateDeriveBitsTask(JSContext* aCx,
3493
                                    const ObjectOrString& aAlgorithm,
3494
                                    CryptoKey& aKey,
3495
                                    uint32_t aLength)
3496
0
{
3497
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DERIVEBITS);
3498
0
3499
0
  // Ensure baseKey is usable for this operation
3500
0
  if (!aKey.HasUsage(CryptoKey::DERIVEBITS)) {
3501
0
    return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
3502
0
  }
3503
0
3504
0
  nsString algName;
3505
0
  nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
3506
0
  if (NS_FAILED(rv)) {
3507
0
    return new FailureTask(rv);
3508
0
  }
3509
0
3510
0
  if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) {
3511
0
    return new DerivePbkdfBitsTask(aCx, aAlgorithm, aKey, aLength);
3512
0
  }
3513
0
3514
0
  if (algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) {
3515
0
    return new DeriveEcdhBitsTask(aCx, aAlgorithm, aKey, aLength);
3516
0
  }
3517
0
3518
0
  if (algName.EqualsASCII(WEBCRYPTO_ALG_DH)) {
3519
0
    return new DeriveDhBitsTask(aCx, aAlgorithm, aKey, aLength);
3520
0
  }
3521
0
3522
0
  if (algName.EqualsASCII(WEBCRYPTO_ALG_HKDF)) {
3523
0
    return new DeriveHkdfBitsTask(aCx, aAlgorithm, aKey, aLength);
3524
0
  }
3525
0
3526
0
  return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3527
0
}
3528
3529
WebCryptoTask*
3530
WebCryptoTask::CreateWrapKeyTask(JSContext* aCx,
3531
                                 const nsAString& aFormat,
3532
                                 CryptoKey& aKey,
3533
                                 CryptoKey& aWrappingKey,
3534
                                 const ObjectOrString& aWrapAlgorithm)
3535
0
{
3536
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_WRAPKEY);
3537
0
3538
0
  // Verify that the format is recognized
3539
0
  if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) &&
3540
0
      !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) &&
3541
0
      !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) &&
3542
0
      !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
3543
0
    return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR);
3544
0
  }
3545
0
3546
0
  // Ensure wrappingKey is usable for this operation
3547
0
  if (!aWrappingKey.HasUsage(CryptoKey::WRAPKEY)) {
3548
0
    return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
3549
0
  }
3550
0
3551
0
  // Ensure key is extractable
3552
0
  if (!aKey.Extractable()) {
3553
0
    return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
3554
0
  }
3555
0
3556
0
  nsString wrapAlgName;
3557
0
  nsresult rv = GetAlgorithmName(aCx, aWrapAlgorithm, wrapAlgName);
3558
0
  if (NS_FAILED(rv)) {
3559
0
    return new FailureTask(rv);
3560
0
  }
3561
0
3562
0
  if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
3563
0
      wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
3564
0
      wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
3565
0
    return new WrapKeyTask<AesTask>(aCx, aFormat, aKey,
3566
0
                                    aWrappingKey, aWrapAlgorithm);
3567
0
  } else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
3568
0
    return new WrapKeyTask<AesKwTask>(aCx, aFormat, aKey,
3569
0
                                    aWrappingKey, aWrapAlgorithm);
3570
0
  } else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
3571
0
    return new WrapKeyTask<RsaOaepTask>(aCx, aFormat, aKey,
3572
0
                                        aWrappingKey, aWrapAlgorithm);
3573
0
  }
3574
0
3575
0
  return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3576
0
}
3577
3578
WebCryptoTask*
3579
WebCryptoTask::CreateUnwrapKeyTask(nsIGlobalObject* aGlobal,
3580
                                   JSContext* aCx,
3581
                                   const nsAString& aFormat,
3582
                                   const ArrayBufferViewOrArrayBuffer& aWrappedKey,
3583
                                   CryptoKey& aUnwrappingKey,
3584
                                   const ObjectOrString& aUnwrapAlgorithm,
3585
                                   const ObjectOrString& aUnwrappedKeyAlgorithm,
3586
                                   bool aExtractable,
3587
                                   const Sequence<nsString>& aKeyUsages)
3588
0
{
3589
0
  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_UNWRAPKEY);
3590
0
3591
0
  // Ensure key is usable for this operation
3592
0
  if (!aUnwrappingKey.HasUsage(CryptoKey::UNWRAPKEY)) {
3593
0
    return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
3594
0
  }
3595
0
3596
0
  // Verify that aKeyUsages does not contain an unrecognized value
3597
0
  if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) {
3598
0
    return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR);
3599
0
  }
3600
0
3601
0
  nsString keyAlgName;
3602
0
  nsresult rv = GetAlgorithmName(aCx, aUnwrappedKeyAlgorithm, keyAlgName);
3603
0
  if (NS_FAILED(rv)) {
3604
0
    return new FailureTask(rv);
3605
0
  }
3606
0
3607
0
  CryptoOperationData dummy;
3608
0
  RefPtr<ImportKeyTask> importTask;
3609
0
  if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_CBC) ||
3610
0
      keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_CTR) ||
3611
0
      keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) ||
3612
0
      keyAlgName.EqualsASCII(WEBCRYPTO_ALG_HKDF) ||
3613
0
      keyAlgName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
3614
0
    importTask = new ImportSymmetricKeyTask(aGlobal, aCx, aFormat,
3615
0
                                            aUnwrappedKeyAlgorithm,
3616
0
                                            aExtractable, aKeyUsages);
3617
0
  } else if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
3618
0
             keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) ||
3619
0
             keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS)) {
3620
0
    importTask = new ImportRsaKeyTask(aGlobal, aCx, aFormat,
3621
0
                                      aUnwrappedKeyAlgorithm,
3622
0
                                      aExtractable, aKeyUsages);
3623
0
  } else {
3624
0
    return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3625
0
  }
3626
0
3627
0
  nsString unwrapAlgName;
3628
0
  rv = GetAlgorithmName(aCx, aUnwrapAlgorithm, unwrapAlgName);
3629
0
  if (NS_FAILED(rv)) {
3630
0
    return new FailureTask(rv);
3631
0
  }
3632
0
  if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
3633
0
      unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
3634
0
      unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
3635
0
    return new UnwrapKeyTask<AesTask>(aCx, aWrappedKey,
3636
0
                                      aUnwrappingKey, aUnwrapAlgorithm,
3637
0
                                      importTask);
3638
0
  } else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
3639
0
    return new UnwrapKeyTask<AesKwTask>(aCx, aWrappedKey,
3640
0
                                      aUnwrappingKey, aUnwrapAlgorithm,
3641
0
                                      importTask);
3642
0
  } else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
3643
0
    return new UnwrapKeyTask<RsaOaepTask>(aCx, aWrappedKey,
3644
0
                                      aUnwrappingKey, aUnwrapAlgorithm,
3645
0
                                      importTask);
3646
0
  }
3647
0
3648
0
  return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
3649
0
}
3650
3651
WebCryptoTask::WebCryptoTask()
3652
  : CancelableRunnable("WebCryptoTask")
3653
  , mEarlyRv(NS_OK)
3654
  , mEarlyComplete(false)
3655
  , mOriginalEventTarget(nullptr)
3656
  , mRv(NS_ERROR_NOT_INITIALIZED)
3657
0
{
3658
0
}
3659
3660
0
WebCryptoTask::~WebCryptoTask() = default;
3661
3662
} // namespace dom
3663
} // namespace mozilla