зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
8d8df0c940
Коммит
01fedee2de
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче