Bug 998471 - Add support for key generation to WebCrypto API. r=bz,dkeeler

* * *
Change from SetCapacity to SetLength so that strings clone properly
This commit is contained in:
Richard Barnes 2014-05-26 12:05:00 +02:00
Родитель 8d8df0c940
Коммит 01fedee2de
12 изменённых файлов: 525 добавлений и 20 удалений

Просмотреть файл

@ -19,6 +19,7 @@ CryptoBuffer::Assign(const uint8_t* aData, uint32_t aLength)
uint8_t*
CryptoBuffer::Assign(const SECItem* aItem)
{
MOZ_ASSERT(aItem);
return Assign(aItem->data, aItem->len);
}

Просмотреть файл

@ -27,6 +27,14 @@ public:
uint8_t* Assign(const ArrayBufferViewOrArrayBuffer& aData);
uint8_t* Assign(const OwningArrayBufferViewOrArrayBuffer& aData);
template<typename T,
JSObject* UnboxArray(JSObject*, uint32_t*, T**)>
uint8_t* Assign(const TypedArray_base<T, UnboxArray>& aData)
{
return Assign(aData.Data(), aData.Length());
}
SECItem* ToSECItem();
bool GetBigIntValue(unsigned long& aRetVal);

Просмотреть файл

@ -22,6 +22,31 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Key)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
nsresult
StringToUsage(const nsString& aUsage, Key::KeyUsage& aUsageOut)
{
if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_ENCRYPT)) {
aUsageOut = Key::ENCRYPT;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_DECRYPT)) {
aUsageOut = Key::DECRYPT;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_SIGN)) {
aUsageOut = Key::SIGN;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_VERIFY)) {
aUsageOut = Key::VERIFY;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_DERIVEKEY)) {
aUsageOut = Key::DERIVEKEY;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_DERIVEBITS)) {
aUsageOut = Key::DERIVEBITS;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_WRAPKEY)) {
aUsageOut = Key::WRAPKEY;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_UNWRAPKEY)) {
aUsageOut = Key::UNWRAPKEY;
} else {
return NS_ERROR_DOM_SYNTAX_ERR;
}
return NS_OK;
}
Key::Key(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal)
, mAttributes(0)
@ -155,26 +180,22 @@ Key::ClearUsages()
nsresult
Key::AddUsage(const nsString& aUsage)
{
if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_ENCRYPT)) {
mAttributes |= ENCRYPT;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_DECRYPT)) {
mAttributes |= DECRYPT;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_SIGN)) {
mAttributes |= SIGN;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_VERIFY)) {
mAttributes |= VERIFY;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_DERIVEKEY)) {
mAttributes |= DERIVEKEY;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_DERIVEBITS)) {
mAttributes |= DERIVEBITS;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_WRAPKEY)) {
mAttributes |= WRAPKEY;
} else if (aUsage.EqualsLiteral(WEBCRYPTO_KEY_USAGE_UNWRAPKEY)) {
mAttributes |= UNWRAPKEY;
} else {
return AddUsageIntersecting(aUsage, USAGES_MASK);
}
nsresult
Key::AddUsageIntersecting(const nsString& aUsage, uint32_t aUsageMask)
{
KeyUsage usage;
if (NS_FAILED(StringToUsage(aUsage, usage))) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
if (usage & aUsageMask) {
AddUsage(usage);
return NS_OK;
}
return NS_OK;
}

Просмотреть файл

@ -113,6 +113,7 @@ public:
void SetAlgorithm(KeyAlgorithm* aAlgorithm);
void ClearUsages();
nsresult AddUsage(const nsString& aUsage);
nsresult AddUsageIntersecting(const nsString& aUsage, uint32_t aUsageMask);
void AddUsage(KeyUsage aUsage);
bool HasUsage(KeyUsage aUsage);
bool HasUsageOtherThan(uint32_t aUsages);

31
dom/crypto/KeyPair.cpp Normal file
Просмотреть файл

@ -0,0 +1,31 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/KeyPair.h"
#include "mozilla/dom/SubtleCryptoBinding.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(KeyPair, mGlobal, mPublicKey, mPrivateKey)
NS_IMPL_CYCLE_COLLECTING_ADDREF(KeyPair)
NS_IMPL_CYCLE_COLLECTING_RELEASE(KeyPair)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(KeyPair)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
KeyPair::WrapObject(JSContext* aCx)
{
return KeyPairBinding::Wrap(aCx, this);
}
} // namespace dom
} // namespace mozilla

63
dom/crypto/KeyPair.h Normal file
Просмотреть файл

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_KeyPair_h
#define mozilla_dom_KeyPair_h
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "nsIGlobalObject.h"
#include "mozilla/dom/Key.h"
#include "js/TypeDecls.h"
namespace mozilla {
namespace dom {
class KeyPair MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(KeyPair)
public:
KeyPair(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal)
, mPublicKey(new Key(aGlobal))
, mPrivateKey(new Key(aGlobal))
{
SetIsDOMBinding();
}
~KeyPair() {}
nsIGlobalObject* GetParentObject() const
{
return mGlobal;
}
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
Key* PublicKey() const
{
return mPublicKey;
}
Key* PrivateKey() const
{
return mPrivateKey;
}
private:
nsRefPtr<nsIGlobalObject> mGlobal;
nsRefPtr<Key> mPublicKey;
nsRefPtr<Key> mPrivateKey;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_KeyPair_h

Просмотреть файл

@ -74,10 +74,9 @@ ReadString(JSStructuredCloneReader* aReader, nsString& aString)
return false;
}
aString.SetCapacity(nameLength+1);
aString.SetLength(nameLength);
size_t charSize = sizeof(nsString::char_type);
read = JS_ReadBytes(aReader, (void*) aString.BeginWriting(), nameLength * charSize);
aString.SetCharAt('\0', nameLength);
if (!read) {
return false;
}

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/dom/TypedArray.h"
#include "mozilla/dom/Key.h"
#include "mozilla/dom/KeyAlgorithm.h"
#include "mozilla/dom/KeyPair.h"
#include "mozilla/dom/AesKeyAlgorithm.h"
#include "mozilla/dom/HmacKeyAlgorithm.h"
#include "mozilla/dom/RsaKeyAlgorithm.h"
@ -39,6 +40,12 @@ namespace dom {
return NS_ERROR_DOM_UNKNOWN_ERR; \
}
// OOM-safe CryptoBuffer copy, suitable for DoCrypto
#define ATTEMPT_BUFFER_ASSIGN(dst, src) \
if (!dst.Assign(src)) { \
return NS_ERROR_DOM_UNKNOWN_ERR; \
}
class ClearException
{
public:
@ -959,6 +966,307 @@ private:
}
};
class GenerateSymmetricKeyTask : public WebCryptoTask
{
public:
GenerateSymmetricKeyTask(JSContext* aCx,
const ObjectOrString& aAlgorithm, bool aExtractable,
const Sequence<nsString>& aKeyUsages)
{
nsIGlobalObject* global = xpc::GetNativeForGlobal(JS::CurrentGlobalOrNull(aCx));
if (!global) {
mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
return;
}
// Create an empty key and set easy attributes
mKey = new Key(global);
mKey->SetExtractable(aExtractable);
mKey->SetType(Key::SECRET);
// Extract algorithm name
nsString algName;
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
if (NS_FAILED(mEarlyRv)) {
return;
}
// Construct an appropriate KeyAlorithm
nsRefPtr<KeyAlgorithm> algorithm;
uint32_t allowedUsages = 0;
if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
RootedDictionary<AesKeyGenParams> params(aCx);
mEarlyRv = Coerce(aCx, params, aAlgorithm);
if (NS_FAILED(mEarlyRv) || !params.mLength.WasPassed()) {
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
}
mLength = params.mLength.Value();
if (mLength != 128 && mLength != 192 && mLength != 256) {
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
return;
}
algorithm = new AesKeyAlgorithm(global, algName, mLength);
allowedUsages = Key::ENCRYPT | Key::DECRYPT;
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
RootedDictionary<HmacKeyGenParams> params(aCx);
mEarlyRv = Coerce(aCx, params, aAlgorithm);
if (NS_FAILED(mEarlyRv) || !params.mLength.WasPassed() ||
!params.mHash.WasPassed()) {
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
return;
}
nsString hashName;
if (params.mHash.Value().IsString()) {
hashName.Assign(params.mHash.Value().GetAsString());
} else {
Algorithm hashAlg;
mEarlyRv = Coerce(aCx, hashAlg, params.mHash.Value());
if (NS_FAILED(mEarlyRv) || !hashAlg.mName.WasPassed()) {
return;
}
hashName.Assign(hashAlg.mName.Value());
}
mLength = params.mLength.Value();
algorithm = new HmacKeyAlgorithm(global, algName, mLength, hashName);
allowedUsages = Key::SIGN | Key::VERIFY;
} else {
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
return;
}
// Add key usages
mKey->ClearUsages();
for (uint32_t i = 0; i < aKeyUsages.Length(); ++i) {
mEarlyRv = mKey->AddUsageIntersecting(aKeyUsages[i], allowedUsages);
if (NS_FAILED(mEarlyRv)) {
return;
}
}
mLength = mLength >> 3; // bits to bytes
mMechanism = algorithm->Mechanism();
mKey->SetAlgorithm(algorithm);
// SetSymKey done in Resolve, after we've done the keygen
return;
}
private:
nsRefPtr<Key> mKey;
size_t mLength;
CK_MECHANISM_TYPE mMechanism;
CryptoBuffer mKeyData;
virtual nsresult DoCrypto() MOZ_OVERRIDE
{
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
MOZ_ASSERT(slot.get());
ScopedPK11SymKey symKey(PK11_KeyGen(slot.get(), mMechanism, nullptr,
mLength, nullptr));
if (!symKey) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey));
if (NS_FAILED(rv)) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
// This doesn't leak, because the SECItem* returned by PK11_GetKeyData
// just refers to a buffer managed by symKey. The assignment copies the
// data, so mKeyData manages one copy, while symKey manages another.
ATTEMPT_BUFFER_ASSIGN(mKeyData, PK11_GetKeyData(symKey));
return NS_OK;
}
virtual void Resolve() {
mKey->SetSymKey(mKeyData);
mResultPromise->MaybeResolve(mKey);
}
virtual void Cleanup() {
mKey = nullptr;
}
};
class GenerateAsymmetricKeyTask : public WebCryptoTask
{
public:
GenerateAsymmetricKeyTask(JSContext* aCx,
const ObjectOrString& aAlgorithm, bool aExtractable,
const Sequence<nsString>& aKeyUsages)
{
nsIGlobalObject* global = xpc::GetNativeForGlobal(JS::CurrentGlobalOrNull(aCx));
if (!global) {
mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
return;
}
// Create an empty key and set easy attributes
mKeyPair = new KeyPair(global);
// Extract algorithm name
nsString algName;
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
if (NS_FAILED(mEarlyRv)) {
return;
}
// Construct an appropriate KeyAlorithm
KeyAlgorithm* algorithm;
uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0;
if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
RootedDictionary<RsaHashedKeyGenParams> params(aCx);
mEarlyRv = Coerce(aCx, params, aAlgorithm);
if (NS_FAILED(mEarlyRv) || !params.mModulusLength.WasPassed() ||
!params.mPublicExponent.WasPassed() ||
!params.mHash.WasPassed()) {
// TODO fix error and handle default values
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
}
// Pull relevant info
uint32_t modulusLength = params.mModulusLength.Value();
CryptoBuffer publicExponent;
ATTEMPT_BUFFER_INIT(publicExponent, params.mPublicExponent.Value());
nsString hashName;
mEarlyRv = GetAlgorithmName(aCx, params.mHash.Value(), hashName);
if (NS_FAILED(mEarlyRv)) {
return;
}
// Create algorithm
algorithm = new RsaHashedKeyAlgorithm(global, algName, modulusLength,
publicExponent, hashName);
mKeyPair->PublicKey()->SetAlgorithm(algorithm);
mKeyPair->PrivateKey()->SetAlgorithm(algorithm);
mMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
// Set up params struct
mRsaParams.keySizeInBits = modulusLength;
bool converted = publicExponent.GetBigIntValue(mRsaParams.pe);
if (!converted) {
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
return;
}
privateAllowedUsages = Key::SIGN;
publicAllowedUsages = Key::VERIFY;
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) {
RootedDictionary<RsaKeyGenParams> params(aCx);
mEarlyRv = Coerce(aCx, params, aAlgorithm);
if (NS_FAILED(mEarlyRv) || !params.mModulusLength.WasPassed() ||
!params.mPublicExponent.WasPassed()) {
// TODO fix error and handle default values
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
}
// Pull relevant info
uint32_t modulusLength = params.mModulusLength.Value();
CryptoBuffer publicExponent;
ATTEMPT_BUFFER_INIT(publicExponent, params.mPublicExponent.Value());
// Create algorithm and note the mechanism
algorithm = new RsaKeyAlgorithm(global, algName, modulusLength,
publicExponent);
mKeyPair->PublicKey()->SetAlgorithm(algorithm);
mKeyPair->PrivateKey()->SetAlgorithm(algorithm);
mMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
// Set up params struct
mRsaParams.keySizeInBits = modulusLength;
bool converted = publicExponent.GetBigIntValue(mRsaParams.pe);
if (!converted) {
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
return;
}
privateAllowedUsages = Key::DECRYPT | Key::UNWRAPKEY;
publicAllowedUsages = Key::ENCRYPT | Key::WRAPKEY;
} else {
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
return;
}
mKeyPair->PrivateKey()->SetExtractable(aExtractable);
mKeyPair->PrivateKey()->SetType(Key::PRIVATE);
mKeyPair->PublicKey()->SetExtractable(true);
mKeyPair->PublicKey()->SetType(Key::PUBLIC);
mKeyPair->PrivateKey()->ClearUsages();
mKeyPair->PublicKey()->ClearUsages();
for (uint32_t i=0; i < aKeyUsages.Length(); ++i) {
mEarlyRv = mKeyPair->PrivateKey()->AddUsageIntersecting(aKeyUsages[i],
privateAllowedUsages);
if (NS_FAILED(mEarlyRv)) {
return;
}
mEarlyRv = mKeyPair->PublicKey()->AddUsageIntersecting(aKeyUsages[i],
publicAllowedUsages);
if (NS_FAILED(mEarlyRv)) {
return;
}
}
return;
}
private:
nsRefPtr<KeyPair> mKeyPair;
CK_MECHANISM_TYPE mMechanism;
PK11RSAGenParams mRsaParams;
ScopedSECKEYPublicKey mPublicKey;
ScopedSECKEYPrivateKey mPrivateKey;
virtual void ReleaseNSSResources() MOZ_OVERRIDE
{
mPublicKey.dispose();
mPrivateKey.dispose();
}
virtual nsresult DoCrypto() MOZ_OVERRIDE
{
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
MOZ_ASSERT(slot.get());
void* param;
switch (mMechanism) {
case CKM_RSA_PKCS_KEY_PAIR_GEN: param = &mRsaParams; break;
default: return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
SECKEYPublicKey* pubKey;
mPrivateKey = PK11_GenerateKeyPair(slot.get(), mMechanism, param, &pubKey,
PR_FALSE, PR_FALSE, nullptr);
mPublicKey = pubKey;
if (!mPrivateKey.get() || !mPublicKey.get()) {
return NS_ERROR_DOM_UNKNOWN_ERR;
}
mKeyPair->PrivateKey()->SetPrivateKey(mPrivateKey);
mKeyPair->PublicKey()->SetPublicKey(mPublicKey);
return NS_OK;
}
virtual void Resolve() MOZ_OVERRIDE
{
mResultPromise->MaybeResolve(mKeyPair);
}
virtual void Cleanup() MOZ_OVERRIDE
{
mKeyPair = nullptr;
}
};
// Task creation methods for WebCryptoTask
@ -1075,7 +1383,23 @@ WebCryptoTask::GenerateKeyTask(JSContext* aCx,
bool aExtractable,
const Sequence<nsString>& aKeyUsages)
{
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
nsString algName;
nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
if (NS_FAILED(rv)) {
return new FailureTask(rv);
}
if (algName.EqualsASCII(WEBCRYPTO_ALG_AES_CBC) ||
algName.EqualsASCII(WEBCRYPTO_ALG_AES_CTR) ||
algName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) ||
algName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
} else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSAES_PKCS1) ||
algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
return new GenerateAsymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
} else {
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
}
}
WebCryptoTask*

