From 63afe24da89ecf08053dbc89cb22db6c731fb069 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 27 Sep 2014 14:22:57 -0400 Subject: [PATCH] Bug 1037892 - Implement changes to WebCrypto API from latest Editor's Draft r=bz,ttaubert --- dom/crypto/AesKeyAlgorithm.cpp | 82 --- dom/crypto/AesKeyAlgorithm.h | 38 - dom/crypto/BasicSymmetricKeyAlgorithm.h | 38 - dom/crypto/CryptoBuffer.cpp | 7 + dom/crypto/CryptoBuffer.h | 1 + dom/crypto/CryptoKey.cpp | 116 ++- dom/crypto/CryptoKey.h | 16 +- dom/crypto/CryptoKeyPair.cpp | 31 - dom/crypto/CryptoKeyPair.h | 63 -- dom/crypto/EcKeyAlgorithm.cpp | 43 -- dom/crypto/EcKeyAlgorithm.h | 48 -- dom/crypto/HmacKeyAlgorithm.cpp | 64 -- dom/crypto/HmacKeyAlgorithm.h | 72 -- dom/crypto/KeyAlgorithm.cpp | 116 --- dom/crypto/KeyAlgorithm.h | 80 -- dom/crypto/KeyAlgorithmProxy.cpp | 215 ++++++ dom/crypto/KeyAlgorithmProxy.h | 117 +++ dom/crypto/RsaHashedKeyAlgorithm.cpp | 80 -- dom/crypto/RsaHashedKeyAlgorithm.h | 53 -- dom/crypto/RsaKeyAlgorithm.cpp | 46 -- dom/crypto/RsaKeyAlgorithm.h | 63 -- dom/crypto/WebCryptoCommon.h | 43 +- dom/crypto/WebCryptoTask.cpp | 681 ++++++++---------- dom/crypto/moz.build | 17 +- dom/crypto/test/test_WebCrypto.html | 160 ++-- dom/crypto/test/test_WebCrypto_ECDH.html | 14 +- dom/crypto/test/test_WebCrypto_JWK.html | 2 - dom/crypto/test/test_WebCrypto_PBKDF2.html | 5 +- dom/crypto/test/test_WebCrypto_RSA_OAEP.html | 3 +- .../mochitest/general/test_interfaces.html | 2 - dom/webidl/KeyAlgorithm.webidl | 32 + dom/webidl/SubtleCrypto.webidl | 102 +-- dom/webidl/moz.build | 1 + 33 files changed, 889 insertions(+), 1562 deletions(-) delete mode 100644 dom/crypto/AesKeyAlgorithm.cpp delete mode 100644 dom/crypto/AesKeyAlgorithm.h delete mode 100644 dom/crypto/BasicSymmetricKeyAlgorithm.h delete mode 100644 dom/crypto/CryptoKeyPair.cpp delete mode 100644 dom/crypto/CryptoKeyPair.h delete mode 100644 dom/crypto/EcKeyAlgorithm.cpp delete mode 100644 dom/crypto/EcKeyAlgorithm.h delete mode 100644 dom/crypto/HmacKeyAlgorithm.cpp delete mode 100644 dom/crypto/HmacKeyAlgorithm.h delete mode 100644 dom/crypto/KeyAlgorithm.cpp delete mode 100644 dom/crypto/KeyAlgorithm.h create mode 100644 dom/crypto/KeyAlgorithmProxy.cpp create mode 100644 dom/crypto/KeyAlgorithmProxy.h delete mode 100644 dom/crypto/RsaHashedKeyAlgorithm.cpp delete mode 100644 dom/crypto/RsaHashedKeyAlgorithm.h delete mode 100644 dom/crypto/RsaKeyAlgorithm.cpp delete mode 100644 dom/crypto/RsaKeyAlgorithm.h create mode 100644 dom/webidl/KeyAlgorithm.webidl diff --git a/dom/crypto/AesKeyAlgorithm.cpp b/dom/crypto/AesKeyAlgorithm.cpp deleted file mode 100644 index 78d0ea997932..000000000000 --- a/dom/crypto/AesKeyAlgorithm.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- 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/AesKeyAlgorithm.h" -#include "mozilla/dom/SubtleCryptoBinding.h" -#include "mozilla/dom/WebCryptoCommon.h" - -namespace mozilla { -namespace dom { - -JSObject* -AesKeyAlgorithm::WrapObject(JSContext* aCx) -{ - return AesKeyAlgorithmBinding::Wrap(aCx, this); -} - -nsString -AesKeyAlgorithm::ToJwkAlg() const -{ - if (mName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) { - switch (mLength) { - case 128: return NS_LITERAL_STRING(JWK_ALG_A128CBC); - case 192: return NS_LITERAL_STRING(JWK_ALG_A192CBC); - case 256: return NS_LITERAL_STRING(JWK_ALG_A256CBC); - } - } - - if (mName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) { - switch (mLength) { - case 128: return NS_LITERAL_STRING(JWK_ALG_A128CTR); - case 192: return NS_LITERAL_STRING(JWK_ALG_A192CTR); - case 256: return NS_LITERAL_STRING(JWK_ALG_A256CTR); - } - } - - if (mName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) { - switch (mLength) { - case 128: return NS_LITERAL_STRING(JWK_ALG_A128GCM); - case 192: return NS_LITERAL_STRING(JWK_ALG_A192GCM); - case 256: return NS_LITERAL_STRING(JWK_ALG_A256GCM); - } - } - - if (mName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) { - switch (mLength) { - case 128: return NS_LITERAL_STRING(JWK_ALG_A128KW); - case 192: return NS_LITERAL_STRING(JWK_ALG_A192KW); - case 256: return NS_LITERAL_STRING(JWK_ALG_A256KW); - } - } - - return nsString(); -} - -bool -AesKeyAlgorithm::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const -{ - return JS_WriteUint32Pair(aWriter, SCTAG_AESKEYALG, 0) && - JS_WriteUint32Pair(aWriter, mLength, 0) && - WriteString(aWriter, mName); -} - -KeyAlgorithm* -AesKeyAlgorithm::Create(nsIGlobalObject* aGlobal, JSStructuredCloneReader* aReader) -{ - uint32_t length, zero; - nsString name; - bool read = JS_ReadUint32Pair(aReader, &length, &zero) && - ReadString(aReader, name); - if (!read) { - return nullptr; - } - - return new AesKeyAlgorithm(aGlobal, name, length); -} - - -} // namespace dom -} // namespace mozilla diff --git a/dom/crypto/AesKeyAlgorithm.h b/dom/crypto/AesKeyAlgorithm.h deleted file mode 100644 index 737576aa2890..000000000000 --- a/dom/crypto/AesKeyAlgorithm.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- 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_AesKeyAlgorithm_h -#define mozilla_dom_AesKeyAlgorithm_h - -#include "mozilla/dom/BasicSymmetricKeyAlgorithm.h" -#include "js/TypeDecls.h" - -namespace mozilla { -namespace dom { - -class AesKeyAlgorithm MOZ_FINAL : public BasicSymmetricKeyAlgorithm -{ -public: - AesKeyAlgorithm(nsIGlobalObject* aGlobal, const nsString& aName, uint16_t aLength) - : BasicSymmetricKeyAlgorithm(aGlobal, aName, aLength) - {} - - ~AesKeyAlgorithm() - {} - - virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; - - virtual nsString ToJwkAlg() const MOZ_OVERRIDE; - - virtual bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const MOZ_OVERRIDE; - static KeyAlgorithm* Create(nsIGlobalObject* aGlobal, - JSStructuredCloneReader* aReader); -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_AesKeyAlgorithm_h diff --git a/dom/crypto/BasicSymmetricKeyAlgorithm.h b/dom/crypto/BasicSymmetricKeyAlgorithm.h deleted file mode 100644 index afcdc5f20346..000000000000 --- a/dom/crypto/BasicSymmetricKeyAlgorithm.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- 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_BasicSymmetricKeyAlgorithm_h -#define mozilla_dom_BasicSymmetricKeyAlgorithm_h - -#include "mozilla/dom/KeyAlgorithm.h" - -namespace mozilla { -namespace dom { - -class BasicSymmetricKeyAlgorithm : public KeyAlgorithm -{ -public: - BasicSymmetricKeyAlgorithm(nsIGlobalObject* aGlobal, const nsString& aName, uint16_t aLength) - : KeyAlgorithm(aGlobal, aName) - , mLength(aLength) - {} - - ~BasicSymmetricKeyAlgorithm() - {} - - uint16_t Length() const - { - return mLength; - } - -protected: - uint16_t mLength; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_BasicSymmetricKeyAlgorithm_h diff --git a/dom/crypto/CryptoBuffer.cpp b/dom/crypto/CryptoBuffer.cpp index d719cf6a94d6..73a5f81d68e5 100644 --- a/dom/crypto/CryptoBuffer.cpp +++ b/dom/crypto/CryptoBuffer.cpp @@ -161,6 +161,13 @@ CryptoBuffer::ToSECItem() const return item; } +JSObject* +CryptoBuffer::ToUint8Array(JSContext* aCx) const +{ + return Uint8Array::Create(aCx, Length(), Elements()); +} + + // "BigInt" comes from the WebCrypto spec // ("unsigned long" isn't very "big", of course) // Likewise, the spec calls for big-endian ints diff --git a/dom/crypto/CryptoBuffer.h b/dom/crypto/CryptoBuffer.h index 6a9c4eb60b39..e5ec172c15d4 100644 --- a/dom/crypto/CryptoBuffer.h +++ b/dom/crypto/CryptoBuffer.h @@ -40,6 +40,7 @@ public: nsresult FromJwkBase64(const nsString& aBase64); nsresult ToJwkBase64(nsString& aBase64); SECItem* ToSECItem() const; + JSObject* ToUint8Array(JSContext* aCx) const; bool GetBigIntValue(unsigned long& aRetVal); }; diff --git a/dom/crypto/CryptoKey.cpp b/dom/crypto/CryptoKey.cpp index 42ac26d5d86b..3647ecb27b46 100644 --- a/dom/crypto/CryptoKey.cpp +++ b/dom/crypto/CryptoKey.cpp @@ -10,11 +10,12 @@ #include "mozilla/dom/CryptoKey.h" #include "mozilla/dom/WebCryptoCommon.h" #include "mozilla/dom/SubtleCryptoBinding.h" +#include "mozilla/dom/ToJSValue.h" namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CryptoKey, mGlobal, mAlgorithm) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CryptoKey, mGlobal) NS_IMPL_CYCLE_COLLECTING_ADDREF(CryptoKey) NS_IMPL_CYCLE_COLLECTING_RELEASE(CryptoKey) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CryptoKey) @@ -90,10 +91,35 @@ CryptoKey::Extractable() const return (mAttributes & EXTRACTABLE); } -KeyAlgorithm* -CryptoKey::Algorithm() const +void +CryptoKey::GetAlgorithm(JSContext* cx, JS::MutableHandle aRetVal, + ErrorResult& aRv) const { - return mAlgorithm; + bool converted = false; + JS::RootedValue val(cx); + switch (mAlgorithm.mType) { + case KeyAlgorithmProxy::AES: + converted = ToJSValue(cx, mAlgorithm.mAes, &val); + break; + case KeyAlgorithmProxy::HMAC: + converted = ToJSValue(cx, mAlgorithm.mHmac, &val); + break; + case KeyAlgorithmProxy::RSA: { + RootedDictionary rsa(cx); + mAlgorithm.mRsa.ToKeyAlgorithm(cx, rsa); + converted = ToJSValue(cx, rsa, &val); + break; + } + case KeyAlgorithmProxy::EC: + converted = ToJSValue(cx, mAlgorithm.mEc, &val); + break; + } + if (!converted) { + aRv.Throw(NS_ERROR_DOM_OPERATION_ERR); + return; + } + + aRetVal.set(&val.toObject()); } void @@ -125,6 +151,18 @@ CryptoKey::GetUsages(nsTArray& aRetVal) const } } +KeyAlgorithmProxy& +CryptoKey::Algorithm() +{ + return mAlgorithm; +} + +const KeyAlgorithmProxy& +CryptoKey::Algorithm() const +{ + return mAlgorithm; +} + CryptoKey::KeyType CryptoKey::GetKeyType() const { @@ -165,12 +203,6 @@ CryptoKey::SetExtractable(bool aExtractable) } } -void -CryptoKey::SetAlgorithm(KeyAlgorithm* aAlgorithm) -{ - mAlgorithm = aAlgorithm; -} - void CryptoKey::ClearUsages() { @@ -205,6 +237,12 @@ CryptoKey::AddUsage(CryptoKey::KeyUsage aUsage) mAttributes |= aUsage; } +bool +CryptoKey::HasAnyUsage() +{ + return !!(mAttributes & USAGES_MASK); +} + bool CryptoKey::HasUsage(CryptoKey::KeyUsage aUsage) { @@ -217,6 +255,25 @@ CryptoKey::HasUsageOtherThan(uint32_t aUsages) return !!(mAttributes & USAGES_MASK & ~aUsages); } +bool +CryptoKey::IsRecognizedUsage(const nsString& aUsage) +{ + KeyUsage dummy; + nsresult rv = StringToUsage(aUsage, dummy); + return NS_SUCCEEDED(rv); +} + +bool +CryptoKey::AllUsagesRecognized(const Sequence& aUsages) +{ + for (uint32_t i = 0; i < aUsages.Length(); ++i) { + if (!IsRecognizedUsage(aUsages[i])) { + return false; + } + } + return true; +} + void CryptoKey::SetSymKey(const CryptoBuffer& aSymKey) { mSymKey = aSymKey; @@ -441,14 +498,10 @@ SECKEYPrivateKey* CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { - if (!aJwk.mKty.WasPassed()) { - return nullptr; - } - CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY; CK_BBOOL falseValue = CK_FALSE; - if (aJwk.mKty.Value().EqualsLiteral(JWK_TYPE_EC)) { + if (aJwk.mKty.EqualsLiteral(JWK_TYPE_EC)) { // Verify that all of the required parameters are present CryptoBuffer x, y, d; if (!aJwk.mCrv.WasPassed() || @@ -459,7 +512,7 @@ CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk, } nsString namedCurve; - if (!NormalizeNamedCurveValue(aJwk.mCrv.Value(), namedCurve)) { + if (!NormalizeToken(aJwk.mCrv.Value(), namedCurve)) { return nullptr; } @@ -504,7 +557,7 @@ CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk, PR_ARRAY_SIZE(keyTemplate)); } - if (aJwk.mKty.Value().EqualsLiteral(JWK_TYPE_RSA)) { + if (aJwk.mKty.EqualsLiteral(JWK_TYPE_RSA)) { // Verify that all of the required parameters are present CryptoBuffer n, e, d, p, q, dp, dq, qi; if (!aJwk.mN.WasPassed() || NS_FAILED(n.FromJwkBase64(aJwk.mN.Value())) || @@ -643,7 +696,7 @@ ECKeyToJwk(const PK11ObjectType aKeyType, void* aKey, const SECItem* aEcParams, return false; } - aRetVal.mKty.Construct(NS_LITERAL_STRING(JWK_TYPE_EC)); + aRetVal.mKty = NS_LITERAL_STRING(JWK_TYPE_EC); return true; } @@ -674,7 +727,7 @@ CryptoKey::PrivateKeyToJwk(SECKEYPrivateKey* aPrivKey, return NS_ERROR_DOM_OPERATION_ERR; } - aRetVal.mKty.Construct(NS_LITERAL_STRING(JWK_TYPE_RSA)); + aRetVal.mKty = NS_LITERAL_STRING(JWK_TYPE_RSA); return NS_OK; } case ecKey: { @@ -716,11 +769,7 @@ SECKEYPublicKey* CryptoKey::PublicKeyFromJwk(const JsonWebKey& aJwk, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { - if (!aJwk.mKty.WasPassed()) { - return nullptr; - } - - if (aJwk.mKty.Value().EqualsLiteral(JWK_TYPE_RSA)) { + if (aJwk.mKty.EqualsLiteral(JWK_TYPE_RSA)) { // Verify that all of the required parameters are present CryptoBuffer n, e; if (!aJwk.mN.WasPassed() || NS_FAILED(n.FromJwkBase64(aJwk.mN.Value())) || @@ -753,7 +802,7 @@ CryptoKey::PublicKeyFromJwk(const JsonWebKey& aJwk, return SECKEY_ImportDERPublicKey(pkDer.get(), CKK_RSA); } - if (aJwk.mKty.Value().EqualsLiteral(JWK_TYPE_EC)) { + if (aJwk.mKty.EqualsLiteral(JWK_TYPE_EC)) { // Verify that all of the required parameters are present CryptoBuffer x, y; if (!aJwk.mCrv.WasPassed() || @@ -777,7 +826,7 @@ CryptoKey::PublicKeyFromJwk(const JsonWebKey& aJwk, key->pkcs11ID = CK_INVALID_HANDLE; nsString namedCurve; - if (!NormalizeNamedCurveValue(aJwk.mCrv.Value(), namedCurve)) { + if (!NormalizeToken(aJwk.mCrv.Value(), namedCurve)) { return nullptr; } @@ -819,7 +868,7 @@ CryptoKey::PublicKeyToJwk(SECKEYPublicKey* aPubKey, return NS_ERROR_DOM_OPERATION_ERR; } - aRetVal.mKty.Construct(NS_LITERAL_STRING(JWK_TYPE_RSA)); + aRetVal.mKty = NS_LITERAL_STRING(JWK_TYPE_RSA); return NS_OK; } case ecKey: @@ -857,11 +906,11 @@ CryptoKey::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const CryptoKey::PublicKeyToSpki(mPublicKey, pub, locker); } - return JS_WriteUint32Pair(aWriter, mAttributes, 0) && + return JS_WriteUint32Pair(aWriter, mAttributes, CRYPTOKEY_SC_VERSION) && WriteBuffer(aWriter, mSymKey) && WriteBuffer(aWriter, priv) && WriteBuffer(aWriter, pub) && - mAlgorithm->WriteStructuredClone(aWriter); + mAlgorithm.WriteStructuredClone(aWriter); } bool @@ -872,15 +921,15 @@ CryptoKey::ReadStructuredClone(JSStructuredCloneReader* aReader) return false; } - uint32_t zero; + uint32_t version; CryptoBuffer sym, priv, pub; - nsRefPtr algorithm; - bool read = JS_ReadUint32Pair(aReader, &mAttributes, &zero) && + bool read = JS_ReadUint32Pair(aReader, &mAttributes, &version) && + (version == CRYPTOKEY_SC_VERSION) && ReadBuffer(aReader, sym) && ReadBuffer(aReader, priv) && ReadBuffer(aReader, pub) && - (algorithm = KeyAlgorithm::Create(mGlobal, aReader)); + mAlgorithm.ReadStructuredClone(aReader); if (!read) { return false; } @@ -894,7 +943,6 @@ CryptoKey::ReadStructuredClone(JSStructuredCloneReader* aReader) if (pub.Length() > 0) { mPublicKey = CryptoKey::PublicKeyFromSpki(pub, locker); } - mAlgorithm = algorithm; // Ensure that what we've read is consistent // If the attributes indicate a key type, should have a key of that type diff --git a/dom/crypto/CryptoKey.h b/dom/crypto/CryptoKey.h index 44ae8195460b..d1f6f71d2f18 100644 --- a/dom/crypto/CryptoKey.h +++ b/dom/crypto/CryptoKey.h @@ -14,11 +14,14 @@ #include "pk11pub.h" #include "keyhi.h" #include "ScopedNSSTypes.h" -#include "mozilla/dom/KeyAlgorithm.h" +#include "mozilla/ErrorResult.h" #include "mozilla/dom/CryptoBuffer.h" +#include "mozilla/dom/KeyAlgorithmProxy.h" #include "js/StructuredClone.h" #include "js/TypeDecls.h" +#define CRYPTOKEY_SC_VERSION 0x00000001 + class nsIGlobalObject; namespace mozilla { @@ -100,23 +103,28 @@ public: // WebIDL methods void GetType(nsString& aRetVal) const; bool Extractable() const; - KeyAlgorithm* Algorithm() const; + void GetAlgorithm(JSContext* cx, JS::MutableHandle aRetVal, + ErrorResult& aRv) const; void GetUsages(nsTArray& aRetVal) const; // The below methods are not exposed to JS, but C++ can use // them to manipulate the object + KeyAlgorithmProxy& Algorithm(); + const KeyAlgorithmProxy& Algorithm() const; KeyType GetKeyType() const; nsresult SetType(const nsString& aType); void SetType(KeyType aType); void SetExtractable(bool aExtractable); - void SetAlgorithm(KeyAlgorithm* aAlgorithm); void ClearUsages(); nsresult AddUsage(const nsString& aUsage); nsresult AddUsageIntersecting(const nsString& aUsage, uint32_t aUsageMask); void AddUsage(KeyUsage aUsage); + bool HasAnyUsage(); bool HasUsage(KeyUsage aUsage); bool HasUsageOtherThan(uint32_t aUsages); + static bool IsRecognizedUsage(const nsString& aUsage); + static bool AllUsagesRecognized(const Sequence& aUsages); void SetSymKey(const CryptoBuffer& aSymKey); void SetPrivateKey(SECKEYPrivateKey* aPrivateKey); @@ -172,7 +180,7 @@ private: nsRefPtr mGlobal; uint32_t mAttributes; // see above - nsRefPtr mAlgorithm; + KeyAlgorithmProxy mAlgorithm; // Only one key handle should be set, according to the KeyType CryptoBuffer mSymKey; diff --git a/dom/crypto/CryptoKeyPair.cpp b/dom/crypto/CryptoKeyPair.cpp deleted file mode 100644 index 3a3bfc5fb108..000000000000 --- a/dom/crypto/CryptoKeyPair.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- 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/CryptoKeyPair.h" -#include "mozilla/dom/SubtleCryptoBinding.h" -#include "nsContentUtils.h" - -namespace mozilla { -namespace dom { - - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CryptoKeyPair, mGlobal, mPublicKey, mPrivateKey) -NS_IMPL_CYCLE_COLLECTING_ADDREF(CryptoKeyPair) -NS_IMPL_CYCLE_COLLECTING_RELEASE(CryptoKeyPair) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CryptoKeyPair) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -JSObject* -CryptoKeyPair::WrapObject(JSContext* aCx) -{ - return CryptoKeyPairBinding::Wrap(aCx, this); -} - - -} // namespace dom -} // namespace mozilla diff --git a/dom/crypto/CryptoKeyPair.h b/dom/crypto/CryptoKeyPair.h deleted file mode 100644 index 788a68732227..000000000000 --- a/dom/crypto/CryptoKeyPair.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- 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_CryptoKeyPair_h -#define mozilla_dom_CryptoKeyPair_h - -#include "nsCycleCollectionParticipant.h" -#include "nsWrapperCache.h" -#include "nsIGlobalObject.h" -#include "mozilla/dom/CryptoKey.h" -#include "js/TypeDecls.h" - -namespace mozilla { -namespace dom { - -class CryptoKeyPair MOZ_FINAL : public nsISupports, - public nsWrapperCache -{ -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CryptoKeyPair) - -public: - explicit CryptoKeyPair(nsIGlobalObject* aGlobal) - : mGlobal(aGlobal) - , mPublicKey(new CryptoKey(aGlobal)) - , mPrivateKey(new CryptoKey(aGlobal)) - { - SetIsDOMBinding(); - } - - nsIGlobalObject* GetParentObject() const - { - return mGlobal; - } - - virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; - - CryptoKey* PublicKey() const - { - return mPublicKey; - } - - CryptoKey* PrivateKey() const - { - return mPrivateKey; - } - -private: - ~CryptoKeyPair() {} - - nsRefPtr mGlobal; - nsRefPtr mPublicKey; - nsRefPtr mPrivateKey; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_CryptoKeyPair_h diff --git a/dom/crypto/EcKeyAlgorithm.cpp b/dom/crypto/EcKeyAlgorithm.cpp deleted file mode 100644 index 3dbb4d0009fe..000000000000 --- a/dom/crypto/EcKeyAlgorithm.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- 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/EcKeyAlgorithm.h" -#include "mozilla/dom/SubtleCryptoBinding.h" -#include "mozilla/dom/WebCryptoCommon.h" - -namespace mozilla { -namespace dom { - -JSObject* -EcKeyAlgorithm::WrapObject(JSContext* aCx) -{ - return EcKeyAlgorithmBinding::Wrap(aCx, this); -} - -bool -EcKeyAlgorithm::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const -{ - return JS_WriteUint32Pair(aWriter, SCTAG_ECKEYALG, 0) && - WriteString(aWriter, mNamedCurve) && - WriteString(aWriter, mName); -} - -KeyAlgorithm* -EcKeyAlgorithm::Create(nsIGlobalObject* aGlobal, JSStructuredCloneReader* aReader) -{ - nsString name; - nsString namedCurve; - bool read = ReadString(aReader, namedCurve) && - ReadString(aReader, name); - if (!read) { - return nullptr; - } - - return new EcKeyAlgorithm(aGlobal, name, namedCurve); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/crypto/EcKeyAlgorithm.h b/dom/crypto/EcKeyAlgorithm.h deleted file mode 100644 index f456e807b592..000000000000 --- a/dom/crypto/EcKeyAlgorithm.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- 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_EcKeyAlgorithm_h -#define mozilla_dom_EcKeyAlgorithm_h - -#include "mozilla/ErrorResult.h" -#include "mozilla/dom/KeyAlgorithm.h" -#include "js/TypeDecls.h" - -namespace mozilla { -namespace dom { - -class EcKeyAlgorithm : public KeyAlgorithm -{ -public: - EcKeyAlgorithm(nsIGlobalObject* aGlobal, - const nsString& aName, - const nsString& aNamedCurve) - : KeyAlgorithm(aGlobal, aName) - , mNamedCurve(aNamedCurve) - {} - - ~EcKeyAlgorithm() - {} - - virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; - - void GetNamedCurve(nsString& aRetVal) const - { - aRetVal.Assign(mNamedCurve); - } - - virtual bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const MOZ_OVERRIDE; - static KeyAlgorithm* Create(nsIGlobalObject* aGlobal, - JSStructuredCloneReader* aReader); - -protected: - nsString mNamedCurve; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_EcKeyAlgorithm_h diff --git a/dom/crypto/HmacKeyAlgorithm.cpp b/dom/crypto/HmacKeyAlgorithm.cpp deleted file mode 100644 index 858287139f6f..000000000000 --- a/dom/crypto/HmacKeyAlgorithm.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- 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/HmacKeyAlgorithm.h" -#include "mozilla/dom/SubtleCryptoBinding.h" - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_INHERITED(HmacKeyAlgorithm, KeyAlgorithm, mHash) -NS_IMPL_ADDREF_INHERITED(HmacKeyAlgorithm, KeyAlgorithm) -NS_IMPL_RELEASE_INHERITED(HmacKeyAlgorithm, KeyAlgorithm) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HmacKeyAlgorithm) -NS_INTERFACE_MAP_END_INHERITING(KeyAlgorithm) - -JSObject* -HmacKeyAlgorithm::WrapObject(JSContext* aCx) -{ - return HmacKeyAlgorithmBinding::Wrap(aCx, this); -} - -nsString -HmacKeyAlgorithm::ToJwkAlg() const -{ - switch (mMechanism) { - case CKM_SHA_1_HMAC: return NS_LITERAL_STRING(JWK_ALG_HS1); - case CKM_SHA256_HMAC: return NS_LITERAL_STRING(JWK_ALG_HS256); - case CKM_SHA384_HMAC: return NS_LITERAL_STRING(JWK_ALG_HS384); - case CKM_SHA512_HMAC: return NS_LITERAL_STRING(JWK_ALG_HS512); - } - return nsString(); -} - -bool -HmacKeyAlgorithm::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const -{ - nsString hashName; - mHash->GetName(hashName); - return JS_WriteUint32Pair(aWriter, SCTAG_HMACKEYALG, 0) && - JS_WriteUint32Pair(aWriter, mLength, 0) && - WriteString(aWriter, hashName) && - WriteString(aWriter, mName); -} - -KeyAlgorithm* -HmacKeyAlgorithm::Create(nsIGlobalObject* aGlobal, JSStructuredCloneReader* aReader) -{ - uint32_t length, zero; - nsString hash, name; - bool read = JS_ReadUint32Pair(aReader, &length, &zero) && - ReadString(aReader, hash) && - ReadString(aReader, name); - if (!read) { - return nullptr; - } - - return new HmacKeyAlgorithm(aGlobal, name, length, hash); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/crypto/HmacKeyAlgorithm.h b/dom/crypto/HmacKeyAlgorithm.h deleted file mode 100644 index 72b9c28cddd1..000000000000 --- a/dom/crypto/HmacKeyAlgorithm.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- 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_HmacKeyAlgorithm_h -#define mozilla_dom_HmacKeyAlgorithm_h - -#include "nsCycleCollectionParticipant.h" -#include "nsWrapperCache.h" -#include "nsAutoPtr.h" -#include "mozilla/dom/KeyAlgorithm.h" -#include "mozilla/dom/WebCryptoCommon.h" -#include "js/TypeDecls.h" - -namespace mozilla { -namespace dom { - -class HmacKeyAlgorithm MOZ_FINAL : public KeyAlgorithm -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HmacKeyAlgorithm, KeyAlgorithm) - - HmacKeyAlgorithm(nsIGlobalObject* aGlobal, - const nsString& aName, - uint32_t aLength, - const nsString& aHash) - : KeyAlgorithm(aGlobal, aName) - , mHash(new KeyAlgorithm(aGlobal, aHash)) - , mLength(aLength) - { - switch (mHash->Mechanism()) { - case CKM_SHA_1: mMechanism = CKM_SHA_1_HMAC; break; - case CKM_SHA256: mMechanism = CKM_SHA256_HMAC; break; - case CKM_SHA384: mMechanism = CKM_SHA384_HMAC; break; - case CKM_SHA512: mMechanism = CKM_SHA512_HMAC; break; - default: mMechanism = UNKNOWN_CK_MECHANISM; break; - } - } - - virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; - - KeyAlgorithm* Hash() const - { - return mHash; - } - - uint32_t Length() const - { - return mLength; - } - - virtual nsString ToJwkAlg() const MOZ_OVERRIDE; - - virtual bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const MOZ_OVERRIDE; - static KeyAlgorithm* Create(nsIGlobalObject* aGlobal, - JSStructuredCloneReader* aReader); - -protected: - ~HmacKeyAlgorithm() - {} - - nsRefPtr mHash; - uint32_t mLength; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_HmacKeyAlgorithm_h diff --git a/dom/crypto/KeyAlgorithm.cpp b/dom/crypto/KeyAlgorithm.cpp deleted file mode 100644 index 13d0ffb818c5..000000000000 --- a/dom/crypto/KeyAlgorithm.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* -*- 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/KeyAlgorithm.h" -#include "mozilla/dom/WebCryptoCommon.h" -#include "mozilla/dom/AesKeyAlgorithm.h" -#include "mozilla/dom/EcKeyAlgorithm.h" -#include "mozilla/dom/HmacKeyAlgorithm.h" -#include "mozilla/dom/RsaKeyAlgorithm.h" -#include "mozilla/dom/RsaHashedKeyAlgorithm.h" -#include "mozilla/dom/SubtleCryptoBinding.h" -#include "mozilla/dom/WebCryptoCommon.h" - -namespace mozilla { -namespace dom { - - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(KeyAlgorithm, mGlobal) -NS_IMPL_CYCLE_COLLECTING_ADDREF(KeyAlgorithm) -NS_IMPL_CYCLE_COLLECTING_RELEASE(KeyAlgorithm) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(KeyAlgorithm) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -KeyAlgorithm::KeyAlgorithm(nsIGlobalObject* aGlobal, const nsString& aName) - : mGlobal(aGlobal) - , mName(aName) -{ - SetIsDOMBinding(); - - // Set mechanism based on algorithm name - mMechanism = MapAlgorithmNameToMechanism(aName); - - // HMAC not handled here, since it requires extra info -} - -KeyAlgorithm::~KeyAlgorithm() -{ -} - -JSObject* -KeyAlgorithm::WrapObject(JSContext* aCx) -{ - return KeyAlgorithmBinding::Wrap(aCx, this); -} - -nsString -KeyAlgorithm::ToJwkAlg() const -{ - return nsString(); -} - -void -KeyAlgorithm::GetName(nsString& aRetVal) const -{ - aRetVal.Assign(mName); -} - -bool -KeyAlgorithm::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const -{ - return WriteString(aWriter, mName); -} - -KeyAlgorithm* -KeyAlgorithm::Create(nsIGlobalObject* aGlobal, JSStructuredCloneReader* aReader) -{ - uint32_t tag, zero; - bool read = JS_ReadUint32Pair( aReader, &tag, &zero ); - if (!read) { - return nullptr; - } - - KeyAlgorithm* algorithm = nullptr; - switch (tag) { - case SCTAG_KEYALG: { - nsString name; - read = ReadString(aReader, name); - if (!read) { - return nullptr; - } - algorithm = new KeyAlgorithm(aGlobal, name); - break; - } - case SCTAG_AESKEYALG: { - algorithm = AesKeyAlgorithm::Create(aGlobal, aReader); - break; - } - case SCTAG_ECKEYALG: { - algorithm = EcKeyAlgorithm::Create(aGlobal, aReader); - break; - } - case SCTAG_HMACKEYALG: { - algorithm = HmacKeyAlgorithm::Create(aGlobal, aReader); - break; - } - case SCTAG_RSAKEYALG: { - algorithm = RsaKeyAlgorithm::Create(aGlobal, aReader); - break; - } - case SCTAG_RSAHASHEDKEYALG: { - algorithm = RsaHashedKeyAlgorithm::Create(aGlobal, aReader); - break; - } - // No default, algorithm is already nullptr - } - - return algorithm; -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/crypto/KeyAlgorithm.h b/dom/crypto/KeyAlgorithm.h deleted file mode 100644 index 32aaccbce804..000000000000 --- a/dom/crypto/KeyAlgorithm.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- 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_KeyAlgorithm_h -#define mozilla_dom_KeyAlgorithm_h - -#include "nsCycleCollectionParticipant.h" -#include "nsIGlobalObject.h" -#include "nsWrapperCache.h" -#include "pk11pub.h" -#include "mozilla/dom/CryptoBuffer.h" -#include "js/StructuredClone.h" -#include "js/TypeDecls.h" - -namespace mozilla { -namespace dom { - -class CryptoKey; -class KeyAlgorithm; - -enum KeyAlgorithmStructuredCloneTags { - SCTAG_KEYALG, - SCTAG_AESKEYALG, - SCTAG_ECKEYALG, - SCTAG_HMACKEYALG, - SCTAG_RSAKEYALG, - SCTAG_RSAHASHEDKEYALG -}; - -} - -namespace dom { - -class KeyAlgorithm : public nsISupports, - public nsWrapperCache -{ -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(KeyAlgorithm) - -public: - KeyAlgorithm(nsIGlobalObject* aGlobal, const nsString& aName); - - nsIGlobalObject* GetParentObject() const - { - return mGlobal; - } - - virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; - - void GetName(nsString& aRetVal) const; - - virtual nsString ToJwkAlg() const; - - // Structured clone support methods - virtual bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const; - static KeyAlgorithm* Create(nsIGlobalObject* aGlobal, - JSStructuredCloneReader* aReader); - - // Helper method to look up NSS methods - // Sub-classes should assign mMechanism on constructor - CK_MECHANISM_TYPE Mechanism() const { - return mMechanism; - } - -protected: - virtual ~KeyAlgorithm(); - - nsRefPtr mGlobal; - nsString mName; - CK_MECHANISM_TYPE mMechanism; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_KeyAlgorithm_h diff --git a/dom/crypto/KeyAlgorithmProxy.cpp b/dom/crypto/KeyAlgorithmProxy.cpp new file mode 100644 index 000000000000..6fcc943bdf29 --- /dev/null +++ b/dom/crypto/KeyAlgorithmProxy.cpp @@ -0,0 +1,215 @@ +/* -*- 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/KeyAlgorithmProxy.h" +#include "mozilla/dom/WebCryptoCommon.h" + +namespace mozilla { +namespace dom { + +bool +KeyAlgorithmProxy::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const +{ + if (!WriteString(aWriter, mName) || + !JS_WriteUint32Pair(aWriter, mType, KEY_ALGORITHM_SC_VERSION)) { + return false; + } + + switch (mType) { + case AES: + return JS_WriteUint32Pair(aWriter, mAes.mLength, 0); + case HMAC: + return JS_WriteUint32Pair(aWriter, mHmac.mLength, 0) && + WriteString(aWriter, mHmac.mHash.mName); + case RSA: { + return JS_WriteUint32Pair(aWriter, mRsa.mModulusLength, 0) && + WriteBuffer(aWriter, mRsa.mPublicExponent) && + WriteString(aWriter, mRsa.mHash.mName); + } + case EC: + return WriteString(aWriter, mEc.mNamedCurve); + } + + return false; +} + +bool +KeyAlgorithmProxy::ReadStructuredClone(JSStructuredCloneReader* aReader) +{ + uint32_t type, version, dummy; + if (!ReadString(aReader, mName) || + !JS_ReadUint32Pair(aReader, &type, &version)) { + return false; + } + + if (version != KEY_ALGORITHM_SC_VERSION) { + return false; + } + + mType = (KeyAlgorithmType) type; + switch (mType) { + case AES: { + uint32_t length; + if (!JS_ReadUint32Pair(aReader, &length, &dummy)) { + return false; + } + + mAes.mLength = length; + mAes.mName = mName; + return true; + } + case HMAC: { + if (!JS_ReadUint32Pair(aReader, &mHmac.mLength, &dummy) || + !ReadString(aReader, mHmac.mHash.mName)) { + return false; + } + + mHmac.mName = mName; + return true; + } + case RSA: { + uint32_t modulusLength; + nsString hashName; + if (!JS_ReadUint32Pair(aReader, &modulusLength, &dummy) || + !ReadBuffer(aReader, mRsa.mPublicExponent) || + !ReadString(aReader, mRsa.mHash.mName)) { + return false; + } + + mRsa.mModulusLength = modulusLength; + mRsa.mName = mName; + return true; + } + case EC: { + nsString namedCurve; + if (!ReadString(aReader, mEc.mNamedCurve)) { + return false; + } + + mEc.mName = mName; + return true; + } + } + + return false; +} + +CK_MECHANISM_TYPE +KeyAlgorithmProxy::Mechanism() const +{ + if (mType == HMAC) { + return GetMechanism(mHmac); + } + return MapAlgorithmNameToMechanism(mName); +} + +nsString +KeyAlgorithmProxy::JwkAlg() const +{ + if (mName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) { + switch (mAes.mLength) { + case 128: return NS_LITERAL_STRING(JWK_ALG_A128CBC); + case 192: return NS_LITERAL_STRING(JWK_ALG_A192CBC); + case 256: return NS_LITERAL_STRING(JWK_ALG_A256CBC); + } + } + + if (mName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) { + switch (mAes.mLength) { + case 128: return NS_LITERAL_STRING(JWK_ALG_A128CTR); + case 192: return NS_LITERAL_STRING(JWK_ALG_A192CTR); + case 256: return NS_LITERAL_STRING(JWK_ALG_A256CTR); + } + } + + if (mName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) { + switch (mAes.mLength) { + case 128: return NS_LITERAL_STRING(JWK_ALG_A128GCM); + case 192: return NS_LITERAL_STRING(JWK_ALG_A192GCM); + case 256: return NS_LITERAL_STRING(JWK_ALG_A256GCM); + } + } + + if (mName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) { + switch (mAes.mLength) { + case 128: return NS_LITERAL_STRING(JWK_ALG_A128KW); + case 192: return NS_LITERAL_STRING(JWK_ALG_A192KW); + case 256: return NS_LITERAL_STRING(JWK_ALG_A256KW); + } + } + + if (mName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { + nsString hashName = mHmac.mHash.mName; + if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) { + return NS_LITERAL_STRING(JWK_ALG_HS1); + } else if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) { + return NS_LITERAL_STRING(JWK_ALG_HS256); + } else if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) { + return NS_LITERAL_STRING(JWK_ALG_HS384); + } else if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) { + return NS_LITERAL_STRING(JWK_ALG_HS512); + } + } + + if (mName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { + nsString hashName = mRsa.mHash.mName; + if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) { + return NS_LITERAL_STRING(JWK_ALG_RS1); + } else if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) { + return NS_LITERAL_STRING(JWK_ALG_RS256); + } else if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) { + return NS_LITERAL_STRING(JWK_ALG_RS384); + } else if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) { + return NS_LITERAL_STRING(JWK_ALG_RS512); + } + } + + if (mName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { + nsString hashName = mRsa.mHash.mName; + if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA1)) { + return NS_LITERAL_STRING(JWK_ALG_RSA_OAEP); + } else if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) { + return NS_LITERAL_STRING(JWK_ALG_RSA_OAEP_256); + } else if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) { + return NS_LITERAL_STRING(JWK_ALG_RSA_OAEP_384); + } else if (hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) { + return NS_LITERAL_STRING(JWK_ALG_RSA_OAEP_512); + } + } + + return nsString(); +} + +CK_MECHANISM_TYPE +KeyAlgorithmProxy::GetMechanism(const KeyAlgorithm& aAlgorithm) +{ + // For everything but HMAC, the name determines the mechanism + // HMAC is handled by the specialization below + return MapAlgorithmNameToMechanism(aAlgorithm.mName); +} + +CK_MECHANISM_TYPE +KeyAlgorithmProxy::GetMechanism(const HmacKeyAlgorithm& aAlgorithm) +{ + // The use of HmacKeyAlgorithm doesn't completely prevent this + // method from being called with dictionaries that don't really + // represent HMAC key algorithms. + MOZ_ASSERT(aAlgorithm.mName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)); + + CK_MECHANISM_TYPE hashMech; + hashMech = MapAlgorithmNameToMechanism(aAlgorithm.mHash.mName); + + switch (hashMech) { + case CKM_SHA_1: return CKM_SHA_1_HMAC; + case CKM_SHA256: return CKM_SHA256_HMAC; + case CKM_SHA384: return CKM_SHA384_HMAC; + case CKM_SHA512: return CKM_SHA512_HMAC; + } + return UNKNOWN_CK_MECHANISM; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/crypto/KeyAlgorithmProxy.h b/dom/crypto/KeyAlgorithmProxy.h new file mode 100644 index 000000000000..1d5f3eac5bfb --- /dev/null +++ b/dom/crypto/KeyAlgorithmProxy.h @@ -0,0 +1,117 @@ +/* -*- 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_KeyAlgorithmProxy_h +#define mozilla_dom_KeyAlgorithmProxy_h + +#include "pk11pub.h" +#include "js/StructuredClone.h" +#include "mozilla/dom/KeyAlgorithmBinding.h" +#include "mozilla/dom/WebCryptoCommon.h" + +#define KEY_ALGORITHM_SC_VERSION 0x00000001 + +namespace mozilla { +namespace dom { + +// A heap-safe variant of RsaHashedKeyAlgorithm +// The only difference is that it uses CryptoBuffer instead of Uint8Array +struct RsaHashedKeyAlgorithmStorage { + nsString mName; + KeyAlgorithm mHash; + uint16_t mModulusLength; + CryptoBuffer mPublicExponent; + + void + ToKeyAlgorithm(JSContext* aCx, RsaHashedKeyAlgorithm& aRsa) const + { + aRsa.mName = mName; + aRsa.mModulusLength = mModulusLength; + aRsa.mHash.mName = mHash.mName; + aRsa.mPublicExponent.Init(mPublicExponent.ToUint8Array(aCx)); + aRsa.mPublicExponent.ComputeLengthAndData(); + } +}; + +// This class encapuslates a KeyAlgorithm object, and adds several +// methods that make WebCrypto operations simpler. +struct KeyAlgorithmProxy +{ + enum KeyAlgorithmType { + AES, + HMAC, + RSA, + EC + }; + KeyAlgorithmType mType; + + // Plain is always populated with the algorithm name + // Others are only populated for the corresponding key type + nsString mName; + AesKeyAlgorithm mAes; + HmacKeyAlgorithm mHmac; + RsaHashedKeyAlgorithmStorage mRsa; + EcKeyAlgorithm mEc; + + // Structured clone + bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const; + bool ReadStructuredClone(JSStructuredCloneReader* aReader); + + // Extract various forms of derived information + CK_MECHANISM_TYPE Mechanism() const; + nsString JwkAlg() const; + + // And in static form for calling on raw KeyAlgorithm dictionaries + static CK_MECHANISM_TYPE GetMechanism(const KeyAlgorithm& aAlgorithm); + static CK_MECHANISM_TYPE GetMechanism(const HmacKeyAlgorithm& aAlgorithm); + static nsString GetJwkAlg(const KeyAlgorithm& aAlgorithm); + + // Construction of the various algorithm types + void + MakeAes(const nsString& aName, uint32_t aLength) + { + mType = AES; + mName = aName; + mAes.mName = aName; + mAes.mLength = aLength; + } + + void + MakeHmac(uint32_t aLength, const nsString& aHashName) + { + mType = HMAC; + mName = NS_LITERAL_STRING(WEBCRYPTO_ALG_HMAC); + mHmac.mName = NS_LITERAL_STRING(WEBCRYPTO_ALG_HMAC); + mHmac.mLength = aLength; + mHmac.mHash.mName = aHashName; + } + + void + MakeRsa(const nsString& aName, uint32_t aModulusLength, + const CryptoBuffer& aPublicExponent, const nsString& aHashName) + { + mType = RSA; + mName = aName; + mRsa.mName = aName; + mRsa.mModulusLength = aModulusLength; + mRsa.mHash.mName = aHashName; + mRsa.mPublicExponent.Assign(aPublicExponent); + } + + void + MakeEc(const nsString& aName, const nsString& aNamedCurve) + { + mType = EC; + mName = aName; + mEc.mName = aName; + mEc.mNamedCurve = aNamedCurve; + } +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_KeyAlgorithmProxy_h diff --git a/dom/crypto/RsaHashedKeyAlgorithm.cpp b/dom/crypto/RsaHashedKeyAlgorithm.cpp deleted file mode 100644 index 70623fcf22a6..000000000000 --- a/dom/crypto/RsaHashedKeyAlgorithm.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- 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/RsaHashedKeyAlgorithm.h" -#include "mozilla/dom/SubtleCryptoBinding.h" -#include "mozilla/dom/WebCryptoCommon.h" - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_INHERITED(RsaHashedKeyAlgorithm, RsaKeyAlgorithm, mHash) -NS_IMPL_ADDREF_INHERITED(RsaHashedKeyAlgorithm, RsaKeyAlgorithm) -NS_IMPL_RELEASE_INHERITED(RsaHashedKeyAlgorithm, RsaKeyAlgorithm) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RsaHashedKeyAlgorithm) -NS_INTERFACE_MAP_END_INHERITING(RsaKeyAlgorithm) - -JSObject* -RsaHashedKeyAlgorithm::WrapObject(JSContext* aCx) -{ - return RsaHashedKeyAlgorithmBinding::Wrap(aCx, this); -} - -nsString -RsaHashedKeyAlgorithm::ToJwkAlg() const -{ - if (mName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { - switch (mHash->Mechanism()) { - case CKM_SHA_1: return NS_LITERAL_STRING(JWK_ALG_RS1); - case CKM_SHA256: return NS_LITERAL_STRING(JWK_ALG_RS256); - case CKM_SHA384: return NS_LITERAL_STRING(JWK_ALG_RS384); - case CKM_SHA512: return NS_LITERAL_STRING(JWK_ALG_RS512); - } - } - - if (mName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { - switch(mHash->Mechanism()) { - case CKM_SHA_1: return NS_LITERAL_STRING(JWK_ALG_RSA_OAEP); - case CKM_SHA256: return NS_LITERAL_STRING(JWK_ALG_RSA_OAEP_256); - case CKM_SHA384: return NS_LITERAL_STRING(JWK_ALG_RSA_OAEP_256); - case CKM_SHA512: return NS_LITERAL_STRING(JWK_ALG_RSA_OAEP_512); - } - } - - return nsString(); -} - -bool -RsaHashedKeyAlgorithm::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const -{ - nsString hashName; - mHash->GetName(hashName); - return JS_WriteUint32Pair(aWriter, SCTAG_RSAHASHEDKEYALG, 0) && - JS_WriteUint32Pair(aWriter, mModulusLength, 0) && - WriteBuffer(aWriter, mPublicExponent) && - WriteString(aWriter, hashName) && - WriteString(aWriter, mName); -} - -KeyAlgorithm* -RsaHashedKeyAlgorithm::Create(nsIGlobalObject* aGlobal, JSStructuredCloneReader* aReader) { - uint32_t modulusLength, zero; - CryptoBuffer publicExponent; - nsString name, hash; - - bool read = JS_ReadUint32Pair(aReader, &modulusLength, &zero) && - ReadBuffer(aReader, publicExponent) && - ReadString(aReader, hash) && - ReadString(aReader, name); - if (!read) { - return nullptr; - } - - return new RsaHashedKeyAlgorithm(aGlobal, name, modulusLength, publicExponent, hash); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/crypto/RsaHashedKeyAlgorithm.h b/dom/crypto/RsaHashedKeyAlgorithm.h deleted file mode 100644 index e8d546f74c9a..000000000000 --- a/dom/crypto/RsaHashedKeyAlgorithm.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- 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_RsaHashedKeyAlgorithm_h -#define mozilla_dom_RsaHashedKeyAlgorithm_h - -#include "nsAutoPtr.h" -#include "mozilla/dom/RsaKeyAlgorithm.h" - -namespace mozilla { -namespace dom { - -class RsaHashedKeyAlgorithm MOZ_FINAL : public RsaKeyAlgorithm -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(RsaHashedKeyAlgorithm, RsaKeyAlgorithm) - - RsaHashedKeyAlgorithm(nsIGlobalObject* aGlobal, - const nsString& aName, - uint32_t aModulusLength, - const CryptoBuffer& aPublicExponent, - const nsString& aHashName) - : RsaKeyAlgorithm(aGlobal, aName, aModulusLength, aPublicExponent) - , mHash(new KeyAlgorithm(aGlobal, aHashName)) - {} - - virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; - - virtual nsString ToJwkAlg() const MOZ_OVERRIDE; - - KeyAlgorithm* Hash() const - { - return mHash; - } - - virtual bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const MOZ_OVERRIDE; - static KeyAlgorithm* Create(nsIGlobalObject* aGlobal, - JSStructuredCloneReader* aReader); - -private: - ~RsaHashedKeyAlgorithm() {} - - nsRefPtr mHash; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_RsaHashedKeyAlgorithm_h diff --git a/dom/crypto/RsaKeyAlgorithm.cpp b/dom/crypto/RsaKeyAlgorithm.cpp deleted file mode 100644 index 65f5ba4cd225..000000000000 --- a/dom/crypto/RsaKeyAlgorithm.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- 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/RsaKeyAlgorithm.h" -#include "mozilla/dom/SubtleCryptoBinding.h" -#include "mozilla/dom/WebCryptoCommon.h" - -namespace mozilla { -namespace dom { - -JSObject* -RsaKeyAlgorithm::WrapObject(JSContext* aCx) -{ - return RsaKeyAlgorithmBinding::Wrap(aCx, this); -} - -bool -RsaKeyAlgorithm::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const -{ - return JS_WriteUint32Pair(aWriter, SCTAG_RSAKEYALG, 0) && - JS_WriteUint32Pair(aWriter, mModulusLength, 0) && - WriteBuffer(aWriter, mPublicExponent) && - WriteString(aWriter, mName); -} - -KeyAlgorithm* -RsaKeyAlgorithm::Create(nsIGlobalObject* aGlobal, JSStructuredCloneReader* aReader) -{ - uint32_t modulusLength, zero; - CryptoBuffer publicExponent; - nsString name; - bool read = JS_ReadUint32Pair(aReader, &modulusLength, &zero) && - ReadBuffer(aReader, publicExponent) && - ReadString(aReader, name); - if (!read) { - return nullptr; - } - - return new RsaKeyAlgorithm(aGlobal, name, modulusLength, publicExponent); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/crypto/RsaKeyAlgorithm.h b/dom/crypto/RsaKeyAlgorithm.h deleted file mode 100644 index 9aa9e53782b0..000000000000 --- a/dom/crypto/RsaKeyAlgorithm.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- 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_RsaKeyAlgorithm_h -#define mozilla_dom_RsaKeyAlgorithm_h - -#include "mozilla/ErrorResult.h" -#include "mozilla/dom/KeyAlgorithm.h" -#include "js/TypeDecls.h" - -namespace mozilla { -namespace dom { - -class RsaKeyAlgorithm : public KeyAlgorithm -{ -public: - RsaKeyAlgorithm(nsIGlobalObject* aGlobal, - const nsString& aName, - uint32_t aModulusLength, - const CryptoBuffer& aPublicExponent) - : KeyAlgorithm(aGlobal, aName) - , mModulusLength(aModulusLength) - , mPublicExponent(aPublicExponent) - {} - - ~RsaKeyAlgorithm() - {} - - virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; - - uint32_t ModulusLength() const - { - return mModulusLength; - } - - void GetPublicExponent(JSContext* cx, JS::MutableHandle aRetval, - ErrorResult& aError) const - { - TypedArrayCreator creator(mPublicExponent); - JSObject* retval = creator.Create(cx); - if (!retval) { - aError.Throw(NS_ERROR_OUT_OF_MEMORY); - } else { - aRetval.set(retval); - } - } - - virtual bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const MOZ_OVERRIDE; - static KeyAlgorithm* Create(nsIGlobalObject* aGlobal, - JSStructuredCloneReader* aReader); - -protected: - uint32_t mModulusLength; - CryptoBuffer mPublicExponent; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_RsaKeyAlgorithm_h diff --git a/dom/crypto/WebCryptoCommon.h b/dom/crypto/WebCryptoCommon.h index 5a0e2c1e00a3..891c4c981105 100644 --- a/dom/crypto/WebCryptoCommon.h +++ b/dom/crypto/WebCryptoCommon.h @@ -9,6 +9,7 @@ #include "pk11pub.h" #include "nsString.h" +#include "nsContentUtils.h" #include "mozilla/dom/CryptoBuffer.h" #include "js/StructuredClone.h" @@ -23,7 +24,6 @@ #define WEBCRYPTO_ALG_SHA512 "SHA-512" #define WEBCRYPTO_ALG_HMAC "HMAC" #define WEBCRYPTO_ALG_PBKDF2 "PBKDF2" -#define WEBCRYPTO_ALG_RSAES_PKCS1 "RSAES-PKCS1-v1_5" #define WEBCRYPTO_ALG_RSASSA_PKCS1 "RSASSA-PKCS1-v1_5" #define WEBCRYPTO_ALG_RSA_OAEP "RSA-OAEP" #define WEBCRYPTO_ALG_ECDH "ECDH" @@ -181,8 +181,6 @@ MapAlgorithmNameToMechanism(const nsString& aName) mechanism = CKM_SHA512; } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) { mechanism = CKM_PKCS5_PBKD2; - } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) { - mechanism = CKM_RSA_PKCS; } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { mechanism = CKM_RSA_PKCS; } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { @@ -194,14 +192,45 @@ MapAlgorithmNameToMechanism(const nsString& aName) return mechanism; } +#define NORMALIZED_EQUALS(aTest, aConst) \ + nsContentUtils::EqualsIgnoreASCIICase(aTest, NS_LITERAL_STRING(aConst)) + inline bool -NormalizeNamedCurveValue(const nsString& aNamedCurve, nsString& aDest) +NormalizeToken(const nsString& aName, nsString& aDest) { - if (aNamedCurve.EqualsIgnoreCase(WEBCRYPTO_NAMED_CURVE_P256)) { + // Algorithm names + if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_CBC)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_AES_CBC); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_CTR)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_AES_CTR); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_GCM)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_AES_GCM); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_AES_KW)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_AES_KW); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA1)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_SHA1); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA256)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_SHA256); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA384)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_SHA384); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_SHA512)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_SHA512); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_HMAC)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_HMAC); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_PBKDF2)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_PBKDF2); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSASSA_PKCS1)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_OAEP)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP); + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) { + aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH); + // Named curve values + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P256)) { aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256); - } else if (aNamedCurve.EqualsIgnoreCase(WEBCRYPTO_NAMED_CURVE_P384)) { + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P384)) { aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384); - } else if (aNamedCurve.EqualsIgnoreCase(WEBCRYPTO_NAMED_CURVE_P521)) { + } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P521)) { aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521); } else { return false; diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp index accb59954524..90bf6c6002f4 100644 --- a/dom/crypto/WebCryptoTask.cpp +++ b/dom/crypto/WebCryptoTask.cpp @@ -11,16 +11,9 @@ #include "jsapi.h" #include "mozilla/Telemetry.h" -#include "mozilla/dom/AesKeyAlgorithm.h" #include "mozilla/dom/CryptoBuffer.h" #include "mozilla/dom/CryptoKey.h" -#include "mozilla/dom/CryptoKeyPair.h" -#include "mozilla/dom/EcKeyAlgorithm.h" -#include "mozilla/dom/HmacKeyAlgorithm.h" -#include "mozilla/dom/KeyAlgorithm.h" -#include "mozilla/dom/RsaHashedKeyAlgorithm.h" -#include "mozilla/dom/RsaKeyAlgorithm.h" -#include "mozilla/dom/ToJSValue.h" +#include "mozilla/dom/KeyAlgorithmProxy.h" #include "mozilla/dom/TypedArray.h" #include "mozilla/dom/WebCryptoCommon.h" #include "mozilla/dom/WebCryptoTask.h" @@ -54,7 +47,7 @@ enum TelemetryAlgorithm { TA_AES_CFB = 2, TA_AES_CTR = 3, TA_AES_GCM = 4, - TA_RSAES_PKCS1 = 5, + TA_RSAES_PKCS1 = 5, // NB: This algorithm has been removed TA_RSA_OAEP = 6, // sign/verify TA_RSASSA_PKCS1 = 7, @@ -99,9 +92,7 @@ enum TelemetryAlgorithm { // Safety check for algorithms that use keys, suitable for constructors #define CHECK_KEY_ALGORITHM(keyAlg, algName) \ { \ - nsString keyAlgName; \ - keyAlg->GetName(keyAlgName); \ - if (!keyAlgName.EqualsLiteral(algName)) { \ + if (!NORMALIZED_EQUALS(keyAlg.mName, algName)) { \ mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; \ return; \ } \ @@ -137,42 +128,15 @@ GetAlgorithmName(JSContext* aCx, const OOS& aAlgorithm, nsString& aName) JS::RootedValue value(aCx, JS::ObjectValue(*aAlgorithm.GetAsObject())); Algorithm alg; - if (!alg.Init(aCx, value) || !alg.mName.WasPassed()) { + if (!alg.Init(aCx, value)) { return NS_ERROR_DOM_SYNTAX_ERR; } - aName.Assign(alg.mName.Value()); + aName = alg.mName; } - // Normalize algorithm names. - if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_AES_CBC)) { - aName.AssignLiteral(WEBCRYPTO_ALG_AES_CBC); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_AES_CTR)) { - aName.AssignLiteral(WEBCRYPTO_ALG_AES_CTR); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_AES_GCM)) { - aName.AssignLiteral(WEBCRYPTO_ALG_AES_GCM); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_AES_KW)) { - aName.AssignLiteral(WEBCRYPTO_ALG_AES_KW); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_SHA1)) { - aName.AssignLiteral(WEBCRYPTO_ALG_SHA1); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_SHA256)) { - aName.AssignLiteral(WEBCRYPTO_ALG_SHA256); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_SHA384)) { - aName.AssignLiteral(WEBCRYPTO_ALG_SHA384); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_SHA512)) { - aName.AssignLiteral(WEBCRYPTO_ALG_SHA512); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_HMAC)) { - aName.AssignLiteral(WEBCRYPTO_ALG_HMAC); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_PBKDF2)) { - aName.AssignLiteral(WEBCRYPTO_ALG_PBKDF2); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_RSAES_PKCS1)) { - aName.AssignLiteral(WEBCRYPTO_ALG_RSAES_PKCS1); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_RSASSA_PKCS1)) { - aName.AssignLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_RSA_OAEP)) { - aName.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP); - } else if (aName.EqualsIgnoreCase(WEBCRYPTO_ALG_ECDH)) { - aName.AssignLiteral(WEBCRYPTO_ALG_ECDH); + if (!NormalizeToken(aName, aName)) { + return NS_ERROR_DOM_SYNTAX_ERR; } return NS_OK; @@ -230,17 +194,17 @@ GetKeyLengthForAlgorithm(JSContext* aCx, const ObjectOrString& aAlgorithm, algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) || algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) { RootedDictionary params(aCx); - if (NS_FAILED(Coerce(aCx, params, aAlgorithm)) || - !params.mLength.WasPassed()) { + if (NS_FAILED(Coerce(aCx, params, aAlgorithm))) { return NS_ERROR_DOM_SYNTAX_ERR; } - size_t length = params.mLength.Value(); - if (length != 128 && length != 192 && length != 256) { + if (params.mLength != 128 && + params.mLength != 192 && + params.mLength != 256) { return NS_ERROR_DOM_DATA_ERR; } - aLength = length; + aLength = params.mLength; return NS_OK; } @@ -248,8 +212,7 @@ GetKeyLengthForAlgorithm(JSContext* aCx, const ObjectOrString& aAlgorithm, // determine key length as the block size of the given hash. if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { RootedDictionary params(aCx); - if (NS_FAILED(Coerce(aCx, params, aAlgorithm)) || - !params.mHash.WasPassed()) { + if (NS_FAILED(Coerce(aCx, params, aAlgorithm))) { return NS_ERROR_DOM_SYNTAX_ERR; } @@ -260,7 +223,7 @@ GetKeyLengthForAlgorithm(JSContext* aCx, const ObjectOrString& aAlgorithm, } nsString hashName; - if (NS_FAILED(GetAlgorithmName(aCx, params.mHash.Value(), hashName))) { + if (NS_FAILED(GetAlgorithmName(aCx, params.mHash, hashName))) { return NS_ERROR_DOM_SYNTAX_ERR; } @@ -318,7 +281,6 @@ CloneData(JSContext* aCx, CryptoBuffer& aDst, JS::Handle aSrc) return false; } - // Implementation of WebCryptoTask methods void @@ -464,12 +426,12 @@ public: telemetryAlg = TA_AES_CBC; AesCbcParams params; nsresult rv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(rv) || !params.mIv.WasPassed()) { + if (NS_FAILED(rv)) { mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; return; } - ATTEMPT_BUFFER_INIT(mIv, params.mIv.Value()) + ATTEMPT_BUFFER_INIT(mIv, params.mIv) if (mIv.Length() != 16) { mEarlyRv = NS_ERROR_DOM_DATA_ERR; return; @@ -481,19 +443,18 @@ public: telemetryAlg = TA_AES_CTR; AesCtrParams params; nsresult rv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(rv) || !params.mCounter.WasPassed() || - !params.mLength.WasPassed()) { + if (NS_FAILED(rv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } - ATTEMPT_BUFFER_INIT(mIv, params.mCounter.Value()) + ATTEMPT_BUFFER_INIT(mIv, params.mCounter) if (mIv.Length() != 16) { mEarlyRv = NS_ERROR_DOM_DATA_ERR; return; } - mCounterLength = params.mLength.Value(); + mCounterLength = params.mLength; } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) { CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_GCM); @@ -501,12 +462,12 @@ public: telemetryAlg = TA_AES_GCM; AesGcmParams params; nsresult rv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(rv) || !params.mIv.WasPassed()) { + if (NS_FAILED(rv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } - ATTEMPT_BUFFER_INIT(mIv, params.mIv.Value()) + ATTEMPT_BUFFER_INIT(mIv, params.mIv) if (params.mAdditionalData.WasPassed()) { ATTEMPT_BUFFER_INIT(mAad, params.mAdditionalData.Value()) @@ -743,104 +704,6 @@ private: } }; -class RsaesPkcs1Task : public ReturnArrayBufferViewTask, - public DeferredData -{ -public: - RsaesPkcs1Task(JSContext* aCx, const ObjectOrString& aAlgorithm, - CryptoKey& aKey, bool aEncrypt) - : mPrivKey(aKey.GetPrivateKey()) - , mPubKey(aKey.GetPublicKey()) - , mEncrypt(aEncrypt) - { - Init(aCx, aAlgorithm, aKey, aEncrypt); - } - - RsaesPkcs1Task(JSContext* aCx, const ObjectOrString& aAlgorithm, - CryptoKey& aKey, const CryptoOperationData& aData, - bool aEncrypt) - : mPrivKey(aKey.GetPrivateKey()) - , mPubKey(aKey.GetPublicKey()) - , mEncrypt(aEncrypt) - { - Init(aCx, aAlgorithm, aKey, aEncrypt); - SetData(aData); - } - - void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, - CryptoKey& aKey, bool aEncrypt) - { - - Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSAES_PKCS1); - - CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_RSAES_PKCS1); - - if (mEncrypt) { - if (!mPubKey) { - mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; - return; - } - mStrength = SECKEY_PublicKeyStrength(mPubKey); - } else { - if (!mPrivKey) { - mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; - return; - } - mStrength = PK11_GetPrivateModulusLen(mPrivKey); - } - } - -private: - ScopedSECKEYPrivateKey mPrivKey; - ScopedSECKEYPublicKey mPubKey; - uint32_t mStrength; - bool mEncrypt; - - virtual nsresult BeforeCrypto() MOZ_OVERRIDE - { - if (!mDataIsSet) { - return NS_ERROR_DOM_OPERATION_ERR; - } - - // Verify that the data input is not too big - // (as required by PKCS#1 / RFC 3447, Section 7.2) - // http://tools.ietf.org/html/rfc3447#section-7.2 - if (mEncrypt && mData.Length() > mStrength - 11) { - return NS_ERROR_DOM_DATA_ERR; - } - - return NS_OK; - } - - virtual nsresult DoCrypto() MOZ_OVERRIDE - { - nsresult rv; - - // Ciphertext is an integer mod the modulus, so it will be - // no longer than mStrength octets - if (!mResult.SetLength(mStrength)) { - return NS_ERROR_DOM_UNKNOWN_ERR; - } - - if (mEncrypt) { - rv = MapSECStatus(PK11_PubEncryptPKCS1( - mPubKey.get(), mResult.Elements(), - mData.Elements(), mData.Length(), - nullptr)); - } else { - uint32_t outLen; - rv = MapSECStatus(PK11_PrivDecryptPKCS1( - mPrivKey.get(), mResult.Elements(), - &outLen, mResult.Length(), - mData.Elements(), mData.Length())); - mResult.SetLength(outLen); - } - - NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); - return NS_OK; - } -}; - class RsaOaepTask : public ReturnArrayBufferViewTask, public DeferredData { @@ -896,8 +759,8 @@ public: return; } - if (params.mLabel.WasPassed() && !params.mLabel.Value().IsNull()) { - ATTEMPT_BUFFER_INIT(mLabel, params.mLabel.Value().Value()); + if (params.mLabel.WasPassed()) { + ATTEMPT_BUFFER_INIT(mLabel, params.mLabel.Value()); } } // Otherwise mLabel remains the empty octet string, as intended @@ -906,10 +769,7 @@ public: // static_cast is safe because we only get here if the algorithm name // is RSA-OAEP, and that only happens if we've constructed // an RsaHashedKeyAlgorithm. - // TODO: Add As* methods to KeyAlgorithm (Bug 1036734) - nsRefPtr rsaAlg = - static_cast(aKey.Algorithm()); - mHashMechanism = rsaAlg->Hash()->Mechanism(); + mHashMechanism = KeyAlgorithmProxy::GetMechanism(aKey.Algorithm().mRsa.mHash); switch (mHashMechanism) { case CKM_SHA_1: @@ -996,7 +856,7 @@ public: const CryptoOperationData& aSignature, const CryptoOperationData& aData, bool aSign) - : mMechanism(aKey.Algorithm()->Mechanism()) + : mMechanism(aKey.Algorithm().Mechanism()) , mSymKey(aKey.GetSymKey()) , mSign(aSign) { @@ -1120,10 +980,10 @@ public: // static_cast is safe because we only get here if the algorithm name // is RSASSA-PKCS1-v1_5, and that only happens if we've constructed // an RsaHashedKeyAlgorithm - nsRefPtr rsaAlg = static_cast(aKey.Algorithm()); - nsRefPtr hashAlg = rsaAlg->Hash(); + CK_MECHANISM_TYPE mech; + mech = KeyAlgorithmProxy::GetMechanism(aKey.Algorithm().mRsa.mHash); - switch (hashAlg->Mechanism()) { + switch (mech) { case CKM_SHA_1: mOidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; case CKM_SHA256: @@ -1320,7 +1180,7 @@ public: // Check 'alg' if (aJwk.mAlg.WasPassed() && - aJwk.mAlg.Value() != aKey->Algorithm()->ToJwkAlg()) { + aJwk.mAlg.Value() != aKey->Algorithm().JwkAlg()) { return false; } @@ -1349,6 +1209,7 @@ public: SetJwkFromKeyData(); } } else { + ClearException ce(aCx); JS::RootedValue value(aCx, JS::ObjectValue(*aKeyData)); if (!mJwk.Init(aCx, value)) { return; @@ -1429,6 +1290,10 @@ public: } SetKeyData(aCx, aKeyData); + if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { + mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; + return; + } } void Init(JSContext* aCx, @@ -1445,11 +1310,11 @@ public: if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { RootedDictionary params(aCx); mEarlyRv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(mEarlyRv) || !params.mHash.WasPassed()) { + if (NS_FAILED(mEarlyRv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } - mEarlyRv = GetAlgorithmName(aCx, params.mHash.Value(), mHashName); + mEarlyRv = GetAlgorithmName(aCx, params.mHash, mHashName); if (NS_FAILED(mEarlyRv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; @@ -1481,8 +1346,6 @@ public: // Construct an appropriate KeyAlorithm, // and verify that usages are appropriate - nsRefPtr algorithm; - nsIGlobalObject* global = mKey->GetParentObject(); uint32_t length = 8 * mKeyData.Length(); // bytes to bits if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || @@ -1501,17 +1364,17 @@ public: if ( (length != 128) && (length != 192) && (length != 256) ) { return NS_ERROR_DOM_DATA_ERR; } - algorithm = new AesKeyAlgorithm(global, mAlgName, length); + mKey->Algorithm().MakeAes(mAlgName, length); if (mDataIsJwk && mJwk.mUse.WasPassed() && !mJwk.mUse.Value().EqualsLiteral(JWK_USE_ENC)) { return NS_ERROR_DOM_DATA_ERR; } } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) { - if (mKey->HasUsageOtherThan(CryptoKey::DERIVEKEY)) { + if (mKey->HasUsageOtherThan(CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS)) { return NS_ERROR_DOM_DATA_ERR; } - algorithm = new BasicSymmetricKeyAlgorithm(global, mAlgName, length); + mKey->Algorithm().MakeAes(mAlgName, length); if (mDataIsJwk && mJwk.mUse.WasPassed()) { // There is not a 'use' value consistent with PBKDF @@ -1522,8 +1385,9 @@ public: return NS_ERROR_DOM_DATA_ERR; } - algorithm = new HmacKeyAlgorithm(global, mAlgName, length, mHashName); - if (algorithm->Mechanism() == UNKNOWN_CK_MECHANISM) { + mKey->Algorithm().MakeHmac(length, mHashName); + + if (mKey->Algorithm().Mechanism() == UNKNOWN_CK_MECHANISM) { return NS_ERROR_DOM_SYNTAX_ERR; } @@ -1535,18 +1399,14 @@ public: return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } - mKey->SetAlgorithm(algorithm); mKey->SetSymKey(mKeyData); mKey->SetType(CryptoKey::SECRET); - mEarlyComplete = true; - return NS_OK; - } - nsresult AfterCrypto() MOZ_OVERRIDE - { if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) { return NS_ERROR_DOM_DATA_ERR; } + + mEarlyComplete = true; return NS_OK; } @@ -1576,6 +1436,10 @@ public: } SetKeyData(aCx, aKeyData); + if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { + mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; + return; + } } void Init(JSContext* aCx, @@ -1593,16 +1457,24 @@ public: mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { RootedDictionary params(aCx); mEarlyRv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(mEarlyRv) || !params.mHash.WasPassed()) { - mEarlyRv = NS_ERROR_DOM_DATA_ERR; - return; - } - - mEarlyRv = GetAlgorithmName(aCx, params.mHash.Value(), mHashName); if (NS_FAILED(mEarlyRv)) { mEarlyRv = NS_ERROR_DOM_DATA_ERR; return; } + + mEarlyRv = GetAlgorithmName(aCx, params.mHash, mHashName); + if (NS_FAILED(mEarlyRv)) { + mEarlyRv = NS_ERROR_DOM_DATA_ERR; + return; + } + } + + // Check support for the algorithm and hash names + CK_MECHANISM_TYPE mech1 = MapAlgorithmNameToMechanism(mAlgName); + CK_MECHANISM_TYPE mech2 = MapAlgorithmNameToMechanism(mHashName); + if ((mech1 == UNKNOWN_CK_MECHANISM) || (mech2 == UNKNOWN_CK_MECHANISM)) { + mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; + return; } } @@ -1669,9 +1541,7 @@ private: virtual nsresult AfterCrypto() MOZ_OVERRIDE { // Check permissions for the requested operation - nsIGlobalObject* global = mKey->GetParentObject(); - if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1) || - mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { + if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { if ((mKey->GetKeyType() == CryptoKey::PUBLIC && mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::WRAPKEY)) || (mKey->GetKeyType() == CryptoKey::PRIVATE && @@ -1687,23 +1557,9 @@ private: } } - // Construct an appropriate KeyAlgorithm - if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) { - mKey->SetAlgorithm(new RsaKeyAlgorithm(global, mAlgName, mModulusLength, mPublicExponent)); - } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || - mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { - nsRefPtr algorithm = - new RsaHashedKeyAlgorithm(global, mAlgName, - mModulusLength, mPublicExponent, mHashName); - if (algorithm->Mechanism() == UNKNOWN_CK_MECHANISM) { - return NS_ERROR_DOM_SYNTAX_ERR; - } - - if (algorithm->Hash()->Mechanism() == UNKNOWN_CK_MECHANISM) { - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; - } - mKey->SetAlgorithm(algorithm); - } + // Set an appropriate KeyAlgorithm + mKey->Algorithm().MakeRsa(mAlgName, mModulusLength, + mPublicExponent, mHashName); if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) { return NS_ERROR_DOM_DATA_ERR; @@ -1793,7 +1649,7 @@ private: // Extract 'crv' parameter from JWKs. if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { - if (!NormalizeNamedCurveValue(mJwk.mCrv.Value(), mNamedCurve)) { + if (!NormalizeToken(mJwk.mCrv.Value(), mNamedCurve)) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } } @@ -1809,8 +1665,7 @@ private: return NS_ERROR_DOM_DATA_ERR; } - nsIGlobalObject* global = mKey->GetParentObject(); - mKey->SetAlgorithm(new EcKeyAlgorithm(global, mAlgName, mNamedCurve)); + mKey->Algorithm().MakeEc(mAlgName, mNamedCurve); if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) { return NS_ERROR_DOM_DATA_ERR; @@ -1830,13 +1685,8 @@ public: , mPublicKey(aKey.GetPublicKey()) , mKeyType(aKey.GetKeyType()) , mExtractable(aKey.Extractable()) - , mAlg(aKey.Algorithm()->ToJwkAlg()) + , mAlg(aKey.Algorithm().JwkAlg()) { - if (!aKey.Extractable()) { - mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; - return; - } - aKey.GetUsages(mKeyUsages); } @@ -1897,7 +1747,7 @@ private: return NS_ERROR_DOM_OPERATION_ERR; } mJwk.mK.Construct(k); - mJwk.mKty.Construct(NS_LITERAL_STRING(JWK_TYPE_SYMMETRIC)); + mJwk.mKty = NS_LITERAL_STRING(JWK_TYPE_SYMMETRIC); } else if (mKeyType == CryptoKey::PUBLIC) { if (!mPublicKey) { return NS_ERROR_DOM_UNKNOWN_ERR; @@ -1975,7 +1825,6 @@ public: } // Construct an appropriate KeyAlorithm - nsRefPtr algorithm; uint32_t allowedUsages = 0; if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || @@ -1985,19 +1834,20 @@ public: if (NS_FAILED(mEarlyRv)) { return; } - algorithm = new AesKeyAlgorithm(global, algName, mLength); + mKey->Algorithm().MakeAes(algName, mLength); + allowedUsages = CryptoKey::ENCRYPT | CryptoKey::DECRYPT | CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY; } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { RootedDictionary params(aCx); mEarlyRv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(mEarlyRv) || !params.mHash.WasPassed()) { + if (NS_FAILED(mEarlyRv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } nsString hashName; - mEarlyRv = GetAlgorithmName(aCx, params.mHash.Value(), hashName); + mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName); if (NS_FAILED(mEarlyRv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; @@ -2014,7 +1864,7 @@ public: return; } - algorithm = new HmacKeyAlgorithm(global, algName, mLength, hashName); + mKey->Algorithm().MakeHmac(mLength, hashName); allowedUsages = CryptoKey::SIGN | CryptoKey::VERIFY; } else { mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; @@ -2031,8 +1881,7 @@ public: } mLength = mLength >> 3; // bits to bytes - mMechanism = algorithm->Mechanism(); - mKey->SetAlgorithm(algorithm); + mMechanism = mKey->Algorithm().Mechanism(); // SetSymKey done in Resolve, after we've done the keygen } @@ -2089,7 +1938,8 @@ public: } // Create an empty key and set easy attributes - mKeyPair = new CryptoKeyPair(global); + mKeyPair.mPrivateKey = new CryptoKey(global); + mKeyPair.mPublicKey = new CryptoKey(global); // Extract algorithm name nsString algName; @@ -2100,63 +1950,36 @@ public: } // Construct an appropriate KeyAlorithm - KeyAlgorithm* algorithm; uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0; if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { RootedDictionary params(aCx); mEarlyRv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(mEarlyRv) || !params.mModulusLength.WasPassed() || - !params.mPublicExponent.WasPassed() || - !params.mHash.WasPassed()) { + if (NS_FAILED(mEarlyRv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } // Pull relevant info - uint32_t modulusLength = params.mModulusLength.Value(); + uint32_t modulusLength = params.mModulusLength; CryptoBuffer publicExponent; - ATTEMPT_BUFFER_INIT(publicExponent, params.mPublicExponent.Value()); + ATTEMPT_BUFFER_INIT(publicExponent, params.mPublicExponent); nsString hashName; - mEarlyRv = GetAlgorithmName(aCx, params.mHash.Value(), hashName); + mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName); if (NS_FAILED(mEarlyRv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; 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; - } - } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) { - RootedDictionary params(aCx); - mEarlyRv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(mEarlyRv) || !params.mModulusLength.WasPassed() || - !params.mPublicExponent.WasPassed()) { - mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; - return; - } - - // 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); + mKeyPair.mPublicKey.get()->Algorithm().MakeRsa(algName, + modulusLength, + publicExponent, + hashName); + mKeyPair.mPrivateKey.get()->Algorithm().MakeRsa(algName, + modulusLength, + publicExponent, + hashName); mMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; // Set up params struct @@ -2169,20 +1992,19 @@ public: } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) { RootedDictionary params(aCx); mEarlyRv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(mEarlyRv) || !params.mNamedCurve.WasPassed()) { + if (NS_FAILED(mEarlyRv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } - if (!NormalizeNamedCurveValue(params.mNamedCurve.Value(), mNamedCurve)) { + if (!NormalizeToken(params.mNamedCurve, mNamedCurve)) { mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; return; } // Create algorithm. - algorithm = new EcKeyAlgorithm(global, algName, mNamedCurve); - mKeyPair->PublicKey()->SetAlgorithm(algorithm); - mKeyPair->PrivateKey()->SetAlgorithm(algorithm); + mKeyPair.mPublicKey.get()->Algorithm().MakeEc(algName, mNamedCurve); + mKeyPair.mPrivateKey.get()->Algorithm().MakeEc(algName, mNamedCurve); mMechanism = CKM_EC_KEY_PAIR_GEN; } else { mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; @@ -2193,8 +2015,7 @@ public: if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { privateAllowedUsages = CryptoKey::SIGN; publicAllowedUsages = CryptoKey::VERIFY; - } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1) || - algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { + } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { privateAllowedUsages = CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY; publicAllowedUsages = CryptoKey::ENCRYPT | CryptoKey::WRAPKEY; } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) { @@ -2202,31 +2023,38 @@ public: publicAllowedUsages = 0; } - mKeyPair->PrivateKey()->SetExtractable(aExtractable); - mKeyPair->PrivateKey()->SetType(CryptoKey::PRIVATE); + mKeyPair.mPrivateKey.get()->SetExtractable(aExtractable); + mKeyPair.mPrivateKey.get()->SetType(CryptoKey::PRIVATE); - mKeyPair->PublicKey()->SetExtractable(true); - mKeyPair->PublicKey()->SetType(CryptoKey::PUBLIC); + mKeyPair.mPublicKey.get()->SetExtractable(true); + mKeyPair.mPublicKey.get()->SetType(CryptoKey::PUBLIC); - mKeyPair->PrivateKey()->ClearUsages(); - mKeyPair->PublicKey()->ClearUsages(); + mKeyPair.mPrivateKey.get()->ClearUsages(); + mKeyPair.mPublicKey.get()->ClearUsages(); for (uint32_t i=0; i < aKeyUsages.Length(); ++i) { - mEarlyRv = mKeyPair->PrivateKey()->AddUsageIntersecting(aKeyUsages[i], - privateAllowedUsages); + mEarlyRv = mKeyPair.mPrivateKey.get()->AddUsageIntersecting(aKeyUsages[i], + privateAllowedUsages); if (NS_FAILED(mEarlyRv)) { return; } - mEarlyRv = mKeyPair->PublicKey()->AddUsageIntersecting(aKeyUsages[i], - publicAllowedUsages); + mEarlyRv = mKeyPair.mPublicKey.get()->AddUsageIntersecting(aKeyUsages[i], + publicAllowedUsages); if (NS_FAILED(mEarlyRv)) { return; } } + + // If no usages ended up being allowed, DataError + if (!mKeyPair.mPrivateKey.get()->HasAnyUsage() || + !mKeyPair.mPrivateKey.get()->HasAnyUsage()) { + mEarlyRv = NS_ERROR_DOM_DATA_ERR; + return; + } } private: - nsRefPtr mKeyPair; + CryptoKeyPair mKeyPair; CK_MECHANISM_TYPE mMechanism; PK11RSAGenParams mRsaParams; ScopedSECKEYPublicKey mPublicKey; @@ -2275,8 +2103,8 @@ private: return NS_ERROR_DOM_UNKNOWN_ERR; } - mKeyPair->PrivateKey()->SetPrivateKey(mPrivateKey); - mKeyPair->PublicKey()->SetPublicKey(mPublicKey); + mKeyPair.mPrivateKey.get()->SetPrivateKey(mPrivateKey); + mKeyPair.mPublicKey.get()->SetPublicKey(mPublicKey); return NS_OK; } @@ -2284,11 +2112,6 @@ private: { mResultPromise->MaybeResolve(mKeyPair); } - - virtual void Cleanup() MOZ_OVERRIDE - { - mKeyPair = nullptr; - } }; class DerivePbkdfBitsTask : public ReturnArrayBufferViewTask @@ -2326,8 +2149,7 @@ public: RootedDictionary params(aCx); mEarlyRv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(mEarlyRv) || !params.mHash.WasPassed() || - !params.mIterations.WasPassed() || !params.mSalt.WasPassed()) { + if (NS_FAILED(mEarlyRv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } @@ -2340,7 +2162,7 @@ public: // Extract the hash algorithm. nsString hashName; - mEarlyRv = GetAlgorithmName(aCx, params.mHash.Value(), hashName); + mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName); if (NS_FAILED(mEarlyRv)) { return; } @@ -2357,9 +2179,9 @@ public: } } - ATTEMPT_BUFFER_INIT(mSalt, params.mSalt.Value()) + ATTEMPT_BUFFER_INIT(mSalt, params.mSalt) mLength = aLength >> 3; // bits to bytes - mIterations = params.mIterations.Value(); + mIterations = params.mIterations; } private: @@ -2494,25 +2316,23 @@ public: // Retrieve the peer's public key. RootedDictionary params(aCx); mEarlyRv = Coerce(aCx, params, aAlgorithm); - if (NS_FAILED(mEarlyRv) || !params.mPublic.WasPassed()) { + if (NS_FAILED(mEarlyRv)) { mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR; return; } - CryptoKey* publicKey = params.mPublic.Value(); + CryptoKey* publicKey = params.mPublic; mPubKey = publicKey->GetPublicKey(); if (!mPubKey) { mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR; return; } - nsRefPtr publicAlgorithm = publicKey->Algorithm(); - CHECK_KEY_ALGORITHM(publicAlgorithm, WEBCRYPTO_ALG_ECDH); + CHECK_KEY_ALGORITHM(publicKey->Algorithm(), WEBCRYPTO_ALG_ECDH); // Both keys must use the same named curve. - nsString curve1, curve2; - static_cast(aKey.Algorithm())->GetNamedCurve(curve1); - static_cast(publicAlgorithm.get())->GetNamedCurve(curve2); + nsString curve1 = aKey.Algorithm().mEc.mNamedCurve; + nsString curve2 = publicKey->Algorithm().mEc.mNamedCurve; if (!curve1.Equals(curve2)) { mEarlyRv = NS_ERROR_DOM_DATA_ERR; @@ -2645,35 +2465,48 @@ private: // Task creation methods for WebCryptoTask +// Note: We do not perform algorithm normalization as a monolithic process, +// as described in the spec. Instead: +// * Each method handles its slice of the supportedAlgorithms structure +// * Task constructors take care of: +// * Coercing the algorithm to the proper concrete type +// * Cloning subordinate data items +// * Cloning input data as needed +// +// Thus, support for different algorithms is determined by the if-statements +// below, rather than a data structure. +// +// This results in algorithm normalization coming after some other checks, +// and thus slightly more steps being done synchronously than the spec calls +// for. But none of these steps is especially time-consuming. + WebCryptoTask* WebCryptoTask::CreateEncryptDecryptTask(JSContext* aCx, - const ObjectOrString& aAlgorithm, - CryptoKey& aKey, - const CryptoOperationData& aData, - bool aEncrypt) + const ObjectOrString& aAlgorithm, + CryptoKey& aKey, + const CryptoOperationData& aData, + bool aEncrypt) { TelemetryMethod method = (aEncrypt)? TM_ENCRYPT : TM_DECRYPT; Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, method); Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_ENC, aKey.Extractable()); - nsString algName; - nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); - if (NS_FAILED(rv)) { - return new FailureTask(rv); - } - // Ensure key is usable for this operation if ((aEncrypt && !aKey.HasUsage(CryptoKey::ENCRYPT)) || (!aEncrypt && !aKey.HasUsage(CryptoKey::DECRYPT))) { return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); } + nsString algName; + nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); + if (NS_FAILED(rv)) { + return new FailureTask(rv); + } + if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) { return new AesTask(aCx, aAlgorithm, aKey, aData, aEncrypt); - } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) { - return new RsaesPkcs1Task(aCx, aAlgorithm, aKey, aData, aEncrypt); } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { return new RsaOaepTask(aCx, aAlgorithm, aKey, aData, aEncrypt); } @@ -2683,28 +2516,28 @@ WebCryptoTask::CreateEncryptDecryptTask(JSContext* aCx, WebCryptoTask* WebCryptoTask::CreateSignVerifyTask(JSContext* aCx, - const ObjectOrString& aAlgorithm, - CryptoKey& aKey, - const CryptoOperationData& aSignature, - const CryptoOperationData& aData, - bool aSign) + const ObjectOrString& aAlgorithm, + CryptoKey& aKey, + const CryptoOperationData& aSignature, + const CryptoOperationData& aData, + bool aSign) { TelemetryMethod method = (aSign)? TM_SIGN : TM_VERIFY; Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, method); Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_SIG, aKey.Extractable()); - nsString algName; - nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); - if (NS_FAILED(rv)) { - return new FailureTask(rv); - } - // Ensure key is usable for this operation if ((aSign && !aKey.HasUsage(CryptoKey::SIGN)) || (!aSign && !aKey.HasUsage(CryptoKey::VERIFY))) { return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); } + nsString algName; + nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); + if (NS_FAILED(rv)) { + return new FailureTask(rv); + } + if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { return new HmacTask(aCx, aAlgorithm, aKey, aSignature, aData, aSign); } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { @@ -2716,23 +2549,10 @@ WebCryptoTask::CreateSignVerifyTask(JSContext* aCx, WebCryptoTask* WebCryptoTask::CreateDigestTask(JSContext* aCx, - const ObjectOrString& aAlgorithm, - const CryptoOperationData& aData) + const ObjectOrString& aAlgorithm, + const CryptoOperationData& aData) { Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DIGEST); - return new DigestTask(aCx, aAlgorithm, aData); -} - -WebCryptoTask* -WebCryptoTask::CreateImportKeyTask(JSContext* aCx, - const nsAString& aFormat, - JS::Handle aKeyData, - const ObjectOrString& aAlgorithm, - bool aExtractable, - const Sequence& aKeyUsages) -{ - Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_IMPORTKEY); - Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_IMPORT, aExtractable); nsString algName; nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); @@ -2740,6 +2560,48 @@ WebCryptoTask::CreateImportKeyTask(JSContext* aCx, return new FailureTask(rv); } + if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA1) || + algName.EqualsLiteral(WEBCRYPTO_ALG_SHA256) || + algName.EqualsLiteral(WEBCRYPTO_ALG_SHA384) || + algName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) { + return new DigestTask(aCx, aAlgorithm, aData); + } + + return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); +} + +WebCryptoTask* +WebCryptoTask::CreateImportKeyTask(JSContext* aCx, + const nsAString& aFormat, + JS::Handle aKeyData, + const ObjectOrString& aAlgorithm, + bool aExtractable, + const Sequence& aKeyUsages) +{ + Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_IMPORTKEY); + Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_IMPORT, aExtractable); + + // Verify that the format is recognized + if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) && + !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) && + !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) && + !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { + return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); + } + + // Verify that aKeyUsages does not contain an unrecognized value + if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) { + return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); + } + + nsString algName; + nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); + if (NS_FAILED(rv)) { + return new FailureTask(rv); + } + + // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation. + // However, the spec should be updated to allow it. if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) || @@ -2748,8 +2610,7 @@ WebCryptoTask::CreateImportKeyTask(JSContext* aCx, algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) { return new ImportSymmetricKeyTask(aCx, aFormat, aKeyData, aAlgorithm, aExtractable, aKeyUsages); - } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1) || - algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || + } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { return new ImportRsaKeyTask(aCx, aFormat, aKeyData, aAlgorithm, aExtractable, aKeyUsages); @@ -2763,22 +2624,58 @@ WebCryptoTask::CreateImportKeyTask(JSContext* aCx, WebCryptoTask* WebCryptoTask::CreateExportKeyTask(const nsAString& aFormat, - CryptoKey& aKey) + CryptoKey& aKey) { Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_EXPORTKEY); - return new ExportKeyTask(aFormat, aKey); + // Verify that the format is recognized + if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) && + !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) && + !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) && + !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { + return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); + } + + // Verify that the key is extractable + if (!aKey.Extractable()) { + return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); + } + + // Verify that the algorithm supports export + // SPEC-BUG: PBKDF2 is not supposed to be supported for this operation. + // However, the spec should be updated to allow it. + nsString algName = aKey.Algorithm().mName; + if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) || + algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) || + algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) || + algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) || + algName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2) || + algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC) || + algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) || + algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) || + algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) { + return new ExportKeyTask(aFormat, aKey); + } + + return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR); } WebCryptoTask* WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx, - const ObjectOrString& aAlgorithm, - bool aExtractable, - const Sequence& aKeyUsages) + const ObjectOrString& aAlgorithm, + bool aExtractable, + const Sequence& aKeyUsages) { Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_GENERATEKEY); Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_GENERATE, aExtractable); + // Verify that aKeyUsages does not contain an unrecognized value + // SPEC-BUG: Spec says that this should be InvalidAccessError, but that + // is inconsistent with other analogous points in the spec + if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) { + return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); + } + nsString algName; nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); if (NS_FAILED(rv)) { @@ -2791,8 +2688,7 @@ WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx, algName.EqualsASCII(WEBCRYPTO_ALG_AES_KW) || 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) || + } else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) || algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) || algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) { return new GenerateAsymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages); @@ -2803,14 +2699,24 @@ WebCryptoTask::CreateGenerateKeyTask(JSContext* aCx, WebCryptoTask* WebCryptoTask::CreateDeriveKeyTask(JSContext* aCx, - const ObjectOrString& aAlgorithm, - CryptoKey& aBaseKey, - const ObjectOrString& aDerivedKeyType, - bool aExtractable, - const Sequence& aKeyUsages) + const ObjectOrString& aAlgorithm, + CryptoKey& aBaseKey, + const ObjectOrString& aDerivedKeyType, + bool aExtractable, + const Sequence& aKeyUsages) { Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DERIVEKEY); + // Ensure baseKey is usable for this operation + if (!aBaseKey.HasUsage(CryptoKey::DERIVEKEY)) { + return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); + } + + // Verify that aKeyUsages does not contain an unrecognized value + if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) { + return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); + } + nsString algName; nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); if (NS_FAILED(rv)) { @@ -2834,12 +2740,17 @@ WebCryptoTask::CreateDeriveKeyTask(JSContext* aCx, WebCryptoTask* WebCryptoTask::CreateDeriveBitsTask(JSContext* aCx, - const ObjectOrString& aAlgorithm, - CryptoKey& aKey, - uint32_t aLength) + const ObjectOrString& aAlgorithm, + CryptoKey& aKey, + uint32_t aLength) { Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_DERIVEBITS); + // Ensure baseKey is usable for this operation + if (!aKey.HasUsage(CryptoKey::DERIVEBITS)) { + return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); + } + nsString algName; nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName); if (NS_FAILED(rv)) { @@ -2859,18 +2770,31 @@ WebCryptoTask::CreateDeriveBitsTask(JSContext* aCx, WebCryptoTask* WebCryptoTask::CreateWrapKeyTask(JSContext* aCx, - const nsAString& aFormat, - CryptoKey& aKey, - CryptoKey& aWrappingKey, - const ObjectOrString& aWrapAlgorithm) + const nsAString& aFormat, + CryptoKey& aKey, + CryptoKey& aWrappingKey, + const ObjectOrString& aWrapAlgorithm) { Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_WRAPKEY); - // Ensure key is usable for this operation + // Verify that the format is recognized + if (!aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) && + !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI) && + !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8) && + !aFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) { + return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); + } + + // Ensure wrappingKey is usable for this operation if (!aWrappingKey.HasUsage(CryptoKey::WRAPKEY)) { return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); } + // Ensure key is extractable + if (!aKey.Extractable()) { + return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); + } + nsString wrapAlgName; nsresult rv = GetAlgorithmName(aCx, aWrapAlgorithm, wrapAlgName); if (NS_FAILED(rv)) { @@ -2885,9 +2809,6 @@ WebCryptoTask::CreateWrapKeyTask(JSContext* aCx, } else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) { return new WrapKeyTask(aCx, aFormat, aKey, aWrappingKey, aWrapAlgorithm); - } else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) { - return new WrapKeyTask(aCx, aFormat, aKey, - aWrappingKey, aWrapAlgorithm); } else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { return new WrapKeyTask(aCx, aFormat, aKey, aWrappingKey, aWrapAlgorithm); @@ -2898,13 +2819,13 @@ WebCryptoTask::CreateWrapKeyTask(JSContext* aCx, WebCryptoTask* WebCryptoTask::CreateUnwrapKeyTask(JSContext* aCx, - const nsAString& aFormat, - const ArrayBufferViewOrArrayBuffer& aWrappedKey, - CryptoKey& aUnwrappingKey, - const ObjectOrString& aUnwrapAlgorithm, - const ObjectOrString& aUnwrappedKeyAlgorithm, - bool aExtractable, - const Sequence& aKeyUsages) + const nsAString& aFormat, + const ArrayBufferViewOrArrayBuffer& aWrappedKey, + CryptoKey& aUnwrappingKey, + const ObjectOrString& aUnwrapAlgorithm, + const ObjectOrString& aUnwrappedKeyAlgorithm, + bool aExtractable, + const Sequence& aKeyUsages) { Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_UNWRAPKEY); @@ -2913,6 +2834,11 @@ WebCryptoTask::CreateUnwrapKeyTask(JSContext* aCx, return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR); } + // Verify that aKeyUsages does not contain an unrecognized value + if (!CryptoKey::AllUsagesRecognized(aKeyUsages)) { + return new FailureTask(NS_ERROR_DOM_SYNTAX_ERR); + } + nsString keyAlgName; nsresult rv = GetAlgorithmName(aCx, aUnwrappedKeyAlgorithm, keyAlgName); if (NS_FAILED(rv)) { @@ -2928,8 +2854,7 @@ WebCryptoTask::CreateUnwrapKeyTask(JSContext* aCx, importTask = new ImportSymmetricKeyTask(aCx, aFormat, aUnwrappedKeyAlgorithm, aExtractable, aKeyUsages); - } else if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSAES_PKCS1) || - keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) || + } else if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) || keyAlgName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP)) { importTask = new ImportRsaKeyTask(aCx, aFormat, aUnwrappedKeyAlgorithm, @@ -2953,10 +2878,6 @@ WebCryptoTask::CreateUnwrapKeyTask(JSContext* aCx, return new UnwrapKeyTask(aCx, aWrappedKey, aUnwrappingKey, aUnwrapAlgorithm, importTask); - } else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) { - return new UnwrapKeyTask(aCx, aWrappedKey, - aUnwrappingKey, aUnwrapAlgorithm, - importTask); } else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) { return new UnwrapKeyTask(aCx, aWrappedKey, aUnwrappingKey, aUnwrapAlgorithm, diff --git a/dom/crypto/moz.build b/dom/crypto/moz.build index 08c7227f17d3..b4f1fc3180ab 100644 --- a/dom/crypto/moz.build +++ b/dom/crypto/moz.build @@ -5,30 +5,17 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS.mozilla.dom += [ - 'AesKeyAlgorithm.h', - 'BasicSymmetricKeyAlgorithm.h', 'CryptoBuffer.h', 'CryptoKey.h', - 'CryptoKeyPair.h', - 'EcKeyAlgorithm.h', - 'HmacKeyAlgorithm.h', - 'KeyAlgorithm.h', - 'RsaHashedKeyAlgorithm.h', - 'RsaKeyAlgorithm.h', + 'KeyAlgorithmProxy.h', 'WebCryptoCommon.h', 'WebCryptoTask.h', ] UNIFIED_SOURCES += [ - 'AesKeyAlgorithm.cpp', 'CryptoBuffer.cpp', 'CryptoKey.cpp', - 'CryptoKeyPair.cpp', - 'EcKeyAlgorithm.cpp', - 'HmacKeyAlgorithm.cpp', - 'KeyAlgorithm.cpp', - 'RsaHashedKeyAlgorithm.cpp', - 'RsaKeyAlgorithm.cpp', + 'KeyAlgorithmProxy.cpp', 'WebCryptoTask.cpp', ] diff --git a/dom/crypto/test/test_WebCrypto.html b/dom/crypto/test/test_WebCrypto.html index 2f868e8a8e3a..9768a3a73bb9 100644 --- a/dom/crypto/test/test_WebCrypto.html +++ b/dom/crypto/test/test_WebCrypto.html @@ -71,7 +71,6 @@ TestArray.addTest( function doExport(x) { if (!hasKeyFields(x)) { - window.result = x; throw "Invalid key; missing field(s)"; } else if ((x.algorithm.name != alg) || (x.algorithm.length != 8 * tv.raw.length) || @@ -85,7 +84,7 @@ TestArray.addTest( } crypto.subtle.importKey("raw", tv.raw, alg, true, ["encrypt"]) - .then(doExport, error(that)) + .then(doExport) .then( memcmp_complete(that, tv.raw), error(that) @@ -153,7 +152,7 @@ TestArray.addTest( } crypto.subtle.importKey("pkcs8", tv.pkcs8, alg, true, ["sign"]) - .then(doExport, error(that)) + .then(doExport) .then( memcmp_complete(that, tv.pkcs8), error(that) @@ -178,24 +177,27 @@ TestArray.addTest( "Import / export round-trip with 'spki'", function() { var that = this; - var alg = "RSAES-PKCS1-v1_5"; + var alg = { + name: "RSASSA-PKCS1-v1_5", + hash: "SHA-256" + }; function doExport(x) { if (!hasKeyFields(x)) { throw "Invalid key; missing field(s)"; - } else if ((x.algorithm.name != alg) || + } else if ((x.algorithm.name != alg.name) || (x.algorithm.modulusLength != 1024) || (x.algorithm.publicExponent.byteLength != 3) || (x.type != "public") || (!x.extractable) || (x.usages.length != 1) || - (x.usages[0] != 'encrypt')){ + (x.usages[0] != 'verify')){ throw "Invalid key: incorrect key data"; } return crypto.subtle.exportKey("spki", x); } - crypto.subtle.importKey("spki", tv.spki, alg, true, ["encrypt"]) + crypto.subtle.importKey("spki", tv.spki, alg, true, ["verify"]) .then(doExport, error(that)) .then( memcmp_complete(that, tv.spki), @@ -209,7 +211,10 @@ TestArray.addTest( "Import failure with format 'spki'", function() { var that = this; - var alg = "RSAES-PKCS1-v1_5"; + var alg = { + name: "RSASSA-PKCS1-v1_5", + hash: "SHA-256" + }; crypto.subtle.importKey("spki", tv.negative_spki, alg, true, ["encrypt"]) .then(error(that), complete(that)); @@ -382,11 +387,12 @@ TestArray.addTest( function() { var that = this; var alg = { - name: "RSAES-PKCS1-v1_5", + name: "RSASSA-PKCS1-v1_5", + hash: "SHA-256", modulusLength: 1024, publicExponent: new Uint8Array([0x01, 0x00, 0x01]) }; - crypto.subtle.generateKey(alg, false, ["encrypt", "decrypt"]).then( + crypto.subtle.generateKey(alg, false, ["sign", "verify"]).then( complete(that, function(x) { return exists(x.publicKey) && (x.publicKey.algorithm.name == alg.name) && @@ -394,14 +400,14 @@ TestArray.addTest( (x.publicKey.type == "public") && x.publicKey.extractable && (x.publicKey.usages.length == 1) && - (x.publicKey.usages[0] == "encrypt") && + (x.publicKey.usages[0] == "verify") && 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"); + (x.privateKey.usages[0] == "sign"); }), error(that) ); @@ -414,12 +420,13 @@ TestArray.addTest( function() { var that = this; var alg = { - name: "RSAES-PKCS1-v1_5", + name: "RSASSA-PKCS1-v1_5", + hash: "SHA-256", modulusLength: 2299, // NSS does not like this key length publicExponent: new Uint8Array([0x01, 0x00, 0x01]) }; - crypto.subtle.generateKey(alg, false, ["encrypt"]) + crypto.subtle.generateKey(alg, false, ["sign"]) .then( error(that), complete(that) ); } ); @@ -455,7 +462,6 @@ TestArray.addTest( var that = this; function doEncrypt(x) { - console.log(x); return crypto.subtle.encrypt( { name: "AES-CBC", iv: tv.aes_cbc_enc.iv }, x, tv.aes_cbc_enc.data); @@ -477,7 +483,6 @@ TestArray.addTest( var that = this; function encrypt(x, iv) { - console.log(x); return crypto.subtle.encrypt( { name: "AES-CBC", iv: iv }, x, tv.aes_cbc_enc.data); @@ -822,58 +827,6 @@ TestArray.addTest( } ); -// ----------------------------------------------------------------------------- -TestArray.addTest( - "RSAES-PKCS#1 encrypt/decrypt round-trip", - function () { - var that = this; - var privKey, pubKey; - var alg = {name:"RSAES-PKCS1-v1_5"}; - - var privKey, pubKey, data, ct, pt; - function setPriv(x) { privKey = x; } - function setPub(x) { pubKey = x; } - function doEncrypt() { - return crypto.subtle.encrypt(alg.name, pubKey, tv.rsaes.data); - } - function doDecrypt(x) { - return crypto.subtle.decrypt(alg.name, privKey, x); - } - - function fail() { error(that); } - - Promise.all([ - crypto.subtle.importKey("pkcs8", tv.rsaes.pkcs8, alg, false, ['decrypt']) - .then(setPriv, error(that)), - crypto.subtle.importKey("spki", tv.rsaes.spki, alg, false, ['encrypt']) - .then(setPub, error(that)) - ]).then(doEncrypt, error(that)) - .then(doDecrypt, error(that)) - .then( - memcmp_complete(that, tv.rsaes.data), - error(that) - ); - } -); - -// ----------------------------------------------------------------------------- -TestArray.addTest( - "RSAES-PKCS#1 decryption known answer", - function () { - var that = this; - var alg = {name:"RSAES-PKCS1-v1_5"}; - - function doDecrypt(x) { - return crypto.subtle.decrypt(alg.name, x, tv.rsaes.result); - } - function fail() { error(that); } - - crypto.subtle.importKey("pkcs8", tv.rsaes.pkcs8, alg, false, ['decrypt']) - .then( doDecrypt, fail ) - .then( memcmp_complete(that, tv.rsaes.data), fail ); - } -); - // ----------------------------------------------------------------------------- TestArray.addTest( "RSASSA/SHA-1 signature", @@ -882,15 +835,12 @@ TestArray.addTest( var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" }; function doSign(x) { - console.log("sign"); - console.log(x); return crypto.subtle.sign(alg.name, x, tv.rsassa.data); } - function fail() { console.log("fail"); error(that); } crypto.subtle.importKey("pkcs8", tv.rsassa.pkcs8, alg, false, ['sign']) - .then( doSign, fail ) - .then( memcmp_complete(that, tv.rsassa.sig1), fail ); + .then( doSign ) + .then( memcmp_complete(that, tv.rsassa.sig1), error(that) ); } ); @@ -904,13 +854,12 @@ TestArray.addTest( function doVerify(x) { return crypto.subtle.verify(alg.name, x, tv.rsassa.sig1, tv.rsassa.data); } - function fail(x) { error(that); } crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ['verify']) - .then( doVerify, fail ) + .then( doVerify ) .then( complete(that, function(x) { return x; }), - fail + error(that) ); } ); @@ -925,13 +874,12 @@ TestArray.addTest( function doVerify(x) { return crypto.subtle.verify(alg.name, x, tv.rsassa.sig_fail, tv.rsassa.data); } - function fail(x) { error(that); } crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ['verify']) - .then( doVerify, fail ) + .then( doVerify ) .then( complete(that, function(x) { return !x; }), - fail + error(that) ); } ); @@ -946,11 +894,10 @@ TestArray.addTest( function doSign(x) { return crypto.subtle.sign(alg.name, x, tv.rsassa.data); } - function fail(x) { console.log(x); error(that); } crypto.subtle.importKey("pkcs8", tv.rsassa.pkcs8, alg, false, ['sign']) - .then( doSign, fail ) - .then( memcmp_complete(that, tv.rsassa.sig256), fail ); + .then( doSign ) + .then( memcmp_complete(that, tv.rsassa.sig256), error(that) ); } ); @@ -964,13 +911,12 @@ TestArray.addTest( function doVerify(x) { return crypto.subtle.verify(alg.name, x, tv.rsassa.sig256, tv.rsassa.data); } - function fail(x) { error(that); } crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ['verify']) - .then( doVerify, fail ) + .then( doVerify ) .then( complete(that, function(x) { return x; }), - fail + error(that) ); } ); @@ -984,17 +930,14 @@ TestArray.addTest( var use = ['sign', 'verify']; function doVerify(x) { - console.log("verifying") return crypto.subtle.verify(alg.name, x, tv.rsassa.sig_fail, tv.rsassa.data); } - function fail(x) { console.log("failing"); error(that)(x); } - console.log("running") crypto.subtle.importKey("spki", tv.rsassa.spki, alg, false, ['verify']) - .then( doVerify, fail ) + .then( doVerify ) .then( complete(that, function(x) { return !x; }), - fail + error(that) ); } ); @@ -1175,20 +1118,18 @@ TestArray.addTest( true, ['sign', 'verify']); } - function temperr(x) { return function(y) { console.log("error in "+x); console.log(y); } } - Promise.all([ crypto.subtle.importKey("jwk", tv.aes_gcm_enc.key_jwk, "AES-GCM", false, ['wrapKey','unwrapKey']) - .then(function(x) { console.log("wrapKey"); wrapKey = x; }), + .then(function(x) { wrapKey = x; }), crypto.subtle.generateKey(genAlg, true, ['sign', 'verify']) - .then(function(x) { console.log("originalKey"); originalKey = x; return x; }) + .then(function(x) { originalKey = x; return x; }) .then(doExport) .then(function(x) { originalKeyJwk = x; }) ]) - .then(doWrap, temperr("initial phase")) - .then(doUnwrap, temperr("wrap")) - .then(doExport, temperr("unwrap")) + .then(doWrap) + .then(doUnwrap) + .then(doExport) .then( complete(that, function(x) { return exists(x.k) && x.k == originalKeyJwk.k; @@ -1269,9 +1210,9 @@ TestArray.addTest( Promise.all([ crypto.subtle.importKey("jwk", tv.aes_kw.wrapping_key, "AES-KW", false, ['wrapKey','unwrapKey']) - .then(function(x) { console.log("wrapKey"); wrapKey = x; }), + .then(function(x) { wrapKey = x; }), crypto.subtle.generateKey(genAlg, true, ['sign']) - .then(function(x) { console.log("originalKey"); originalKey = x; return x; }) + .then(function(x) { originalKey = x; return x; }) .then(doExport) .then(function(x) { originalKeyJwk = x; }) ]) @@ -1332,7 +1273,7 @@ TestArray.addTest( modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]) }; - return crypto.subtle.generateKey(alg, false, ["encrypt"]); + return crypto.subtle.generateKey(alg, false, ["encrypt", "decrypt"]); } function doGenerateRsaSsaPkcs1Key() { @@ -1364,24 +1305,7 @@ TestArray.addTest( return crypto.subtle.generateKey(alg, false, ["sign"]).then(doSign); } - function doCheckRSAES() { - var alg = { - name: "RSAES-PKCS1-v1_5", - modulusLength: 1024, - publicExponent: new Uint8Array([0x01, 0x00, 0x01]) - }; - - function doEncrypt(x) { - var alg = {name: "RSA-OAEP", hash: "SHA-1"}; - return crypto.subtle.encrypt(alg, x.publicKey, new Uint8Array()); - } - - return crypto.subtle.generateKey(alg, false, ["encrypt"]).then(doEncrypt); - } - - doCheckRSASSA().then(error(that), function () { - doCheckRSAES().then(error(that), complete(that)); - }); + doCheckRSASSA().then(error(that), complete(that)); } ); /*]]>*/ diff --git a/dom/crypto/test/test_WebCrypto_ECDH.html b/dom/crypto/test/test_WebCrypto_ECDH.html index 12793263ecd2..04dc0c00e1d7 100644 --- a/dom/crypto/test/test_WebCrypto_ECDH.html +++ b/dom/crypto/test/test_WebCrypto_ECDH.html @@ -103,7 +103,7 @@ TestArray.addTest( modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]) }; - return crypto.subtle.generateKey(alg, false, ["encrypt"]) + return crypto.subtle.generateKey(alg, false, ["encrypt", "decrypt"]) } function doDerive() { @@ -336,12 +336,12 @@ TestArray.addTest( } Promise.all([ - crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_priv, alg, false, ["deriveBits"]) - .then(setPriv, error(that)), - crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_pub, alg, false, ["deriveBits"]) - .then(setPub, error(that)) - ]).then(doDerive, error(that)) - .then(doSignAndVerify, error(that)) + crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_priv, alg, false, ["deriveKey"]) + .then(setPriv), + crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_pub, alg, false, ["deriveKey"]) + .then(setPub) + ]).then(doDerive) + .then(doSignAndVerify) .then(complete(that), error(that)); } ); diff --git a/dom/crypto/test/test_WebCrypto_JWK.html b/dom/crypto/test/test_WebCrypto_JWK.html index 710c04a68444..39b41d85d004 100644 --- a/dom/crypto/test/test_WebCrypto_JWK.html +++ b/dom/crypto/test/test_WebCrypto_JWK.html @@ -192,8 +192,6 @@ TestArray.addTest( .then(doExport) .then( complete(that, function(x) { - window.jwk_priv = x; - console.log(JSON.stringify(x)); return hasBaseJwkFields(x) && hasFields(x, ['n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi']) && x.kty == 'RSA' && diff --git a/dom/crypto/test/test_WebCrypto_PBKDF2.html b/dom/crypto/test/test_WebCrypto_PBKDF2.html index 21dd1e86f319..f1cf66c7bf38 100644 --- a/dom/crypto/test/test_WebCrypto_PBKDF2.html +++ b/dom/crypto/test/test_WebCrypto_PBKDF2.html @@ -46,7 +46,6 @@ TestArray.addTest( var key = tv.pbkdf2_sha1.password; function doDerive(x) { - console.log("deriving"); if (!hasKeyFields(x)) { throw "Invalid key; missing field(s)"; } @@ -61,7 +60,7 @@ TestArray.addTest( } function fail(x) { console.log("failing"); error(that)(x); } - crypto.subtle.importKey("raw", key, alg, false, ["deriveKey"]) + crypto.subtle.importKey("raw", key, alg, false, ["deriveBits"]) .then( doDerive, fail ) .then( memcmp_complete(that, tv.pbkdf2_sha1.derived), fail ); } @@ -76,7 +75,6 @@ TestArray.addTest( var key = tv.pbkdf2_sha1.password; function doDerive(x) { - console.log("deriving"); if (!hasKeyFields(x)) { throw "Invalid key; missing field(s)"; } @@ -161,7 +159,6 @@ TestArray.addTest( var key = tv.pbkdf2_sha256.password; function doDerive(x) { - console.log("deriving"); if (!hasKeyFields(x)) { throw "Invalid key; missing field(s)"; } diff --git a/dom/crypto/test/test_WebCrypto_RSA_OAEP.html b/dom/crypto/test/test_WebCrypto_RSA_OAEP.html index 0d2c2ff7be30..082e8c0a6045 100644 --- a/dom/crypto/test/test_WebCrypto_RSA_OAEP.html +++ b/dom/crypto/test/test_WebCrypto_RSA_OAEP.html @@ -120,12 +120,13 @@ TestArray.addTest( var privKey, pubKey; function setKey(x) { pubKey = x.publicKey; privKey = x.privateKey; } function doEncrypt(n) { + console.log("entered encrypt("+ n +")"); return function () { return crypto.subtle.encrypt(alg, pubKey, new Uint8Array(n)); } } - crypto.subtle.generateKey(alg, false, ['encrypt']) + crypto.subtle.generateKey(alg, false, ['encrypt', 'decrypt']) .then(setKey, error(that)) .then(doEncrypt(214), error(that)) .then(doEncrypt(215), error(that)) diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index f57aff300217..c2c9495d7efb 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -244,8 +244,6 @@ var interfaceNamesInGlobalScope = "Crypto", // IMPORTANT: Do not change this list without review from a DOM peer! {name: "CryptoKey", pref: "dom.webcrypto.enabled"}, -// IMPORTANT: Do not change this list without review from a DOM peer! - {name: "CryptoKeyPair", pref: "dom.webcrypto.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! "CSS", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/webidl/KeyAlgorithm.webidl b/dom/webidl/KeyAlgorithm.webidl new file mode 100644 index 000000000000..ca6706fbbec7 --- /dev/null +++ b/dom/webidl/KeyAlgorithm.webidl @@ -0,0 +1,32 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://www.w3.org/TR/WebCryptoAPI/ + */ + +dictionary KeyAlgorithm { + required DOMString name; +}; + +dictionary AesKeyAlgorithm : KeyAlgorithm { + required unsigned short length; +}; + +dictionary EcKeyAlgorithm : KeyAlgorithm { + required DOMString namedCurve; +}; + +dictionary HmacKeyAlgorithm : KeyAlgorithm { + required KeyAlgorithm hash; + required unsigned long length; +}; + +dictionary RsaHashedKeyAlgorithm : KeyAlgorithm { + required unsigned short modulusLength; + required Uint8Array publicExponent; + required KeyAlgorithm hash; +}; + diff --git a/dom/webidl/SubtleCrypto.webidl b/dom/webidl/SubtleCrypto.webidl index 4e07329f6ea4..a4e1b07950cb 100644 --- a/dom/webidl/SubtleCrypto.webidl +++ b/dom/webidl/SubtleCrypto.webidl @@ -9,113 +9,74 @@ typedef DOMString KeyType; typedef DOMString KeyUsage; +typedef DOMString NamedCurve; typedef Uint8Array BigInteger; -/***** KeyAlgorithm interfaces *****/ - -[NoInterfaceObject] -interface KeyAlgorithm { - readonly attribute DOMString name; -}; - -[NoInterfaceObject] -interface AesKeyAlgorithm : KeyAlgorithm { - readonly attribute unsigned short length; -}; - -[NoInterfaceObject] -interface HmacKeyAlgorithm : KeyAlgorithm { - readonly attribute KeyAlgorithm hash; - readonly attribute unsigned long length; -}; - -[NoInterfaceObject] -interface RsaKeyAlgorithm : KeyAlgorithm { - readonly attribute unsigned long modulusLength; - [Throws] - readonly attribute BigInteger publicExponent; -}; - -[NoInterfaceObject] -interface RsaHashedKeyAlgorithm : RsaKeyAlgorithm { - readonly attribute KeyAlgorithm hash; -}; - -[NoInterfaceObject] -interface EcKeyAlgorithm : KeyAlgorithm { - readonly attribute NamedCurve namedCurve; -}; - - /***** Algorithm dictionaries *****/ dictionary Algorithm { - DOMString name; + required DOMString name; }; dictionary AesCbcParams : Algorithm { - CryptoOperationData iv; + required CryptoOperationData iv; }; dictionary AesCtrParams : Algorithm { - CryptoOperationData counter; - [EnforceRange] octet length; + required CryptoOperationData counter; + [EnforceRange] required octet length; }; dictionary AesGcmParams : Algorithm { - CryptoOperationData iv; + required CryptoOperationData iv; CryptoOperationData additionalData; [EnforceRange] octet tagLength; }; dictionary HmacImportParams : Algorithm { - AlgorithmIdentifier hash; + required AlgorithmIdentifier hash; }; dictionary Pbkdf2Params : Algorithm { - CryptoOperationData salt; - [EnforceRange] unsigned long iterations; - AlgorithmIdentifier hash; + required CryptoOperationData salt; + [EnforceRange] required unsigned long iterations; + required AlgorithmIdentifier hash; }; dictionary RsaHashedImportParams { - AlgorithmIdentifier hash; + required AlgorithmIdentifier hash; }; dictionary AesKeyGenParams : Algorithm { - [EnforceRange] unsigned short length; + [EnforceRange] required unsigned short length; }; dictionary HmacKeyGenParams : Algorithm { - AlgorithmIdentifier hash; + required AlgorithmIdentifier hash; [EnforceRange] unsigned long length; }; -dictionary RsaKeyGenParams : Algorithm { - [EnforceRange] unsigned long modulusLength; - BigInteger publicExponent; -}; - -dictionary RsaHashedKeyGenParams : RsaKeyGenParams { - AlgorithmIdentifier hash; +dictionary RsaHashedKeyGenParams : Algorithm { + [EnforceRange] required unsigned long modulusLength; + required BigInteger publicExponent; + required AlgorithmIdentifier hash; }; dictionary RsaOaepParams : Algorithm { - CryptoOperationData? label; + CryptoOperationData label; }; dictionary DhKeyGenParams : Algorithm { - BigInteger prime; - BigInteger generator; + required BigInteger prime; + required BigInteger generator; }; -typedef DOMString NamedCurve; dictionary EcKeyGenParams : Algorithm { - NamedCurve namedCurve; + required NamedCurve namedCurve; }; dictionary AesDerivedKeyParams : Algorithm { - [EnforceRange] unsigned long length; + [EnforceRange] required unsigned long length; }; dictionary HmacDerivedKeyParams : HmacImportParams { @@ -123,7 +84,7 @@ dictionary HmacDerivedKeyParams : HmacImportParams { }; dictionary EcdhKeyDeriveParams : Algorithm { - CryptoKey public; + required CryptoKey public; }; @@ -131,14 +92,14 @@ dictionary EcdhKeyDeriveParams : Algorithm { dictionary RsaOtherPrimesInfo { // The following fields are defined in Section 6.3.2.7 of JSON Web Algorithms - DOMString r; - DOMString d; - DOMString t; + required DOMString r; + required DOMString d; + required DOMString t; }; dictionary JsonWebKey { // The following fields are defined in Section 3.1 of JSON Web Key - DOMString kty; + required DOMString kty; DOMString use; sequence key_ops; DOMString alg; @@ -169,14 +130,13 @@ dictionary JsonWebKey { interface CryptoKey { readonly attribute KeyType type; readonly attribute boolean extractable; - readonly attribute KeyAlgorithm algorithm; + [Cached, Constant, Throws] readonly attribute object algorithm; [Cached, Constant, Frozen] readonly attribute sequence usages; }; -[Pref="dom.webcrypto.enabled"] -interface CryptoKeyPair { - readonly attribute CryptoKey publicKey; - readonly attribute CryptoKey privateKey; +dictionary CryptoKeyPair { + required CryptoKey publicKey; + required CryptoKey privateKey; }; typedef DOMString KeyFormat; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index b603b4f040d9..cb77cd1d01cc 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -238,6 +238,7 @@ WEBIDL_FILES = [ 'InterAppConnection.webidl', 'InterAppConnectionRequest.webidl', 'InterAppMessagePort.webidl', + 'KeyAlgorithm.webidl', 'KeyboardEvent.webidl', 'KeyEvent.webidl', 'LegacyQueryInterface.webidl',