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.ulIvBits = gcmParams.ulIvLen * 8;
604
gcmParams.pAAD = mAad.Elements();
605
gcmParams.ulAADLen = mAad.Length();
606
gcmParams.ulTagBits = mTagLength;
607
param.type = siBuffer;
608
param.data = (unsigned char*)&gcmParams;
609
param.len = sizeof(gcmParams);
610
break;
611
default:
612
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
613
}
614
615
// Import the key
616
SECItem keyItem = {siBuffer, nullptr, 0};
617
ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
618
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
619
MOZ_ASSERT(slot.get());
620
UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism,
621
PK11_OriginUnwrap, CKA_ENCRYPT,
622
&keyItem, nullptr));
623
if (!symKey) {
624
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
625
}
626
627
// Check whether the integer addition would overflow.
628
if (std::numeric_limits<CryptoBuffer::size_type>::max() - 16 <
629
mData.Length()) {
630
return NS_ERROR_DOM_DATA_ERR;
631
}
632
633
// Initialize the output buffer (enough space for padding / a full tag)
634
if (!mResult.SetLength(mData.Length() + 16, fallible)) {
635
return NS_ERROR_DOM_UNKNOWN_ERR;
636
}
637
638
uint32_t outLen = 0;
639
640
// Perform the encryption/decryption
641
if (mEncrypt) {
642
rv = MapSECStatus(PK11_Encrypt(
643
symKey.get(), mMechanism, &param, mResult.Elements(), &outLen,
644
mResult.Length(), mData.Elements(), mData.Length()));
645
} else {
646
rv = MapSECStatus(PK11_Decrypt(
647
symKey.get(), mMechanism, &param, mResult.Elements(), &outLen,
648
mResult.Length(), mData.Elements(), mData.Length()));
649
}
650
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
651
652
mResult.TruncateLength(outLen);
653
return rv;
654
}
655
};
656
657
// This class looks like an encrypt/decrypt task, like AesTask,
658
// but it is only exposed to wrapKey/unwrapKey, not encrypt/decrypt
659
class AesKwTask : public ReturnArrayBufferViewTask, public DeferredData {
660
public:
661
AesKwTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
662
bool aEncrypt)
663
: mMechanism(CKM_NSS_AES_KEY_WRAP),
664
mSymKey(aKey.GetSymKey()),
665
mEncrypt(aEncrypt) {
666
Init(aCx, aAlgorithm, aKey, aEncrypt);
667
}
668
669
AesKwTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
670
const CryptoOperationData& aData, bool aEncrypt)
671
: mMechanism(CKM_NSS_AES_KEY_WRAP),
672
mSymKey(aKey.GetSymKey()),
673
mEncrypt(aEncrypt) {
674
Init(aCx, aAlgorithm, aKey, aEncrypt);
675
SetData(aData);
676
}
677
678
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
679
bool aEncrypt) {
680
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_KW);
681
682
nsString algName;
683
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
684
if (NS_FAILED(mEarlyRv)) {
685
return;
686
}
687
688
// Check that we got a reasonable key
689
if ((mSymKey.Length() != 16) && (mSymKey.Length() != 24) &&
690
(mSymKey.Length() != 32)) {
691
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
692
return;
693
}
694
695
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_AES_KW);
696
}
697
698
private:
699
CK_MECHANISM_TYPE mMechanism;
700
CryptoBuffer mSymKey;
701
bool mEncrypt;
702
703
virtual nsresult DoCrypto() override {
704
nsresult rv;
705
706
if (!mDataIsSet) {
707
return NS_ERROR_DOM_OPERATION_ERR;
708
}
709
710
// Check that the input is a multiple of 64 bits long
711
if (mData.Length() == 0 || mData.Length() % 8 != 0) {
712
return NS_ERROR_DOM_DATA_ERR;
713
}
714
715
UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
716
if (!arena) {
717
return NS_ERROR_DOM_OPERATION_ERR;
718
}
719
720
// Import the key
721
SECItem keyItem = {siBuffer, nullptr, 0};
722
ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
723
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
724
MOZ_ASSERT(slot.get());
725
UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism,
726
PK11_OriginUnwrap, CKA_WRAP,
727
&keyItem, nullptr));
728
if (!symKey) {
729
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
730
}
731
732
// Import the data to a SECItem
733
SECItem dataItem = {siBuffer, nullptr, 0};
734
ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &dataItem, mData);
735
736
// Parameters for the fake keys
737
CK_MECHANISM_TYPE fakeMechanism = CKM_SHA_1_HMAC;
738
CK_ATTRIBUTE_TYPE fakeOperation = CKA_SIGN;
739
740
if (mEncrypt) {
741
// Import the data into a fake PK11SymKey structure
742
UniquePK11SymKey keyToWrap(
743
PK11_ImportSymKey(slot.get(), fakeMechanism, PK11_OriginUnwrap,
744
fakeOperation, &dataItem, nullptr));
745
if (!keyToWrap) {
746
return NS_ERROR_DOM_OPERATION_ERR;
747
}
748
749
// Encrypt and return the wrapped key
750
// AES-KW encryption results in a wrapped key 64 bits longer
751
if (!mResult.SetLength(mData.Length() + 8, fallible)) {
752
return NS_ERROR_DOM_OPERATION_ERR;
753
}
754
SECItem resultItem = {siBuffer, mResult.Elements(),
755
(unsigned int)mResult.Length()};
756
rv = MapSECStatus(PK11_WrapSymKey(mMechanism, nullptr, symKey.get(),
757
keyToWrap.get(), &resultItem));
758
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
759
} else {
760
// Decrypt the ciphertext into a temporary PK11SymKey
761
// Unwrapped key should be 64 bits shorter
762
int keySize = mData.Length() - 8;
763
UniquePK11SymKey unwrappedKey(
764
PK11_UnwrapSymKey(symKey.get(), mMechanism, nullptr, &dataItem,
765
fakeMechanism, fakeOperation, keySize));
766
if (!unwrappedKey) {
767
return NS_ERROR_DOM_OPERATION_ERR;
768
}
769
770
// Export the key to get the cleartext
771
rv = MapSECStatus(PK11_ExtractKeyValue(unwrappedKey.get()));
772
if (NS_FAILED(rv)) {
773
return NS_ERROR_DOM_UNKNOWN_ERR;
774
}
775
ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(unwrappedKey.get()));
776
}
777
778
return rv;
779
}
780
};
781
782
class RsaOaepTask : public ReturnArrayBufferViewTask, public DeferredData {
783
public:
784
RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
785
bool aEncrypt)
786
: mPrivKey(aKey.GetPrivateKey()),
787
mPubKey(aKey.GetPublicKey()),
788
mEncrypt(aEncrypt) {
789
Init(aCx, aAlgorithm, aKey, aEncrypt);
790
}
791
792
RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
793
const CryptoOperationData& aData, bool aEncrypt)
794
: mPrivKey(aKey.GetPrivateKey()),
795
mPubKey(aKey.GetPublicKey()),
796
mEncrypt(aEncrypt) {
797
Init(aCx, aAlgorithm, aKey, aEncrypt);
798
SetData(aData);
799
}
800
801
void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
802
bool aEncrypt) {
803
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_OAEP);
804
805
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_OAEP);
806
807
if (mEncrypt) {
808
if (!mPubKey) {
809
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
810
return;
811
}
812
mStrength = SECKEY_PublicKeyStrength(mPubKey.get());
813
} else {
814
if (!mPrivKey) {
815
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
816
return;
817
}
818
mStrength = PK11_GetPrivateModulusLen(mPrivKey.get());
819
}
820
821
// The algorithm could just be given as a string
822
// in which case there would be no label specified.
823
if (!aAlgorithm.IsString()) {
824
RootedDictionary<RsaOaepParams> params(aCx);
825
mEarlyRv = Coerce(aCx, params, aAlgorithm);
826
if (NS_FAILED(mEarlyRv)) {
827
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
828
return;
829
}
830
831
if (params.mLabel.WasPassed()) {
832
ATTEMPT_BUFFER_INIT(mLabel, params.mLabel.Value());
833
}
834
}
835
// Otherwise mLabel remains the empty octet string, as intended
836
837
KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash;
838
mHashMechanism = KeyAlgorithmProxy::GetMechanism(hashAlg);
839
mMgfMechanism = MapHashAlgorithmNameToMgfMechanism(hashAlg.mName);
840
841
// Check we found appropriate mechanisms.
842
if (mHashMechanism == UNKNOWN_CK_MECHANISM ||
843
mMgfMechanism == UNKNOWN_CK_MECHANISM) {
844
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
845
return;
846
}
847
}
848
849
private:
850
CK_MECHANISM_TYPE mHashMechanism;
851
CK_MECHANISM_TYPE mMgfMechanism;
852
UniqueSECKEYPrivateKey mPrivKey;
853
UniqueSECKEYPublicKey mPubKey;
854
CryptoBuffer mLabel;
855
uint32_t mStrength;
856
bool mEncrypt;
857
858
virtual nsresult DoCrypto() override {
859
nsresult rv;
860
861
if (!mDataIsSet) {
862
return NS_ERROR_DOM_OPERATION_ERR;
863
}
864
865
// Ciphertext is an integer mod the modulus, so it will be
866
// no longer than mStrength octets
867
if (!mResult.SetLength(mStrength, fallible)) {
868
return NS_ERROR_DOM_UNKNOWN_ERR;
869
}
870
871
CK_RSA_PKCS_OAEP_PARAMS oaepParams;
872
oaepParams.source = CKZ_DATA_SPECIFIED;
873
874
oaepParams.pSourceData = mLabel.Length() ? mLabel.Elements() : nullptr;
875
oaepParams.ulSourceDataLen = mLabel.Length();
876
877
oaepParams.mgf = mMgfMechanism;
878
oaepParams.hashAlg = mHashMechanism;
879
880
SECItem param;
881
param.type = siBuffer;
882
param.data = (unsigned char*)&oaepParams;
883
param.len = sizeof(oaepParams);
884
885
uint32_t outLen = 0;
886
if (mEncrypt) {
887
// PK11_PubEncrypt() checks the plaintext's length and fails if it is too
888
// long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
889
// being the length in octets of the RSA modulus n and 'hLen' being the
890
// output length in octets of the chosen hash function.
892
rv = MapSECStatus(PK11_PubEncrypt(
893
mPubKey.get(), CKM_RSA_PKCS_OAEP, &param, mResult.Elements(), &outLen,
894
mResult.Length(), mData.Elements(), mData.Length(), nullptr));
895
} else {
896
rv = MapSECStatus(PK11_PrivDecrypt(
897
mPrivKey.get(), CKM_RSA_PKCS_OAEP, &param, mResult.Elements(),
898
&outLen, mResult.Length(), mData.Elements(), mData.Length()));
899
}
900
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
901
902
mResult.TruncateLength(outLen);
903
return NS_OK;
904
}
905
};
906
907
class HmacTask : public WebCryptoTask {
908
public:
909
HmacTask(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
910
const CryptoOperationData& aSignature,
911
const CryptoOperationData& aData, bool aSign)
912
: mMechanism(aKey.Algorithm().Mechanism()),
913
mSymKey(aKey.GetSymKey()),
914
mSign(aSign) {
915
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_HMAC);
916
917
ATTEMPT_BUFFER_INIT(mData, aData);
918
if (!aSign) {
919
ATTEMPT_BUFFER_INIT(mSignature, aSignature);
920
}
921
922
// Check that we got a symmetric key
923
if (mSymKey.Length() == 0) {
924
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
925
return;
926
}
927
928
TelemetryAlgorithm telemetryAlg;
929
switch (mMechanism) {
930
case CKM_SHA_1_HMAC:
931
telemetryAlg = TA_HMAC_SHA_1;
932
break;
933
case CKM_SHA224_HMAC:
934
telemetryAlg = TA_HMAC_SHA_224;
935
break;
936
case CKM_SHA256_HMAC:
937
telemetryAlg = TA_HMAC_SHA_256;
938
break;
939
case CKM_SHA384_HMAC:
940
telemetryAlg = TA_HMAC_SHA_384;
941
break;
942
case CKM_SHA512_HMAC:
943
telemetryAlg = TA_HMAC_SHA_512;
944
break;
945
default:
946
telemetryAlg = TA_UNKNOWN;
947
}
948
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg);
949
}
950
951
private:
952
CK_MECHANISM_TYPE mMechanism;
953
CryptoBuffer mSymKey;
954
CryptoBuffer mData;
955
CryptoBuffer mSignature;
956
CryptoBuffer mResult;
957
bool mSign;
958
959
virtual nsresult DoCrypto() override {
960
// Initialize the output buffer
961
if (!mResult.SetLength(HASH_LENGTH_MAX, fallible)) {
962
return NS_ERROR_DOM_UNKNOWN_ERR;
963
}
964
965
UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
966
if (!arena) {
967
return NS_ERROR_DOM_OPERATION_ERR;
968
}
969
970
// Import the key
971
uint32_t outLen;
972
SECItem keyItem = {siBuffer, nullptr, 0};
973
ATTEMPT_BUFFER_TO_SECITEM(arena.get(), &keyItem, mSymKey);
974
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
975
MOZ_ASSERT(slot.get());
976
UniquePK11SymKey symKey(PK11_ImportSymKey(slot.get(), mMechanism,
977
PK11_OriginUnwrap, CKA_SIGN,
978
&keyItem, nullptr));
979
if (!symKey) {
980
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
981
}
982
983
// Compute the MAC
984
SECItem param = {siBuffer, nullptr, 0};
985
UniquePK11Context ctx(
986
PK11_CreateContextBySymKey(mMechanism, CKA_SIGN, symKey.get(), &param));
987
if (!ctx.get()) {
988
return NS_ERROR_DOM_OPERATION_ERR;
989
}
990
nsresult rv = MapSECStatus(PK11_DigestBegin(ctx.get()));
991
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
992
rv = MapSECStatus(
993
PK11_DigestOp(ctx.get(), mData.Elements(), mData.Length()));
994
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
995
rv = MapSECStatus(PK11_DigestFinal(ctx.get(), mResult.Elements(), &outLen,
996
mResult.Length()));
997
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
998
999
mResult.TruncateLength(outLen);
1000
return rv;
1001
}
1002
1003
// Returns mResult as an ArrayBufferView, or an error
1004
virtual void Resolve() override {
1005
if (mSign) {
1006
// Return the computed MAC
1007
TypedArrayCreator<ArrayBuffer> ret(mResult);
1008
mResultPromise->MaybeResolve(ret);
1009
} else {
1010
// Compare the MAC to the provided signature
1011
// No truncation allowed
1012
bool equal = (mResult.Length() == mSignature.Length());
1013
if (equal) {
1014
int cmp = NSS_SecureMemcmp(mSignature.Elements(), mResult.Elements(),
1015
mSignature.Length());
1016
equal = (cmp == 0);
1017
}
1018
mResultPromise->MaybeResolve(equal);
1019
}
1020
}
1021
};
1022
1023
class AsymmetricSignVerifyTask : public WebCryptoTask {
1024
public:
1025
AsymmetricSignVerifyTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
1026
CryptoKey& aKey,
1027
const CryptoOperationData& aSignature,
1028
const CryptoOperationData& aData, bool aSign)
1029
: mOidTag(SEC_OID_UNKNOWN),
1030
mHashMechanism(UNKNOWN_CK_MECHANISM),
1031
mMgfMechanism(UNKNOWN_CK_MECHANISM),
1032
mPrivKey(aKey.GetPrivateKey()),
1033
mPubKey(aKey.GetPublicKey()),
1034
mSaltLength(0),
1035
mSign(aSign),
1036
mVerified(false),
1037
mAlgorithm(Algorithm::UNKNOWN) {
1038
ATTEMPT_BUFFER_INIT(mData, aData);
1039
if (!aSign) {
1040
ATTEMPT_BUFFER_INIT(mSignature, aSignature);
1041
}
1042
1043
nsString algName;
1044
nsString hashAlgName;
1045
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
1046
if (NS_FAILED(mEarlyRv)) {
1047
return;
1048
}
1049
1050
if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
1051
mAlgorithm = Algorithm::RSA_PKCS1;
1052
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSASSA_PKCS1);
1053
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSASSA_PKCS1);
1054
hashAlgName = aKey.Algorithm().mRsa.mHash.mName;
1055
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
1056
mAlgorithm = Algorithm::RSA_PSS;
1057
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_PSS);
1058
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSA_PSS);
1059
1060
KeyAlgorithm& hashAlg = aKey.Algorithm().mRsa.mHash;
1061
hashAlgName = hashAlg.mName;
1062
mHashMechanism = KeyAlgorithmProxy::GetMechanism(hashAlg);
1063
mMgfMechanism = MapHashAlgorithmNameToMgfMechanism(hashAlgName);
1064
1065
// Check we found appropriate mechanisms.
1066
if (mHashMechanism == UNKNOWN_CK_MECHANISM ||
1067
mMgfMechanism == UNKNOWN_CK_MECHANISM) {
1068
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1069
return;
1070
}
1071
1072
RootedDictionary<RsaPssParams> params(aCx);
1073
mEarlyRv = Coerce(aCx, params, aAlgorithm);
1074
if (NS_FAILED(mEarlyRv)) {
1075
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1076
return;
1077
}
1078
1079
mSaltLength = params.mSaltLength;
1080
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
1081
mAlgorithm = Algorithm::ECDSA;
1082
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_ECDSA);
1083
CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_ECDSA);
1084
1085
// For ECDSA, the hash name comes from the algorithm parameter
1086
RootedDictionary<EcdsaParams> params(aCx);
1087
mEarlyRv = Coerce(aCx, params, aAlgorithm);
1088
if (NS_FAILED(mEarlyRv)) {
1089
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1090
return;
1091
}
1092
1093
mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashAlgName);
1094
if (NS_FAILED(mEarlyRv)) {
1095
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1096
return;
1097
}
1098
} else {
1099
// This shouldn't happen; CreateSignVerifyTask shouldn't create
1100
// one of these unless it's for the above algorithms.
1101
MOZ_ASSERT(false);
1102
}
1103
1104
// Must have a valid algorithm by now.
1105
MOZ_ASSERT(mAlgorithm != Algorithm::UNKNOWN);
1106
1107
// Determine hash algorithm to use.
1108
mOidTag = MapHashAlgorithmNameToOID(hashAlgName);
1109
if (mOidTag == SEC_OID_UNKNOWN) {
1110
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1111
return;
1112
}
1113
1114
// Check that we have the appropriate key
1115
if ((mSign && !mPrivKey) || (!mSign && !mPubKey)) {
1116
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
1117
return;
1118
}
1119
}
1120
1121
private:
1122
SECOidTag mOidTag;
1123
CK_MECHANISM_TYPE mHashMechanism;
1124
CK_MECHANISM_TYPE mMgfMechanism;
1125
UniqueSECKEYPrivateKey mPrivKey;
1126
UniqueSECKEYPublicKey mPubKey;
1127
CryptoBuffer mSignature;
1128
CryptoBuffer mData;
1129
uint32_t mSaltLength;
1130
bool mSign;
1131
bool mVerified;
1132
1133
// The signature algorithm to use.
1134
enum class Algorithm : uint8_t { ECDSA, RSA_PKCS1, RSA_PSS, UNKNOWN };
1135
Algorithm mAlgorithm;
1136
1137
virtual nsresult DoCrypto() override {
1138
SECStatus rv;
1139
UniqueSECItem hash(
1140
::SECITEM_AllocItem(nullptr, nullptr, HASH_ResultLenByOidTag(mOidTag)));
1141
if (!hash) {
1142
return NS_ERROR_DOM_OPERATION_ERR;
1143
}
1144
1145
// Compute digest over given data.
1146
rv = PK11_HashBuf(mOidTag, hash->data, mData.Elements(), mData.Length());
1147
NS_ENSURE_SUCCESS(MapSECStatus(rv), NS_ERROR_DOM_OPERATION_ERR);
1148
1149
// Wrap hash in a digest info template (RSA-PKCS1 only).
1150
if (mAlgorithm == Algorithm::RSA_PKCS1) {
1151
UniqueSGNDigestInfo di(
1152
SGN_CreateDigestInfo(mOidTag, hash->data, hash->len));
1153
if (!di) {
1154
return NS_ERROR_DOM_OPERATION_ERR;
1155
}
1156
1157
// Reuse |hash|.
1158
SECITEM_FreeItem(hash.get(), false);
1159
if (!SEC_ASN1EncodeItem(nullptr, hash.get(), di.get(),
1160
SGN_DigestInfoTemplate)) {
1161
return NS_ERROR_DOM_OPERATION_ERR;
1162
}
1163
}
1164
1165
SECItem* params = nullptr;
1166
CK_MECHANISM_TYPE mech =
1167
PK11_MapSignKeyType((mSign ? mPrivKey->keyType : mPubKey->keyType));
1168
1169
CK_RSA_PKCS_PSS_PARAMS rsaPssParams;
1170
SECItem rsaPssParamsItem = {
1171
siBuffer,
1172
};
1173
1174
// Set up parameters for RSA-PSS.
1175
if (mAlgorithm == Algorithm::RSA_PSS) {
1176
rsaPssParams.hashAlg = mHashMechanism;
1177
rsaPssParams.mgf = mMgfMechanism;
1178
rsaPssParams.sLen = mSaltLength;
1179
1180
rsaPssParamsItem.data = (unsigned char*)&rsaPssParams;
1181
rsaPssParamsItem.len = sizeof(rsaPssParams);
1182
params = &rsaPssParamsItem;
1183
1184
mech = CKM_RSA_PKCS_PSS;
1185
}
1186
1187
// Allocate SECItem to hold the signature.
1188
uint32_t len = mSign ? PK11_SignatureLen(mPrivKey.get()) : 0;
1189
UniqueSECItem sig(::SECITEM_AllocItem(nullptr, nullptr, len));
1190
if (!sig) {
1191
return NS_ERROR_DOM_OPERATION_ERR;
1192
}
1193
1194
if (mSign) {
1195
// Sign the hash.
1196
rv = PK11_SignWithMechanism(mPrivKey.get(), mech, params, sig.get(),
1197
hash.get());
1198
NS_ENSURE_SUCCESS(MapSECStatus(rv), NS_ERROR_DOM_OPERATION_ERR);
1199
ATTEMPT_BUFFER_ASSIGN(mSignature, sig.get());
1200
} else {
1201
// Copy the given signature to the SECItem.
1202
if (!mSignature.ToSECItem(nullptr, sig.get())) {
1203
return NS_ERROR_DOM_OPERATION_ERR;
1204
}
1205
1206
// Verify the signature.
1207
rv = PK11_VerifyWithMechanism(mPubKey.get(), mech, params, sig.get(),
1208
hash.get(), nullptr);
1209
mVerified = NS_SUCCEEDED(MapSECStatus(rv));
1210
}
1211
1212
return NS_OK;
1213
}
1214
1215
virtual void Resolve() override {
1216
if (mSign) {
1217
TypedArrayCreator<ArrayBuffer> ret(mSignature);
1218
mResultPromise->MaybeResolve(ret);
1219
} else {
1220
mResultPromise->MaybeResolve(mVerified);
1221
}
1222
}
1223
};
1224
1225
class DigestTask : public ReturnArrayBufferViewTask {
1226
public:
1227
DigestTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
1228
const CryptoOperationData& aData) {
1229
ATTEMPT_BUFFER_INIT(mData, aData);
1230
1231
nsString algName;
1232
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
1233
if (NS_FAILED(mEarlyRv)) {
1234
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1235
return;
1236
}
1237
1238
TelemetryAlgorithm telemetryAlg;
1239
if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) {
1240
telemetryAlg = TA_SHA_1;
1241
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
1242
telemetryAlg = TA_SHA_224;
1243
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
1244
telemetryAlg = TA_SHA_256;
1245
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
1246
telemetryAlg = TA_SHA_384;
1247
} else {
1248
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1249
return;
1250
}
1251
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, telemetryAlg);
1252
mOidTag = MapHashAlgorithmNameToOID(algName);
1253
}
1254
1255
private:
1256
SECOidTag mOidTag;
1257
CryptoBuffer mData;
1258
1259
virtual nsresult DoCrypto() override {
1260
// Resize the result buffer
1261
uint32_t hashLen = HASH_ResultLenByOidTag(mOidTag);
1262
if (!mResult.SetLength(hashLen, fallible)) {
1263
return NS_ERROR_DOM_UNKNOWN_ERR;
1264
}
1265
1266
// Compute the hash
1267
nsresult rv = MapSECStatus(PK11_HashBuf(mOidTag, mResult.Elements(),
1268
mData.Elements(), mData.Length()));
1269
if (NS_FAILED(rv)) {
1270
return NS_ERROR_DOM_UNKNOWN_ERR;
1271
}
1272
1273
return rv;
1274
}
1275
};
1276
1277
class ImportKeyTask : public WebCryptoTask {
1278
public:
1279
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1280
const ObjectOrString& aAlgorithm, bool aExtractable,
1281
const Sequence<nsString>& aKeyUsages) {
1282
mFormat = aFormat;
1283
mDataIsSet = false;
1284
mDataIsJwk = false;
1285
1286
// This stuff pretty much always happens, so we'll do it here
1287
mKey = new CryptoKey(aGlobal);
1288
mKey->SetExtractable(aExtractable);
1289
mKey->ClearUsages();
1290
for (uint32_t i = 0; i < aKeyUsages.Length(); ++i) {
1291
mEarlyRv = mKey->AddUsage(aKeyUsages[i]);
1292
if (NS_FAILED(mEarlyRv)) {
1293
return;
1294
}
1295
}
1296
1297
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, mAlgName);
1298
if (NS_FAILED(mEarlyRv)) {
1299
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1300
return;
1301
}
1302
}
1303
1304
static bool JwkCompatible(const JsonWebKey& aJwk, const CryptoKey* aKey) {
1305
// Check 'ext'
1306
if (aKey->Extractable() && aJwk.mExt.WasPassed() && !aJwk.mExt.Value()) {
1307
return false;
1308
}
1309
1310
// Check 'alg'
1311
if (aJwk.mAlg.WasPassed() &&
1312
aJwk.mAlg.Value() != aKey->Algorithm().JwkAlg()) {
1313
return false;
1314
}
1315
1316
// Check 'key_ops'
1317
if (aJwk.mKey_ops.WasPassed()) {
1318
nsTArray<nsString> usages;
1319
aKey->GetUsages(usages);
1320
for (size_t i = 0; i < usages.Length(); ++i) {
1321
if (!aJwk.mKey_ops.Value().Contains(usages[i])) {
1322
return false;
1323
}
1324
}
1325
}
1326
1327
// Individual algorithms may still have to check 'use'
1328
return true;
1329
}
1330
1331
void SetKeyData(JSContext* aCx, JS::Handle<JSObject*> aKeyData) {
1332
mDataIsJwk = false;
1333
1334
// Try ArrayBuffer
1335
RootedSpiderMonkeyInterface<ArrayBuffer> ab(aCx);
1336
if (ab.Init(aKeyData)) {
1337
if (!mKeyData.Assign(ab)) {
1338
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1339
}
1340
return;
1341
}
1342
1343
// Try ArrayBufferView
1344
RootedSpiderMonkeyInterface<ArrayBufferView> abv(aCx);
1345
if (abv.Init(aKeyData)) {
1346
if (!mKeyData.Assign(abv)) {
1347
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1348
}
1349
return;
1350
}
1351
1352
// Try JWK
1353
ClearException ce(aCx);
1354
JS::RootedValue value(aCx, JS::ObjectValue(*aKeyData));
1355
if (!mJwk.Init(aCx, value)) {
1356
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1357
return;
1358
}
1359
1360
mDataIsJwk = true;
1361
}
1362
1363
void SetKeyDataMaybeParseJWK(const CryptoBuffer& aKeyData) {
1364
if (!mKeyData.Assign(aKeyData)) {
1365
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1366
return;
1367
}
1368
1369
mDataIsJwk = false;
1370
1371
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1372
nsDependentCSubstring utf8(
1373
(const char*)mKeyData.Elements(),
1374
(const char*)(mKeyData.Elements() + mKeyData.Length()));
1375
if (!IsUtf8(utf8)) {
1376
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1377
return;
1378
}
1379
1380
nsString json = NS_ConvertUTF8toUTF16(utf8);
1381
if (!mJwk.Init(json)) {
1382
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1383
return;
1384
}
1385
1386
mDataIsJwk = true;
1387
}
1388
}
1389
1390
void SetRawKeyData(const CryptoBuffer& aKeyData) {
1391
if (!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1392
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1393
return;
1394
}
1395
1396
if (!mKeyData.Assign(aKeyData)) {
1397
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
1398
return;
1399
}
1400
1401
mDataIsJwk = false;
1402
}
1403
1404
protected:
1405
nsString mFormat;
1406
RefPtr<CryptoKey> mKey;
1407
CryptoBuffer mKeyData;
1408
bool mDataIsSet;
1409
bool mDataIsJwk;
1410
JsonWebKey mJwk;
1411
nsString mAlgName;
1412
1413
private:
1414
virtual void Resolve() override { mResultPromise->MaybeResolve(mKey); }
1415
1416
virtual void Cleanup() override { mKey = nullptr; }
1417
};
1418
1419
class ImportSymmetricKeyTask : public ImportKeyTask {
1420
public:
1421
ImportSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1422
const nsAString& aFormat,
1423
const ObjectOrString& aAlgorithm, bool aExtractable,
1424
const Sequence<nsString>& aKeyUsages) {
1425
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1426
}
1427
1428
ImportSymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1429
const nsAString& aFormat,
1430
const JS::Handle<JSObject*> aKeyData,
1431
const ObjectOrString& aAlgorithm, bool aExtractable,
1432
const Sequence<nsString>& aKeyUsages) {
1433
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1434
if (NS_FAILED(mEarlyRv)) {
1435
return;
1436
}
1437
1438
SetKeyData(aCx, aKeyData);
1439
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
1440
if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1441
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1442
return;
1443
}
1444
}
1445
1446
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1447
const ObjectOrString& aAlgorithm, bool aExtractable,
1448
const Sequence<nsString>& aKeyUsages) {
1449
ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable,
1450
aKeyUsages);
1451
if (NS_FAILED(mEarlyRv)) {
1452
return;
1453
}
1454
1455
// This task only supports raw and JWK format.
1456
if (!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1457
!mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1458
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1459
return;
1460
}
1461
1462
// If this is an HMAC key, import the hash name
1463
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
1464
RootedDictionary<HmacImportParams> params(aCx);
1465
mEarlyRv = Coerce(aCx, params, aAlgorithm);
1466
if (NS_FAILED(mEarlyRv)) {
1467
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1468
return;
1469
}
1470
mEarlyRv = GetAlgorithmName(aCx, params.mHash, mHashName);
1471
if (NS_FAILED(mEarlyRv)) {
1472
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1473
return;
1474
}
1475
}
1476
}
1477
1478
virtual nsresult BeforeCrypto() override {
1479
nsresult rv;
1480
1481
// If we're doing a JWK import, import the key data
1482
if (mDataIsJwk) {
1483
if (!mJwk.mK.WasPassed()) {
1484
return NS_ERROR_DOM_DATA_ERR;
1485
}
1486
1487
// Import the key material
1488
rv = mKeyData.FromJwkBase64(mJwk.mK.Value());
1489
if (NS_FAILED(rv)) {
1490
return NS_ERROR_DOM_DATA_ERR;
1491
}
1492
}
1493
// Check that we have valid key data.
1494
if (mKeyData.Length() == 0 &&
1495
!mAlgName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
1496
return NS_ERROR_DOM_DATA_ERR;
1497
}
1498
1499
// Construct an appropriate KeyAlorithm,
1500
// and verify that usages are appropriate
1501
uint32_t length = 8 * mKeyData.Length(); // bytes to bits
1502
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
1503
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
1504
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
1505
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
1506
if (mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::DECRYPT |
1507
CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) {
1508
return NS_ERROR_DOM_DATA_ERR;
1509
}
1510
1511
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) &&
1512
mKey->HasUsageOtherThan(CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) {
1513
return NS_ERROR_DOM_DATA_ERR;
1514
}
1515
1516
if ((length != 128) && (length != 192) && (length != 256)) {
1517
return NS_ERROR_DOM_DATA_ERR;
1518
}
1519
mKey->Algorithm().MakeAes(mAlgName, length);
1520
1521
if (mDataIsJwk && mJwk.mUse.WasPassed() &&
1522
!mJwk.mUse.Value().EqualsLiteral(JWK_USE_ENC)) {
1523
return NS_ERROR_DOM_DATA_ERR;
1524
}
1525
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HKDF) ||
1526
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
1527
if (mKey->HasUsageOtherThan(CryptoKey::DERIVEKEY |
1528
CryptoKey::DERIVEBITS)) {
1529
return NS_ERROR_DOM_DATA_ERR;
1530
}
1531
mKey->Algorithm().MakeAes(mAlgName, length);
1532
1533
if (mDataIsJwk && mJwk.mUse.WasPassed()) {
1534
// There is not a 'use' value consistent with PBKDF or HKDF
1535
return NS_ERROR_DOM_DATA_ERR;
1536
};
1537
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
1538
if (mKey->HasUsageOtherThan(CryptoKey::SIGN | CryptoKey::VERIFY)) {
1539
return NS_ERROR_DOM_DATA_ERR;
1540
}
1541
1542
mKey->Algorithm().MakeHmac(length, mHashName);
1543
1544
if (mKey->Algorithm().Mechanism() == UNKNOWN_CK_MECHANISM) {
1545
return NS_ERROR_DOM_SYNTAX_ERR;
1546
}
1547
1548
if (mDataIsJwk && mJwk.mUse.WasPassed() &&
1549
!mJwk.mUse.Value().EqualsLiteral(JWK_USE_SIG)) {
1550
return NS_ERROR_DOM_DATA_ERR;
1551
}
1552
} else {
1553
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1554
}
1555
1556
if (NS_FAILED(mKey->SetSymKey(mKeyData))) {
1557
return NS_ERROR_DOM_OPERATION_ERR;
1558
}
1559
1560
mKey->SetType(CryptoKey::SECRET);
1561
1562
if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) {
1563
return NS_ERROR_DOM_DATA_ERR;
1564
}
1565
1566
mEarlyComplete = true;
1567
return NS_OK;
1568
}
1569
1570
private:
1571
nsString mHashName;
1572
};
1573
1574
class ImportRsaKeyTask : public ImportKeyTask {
1575
public:
1576
ImportRsaKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1577
const nsAString& aFormat, const ObjectOrString& aAlgorithm,
1578
bool aExtractable, const Sequence<nsString>& aKeyUsages)
1579
: mModulusLength(0) {
1580
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1581
}
1582
1583
ImportRsaKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1584
const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
1585
const ObjectOrString& aAlgorithm, bool aExtractable,
1586
const Sequence<nsString>& aKeyUsages)
1587
: mModulusLength(0) {
1588
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1589
if (NS_FAILED(mEarlyRv)) {
1590
return;
1591
}
1592
1593
SetKeyData(aCx, aKeyData);
1594
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
1595
if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1596
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1597
return;
1598
}
1599
}
1600
1601
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1602
const ObjectOrString& aAlgorithm, bool aExtractable,
1603
const Sequence<nsString>& aKeyUsages) {
1604
ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable,
1605
aKeyUsages);
1606
if (NS_FAILED(mEarlyRv)) {
1607
return;
1608
}
1609
1610
// If this is RSA with a hash, cache the hash name
1611
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
1612
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
1613
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
1614
RootedDictionary<RsaHashedImportParams> params(aCx);
1615
mEarlyRv = Coerce(aCx, params, aAlgorithm);
1616
if (NS_FAILED(mEarlyRv)) {
1617
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1618
return;
1619
}
1620
1621
mEarlyRv = GetAlgorithmName(aCx, params.mHash, mHashName);
1622
if (NS_FAILED(mEarlyRv)) {
1623
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
1624
return;
1625
}
1626
}
1627
1628
// Check support for the algorithm and hash names
1629
CK_MECHANISM_TYPE mech1 = MapAlgorithmNameToMechanism(mAlgName);
1630
CK_MECHANISM_TYPE mech2 = MapAlgorithmNameToMechanism(mHashName);
1631
if ((mech1 == UNKNOWN_CK_MECHANISM) || (mech2 == UNKNOWN_CK_MECHANISM)) {
1632
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1633
return;
1634
}
1635
}
1636
1637
private:
1638
nsString mHashName;
1639
uint32_t mModulusLength;
1640
CryptoBuffer mPublicExponent;
1641
1642
virtual nsresult DoCrypto() override {
1643
// Import the key data itself
1644
UniqueSECKEYPublicKey pubKey;
1645
UniqueSECKEYPrivateKey privKey;
1646
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) ||
1647
(mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1648
!mJwk.mD.WasPassed())) {
1649
// Public key import
1650
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
1651
pubKey = CryptoKey::PublicKeyFromSpki(mKeyData);
1652
} else {
1653
pubKey = CryptoKey::PublicKeyFromJwk(mJwk);
1654
}
1655
1656
if (!pubKey) {
1657
return NS_ERROR_DOM_DATA_ERR;
1658
}
1659
1660
if (NS_FAILED(mKey->SetPublicKey(pubKey.get()))) {
1661
return NS_ERROR_DOM_OPERATION_ERR;
1662
}
1663
1664
mKey->SetType(CryptoKey::PUBLIC);
1665
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) ||
1666
(mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1667
mJwk.mD.WasPassed())) {
1668
// Private key import
1669
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8)) {
1670
privKey = CryptoKey::PrivateKeyFromPkcs8(mKeyData);
1671
} else {
1672
privKey = CryptoKey::PrivateKeyFromJwk(mJwk);
1673
}
1674
1675
if (!privKey) {
1676
return NS_ERROR_DOM_DATA_ERR;
1677
}
1678
1679
if (NS_FAILED(mKey->SetPrivateKey(privKey.get()))) {
1680
return NS_ERROR_DOM_OPERATION_ERR;
1681
}
1682
1683
mKey->SetType(CryptoKey::PRIVATE);
1684
pubKey = UniqueSECKEYPublicKey(SECKEY_ConvertToPublicKey(privKey.get()));
1685
if (!pubKey) {
1686
return NS_ERROR_DOM_UNKNOWN_ERR;
1687
}
1688
} else {
1689
// Invalid key format
1690
return NS_ERROR_DOM_SYNTAX_ERR;
1691
}
1692
1693
// Extract relevant information from the public key
1694
mModulusLength = 8 * pubKey->u.rsa.modulus.len;
1695
if (!mPublicExponent.Assign(&pubKey->u.rsa.publicExponent)) {
1696
return NS_ERROR_DOM_OPERATION_ERR;
1697
}
1698
1699
return NS_OK;
1700
}
1701
1702
virtual nsresult AfterCrypto() override {
1703
// Check permissions for the requested operation
1704
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
1705
if ((mKey->GetKeyType() == CryptoKey::PUBLIC &&
1706
mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::WRAPKEY)) ||
1707
(mKey->GetKeyType() == CryptoKey::PRIVATE &&
1708
mKey->HasUsageOtherThan(CryptoKey::DECRYPT |
1709
CryptoKey::UNWRAPKEY))) {
1710
return NS_ERROR_DOM_DATA_ERR;
1711
}
1712
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
1713
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
1714
if ((mKey->GetKeyType() == CryptoKey::PUBLIC &&
1715
mKey->HasUsageOtherThan(CryptoKey::VERIFY)) ||
1716
(mKey->GetKeyType() == CryptoKey::PRIVATE &&
1717
mKey->HasUsageOtherThan(CryptoKey::SIGN))) {
1718
return NS_ERROR_DOM_DATA_ERR;
1719
}
1720
}
1721
1722
// Set an appropriate KeyAlgorithm
1723
if (!mKey->Algorithm().MakeRsa(mAlgName, mModulusLength, mPublicExponent,
1724
mHashName)) {
1725
return NS_ERROR_DOM_OPERATION_ERR;
1726
}
1727
1728
if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) {
1729
return NS_ERROR_DOM_DATA_ERR;
1730
}
1731
1732
return NS_OK;
1733
}
1734
};
1735
1736
class ImportEcKeyTask : public ImportKeyTask {
1737
public:
1738
ImportEcKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1739
const nsAString& aFormat, const ObjectOrString& aAlgorithm,
1740
bool aExtractable, const Sequence<nsString>& aKeyUsages) {
1741
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1742
}
1743
1744
ImportEcKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
1745
const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
1746
const ObjectOrString& aAlgorithm, bool aExtractable,
1747
const Sequence<nsString>& aKeyUsages) {
1748
Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
1749
if (NS_FAILED(mEarlyRv)) {
1750
return;
1751
}
1752
1753
SetKeyData(aCx, aKeyData);
1754
NS_ENSURE_SUCCESS_VOID(mEarlyRv);
1755
}
1756
1757
void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
1758
const ObjectOrString& aAlgorithm, bool aExtractable,
1759
const Sequence<nsString>& aKeyUsages) {
1760
ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable,
1761
aKeyUsages);
1762
if (NS_FAILED(mEarlyRv)) {
1763
return;
1764
}
1765
1766
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1767
RootedDictionary<EcKeyImportParams> params(aCx);
1768
mEarlyRv = Coerce(aCx, params, aAlgorithm);
1769
if (NS_FAILED(mEarlyRv) || !params.mNamedCurve.WasPassed()) {
1770
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
1771
return;
1772
}
1773
1774
if (!NormalizeToken(params.mNamedCurve.Value(), mNamedCurve)) {
1775
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
1776
return;
1777
}
1778
}
1779
}
1780
1781
private:
1782
nsString mNamedCurve;
1783
1784
virtual nsresult DoCrypto() override {
1785
// Import the key data itself
1786
UniqueSECKEYPublicKey pubKey;
1787
UniqueSECKEYPrivateKey privKey;
1788
1789
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1790
mJwk.mD.WasPassed()) {
1791
// Private key import
1792
privKey = CryptoKey::PrivateKeyFromJwk(mJwk);
1793
if (!privKey) {
1794
return NS_ERROR_DOM_DATA_ERR;
1795
}
1796
1797
if (NS_FAILED(mKey->SetPrivateKey(privKey.get()))) {
1798
return NS_ERROR_DOM_OPERATION_ERR;
1799
}
1800
1801
mKey->SetType(CryptoKey::PRIVATE);
1802
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) ||
1803
mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) ||
1804
(mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK) &&
1805
!mJwk.mD.WasPassed())) {
1806
// Public key import
1807
if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
1808
pubKey = CryptoKey::PublicECKeyFromRaw(mKeyData, mNamedCurve);
1809
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
1810
pubKey = CryptoKey::PublicKeyFromSpki(mKeyData);
1811
} else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
1812
pubKey = CryptoKey::PublicKeyFromJwk(mJwk);
1813
} else {
1814
MOZ_ASSERT(