Просмотреть файл

@ -12,6 +12,7 @@ EXPORTS.mozilla.dom += [
'HmacKeyAlgorithm.h',
'Key.h',
'KeyAlgorithm.h',
'KeyPair.h',
'RsaHashedKeyAlgorithm.h',
'RsaKeyAlgorithm.h',
'WebCryptoCommon.h',
@ -24,6 +25,7 @@ UNIFIED_SOURCES += [
'HmacKeyAlgorithm.cpp',
'Key.cpp',
'KeyAlgorithm.cpp',
'KeyPair.cpp',
'RsaHashedKeyAlgorithm.cpp',
'RsaKeyAlgorithm.cpp',
'WebCryptoTask.cpp',

Просмотреть файл

@ -309,6 +309,53 @@ TestArray.addTest(
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Generate a 192-bit AES key",
function() {
var that = this;
var alg = { name: "AES-GCM", length: 192 };
crypto.subtle.generateKey(alg, true, ["encrypt"]).then(
complete(that, function(x) {
return hasKeyFields(x);
}),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"Generate a 1024-bit RSA key",
function() {
var that = this;
var alg = {
name: "RSAES-PKCS1-v1_5",
modulusLength: 1024,
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
};
crypto.subtle.generateKey(alg, false, ["encrypt", "decrypt"]).then(
complete(that, function(x) {
return exists(x.publicKey) &&
(x.publicKey.algorithm.name == alg.name) &&
(x.publicKey.algorithm.modulusLength == alg.modulusLength) &&
(x.publicKey.type == "public") &&
x.publicKey.extractable &&
(x.publicKey.usages.length == 1) &&
(x.publicKey.usages[0] == "encrypt") &&
exists(x.privateKey) &&
(x.privateKey.algorithm.name == alg.name) &&
(x.privateKey.algorithm.modulusLength == alg.modulusLength) &&
(x.privateKey.type == "private") &&
!x.privateKey.extractable &&
(x.privateKey.usages.length == 1) &&
(x.privateKey.usages[0] == "decrypt");
}),
error(that)
);
}
);
// -----------------------------------------------------------------------------
TestArray.addTest(
"SHA-256 digest",

Просмотреть файл

@ -576,6 +576,8 @@ var interfaceNamesInGlobalScope =
{name: "Key", pref: "dom.webcrypto.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"KeyEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "KeyPair", pref: "dom.webcrypto.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"KeyboardEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!

Просмотреть файл

@ -108,6 +108,12 @@ interface Key {
[Cached, Constant, Frozen] readonly attribute sequence<KeyUsage> usages;
};
[Pref="dom.webcrypto.enabled"]
interface KeyPair {
readonly attribute Key publicKey;
readonly attribute Key privateKey;
};
typedef DOMString KeyFormat;
typedef (ArrayBufferView or ArrayBuffer) CryptoOperationData;
typedef (ArrayBufferView or ArrayBuffer) KeyData;