Source code

Revision control

Other Tools

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/Utf8.h"
16
#include "mozilla/dom/CryptoBuffer.h"
17
#include "mozilla/dom/CryptoKey.h"
18
#include "mozilla/dom/KeyAlgorithmProxy.h"
19
#include "mozilla/dom/TypedArray.h"
20
#include "mozilla/dom/WebCryptoCommon.h"
21
#include "mozilla/dom/WebCryptoTask.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, 0, NULL, sizeof(SGNDigestInfo)},
30
{SEC_ASN1_INLINE, offsetof(SGNDigestInfo, digestAlgorithm),
31
SEC_ASN1_GET(SECOID_AlgorithmIDTemplate)},
32
{SEC_ASN1_OCTET_STRING, offsetof(SGNDigestInfo, digest)},
33
{
34
0,
35
}};
36
37
namespace mozilla {
38
namespace dom {
39
40
// Pre-defined identifiers for telemetry histograms
41
42
enum TelemetryMethod {
43
TM_ENCRYPT = 0,
44
TM_DECRYPT = 1,
45
TM_SIGN = 2,
46
TM_VERIFY = 3,
47
TM_DIGEST = 4,
48
TM_GENERATEKEY = 5,
49
TM_DERIVEKEY = 6,
50
TM_DERIVEBITS = 7,
51
TM_IMPORTKEY = 8,
52
TM_EXPORTKEY = 9,
53
TM_WRAPKEY = 10,
54
TM_UNWRAPKEY = 11
55
};
56
57
enum TelemetryAlgorithm {
58
// Please make additions at the end of the list,
59
// to preserve comparability of histograms over time
60
TA_UNKNOWN = 0,
61
// encrypt / decrypt
62
TA_AES_CBC = 1,
63
TA_AES_CFB = 2,
64
TA_AES_CTR = 3,
65
TA_AES_GCM = 4,
66
TA_RSAES_PKCS1 = 5, // NB: This algorithm has been removed
67
TA_RSA_OAEP = 6,
68
// sign/verify
69
TA_RSASSA_PKCS1 = 7,
70
TA_RSA_PSS = 8,
71
TA_HMAC_SHA_1 = 9,
72
TA_HMAC_SHA_224 = 10,
73
TA_HMAC_SHA_256 = 11,
74
TA_HMAC_SHA_384 = 12,
75
TA_HMAC_SHA_512 = 13,
76
// digest
77
TA_SHA_1 = 14,
78
TA_SHA_224 = 15,
79
TA_SHA_256 = 16,
80
TA_SHA_384 = 17,
81
TA_SHA_512 = 18,
82
// Later additions
83
TA_AES_KW = 19,
84
TA_ECDH = 20,
85
TA_PBKDF2 = 21,
86
TA_ECDSA = 22,
87
TA_HKDF = 23,
88
TA_DH = 24,
89
};
90
91
// Convenience functions for extracting / converting information
92
93
// OOM-safe CryptoBuffer initialization, suitable for constructors
94
#define ATTEMPT_BUFFER_INIT(dst, src) \
95
if (!dst.Assign(src)) { \
96
mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; \
97
return; \
98
}
99
100
// OOM-safe CryptoBuffer-to-SECItem copy, suitable for DoCrypto
101
#define ATTEMPT_BUFFER_TO_SECITEM(arena, dst, src) \
102
if (!src.ToSECItem(arena, dst)) { \
103
return NS_ERROR_DOM_UNKNOWN_ERR; \
104
}
105
106
// OOM-safe CryptoBuffer copy, suitable for DoCrypto
107
#define ATTEMPT_BUFFER_ASSIGN(dst, src) \
108
if (!dst.Assign(src)) { \
109
return NS_ERROR_DOM_UNKNOWN_ERR; \
110
}
111
112
// Safety check for algorithms that use keys, suitable for constructors
113
#define CHECK_KEY_ALGORITHM(keyAlg, algName) \
114
{ \
115
if (!NORMALIZED_EQUALS(keyAlg.mName, algName)) { \
116
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; \
117
return; \
118
} \
119
}
120
121
class ClearException {
122
public:
123
explicit ClearException(JSContext* aCx) : mCx(aCx) {}
124
125
~ClearException() { JS_ClearPendingException(mCx); }
126
127
private:
128
JSContext* mCx;
129
};
130
131
template <class OOS>
132
static nsresult GetAlgorithmName(JSContext* aCx, const OOS& aAlgorithm,
133
nsString& aName) {
134
ClearException ce(aCx);
135
136
if (aAlgorithm.IsString()) {
137
// If string, then treat as algorithm name
138
aName.Assign(aAlgorithm.GetAsString());
139
} else {
140
// Coerce to algorithm and extract name
141
JS::RootedValue value(aCx, JS::ObjectValue(*aAlgorithm.GetAsObject()));
142
Algorithm alg;
143
144
if (!alg.Init(aCx, value)) {
145
return NS_ERROR_DOM_SYNTAX_ERR;
146
}
147
148
aName = alg.mName;
149
}
150
151
if (!NormalizeToken(aName, aName)) {
152
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
153
}
154
155
return NS_OK;
156
}
157
158
template <class T, class OOS>
159
static nsresult Coerce(JSContext* aCx, T& aTarget, const OOS& aAlgorithm) {
160
ClearException ce(aCx);
161
162
if (!aAlgorithm.IsObject()) {
163
return NS_ERROR_DOM_SYNTAX_ERR;
164
}
165
166
JS::RootedValue value(aCx, JS::ObjectValue(*aAlgorithm.GetAsObject()));
167
if (!aTarget.Init(aCx, value)) {
168
return NS_ERROR_DOM_SYNTAX_ERR;
169
}
170
171
return NS_OK;
172
}
173
174
inline size_t MapHashAlgorithmNameToBlockSize(const nsString& aName) {
175
if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1) ||
176
aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
177
return 512;
178
}
179
180
if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384) ||
181
aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
182
return 1024;
183
}
184
185
return 0;
186
}
187
188
inline nsresult GetKeyLengthForAlgorithm(JSContext* aCx,
189
const ObjectOrString& aAlgorithm,
190
size_t& aLength) {
191
aLength = 0;
192
193
// Extract algorithm name
194
nsString algName;
195
if (NS_FAILED(GetAlgorithmName(aCx, aAlgorithm, algName))) {
196
return NS_ERROR_DOM_SYNTAX_ERR;
197
}
198
199
// Read AES key length from given algorithm object.
200
if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
201
algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
202
algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
203
algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
204
RootedDictionary<AesDerivedKeyParams> params(aCx);
205
if (NS_FAILED(Coerce(aCx, params, aAlgorithm))) {
206
return NS_ERROR_DOM_SYNTAX_ERR;
207
}
208
209
if (params.mLength != 128 && params.mLength != 192 &&
210
params.mLength != 256) {
211
return NS_ERROR_DOM_DATA_ERR;
212
}
213
214
aLength = params.mLength;
215
return NS_OK;
216
}
217
218
// Read HMAC key length from given algorithm object or
219
// determine key length as the block size of the given hash.
220
if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
221
RootedDictionary<HmacDerivedKeyParams> params(aCx);
222
if (NS_FAILED(Coerce(aCx, params, aAlgorithm))) {
223
return NS_ERROR_DOM_SYNTAX_ERR;
224
}
225
226
// Return the passed length, if any.
227
if (params.mLength.WasPassed()) {
228
aLength = params.mLength.Value();
229
return NS_OK;
230
}
231
232
nsString hashName;
233
if (NS_FAILED(GetAlgorithmName(aCx, params.mHash, hashName))) {
234
return NS_ERROR_DOM_SYNTAX_ERR;
235
}
236
237
// Return the given hash algorithm's block size as the key length.
238
size_t length = MapHashAlgorithmNameToBlockSize(hashName);
239
if (length == 0) {
240
return NS_ERROR_DOM_SYNTAX_ERR;
241
}
242
243
aLength = length;
244
return NS_OK;
245
}
246
247
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
248
}
249
250
inline bool MapOIDTagToNamedCurve(SECOidTag aOIDTag, nsString& aResult) {
251
switch (aOIDTag) {
252
case SEC_OID_SECG_EC_SECP256R1:
253
aResult.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256);
254
break;
255
case SEC_OID_SECG_EC_SECP384R1:
256
aResult.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384);
257
break;
258
case SEC_OID_SECG_EC_SECP521R1:
259
aResult.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521);
260
break;
261
default:
262
return false;
263
}
264
265
return true;
266
}
267
268
inline SECOidTag MapHashAlgorithmNameToOID(const nsString& aName) {
269
SECOidTag hashOID(SEC_OID_UNKNOWN);
270
271
if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
272
hashOID = SEC_OID_SHA1;
273
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
274
hashOID = SEC_OID_SHA256;
275
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
276
hashOID = SEC_OID_SHA384;
277
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
278
hashOID = SEC_OID_SHA512;
279
}
280
281
return hashOID;
282
}
283
284
inline CK_MECHANISM_TYPE MapHashAlgorithmNameToMgfMechanism(
285
const nsString& aName) {
286
CK_MECHANISM_TYPE mech(UNKNOWN_CK_MECHANISM);
287
288
if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
289
mech = CKG_MGF1_SHA1;
290
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
291
mech = CKG_MGF1_SHA256;
292
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
293
mech = CKG_MGF1_SHA384;
294
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
295
mech = CKG_MGF1_SHA512;
296
}
297
298
return mech;
299
}
300
301
// Implementation of WebCryptoTask methods
302
303
void WebCryptoTask::DispatchWithPromise(Promise* aResultPromise) {
304
mResultPromise = aResultPromise;
305
306
// Fail if an error was set during the constructor
307
MAYBE_EARLY_FAIL(mEarlyRv)
308
309
// Perform pre-NSS operations, and fail if they fail
310
mEarlyRv = BeforeCrypto();
311
MAYBE_EARLY_FAIL(mEarlyRv)
312
313
// Skip dispatch if we're already done. Otherwise launch a CryptoTask
314
if (mEarlyComplete) {
315
CallCallback(mEarlyRv);
316
return;
317
}
318
319
// Store calling thread
320
mOriginalEventTarget = GetCurrentThreadSerialEventTarget();
321
322
// If we are running on a worker thread we must hold the worker
323
// alive while we work on the thread pool. Otherwise the worker
324
// private may get torn down before we dispatch back to complete
325
// the transaction.
326
if (!NS_IsMainThread()) {
327
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
328
MOZ_ASSERT(workerPrivate);
329
330
RefPtr<StrongWorkerRef> workerRef =
331
StrongWorkerRef::Create(workerPrivate, "WebCryptoTask");
332
if (NS_WARN_IF(!workerRef)) {
333
mEarlyRv = NS_BINDING_ABORTED;
334
} else {
335
mWorkerRef = new ThreadSafeWorkerRef(workerRef);
336
}
337
}
338
MAYBE_EARLY_FAIL(mEarlyRv);
339
340
// dispatch to thread pool
341
342
if (!EnsureNSSInitializedChromeOrContent()) {
343
mEarlyRv = NS_ERROR_FAILURE;
344
}
345
MAYBE_EARLY_FAIL(mEarlyRv);
346
347
mEarlyRv = NS_DispatchBackgroundTask(this);
348
MAYBE_EARLY_FAIL(mEarlyRv)
349
}
350
351
NS_IMETHODIMP
352
WebCryptoTask::Run() {
353
// Run heavy crypto operations on the thread pool, off the original thread.
354
if (!IsOnOriginalThread()) {
355
mRv = CalculateResult();
356
357
// Back to the original thread, i.e. continue below.
358
mOriginalEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
359
return NS_OK;
360
}
361
362
// We're now back on the calling thread.
363
CallCallback(mRv);
364
365
// Stop holding the worker thread alive now that the async work has
366
// been completed.
367
mWorkerRef = nullptr;
368
369
return NS_OK;
370
}
371
372
nsresult WebCryptoTask::Cancel() {
373
MOZ_ASSERT(IsOnOriginalThread());
374
FailWithError(NS_BINDING_ABORTED);
375
return NS_OK;
376
}
377
378
void WebCryptoTask::FailWithError(nsresult aRv) {
379
MOZ_ASSERT(IsOnOriginalThread());
380
Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, false);
381
382
// Blindly convert nsresult to DOMException
383
// Individual tasks must ensure they pass the right values
384
mResultPromise->MaybeReject(aRv);
385
// Manually release mResultPromise while we're on the main thread
386
mResultPromise = nullptr;
387
mWorkerRef = nullptr;
388
Cleanup();
389
}
390
391
nsresult WebCryptoTask::CalculateResult() {
392
MOZ_ASSERT(!IsOnOriginalThread());
393
394
return DoCrypto();
395
}
396
397
void WebCryptoTask::CallCallback(nsresult rv) {
398
MOZ_ASSERT(IsOnOriginalThread());
399
if (NS_FAILED(rv)) {
400
FailWithError(rv);
401
return;
402
}
403
404
nsresult rv2 = AfterCrypto();
405
if (NS_FAILED(rv2)) {
406
FailWithError(rv2);
407
return;
408
}
409
410
Resolve();
411
Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, true);
412
413
// Manually release mResultPromise while we're on the main thread
414
mResultPromise = nullptr;
415
Cleanup();
416
}
417
418
// Some generic utility classes
419
420
class FailureTask : public WebCryptoTask {
421
public:
422
explicit FailureTask(nsresult aRv) { mEarlyRv = aRv; }
423
};
424
425
class ReturnArrayBufferViewTask : public WebCryptoTask {
426
protected:
427
CryptoBuffer mResult;
428
429
private:
430
// Returns mResult as an ArrayBufferView, or an error
431
virtual void Resolve() override {
432
TypedArrayCreator<ArrayBuffer> ret(mResult);
433
mResultPromise->MaybeResolve(ret);
434
}
435
};
436
437
class DeferredData {
438
public:
439
template <class T>
440
void SetData(const T& aData) {
441
mDataIsSet = mData.Assign(aData);
442
}
443
444
protected:
445
DeferredData() : mDataIsSet(false) {}
446
447
CryptoBuffer mData;
448
bool mDataIsSet;
449
};
450
451
class AesTask : public ReturnArrayBufferViewTask, public DeferredData {
452
public:
453
AesTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
454
bool aEncrypt)
455
: mMechanism(CKM_INVALID_MECHANISM),
456
mSymKey(aKey.GetSymKey()),
457
mTagLength(0),
458
mCounterLength(0),
459
mEncrypt(aEncrypt) {
460
Init(aCx, aAlgorithm, aKey, aEncrypt);
461
}
462
463
AesTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
464
const CryptoOperationData& aData, bool aEncrypt)
465
: mMechanism(CKM_INVALID_MECHANISM),
466
mSymKey(aKey.GetSymKey()),
467
mTagLength(0),
468
mCounterLength(0),
469
mEncrypt(aEncrypt) {
470
Init(aCx, aAlgorithm, aKey, aEncrypt);
471
SetData(aData);
472
}
473
474
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
475
bool aEncrypt) {
476
nsString algName;
477
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
478
if (NS_FAILED(mEarlyRv)) {
479
return;
480
}
481
482
// Check that we got a reasonable key
483
if ((mSymKey.Length() != 16) && (mSymKey.Length() != 24) &&
484
(mSymKey.Length() != 32)) {
485
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
486
return;
487
}
488
489
// Cache parameters depending on the specific algorithm
490
TelemetryAlgorithm telemetryAlg;
491
if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) {
492
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_CBC);
493
494
mMechanism = CKM_AES_CBC_PAD;
495
telemetryAlg = TA_AES_CBC;
496
RootedDictionary<AesCbcParams> params(aCx);
497
nsresult rv = Coerce(aCx, params, aAlgorithm);
498
if (NS_FAILED(rv)) {
499
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
500
return;
501
}
502
503
ATTEMPT_BUFFER_INIT(mIv, params.mIv)
504
if (mIv.Length() != 16) {
505
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
506
return;
507
}
508
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) {
509
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_CTR);
510
511
mMechanism = CKM_AES_CTR;
512
telemetryAlg = TA_AES_CTR;
513
RootedDictionary<AesCtrParams> params(aCx);
514
nsresult rv = Coerce(aCx, params, aAlgorithm);
515
if (NS_FAILED(rv)) {
516
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
517
return;
518
}
519
520
ATTEMPT_BUFFER_INIT(mIv, params.mCounter)
521
if (mIv.Length() != 16) {
522
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
523
return;
524
}
525
526
mCounterLength = params.mLength;
527
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
528
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_GCM);
529
530
mMechanism = CKM_AES_GCM;
531
telemetryAlg = TA_AES_GCM;
532
RootedDictionary<AesGcmParams> params(aCx);
533
nsresult rv = Coerce(aCx, params, aAlgorithm);
534
if (NS_FAILED(rv)) {
535
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
536
return;
537
}
538
539
ATTEMPT_BUFFER_INIT(mIv, params.mIv)
540
541
if (params.mAdditionalData.WasPassed()) {
542
ATTEMPT_BUFFER_INIT(mAad, params.mAdditionalData.Value())
543
}
544
545
// 32, 64, 96, 104, 112, 120 or 128
546
mTagLength = 128;
547
if (params.mTagLength.WasPassed()) {
548
mTagLength = params.mTagLength.Value();
549
if ((mTagLength > 128) ||
550
!(mTagLength == 32 || mTagLength == 64 ||
551
(mTagLength >= 96 && mTagLength % 8 == 0))) {
552
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
553
return;
554
}
555
}
556
} else {
557
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
558
return;
559
}
560
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg);
561
}
562
563
private:
564
CK_MECHANISM_TYPE mMechanism;
565
CryptoBuffer mSymKey;
566
CryptoBuffer mIv; // Initialization vector
567
CryptoBuffer mAad; // Additional Authenticated Data
568
uint8_t mTagLength;
569
uint8_t mCounterLength;
570
bool mEncrypt;
571
572
virtual nsresult DoCrypto() override {
573
nsresult rv;
574
575
if (!mDataIsSet) {
576
return NS_ERROR_DOM_OPERATION_ERR;
577
}
578
579
UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
580
if (!arena) {
581
return NS_ERROR_DOM_OPERATION_ERR;
582
}
583
584
// Construct the parameters object depending on algorithm
585
SECItem param = {siBuffer, nullptr, 0};
586
CK_AES_CTR_PARAMS ctrParams;
587
CK_GCM_PARAMS gcmParams;
588
switch (mMechanism) {
589
case CKM_AES_CBC_PAD:
590
ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &param, mIv);
591
break;
592
case CKM_AES_CTR:
593
ctrParams.ulCounterBits = mCounterLength;
594
MOZ_ASSERT(mIv.Length() == 16);
595
memcpy(&ctrParams.cb, mIv.Elements(), 16);
596
param.type = siBuffer;
597
param.data = (unsigned char*)&ctrParams;
598
param.len = sizeof(ctrParams);
599
break;
600
case CKM_AES_GCM:
601
gcmParams.pIv = mIv.Elements();
602
gcmParams.ulIvLen = mIv.Length();
603
gcmParams.pAAD = mAad.Elements();
604
gcmParams.ulAADLen = mAad.Length();
605
gcmParams.ulTagBits = mTagLength;
606
param.type = siBuffer;
607
param.data = (unsigned char*)&gcmParams;
608
param.len = sizeof(gcmParams);
609
break;
610
default:
611
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
612
}
613
614
// Import the key
615
SECItem keyItem = {siBuffer, nullptr, 0};
616
ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
617
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
618
MOZ_ASSERT(slot.get());
619
UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism,
620
PK11_OriginUnwrap, CKA_ENCRYPT,
621
&keyItem, nullptr));
622
if (!symKey) {
623
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
624
}
625
626
// Check whether the integer addition would overflow.
627
if (std::numeric_limits<CryptoBuffer::size_type>::max() - 16 <
628
mData.Length()) {
629
return NS_ERROR_DOM_DATA_ERR;
630
}
631
632
// Initialize the output buffer (enough space for padding / a full tag)
633
if (!mResult.SetLength(mData.Length() + 16, fallible)) {
634
return NS_ERROR_DOM_UNKNOWN_ERR;
635
}
636
637
uint32_t outLen = 0;
638
639
// Perform the encryption/decryption
640
if (mEncrypt) {
641
rv = MapSECStatus(PK11_Encrypt(
642
symKey.get(), mMechanism, &param, mResult.Elements(), &outLen,
643
mResult.Length(), mData.Elements(), mData.Length()));
644
} else {
645
rv = MapSECStatus(PK11_Decrypt(
646
symKey.get(), mMechanism, &param, mResult.Elements(), &outLen,
647
mResult.Length(), mData.Elements(), mData.Length()));
648
}
649
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
650
651
mResult.TruncateLength(outLen);
652
return rv;
653
}
654
};
655
656
// This class looks like an encrypt/decrypt task, like AesTask,
657
// but it is only exposed to wrapKey/unwrapKey, not encrypt/decrypt
658
class AesKwTask : public ReturnArrayBufferViewTask, public DeferredData {
659
public:
660
AesKwTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
661
bool aEncrypt)
662
: mMechanism(CKM_NSS_AES_KEY_WRAP),
663
mSymKey(aKey.GetSymKey()),
664
mEncrypt(aEncrypt) {
665
Init(aCx, aAlgorithm, aKey, aEncrypt);
666
}
667
668
AesKwTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
669
const CryptoOperationData& aData, bool aEncrypt)
670
: mMechanism(CKM_NSS_AES_KEY_WRAP),
671
mSymKey(aKey.GetSymKey()),
672
mEncrypt(aEncrypt) {
673
Init(aCx, aAlgorithm, aKey, aEncrypt);
674
SetData(aData);
675
}
676
677
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
678
bool aEncrypt) {
679
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_KW);
680
681
nsString algName;
682
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
683
if (NS_FAILED(mEarlyRv)) {
684
return;
685
}
686
687
// Check that we got a reasonable key
688
if ((mSymKey.Length() != 16) && (mSymKey.Length() != 24) &&
689
(mSymKey.Length() != 32)) {
690
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
691
return;
692
}
693
694
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_AES_KW);
695
}
696
697
private:
698
CK_MECHANISM_TYPE mMechanism;
699
CryptoBuffer mSymKey;
700
bool mEncrypt;
701
702
virtual nsresult DoCrypto() override {
703
nsresult rv;
704
705
if (!mDataIsSet) {
706
return NS_ERROR_DOM_OPERATION_ERR;
707
}
708
709
// Check that the input is a multiple of 64 bits long
710
if (mData.Length() == 0 || mData.Length() % 8 != 0) {
711
return NS_ERROR_DOM_DATA_ERR;
712
}
713
714
UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
715
if (!arena) {
716
return NS_ERROR_DOM_OPERATION_ERR;
717
}
718
719
// Import the key
720
SECItem keyItem = {siBuffer, nullptr, 0};
721
ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
722
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
723
MOZ_ASSERT(slot.get());
724
UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism,
725
PK11_OriginUnwrap, CKA_WRAP,
726
&keyItem, nullptr));
727
if (!symKey) {
728
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
729
}
730
731
// Import the data to a SECItem
732
SECItem dataItem = {siBuffer, nullptr, 0};
733
ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &dataItem, mData);
734
735
// Parameters for the fake keys
736
CK_MECHANISM_TYPE fakeMechanism = CKM_SHA_1_HMAC;
737
CK_ATTRIBUTE_TYPE fakeOperation = CKA_SIGN;
738
739
if (mEncrypt) {
740
// Import the data into a fake PK11SymKey structure
741
UniquePK11SymKey keyToWrap(
742
PK11_ImportSymKey(slot.get(), fakeMechanism, PK11_OriginUnwrap,
743
fakeOperation, &dataItem, nullptr));
744
if (!keyToWrap) {
745
return NS_ERROR_DOM_OPERATION_ERR;
746
}
747
748
// Encrypt and return the wrapped key
749
// AES-KW encryption results in a wrapped key 64 bits longer
750
if (!mResult.SetLength(mData.Length() + 8, fallible)) {
751
return NS_ERROR_DOM_OPERATION_ERR;
752
}
753
SECItem resultItem = {siBuffer, mResult.Elements(),
754
(unsigned int)mResult.Length()};
755
rv = MapSECStatus(PK11_WrapSymKey(mMechanism, nullptr, symKey.get(),
756
keyToWrap.get(), &resultItem));
757
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
758
} else {
759
// Decrypt the ciphertext into a temporary PK11SymKey
760
// Unwrapped key should be 64 bits shorter
761
int keySize = mData.Length() - 8;
762
UniquePK11SymKey unwrappedKey(
763
PK11_UnwrapSymKey(symKey.get(), mMechanism, nullptr, &dataItem,
764
fakeMechanism, fakeOperation, keySize));
765
if (!unwrappedKey) {
766
return NS_ERROR_DOM_OPERATION_ERR;
767
}
768
769
// Export the key to get the cleartext
770
rv = MapSECStatus(PK11_ExtractKeyValue(unwrappedKey.get()));
771
if (NS_FAILED(rv)) {
772
return NS_ERROR_DOM_UNKNOWN_ERR;
773
}
774
ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(unwrappedKey.get()));
775
}
776
777
return rv;
778
}
779
};
780
781
class RsaOaepTask : public ReturnArrayBufferViewTask, public DeferredData {
782
public:
783
RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
784
bool aEncrypt)
785
: mPrivKey(aKey.GetPrivateKey()),
786
mPubKey(aKey.GetPublicKey()),
787
mEncrypt(aEncrypt) {
788
Init(aCx, aAlgorithm, aKey, aEncrypt);
789
}
790
791
RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
792
const CryptoOperationData& aData, bool aEncrypt)
793
: mPrivKey(aKey.GetPrivateKey()),
794
mPubKey(aKey.GetPublicKey()),
795
mEncrypt(aEncrypt) {
796
Init(aCx, aAlgorithm, aKey, aEncrypt);
797
SetData(aData);
798
}
799
800
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
801
bool aEncrypt) {
802
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_OAEP);
803
804
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_OAEP);
805
806
if (mEncrypt) {
807
if (!mPubKey) {
808
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
809
return;
810
}
811
mStrength = SECKEY_PublicKeyStrength(mPubKey.get());
812
} else {
813
if (!mPrivKey) {
814
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
815
return;
816
}
817
mStrength = PK11_GetPrivateModulusLen(mPrivKey.get());
818
}
819
820
// The algorithm could just be given as a string
821
// in which case there would be no label specified.
822
if (!aAlgorithm.IsString()) {
823
RootedDictionary<RsaOaepParams> params(aCx);
824
mEarlyRv = Coerce(aCx, params, aAlgorithm);
825
if (NS_FAILED(mEarlyRv)) {
826
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
827
return;
828
}
829
830
if (params.mLabel.WasPassed()) {
831
ATTEMPT_BUFFER_INIT(mLabel, params.mLabel.Value());
832
}
833
}
834
// Otherwise mLabel remains the empty octet string, as intended
835
836
KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash;
837
mHashMechanism = KeyAlgorithmProxy::GetMechanism(hashAlg);
838
mMgfMechanism = MapHashAlgorithmNameToMgfMechanism(hashAlg.mName);
839
840
// Check we found appropriate mechanisms.
841
if (mHashMechanism == UNKNOWN_CK_MECHANISM ||
842
mMgfMechanism == UNKNOWN_CK_MECHANISM) {
843
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
844
return;
845
}
846
}
847
848
private:
849
CK_MECHANISM_TYPE mHashMechanism;
850
CK_MECHANISM_TYPE mMgfMechanism;
851
UniqueSECKEYPrivateKey mPrivKey;
852
UniqueSECKEYPublicKey mPubKey;
853
CryptoBuffer mLabel;
854
uint32_t mStrength;
855
bool mEncrypt;
856
857
virtual nsresult DoCrypto() override {
858
nsresult rv;
859
860
if (!mDataIsSet) {
861
return NS_ERROR_DOM_OPERATION_ERR;
862
}
863
864
// Ciphertext is an integer mod the modulus, so it will be
865
// no longer than mStrength octets
866
if (!mResult.SetLength(mStrength, fallible)) {
867
return NS_ERROR_DOM_UNKNOWN_ERR;
868
}
869
870
CK_RSA_PKCS_OAEP_PARAMS oaepParams;
871
oaepParams.source = CKZ_DATA_SPECIFIED;
872
873
oaepParams.pSourceData = mLabel.Length() ? mLabel.Elements() : nullptr;
874
oaepParams.ulSourceDataLen = mLabel.Length();
875
876
oaepParams.mgf = mMgfMechanism;
877
oaepParams.hashAlg = mHashMechanism;
878
879
SECItem param;
880
param.type = siBuffer;
881
param.data = (unsigned char*)&oaepParams;
882
param.len = sizeof(oaepParams);
883
884
uint32_t outLen = 0;
885
if (mEncrypt) {
886
// PK11_PubEncrypt() checks the plaintext's length and fails if it is too
887
// long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
888
// being the length in octets of the RSA modulus n and 'hLen' being the
889
// output length in octets of the chosen hash function.
891
rv = MapSECStatus(PK11_PubEncrypt(
892
mPubKey.get(), CKM_RSA_PKCS_OAEP, &param, mResult.Elements(), &outLen,
893
mResult.Length(), mData.Elements(), mData.Length(), nullptr));
894
} else {
895
rv = MapSECStatus(PK11_PrivDecrypt(
896
mPrivKey.get(), CKM_RSA_PKCS_OAEP, &param, mResult.Elements(),
897
&outLen, mResult.Length(), mData.Elements(), mData.Length()));
898
}
899
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
900
901
mResult.TruncateLength(outLen);
902
return NS_OK;
903
}
904
};
905
906
class HmacTask : public WebCryptoTask {
907
public:
908
HmacTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
909
const CryptoOperationData& aSignature,
910
const CryptoOperationData& aData, bool aSign)
911
: mMechanism(aKey.Algorithm().Mechanism()),
912
mSymKey(aKey.GetSymKey()),
913
mSign(aSign) {
914
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_HMAC);
915
916
ATTEMPT_BUFFER_INIT(mData, aData);
917
if (!aSign) {
918
ATTEMPT_BUFFER_INIT(mSignature, aSignature);
919
}
920
921
// Check that we got a symmetric key
922
if (mSymKey.Length() == 0) {
923
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
924
return;
925
}
926
927
TelemetryAlgorithm telemetryAlg;
928
switch (mMechanism) {
929
case CKM_SHA_1_HMAC:
930
telemetryAlg = TA_HMAC_SHA_1;
931
break;
932
case CKM_SHA224_HMAC:
933
telemetryAlg = TA_HMAC_SHA_224;
934
break;
935
case CKM_SHA256_HMAC:
936
telemetryAlg = TA_HMAC_SHA_256;
937
break;
938
case CKM_SHA384_HMAC:
939
telemetryAlg = TA_HMAC_SHA_384;
940
break;
941
case CKM_SHA512_HMAC:
942
telemetryAlg = TA_HMAC_SHA_512;
943
break;
944
default:
945
telemetryAlg = TA_UNKNOWN;
946
}
947
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg);
948
}
949
950
private:
951
CK_MECHANISM_TYPE mMechanism;
952
CryptoBuffer mSymKey;
953
CryptoBuffer mData;
954
CryptoBuffer mSignature;
955
CryptoBuffer mResult;
956
bool mSign;
957
958
virtual nsresult DoCrypto() override {
959
// Initialize the output buffer
960
if (!mResult.SetLength(HASH_LENGTH_MAX, fallible)) {
961
return NS_ERROR_DOM_UNKNOWN_ERR;
962
}
963
964
UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
965
if (!arena) {
966
return NS_ERROR_DOM_OPERATION_ERR;
967
}
968
969
// Import the key
970
uint32_t outLen;
971
SECItem keyItem = {siBuffer, nullptr, 0};
972
ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
973
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
974
MOZ_ASSERT(slot.get());
975
UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism,
976
PK11_OriginUnwrap, CKA_SIGN,
977
&keyItem, nullptr));
978
if (!symKey) {
979
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
980
}
981
982
// Compute the MAC
983
SECItem param = {siBuffer, nullptr, 0};
984
UniquePK11Context ctx(
985
PK11_CreateContextBySymKey(mMechanism, CKA_SIGN, symKey.get(), &param));
986
if (!ctx.get()) {
987
return NS_ERROR_DOM_OPERATION_ERR;
988
}
989
nsresult rv = MapSECStatus(PK11_DigestBegin(ctx.get()));
990
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
991
rv = MapSECStatus(
992
PK11_DigestOp(ctx.get(), mData.Elements(), mData.Length()));
993
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
994
rv = MapSECStatus(PK11_DigestFinal(ctx.get(), mResult.Elements(), &outLen,
995
mResult.Length()));
996
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
997
998
mResult.TruncateLength(outLen);
999
return rv;
1000
}
1001
1002
// Returns mResult as an ArrayBufferView, or an error
1003
virtual void Resolve() override {
1004
if (mSign) {
1005
// Return the computed MAC
1006
TypedArrayCreator<ArrayBuffer> ret(mResult);
1007
mResultPromise->MaybeResolve(ret);
1008
} else {
1009
// Compare the MAC to the provided signature
1010
// No truncation allowed
1011
bool equal = (mResult.Length() == mSignature.Length());
1012
if (equal) {
1013
int cmp = NSS_SecureMemcmp(mSignature.Elements(), mResult.Elements(),
1014
mSignature.Length());
1015
equal = (cmp == 0);
1016
}
1017
mResultPromise->MaybeResolve(equal);
1018
}
1019
}
1020
};
1021
1022
class AsymmetricSignVerifyTask : public WebCryptoTask {
1023
public:
1024
AsymmetricSignVerifyTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
1025
CryptoKey& aKey,
1026
const CryptoOperationData& aSignature,
1027
const CryptoOperationData& aData, bool aSign)
1028
: mOidTag(SEC_OID_UNKNOWN),
1029
mHashMechanism(UNKNOWN_CK_MECHANISM),
1030
mMgfMechanism(UNKNOWN_CK_MECHANISM),
1031
mPrivKey(aKey.GetPrivateKey()),
1032
mPubKey(aKey.GetPublicKey()),
1033
mSaltLength(0),
1034
mSign(aSign),
1035
mVerified(false),
1036
mAlgorithm(Algorithm::UNKNOWN) {
1037
ATTEMPT_BUFFER_INIT(mData, aData);
1038
if (!aSign) {
1039
ATTEMPT_BUFFER_INIT(mSignature, aSignature);
1040
}
1041
1042
nsString algName;
1043
nsString hashAlgName;
1044
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
1045
if (NS_FAILED(mEarlyRv)) {
1046
return;
1047
}
1048
1049
if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
1050
mAlgorithm = Algorithm::RSA_PKCS1;
1051
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1);
1052
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1);
1053
hashAlgName = aKey.Algorithm().mRsa.mHash.mName;
1054
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
1055
mAlgorithm = Algorithm::RSA_PSS;
1056
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_PSS);
1057
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_PSS);
1058
1059
KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash;
1060
hashAlgName = hashAlg.mName;
1061
mHashMechanism = KeyAlgorithmProxy::GetMechanism(hashAlg);
1062
mMgfMechanism = MapHashAlgorithmNameToMgfMechanism(hashAlgName);
1063
1064
// Check we found appropriate mechanisms.
1065
if (mHashMechanism == UNKNOWN_CK_MECHANISM ||
1066
mMgfMechanism == UNKNOWN_CK_MECHANISM) {
1067
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1068
return;
1069
}
1070
1071
RootedDictionary<RsaPssParams> params(aCx);
1072
mEarlyRv = Coerce(aCx, params, aAlgorithm);
1073
if (NS_FAILED(mEarlyRv)) {
1074
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1075
return;
1076
}
1077
1078
mSaltLength = params.mSaltLength;
1079
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
1080
mAlgorithm = Algorithm::ECDSA;
1081
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDSA);
1082
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDSA);
1083
1084
// For ECDSA, the hash name comes from the algorithm parameter
1085
RootedDictionary<EcdsaParams> params(aCx);
1086
mEarlyRv = Coerce(aCx, params, aAlgorithm);
1087
if (NS_FAILED(mEarlyRv)) {
1088
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1089
return;
1090
}
1091
1092
mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashAlgName);
1093
if (NS_FAILED(mEarlyRv)) {
1094
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1095
return;
1096
}
1097
} else {
1098
// This shouldn't happen; CreateSignVerifyTask shouldn't create
1099
// one of these unless it's for the above algorithms.
1100
MOZ_ASSERT(false);
1101
}
1102
1103
// Must have a valid algorithm by now.
1104
MOZ_ASSERT(mAlgorithm != Algorithm::UNKNOWN);
1105
1106
// Determine hash algorithm to use.
1107
mOidTag = MapHashAlgorithmNameToOID(hashAlgName);
1108
if (mOidTag == SEC_OID_UNKNOWN) {
1109
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1110
return;
1111
}
1112
1113
// Check that we have the appropriate key
1114
if ((mSign && !mPrivKey) || (!mSign && !mPubKey)) {
1115
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
1116
return;
1117
}
1118
}
1119
1120
private:
1121
SECOidTag mOidTag;
1122
CK_MECHANISM_TYPE mHashMechanism;
1123
CK_MECHANISM_TYPE mMgfMechanism;
1124
UniqueSECKEYPrivateKey mPrivKey;
1125
UniqueSECKEYPublicKey mPubKey;
1126
CryptoBuffer mSignature;
1127
CryptoBuffer mData;
1128
uint32_t mSaltLength;
1129
bool mSign;
1130
bool mVerified;
1131
1132
// The signature algorithm to use.
1133
enum class Algorithm : uint8_t { ECDSA, RSA_PKCS1, RSA_PSS, UNKNOWN };
1134
Algorithm mAlgorithm;
1135
1136
virtual nsresult DoCrypto() override {
1137
SECStatus rv;
1138
UniqueSECItem hash(
1139
::SECITEM_AllocItem(nullptr, nullptr, HASH_ResultLenByOidTag(mOidTag)));
1140
if (!hash) {
1141
return NS_ERROR_DOM_OPERATION_ERR;
1142
}
1143
1144
// Compute digest over given data.
1145
rv = PK11_HashBuf(mOidTag, hash->data, mData.Elements(), mData.Length());
1146
NS_ENSURE_SUCCESS(MapSECStatus(rv), NS_ERROR_DOM_OPERATION_ERR);
1147
1148
// Wrap hash in a digest info template (RSA-PKCS1 only).
1149
if (mAlgorithm == Algorithm::RSA_PKCS1) {
1150
UniqueSGNDigestInfo di(
1151
SGN_CreateDigestInfo(mOidTag, hash->data, hash->len));
1152
if (!di) {
1153
return NS_ERROR_DOM_OPERATION_ERR;
1154
}
1155
1156
// Reuse |hash|.
1157
SECITEM_FreeItem(hash.get(), false);
1158
if (!SEC_ASN1EncodeItem(nullptr, hash.get(), di.get(),
1159
SGN_DigestInfoTemplate)) {
1160
return NS_ERROR_DOM_OPERATION_ERR;
1161
}
1162
}
1163
1164
SECItem* params = nullptr;
1165
CK_MECHANISM_TYPE mech =
1166
PK11_MapSignKeyType((mSign ? mPrivKey->keyType : mPubKey->keyType));
1167
1168
CK_RSA_PKCS_PSS_PARAMS rsaPssParams;
1169
SECItem rsaPssParamsItem = {
1170
siBuffer,
1171
};
1172
1173
// Set up parameters for RSA-PSS.
1174
if (mAlgorithm == Algorithm::RSA_PSS) {
1175
rsaPssParams.hashAlg = mHashMechanism;
1176
rsaPssParams.mgf = mMgfMechanism;
1177
rsaPssParams.sLen = mSaltLength;
1178
1179
rsaPssParamsItem.data = (unsigned char*)&rsaPssParams;
1180
rsaPssParamsItem.len = sizeof(rsaPssParams);
1181
params = &rsaPssParamsItem;
1182
1183
mech = CKM_RSA_PKCS_PSS;
1184
}
1185
1186
// Allocate SECItem to hold the signature.
1187
uint32_t len = mSign ? PK11_SignatureLen(mPrivKey.get()) : 0;
1188
UniqueSECItem sig(::SECITEM_AllocItem(nullptr, nullptr, len));
1189
if (!sig) {
1190
return NS_ERROR_DOM_OPERATION_ERR;
1191
}
1192
1193
if (mSign) {
1194
// Sign the hash.
1195
rv = PK11_SignWithMechanism(mPrivKey.get(), mech, params, sig.get(),
1196
hash.get());
1197
NS_ENSURE_SUCCESS(MapSECStatus(rv), NS_ERROR_DOM_OPERATION_ERR);
1198
ATTEMPT_BUFFER_ASSIGN(mSignature, sig.get());
1199
} else {
1200
// Copy the given signature to the SECItem.
1201
if (!mSignature.ToSECItem(nullptr, sig.get())) {
1202
return NS_ERROR_DOM_OPERATION_ERR;
1203
}
1204
1205
// Verify the signature.
1206
rv = PK11_VerifyWithMechanism(mPubKey.get(), mech, params, sig.get(),
1207
hash.get(), nullptr);
1208
mVerified = NS_SUCCEEDED(MapSECStatus(rv));
1209
}
1210
1211
return NS_OK;
1212
}
1213
1214
virtual void Resolve() override {
1215
if (mSign) {
1216
TypedArrayCreator<ArrayBuffer> ret(mSignature);
1217
mResultPromise->MaybeResolve(ret);
1218
} else {
1219
mResultPromise->MaybeResolve(mVerified);
1220
}
1221
}
1222
};
1223
1224
class DigestTask : public ReturnArrayBufferViewTask {
1225
public:
1226
DigestTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
1227
const CryptoOperationData& aData) {
1228
ATTEMPT_BUFFER_INIT(mData, aData);
1229
1230
nsString algName;
1231
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
1232
if (NS_FAILED(mEarlyRv)) {
1233
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1234
return;
1235
}
1236
1237
TelemetryAlgorithm telemetryAlg;
1238
if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
1239
telemetryAlg = TA_SHA_1;
1240
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
1241
telemetryAlg = TA_SHA_224;
1242
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
1243
telemetryAlg = TA_SHA_256;
1244
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
1245
telemetryAlg = TA_SHA_384;
1246
} else {
1247
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1248
return;
1249
}
1250
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg);
1251
mOidTag = MapHashAlgorithmNameToOID(algName);
1252
}
1253
1254
private:
1255
SECOidTag mOidTag;
1256
CryptoBuffer mData;
1257
1258
virtual nsresult DoCrypto() override {
1259
// Resize the result buffer
1260
uint32_t hashLen = HASH_ResultLenByOidTag(mOidTag);
1261
if (!mResult.SetLength(hashLen, fallible)) {
1262
return NS_ERROR_DOM_UNKNOWN_ERR;
1263
}
1264
1265
// Compute the hash
1266
nsresult rv = MapSECStatus(PK11_HashBuf(mOidTag, mResult.Elements(),
1267
mData.Elements(), mData.Length()));
1268
if (NS_FAILED(rv)) {
1269
return NS_ERROR_DOM_UNKNOWN_ERR;
1270
}
1271
1272
return rv;
1273
}
1274
};
1275
1276
class ImportKeyTask : public WebCryptoTask {
1277
public:
1278
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1279
const ObjectOrString& aAlgorithm, bool aExtractable,
1280
const Sequence<nsString>& aKeyUsages) {
1281
mFormat = aFormat;
1282
mDataIsSet = false;
1283
mDataIsJwk = false;
1284
1285
// This stuff pretty much always happens, so we'll do it here
1286
mKey = new CryptoKey(aGlobal);
1287
mKey->SetExtractable(aExtractable);
1288
mKey->ClearUsages();
1289
for (uint32_t i = 0; i < aKeyUsages.Length(); ++i) {
1290
mEarlyRv = mKey->AddUsage(aKeyUsages[i]);
1291
if (NS_FAILED(mEarlyRv)) {
1292
return;
1293
}
1294
}
1295
1296
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, mAlgName);
1297
if (NS_FAILED(mEarlyRv)) {
1298
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1299
return;
1300
}
1301
}
1302
1303
static bool JwkCompatible(const JsonWebKey& aJwk, const CryptoKey* aKey) {
1304
// Check 'ext'
1305
if (aKey->Extractable() && aJwk.mExt.WasPassed() && !aJwk.mExt.Value()) {
1306
return false;
1307
}
1308
1309
// Check 'alg'
1310
if (aJwk.mAlg.WasPassed() &&
1311
aJwk.mAlg.Value() != aKey->Algorithm().JwkAlg()) {
1312
return false;
1313
}
1314
1315
// Check 'key_ops'
1316
if (aJwk.mKey_ops.WasPassed()) {
1317
nsTArray<nsString> usages;
1318
aKey->GetUsages(usages);
1319
for (size_t i = 0; i < usages.Length(); ++i) {
1320
if (!aJwk.mKey_ops.Value().Contains(usages[i])) {
1321
return false;
1322
}
1323
}
1324
}
1325
1326
// Individual algorithms may still have to check 'use'
1327
return true;
1328
}
1329
1330
void SetKeyData(JSContext* aCx, JS::Handle<JSObject*> aKeyData) {
1331
mDataIsJwk = false;
1332
1333
// Try ArrayBuffer
1334
RootedSpiderMonkeyInterface<ArrayBuffer> ab(aCx);
1335
if (ab.Init(aKeyData)) {
1336
if (!mKeyData.Assign(ab)) {
1337
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1338
}
1339
return;
1340
}
1341
1342
// Try ArrayBufferView
1343
RootedSpiderMonkeyInterface<ArrayBufferView> abv(aCx);
1344
if (abv.Init(aKeyData)) {
1345
if (!mKeyData.Assign(abv)) {
1346
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1347
}
1348
return;
1349
}
1350
1351
// Try JWK
1352
ClearException ce(aCx);
1353
JS::RootedValue value(aCx, JS::ObjectValue(*aKeyData));
1354
if (!mJwk.Init(aCx, value)) {
1355
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1356
return;
1357
}
1358
1359
mDataIsJwk = true;
1360
}
1361
1362
void SetKeyDataMaybeParseJWK(const CryptoBuffer& aKeyData) {
1363
if (!mKeyData.Assign(aKeyData)) {
1364
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1365
return;
1366
}
1367
1368
mDataIsJwk = false;
1369
1370
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1371
nsDependentCSubstring utf8(
1372
(const char*)mKeyData.Elements(),
1373
(const char*)(mKeyData.Elements() + mKeyData.Length()));
1374
if (!IsUtf8(utf8)) {
1375
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1376
return;
1377
}
1378
1379
nsString json = NS_ConvertUTF8toUTF16(utf8);
1380
if (!mJwk.Init(json)) {
1381
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1382
return;
1383
}
1384
1385
mDataIsJwk = true;
1386
}
1387
}
1388
1389
void SetRawKeyData(const CryptoBuffer& aKeyData) {
1390
if (!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1391
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1392
return;
1393
}
1394
1395
if (!mKeyData.Assign(aKeyData)) {
1396
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1397
return;
1398
}
1399
1400
mDataIsJwk = false;
1401
}
1402
1403
protected:
1404
nsString mFormat;
1405
RefPtr<CryptoKey> mKey;
1406
CryptoBuffer mKeyData;
1407
bool mDataIsSet;
1408
bool mDataIsJwk;
1409
JsonWebKey mJwk;
1410
nsString mAlgName;
1411
1412
private:
1413
virtual void Resolve() override { mResultPromise->MaybeResolve(mKey); }
1414
1415
virtual void Cleanup() override { mKey = nullptr; }
1416
};
1417
1418
class ImportSymmetricKeyTask : public ImportKeyTask {
1419
public:
1420
ImportSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1421
const nsAString& aFormat,
1422
const ObjectOrString& aAlgorithm, bool aExtractable,
1423
const Sequence<nsString>& aKeyUsages) {
1424
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1425
}
1426
1427
ImportSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1428
const nsAString& aFormat,
1429
const JS::Handle<JSObject*> aKeyData,
1430
const ObjectOrString& aAlgorithm, bool aExtractable,
1431
const Sequence<nsString>& aKeyUsages) {
1432
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1433
if (NS_FAILED(mEarlyRv)) {
1434
return;
1435
}
1436
1437
SetKeyData(aCx, aKeyData);
1438
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
1439
if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1440
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1441
return;
1442
}
1443
}
1444
1445
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1446
const ObjectOrString& aAlgorithm, bool aExtractable,
1447
const Sequence<nsString>& aKeyUsages) {
1448
ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable,
1449
aKeyUsages);
1450
if (NS_FAILED(mEarlyRv)) {
1451
return;
1452
}
1453
1454
// This task only supports raw and JWK format.
1455
if (!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1456
!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1457
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1458
return;
1459
}
1460
1461
// If this is an HMAC key, import the hash name
1462
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
1463
RootedDictionary<HmacImportParams> params(aCx);
1464
mEarlyRv = Coerce(aCx, params, aAlgorithm);
1465
if (NS_FAILED(mEarlyRv)) {
1466
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1467
return;
1468
}
1469
mEarlyRv = GetAlgorithmName(aCx, params.mHash, mHashName);
1470
if (NS_FAILED(mEarlyRv)) {
1471
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1472
return;
1473
}
1474
}
1475
}
1476
1477
virtual nsresult BeforeCrypto() override {
1478
nsresult rv;
1479
1480
// If we're doing a JWK import, import the key data
1481
if (mDataIsJwk) {
1482
if (!mJwk.mK.WasPassed()) {
1483
return NS_ERROR_DOM_DATA_ERR;
1484
}
1485
1486
// Import the key material
1487
rv = mKeyData.FromJwkBase64(mJwk.mK.Value());
1488
if (NS_FAILED(rv)) {
1489
return NS_ERROR_DOM_DATA_ERR;
1490
}
1491
}
1492
// Check that we have valid key data.
1493
if (mKeyData.Length() == 0 &&
1494
!mAlgName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
1495
return NS_ERROR_DOM_DATA_ERR;
1496
}
1497
1498
// Construct an appropriate KeyAlorithm,
1499
// and verify that usages are appropriate
1500
uint32_t length = 8 * mKeyData.Length(); // bytes to bits
1501
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
1502
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
1503
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
1504
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
1505
if (mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::DECRYPT |
1506
CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) {
1507
return NS_ERROR_DOM_DATA_ERR;
1508
}
1509
1510
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) &&
1511
mKey->HasUsageOtherThan(CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) {
1512
return NS_ERROR_DOM_DATA_ERR;
1513
}
1514
1515
if ((length != 128) && (length != 192) && (length != 256)) {
1516
return NS_ERROR_DOM_DATA_ERR;
1517
}
1518
mKey->Algorithm().MakeAes(mAlgName, length);
1519
1520
if (mDataIsJwk && mJwk.mUse.WasPassed() &&
1521
!mJwk.mUse.Value().EqualsLiteral(JWK_USE_ENC)) {
1522
return NS_ERROR_DOM_DATA_ERR;
1523
}
1524
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HKDF) ||
1525
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
1526
if (mKey->HasUsageOtherThan(CryptoKey::DERIVEKEY |
1527
CryptoKey::DERIVEBITS)) {
1528
return NS_ERROR_DOM_DATA_ERR;
1529
}
1530
mKey->Algorithm().MakeAes(mAlgName, length);
1531
1532
if (mDataIsJwk && mJwk.mUse.WasPassed()) {
1533
// There is not a 'use' value consistent with PBKDF or HKDF
1534
return NS_ERROR_DOM_DATA_ERR;
1535
};
1536
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
1537
if (mKey->HasUsageOtherThan(CryptoKey::SIGN | CryptoKey::VERIFY)) {
1538
return NS_ERROR_DOM_DATA_ERR;
1539
}
1540
1541
mKey->Algorithm().MakeHmac(length, mHashName);
1542
1543
if (mKey->Algorithm().Mechanism() == UNKNOWN_CK_MECHANISM) {
1544
return NS_ERROR_DOM_SYNTAX_ERR;
1545
}
1546
1547
if (mDataIsJwk && mJwk.mUse.WasPassed() &&
1548
!mJwk.mUse.Value().EqualsLiteral(JWK_USE_SIG)) {
1549
return NS_ERROR_DOM_DATA_ERR;
1550
}
1551
} else {
1552
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1553
}
1554
1555
if (NS_FAILED(mKey->SetSymKey(mKeyData))) {
1556
return NS_ERROR_DOM_OPERATION_ERR;
1557
}
1558
1559
mKey->SetType(CryptoKey::SECRET);
1560
1561
if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) {
1562
return NS_ERROR_DOM_DATA_ERR;
1563
}
1564
1565
mEarlyComplete = true;
1566
return NS_OK;
1567
}
1568
1569
private:
1570
nsString mHashName;
1571
};
1572
1573
class ImportRsaKeyTask : public ImportKeyTask {
1574
public:
1575
ImportRsaKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1576
const nsAString& aFormat, const ObjectOrString& aAlgorithm,
1577
bool aExtractable, const Sequence<nsString>& aKeyUsages)
1578
: mModulusLength(0) {
1579
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1580
}
1581
1582
ImportRsaKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1583
const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
1584
const ObjectOrString& aAlgorithm, bool aExtractable,
1585
const Sequence<nsString>& aKeyUsages)
1586
: mModulusLength(0) {
1587
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1588
if (NS_FAILED(mEarlyRv)) {
1589
return;
1590
}
1591
1592
SetKeyData(aCx, aKeyData);
1593
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
1594
if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1595
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1596
return;
1597
}
1598
}
1599
1600
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1601
const ObjectOrString& aAlgorithm, bool aExtractable,
1602
const Sequence<nsString>& aKeyUsages) {
1603
ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable,
1604
aKeyUsages);
1605
if (NS_FAILED(mEarlyRv)) {
1606
return;
1607
}
1608
1609
// If this is RSA with a hash, cache the hash name
1610
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
1611
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
1612
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
1613
RootedDictionary<RsaHashedImportParams> params(aCx);
1614
mEarlyRv = Coerce(aCx, params, aAlgorithm);
1615
if (NS_FAILED(mEarlyRv)) {
1616
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1617
return;
1618
}
1619
1620
mEarlyRv = GetAlgorithmName(aCx, params.mHash, mHashName);
1621
if (NS_FAILED(mEarlyRv)) {
1622
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1623
return;
1624
}
1625
}
1626
1627
// Check support for the algorithm and hash names
1628
CK_MECHANISM_TYPE mech1 = MapAlgorithmNameToMechanism(mAlgName);
1629
CK_MECHANISM_TYPE mech2 = MapAlgorithmNameToMechanism(mHashName);
1630
if ((mech1 == UNKNOWN_CK_MECHANISM) || (mech2 == UNKNOWN_CK_MECHANISM)) {
1631
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1632
return;
1633
}
1634
}
1635
1636
private:
1637
nsString mHashName;
1638
uint32_t mModulusLength;
1639
CryptoBuffer mPublicExponent;
1640
1641
virtual nsresult DoCrypto() override {
1642
// Import the key data itself
1643
UniqueSECKEYPublicKey pubKey;
1644
UniqueSECKEYPrivateKey privKey;
1645
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) ||
1646
(mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1647
!mJwk.mD.WasPassed())) {
1648
// Public key import
1649
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
1650
pubKey = CryptoKey::PublicKeyFromSpki(mKeyData);
1651
} else {
1652
pubKey = CryptoKey::PublicKeyFromJwk(mJwk);
1653
}
1654
1655
if (!pubKey) {
1656
return NS_ERROR_DOM_DATA_ERR;
1657
}
1658
1659
if (NS_FAILED(mKey->SetPublicKey(pubKey.get()))) {
1660
return NS_ERROR_DOM_OPERATION_ERR;
1661
}
1662
1663
mKey->SetType(CryptoKey::PUBLIC);
1664
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) ||
1665
(mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1666
mJwk.mD.WasPassed())) {
1667
// Private key import
1668
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8)) {
1669
privKey = CryptoKey::PrivateKeyFromPkcs8(mKeyData);
1670
} else {
1671
privKey = CryptoKey::PrivateKeyFromJwk(mJwk);
1672
}
1673
1674
if (!privKey) {
1675
return NS_ERROR_DOM_DATA_ERR;
1676
}
1677
1678
if (NS_FAILED(mKey->SetPrivateKey(privKey.get()))) {
1679
return NS_ERROR_DOM_OPERATION_ERR;
1680
}
1681
1682
mKey->SetType(CryptoKey::PRIVATE);
1683
pubKey = UniqueSECKEYPublicKey(SECKEY_ConvertToPublicKey(privKey.get()));
1684
if (!pubKey) {
1685
return NS_ERROR_DOM_UNKNOWN_ERR;
1686
}
1687
} else {
1688
// Invalid key format
1689
return NS_ERROR_DOM_SYNTAX_ERR;
1690
}
1691
1692
// Extract relevant information from the public key
1693
mModulusLength = 8 * pubKey->u.rsa.modulus.len;
1694
if (!mPublicExponent.Assign(&pubKey->u.rsa.publicExponent)) {
1695
return NS_ERROR_DOM_OPERATION_ERR;
1696
}
1697
1698
return NS_OK;
1699
}
1700
1701
virtual nsresult AfterCrypto() override {
1702
// Check permissions for the requested operation
1703
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
1704
if ((mKey->GetKeyType() == CryptoKey::PUBLIC &&
1705
mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::WRAPKEY)) ||
1706
(mKey->GetKeyType() == CryptoKey::PRIVATE &&
1707
mKey->HasUsageOtherThan(CryptoKey::DECRYPT |
1708
CryptoKey::UNWRAPKEY))) {
1709
return NS_ERROR_DOM_DATA_ERR;
1710
}
1711
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
1712
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
1713
if ((mKey->GetKeyType() == CryptoKey::PUBLIC &&
1714
mKey->HasUsageOtherThan(CryptoKey::VERIFY)) ||
1715
(mKey->GetKeyType() == CryptoKey::PRIVATE &&
1716
mKey->HasUsageOtherThan(CryptoKey::SIGN))) {
1717
return NS_ERROR_DOM_DATA_ERR;
1718
}
1719
}
1720
1721
// Set an appropriate KeyAlgorithm
1722
if (!mKey->Algorithm().MakeRsa(mAlgName, mModulusLength, mPublicExponent,
1723
mHashName)) {
1724
return NS_ERROR_DOM_OPERATION_ERR;
1725
}
1726
1727
if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) {
1728
return NS_ERROR_DOM_DATA_ERR;
1729
}
1730
1731
return NS_OK;
1732
}
1733
};
1734
1735
class ImportEcKeyTask : public ImportKeyTask {
1736
public:
1737
ImportEcKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1738
const nsAString& aFormat, const ObjectOrString& aAlgorithm,
1739
bool aExtractable, const Sequence<nsString>& aKeyUsages) {
1740
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1741
}
1742
1743
ImportEcKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1744
const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
1745
const ObjectOrString& aAlgorithm, bool aExtractable,
1746
const Sequence<nsString>& aKeyUsages) {
1747
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1748
if (NS_FAILED(mEarlyRv)) {
1749
return;
1750
}
1751
1752
SetKeyData(aCx, aKeyData);
1753
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
1754
}
1755
1756
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1757
const ObjectOrString& aAlgorithm, bool aExtractable,
1758
const Sequence<nsString>& aKeyUsages) {
1759
ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable,
1760
aKeyUsages);
1761
if (NS_FAILED(mEarlyRv)) {
1762
return;
1763
}
1764
1765
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1766
RootedDictionary<EcKeyImportParams> params(aCx);
1767
mEarlyRv = Coerce(aCx, params, aAlgorithm);
1768
if (NS_FAILED(mEarlyRv) || !params.mNamedCurve.WasPassed()) {
1769
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1770
return;
1771
}
1772
1773
if (!NormalizeToken(params.mNamedCurve.Value(), mNamedCurve)) {
1774
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1775
return;
1776
}
1777
}
1778
}
1779
1780
private:
1781
nsString mNamedCurve;
1782
1783
virtual nsresult DoCrypto() override {
1784
// Import the key data itself
1785
UniqueSECKEYPublicKey pubKey;
1786
UniqueSECKEYPrivateKey privKey;
1787
1788
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1789
mJwk.mD.WasPassed()) {
1790
// Private key import
1791
privKey = CryptoKey::PrivateKeyFromJwk(mJwk);
1792
if (!privKey) {
1793
return NS_ERROR_DOM_DATA_ERR;
1794
}
1795
1796
if (NS_FAILED(mKey->SetPrivateKey(privKey.get()))) {
1797
return NS_ERROR_DOM_OPERATION_ERR;
1798
}
1799
1800
mKey->SetType(CryptoKey::PRIVATE);
1801
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) ||
1802
mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) ||
1803
(mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1804
!mJwk.mD.WasPassed())) {
1805
// Public key import
1806
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1807
pubKey = CryptoKey::PublicECKeyFromRaw(mKeyData, mNamedCurve);
1808
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
1809
pubKey = CryptoKey::PublicKeyFromSpki(mKeyData);
1810
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1811
pubKey = CryptoKey::PublicKeyFromJwk(mJwk);
1812
} else {
1813
MOZ_ASSERT(false);
1814
}
1815
1816
if