Bug 1037892 - Implement changes to WebCrypto API from latest Editor's Draft r=bz,ttaubert
authorRichard Barnes <rbarnes@mozilla.com>
Sat, 27 Sep 2014 14:22:57 -0400
changeset 223020 62e3d5d264c22f1854bce402d887bb2138acdcd4
parent 223019 68fada9111a32e2be282e9a7a7914418ebd49ca6
child 223021 a1fb032b02164562cbb2c3e8d8f8c7b77c335d55
push id7107
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 17:43:31 +0000
treeherdermozilla-aurora@b4b34e0acc75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, ttaubert
bugs1037892
milestone35.0a1
Bug 1037892 - Implement changes to WebCrypto API from latest Editor's Draft r=bz,ttaubert
dom/crypto/AesKeyAlgorithm.cpp
dom/crypto/AesKeyAlgorithm.h
dom/crypto/BasicSymmetricKeyAlgorithm.h
dom/crypto/CryptoBuffer.cpp
dom/crypto/CryptoBuffer.h
dom/crypto/CryptoKey.cpp
dom/crypto/CryptoKey.h
dom/crypto/CryptoKeyPair.cpp
dom/crypto/CryptoKeyPair.h
dom/crypto/EcKeyAlgorithm.cpp
dom/crypto/EcKeyAlgorithm.h
dom/crypto/HmacKeyAlgorithm.cpp
dom/crypto/HmacKeyAlgorithm.h
dom/crypto/KeyAlgorithm.cpp
dom/crypto/KeyAlgorithm.h
dom/crypto/KeyAlgorithmProxy.cpp
dom/crypto/KeyAlgorithmProxy.h
dom/crypto/RsaHashedKeyAlgorithm.cpp
dom/crypto/RsaHashedKeyAlgorithm.h
dom/crypto/RsaKeyAlgorithm.cpp
dom/crypto/RsaKeyAlgorithm.h
dom/crypto/WebCryptoCommon.h
dom/crypto/WebCryptoTask.cpp
dom/crypto/moz.build
dom/crypto/test/test_WebCrypto.html
dom/crypto/test/test_WebCrypto_ECDH.html
dom/crypto/test/test_WebCrypto_JWK.html
dom/crypto/test/test_WebCrypto_PBKDF2.html
dom/crypto/test/test_WebCrypto_RSA_OAEP.html
dom/tests/mochitest/general/test_interfaces.html
dom/webidl/KeyAlgorithm.webidl
dom/webidl/SubtleCrypto.webidl
dom/webidl/moz.build
deleted file mode 100644
--- 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
deleted file mode 100644
--- 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
deleted file mode 100644
--- 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
--- a/dom/crypto/CryptoBuffer.cpp
+++ b/dom/crypto/CryptoBuffer.cpp
@@ -156,16 +156,23 @@ CryptoBuffer::ToSECItem() const
   item->data = data;
   item->len = Length();
 
   memcpy(item->data, Elements(), Length());
 
   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
 bool
 CryptoBuffer::GetBigIntValue(unsigned long& aRetVal)
 {
   if (Length() > sizeof(aRetVal)) {
     return false;
--- a/dom/crypto/CryptoBuffer.h
+++ b/dom/crypto/CryptoBuffer.h
@@ -35,16 +35,17 @@ public:
   {
     aArray.ComputeLengthAndData();
     return Assign(aArray.Data(), aArray.Length());
   }
 
   nsresult FromJwkBase64(const nsString& aBase64);
   nsresult ToJwkBase64(nsString& aBase64);
   SECItem* ToSECItem() const;
+  JSObject* ToUint8Array(JSContext* aCx) const;
 
   bool GetBigIntValue(unsigned long& aRetVal);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CryptoBuffer_h
--- a/dom/crypto/CryptoKey.cpp
+++ b/dom/crypto/CryptoKey.cpp
@@ -5,21 +5,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "pk11pub.h"
 #include "cryptohi.h"
 #include "ScopedNSSTypes.h"
 #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)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 nsresult
@@ -85,20 +86,45 @@ CryptoKey::GetType(nsString& aRetVal) co
 }
 
 bool
 CryptoKey::Extractable() const
 {
   return (mAttributes & EXTRACTABLE);
 }
 
-KeyAlgorithm*
-CryptoKey::Algorithm() const
+void
+CryptoKey::GetAlgorithm(JSContext* cx, JS::MutableHandle<JSObject*> 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<RsaHashedKeyAlgorithm> 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
 CryptoKey::GetUsages(nsTArray<nsString>& aRetVal) const
 {
   if (mAttributes & ENCRYPT) {
     aRetVal.AppendElement(NS_LITERAL_STRING(WEBCRYPTO_KEY_USAGE_ENCRYPT));
   }
@@ -120,16 +146,28 @@ CryptoKey::GetUsages(nsTArray<nsString>&
   if (mAttributes & WRAPKEY) {
     aRetVal.AppendElement(NS_LITERAL_STRING(WEBCRYPTO_KEY_USAGE_WRAPKEY));
   }
   if (mAttributes & UNWRAPKEY) {
     aRetVal.AppendElement(NS_LITERAL_STRING(WEBCRYPTO_KEY_USAGE_UNWRAPKEY));
   }
 }
 
+KeyAlgorithmProxy&
+CryptoKey::Algorithm()
+{
+  return mAlgorithm;
+}
+
+const KeyAlgorithmProxy&
+CryptoKey::Algorithm() const
+{
+  return mAlgorithm;
+}
+
 CryptoKey::KeyType
 CryptoKey::GetKeyType() const
 {
   return static_cast<CryptoKey::KeyType>(mAttributes & TYPE_MASK);
 }
 
 nsresult
 CryptoKey::SetType(const nsString& aType)
@@ -161,22 +199,16 @@ CryptoKey::SetExtractable(bool aExtracta
 {
   mAttributes &= CLEAR_EXTRACTABLE;
   if (aExtractable) {
     mAttributes |= EXTRACTABLE;
   }
 }
 
 void
-CryptoKey::SetAlgorithm(KeyAlgorithm* aAlgorithm)
-{
-  mAlgorithm = aAlgorithm;
-}
-
-void
 CryptoKey::ClearUsages()
 {
   mAttributes &= CLEAR_USAGES;
 }
 
 nsresult
 CryptoKey::AddUsage(const nsString& aUsage)
 {
@@ -201,27 +233,52 @@ CryptoKey::AddUsageIntersecting(const ns
 
 void
 CryptoKey::AddUsage(CryptoKey::KeyUsage aUsage)
 {
   mAttributes |= aUsage;
 }
 
 bool
+CryptoKey::HasAnyUsage()
+{
+  return !!(mAttributes & USAGES_MASK);
+}
+
+bool
 CryptoKey::HasUsage(CryptoKey::KeyUsage aUsage)
 {
   return !!(mAttributes & aUsage);
 }
 
 bool
 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<nsString>& 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;
 }
 
 void
 CryptoKey::SetPrivateKey(SECKEYPrivateKey* aPrivateKey)
 {
@@ -436,35 +493,31 @@ PrivateKeyFromPrivateKeyTemplate(SECItem
 
   return SECKEY_CopyPrivateKey(privKey.get());
 }
 
 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() ||
         !aJwk.mX.WasPassed() || NS_FAILED(x.FromJwkBase64(aJwk.mX.Value())) ||
         !aJwk.mY.WasPassed() || NS_FAILED(y.FromJwkBase64(aJwk.mY.Value())) ||
         !aJwk.mD.WasPassed() || NS_FAILED(d.FromJwkBase64(aJwk.mD.Value()))) {
       return nullptr;
     }
 
     nsString namedCurve;
-    if (!NormalizeNamedCurveValue(aJwk.mCrv.Value(), namedCurve)) {
+    if (!NormalizeToken(aJwk.mCrv.Value(), namedCurve)) {
       return nullptr;
     }
 
     ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
     if (!arena) {
       return nullptr;
     }
 
@@ -499,17 +552,17 @@ CryptoKey::PrivateKeyFromJwk(const JsonW
       { CKA_EC_POINT,         ecPoint->data,        ecPoint->len },
       { CKA_VALUE,            (void*) d.Elements(), d.Length() },
     };
 
     return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
                                             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())) ||
         !aJwk.mE.WasPassed() || NS_FAILED(e.FromJwkBase64(aJwk.mE.Value())) ||
         !aJwk.mD.WasPassed() || NS_FAILED(d.FromJwkBase64(aJwk.mD.Value())) ||
         !aJwk.mP.WasPassed() || NS_FAILED(p.FromJwkBase64(aJwk.mP.Value())) ||
         !aJwk.mQ.WasPassed() || NS_FAILED(q.FromJwkBase64(aJwk.mQ.Value())) ||
         !aJwk.mDp.WasPassed() || NS_FAILED(dp.FromJwkBase64(aJwk.mDp.Value())) ||
@@ -638,17 +691,17 @@ ECKeyToJwk(const PK11ObjectType aKeyType
   memcpy(ecPointY->data, aPublicValue->data + 1 + flen, flen);
 
   CryptoBuffer x, y;
   if (!x.Assign(ecPointX) || NS_FAILED(x.ToJwkBase64(aRetVal.mX.Value())) ||
       !y.Assign(ecPointY) || NS_FAILED(y.ToJwkBase64(aRetVal.mY.Value()))) {
     return false;
   }
 
-  aRetVal.mKty.Construct(NS_LITERAL_STRING(JWK_TYPE_EC));
+  aRetVal.mKty = NS_LITERAL_STRING(JWK_TYPE_EC);
   return true;
 }
 
 nsresult
 CryptoKey::PrivateKeyToJwk(SECKEYPrivateKey* aPrivKey,
                            JsonWebKey& aRetVal,
                            const nsNSSShutDownPreventionLock& /*proofOfLock*/)
 {
@@ -669,17 +722,17 @@ CryptoKey::PrivateKeyToJwk(SECKEYPrivate
           !ReadAndEncodeAttribute(aPrivKey, CKA_PRIME_1, aRetVal.mP) ||
           !ReadAndEncodeAttribute(aPrivKey, CKA_PRIME_2, aRetVal.mQ) ||
           !ReadAndEncodeAttribute(aPrivKey, CKA_EXPONENT_1, aRetVal.mDp) ||
           !ReadAndEncodeAttribute(aPrivKey, CKA_EXPONENT_2, aRetVal.mDq) ||
           !ReadAndEncodeAttribute(aPrivKey, CKA_COEFFICIENT, aRetVal.mQi)) {
         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: {
       // Read EC params.
       ScopedSECItem params(::SECITEM_AllocItem(nullptr, nullptr, 0));
       SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, aPrivKey,
                                            CKA_EC_PARAMS, params);
       if (rv != SECSuccess) {
@@ -711,21 +764,17 @@ CryptoKey::PrivateKeyToJwk(SECKEYPrivate
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 }
 
 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())) ||
         !aJwk.mE.WasPassed() || NS_FAILED(e.FromJwkBase64(aJwk.mE.Value()))) {
       return nullptr;
     }
 
     // Transcode to a DER RSAPublicKey structure
@@ -748,17 +797,17 @@ CryptoKey::PublicKeyFromJwk(const JsonWe
                                            rsaPublicKeyTemplate));
     if (!pkDer.get()) {
       return nullptr;
     }
 
     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() ||
         !aJwk.mX.WasPassed() || NS_FAILED(x.FromJwkBase64(aJwk.mX.Value())) ||
         !aJwk.mY.WasPassed() || NS_FAILED(y.FromJwkBase64(aJwk.mY.Value()))) {
       return nullptr;
     }
 
@@ -772,17 +821,17 @@ CryptoKey::PublicKeyFromJwk(const JsonWe
       return nullptr;
     }
 
     key->keyType = ecKey;
     key->pkcs11Slot = nullptr;
     key->pkcs11ID = CK_INVALID_HANDLE;
 
     nsString namedCurve;
-    if (!NormalizeNamedCurveValue(aJwk.mCrv.Value(), namedCurve)) {
+    if (!NormalizeToken(aJwk.mCrv.Value(), namedCurve)) {
       return nullptr;
     }
 
     // Create parameters.
     SECItem* params = CreateECParamsForCurve(namedCurve, arena.get());
     if (!params) {
       return nullptr;
     }
@@ -814,17 +863,17 @@ CryptoKey::PublicKeyToJwk(SECKEYPublicKe
 
       if (!n.Assign(&aPubKey->u.rsa.modulus) ||
           !e.Assign(&aPubKey->u.rsa.publicExponent) ||
           NS_FAILED(n.ToJwkBase64(aRetVal.mN.Value())) ||
           NS_FAILED(e.ToJwkBase64(aRetVal.mE.Value()))) {
         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:
       if (!ECKeyToJwk(PK11_TypePubKey, aPubKey, &aPubKey->u.ec.DEREncodedParams,
                       &aPubKey->u.ec.publicValue, aRetVal)) {
         return NS_ERROR_DOM_OPERATION_ERR;
       }
       return NS_OK;
@@ -852,54 +901,53 @@ CryptoKey::WriteStructuredClone(JSStruct
   if (mPrivateKey) {
     CryptoKey::PrivateKeyToPkcs8(mPrivateKey, priv, locker);
   }
 
   if (mPublicKey) {
     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
 CryptoKey::ReadStructuredClone(JSStructuredCloneReader* aReader)
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return false;
   }
 
-  uint32_t zero;
+  uint32_t version;
   CryptoBuffer sym, priv, pub;
-  nsRefPtr<KeyAlgorithm> 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;
   }
 
   if (sym.Length() > 0)  {
     mSymKey = sym;
   }
   if (priv.Length() > 0) {
     mPrivateKey = CryptoKey::PrivateKeyFromPkcs8(priv, locker);
   }
   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
   if (!((GetKeyType() == SECRET  && mSymKey.Length() > 0) ||
         (GetKeyType() == PRIVATE && mPrivateKey) ||
         (GetKeyType() == PUBLIC  && mPublicKey))) {
     return false;
   }
--- a/dom/crypto/CryptoKey.h
+++ b/dom/crypto/CryptoKey.h
@@ -9,21 +9,24 @@
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "nsIGlobalObject.h"
 #include "nsNSSShutDown.h"
 #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 {
 namespace dom {
 
 /*
 
 The internal structure of keys is dictated by the need for cloning.
@@ -95,33 +98,38 @@ public:
     return mGlobal;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   // WebIDL methods
   void GetType(nsString& aRetVal) const;
   bool Extractable() const;
-  KeyAlgorithm* Algorithm() const;
+  void GetAlgorithm(JSContext* cx, JS::MutableHandle<JSObject*> aRetVal,
+                    ErrorResult& aRv) const;
   void GetUsages(nsTArray<nsString>& 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<nsString>& aUsages);
 
   void SetSymKey(const CryptoBuffer& aSymKey);
   void SetPrivateKey(SECKEYPrivateKey* aPrivateKey);
   void SetPublicKey(SECKEYPublicKey* aPublicKey);
 
   // Accessors for the keys themselves
   // Note: GetPrivateKey and GetPublicKey return copies of the internal
   // key handles, which the caller must free with SECKEY_DestroyPrivateKey
@@ -167,17 +175,17 @@ public:
   bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
   bool ReadStructuredClone(JSStructuredCloneReader* aReader);
 
 private:
   ~CryptoKey();
 
   nsRefPtr<nsIGlobalObject> mGlobal;
   uint32_t mAttributes; // see above
-  nsRefPtr<KeyAlgorithm> mAlgorithm;
+  KeyAlgorithmProxy mAlgorithm;
 
   // Only one key handle should be set, according to the KeyType
   CryptoBuffer mSymKey;
   ScopedSECKEYPrivateKey mPrivateKey;
   ScopedSECKEYPublicKey mPublicKey;
 };
 
 } // namespace dom
deleted file mode 100644
--- 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
deleted file mode 100644
--- 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<nsIGlobalObject> mGlobal;
-  nsRefPtr<CryptoKey> mPublicKey;
-  nsRefPtr<CryptoKey> mPrivateKey;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_CryptoKeyPair_h
deleted file mode 100644
--- 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
deleted file mode 100644
--- 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
deleted file mode 100644
--- 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
deleted file mode 100644
--- 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<KeyAlgorithm> mHash;
-  uint32_t mLength;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_HmacKeyAlgorithm_h
deleted file mode 100644
--- 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
deleted file mode 100644
--- 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<nsIGlobalObject> mGlobal;
-  nsString mName;
-  CK_MECHANISM_TYPE mMechanism;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_KeyAlgorithm_h
new file mode 100644
--- /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
new file mode 100644
--- /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
deleted file mode 100644
--- 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
deleted file mode 100644
--- 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<KeyAlgorithm> mHash;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_RsaHashedKeyAlgorithm_h
deleted file mode 100644
--- 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
deleted file mode 100644
--- 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<JSObject*> aRetval,
-                         ErrorResult& aError) const
-  {
-    TypedArrayCreator<Uint8Array> 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
--- a/dom/crypto/WebCryptoCommon.h
+++ b/dom/crypto/WebCryptoCommon.h
@@ -4,31 +4,31 @@
  * 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_WebCryptoCommon_h
 #define mozilla_dom_WebCryptoCommon_h
 
 #include "pk11pub.h"
 #include "nsString.h"
+#include "nsContentUtils.h"
 #include "mozilla/dom/CryptoBuffer.h"
 #include "js/StructuredClone.h"
 
 // WebCrypto algorithm names
 #define WEBCRYPTO_ALG_AES_CBC       "AES-CBC"
 #define WEBCRYPTO_ALG_AES_CTR       "AES-CTR"
 #define WEBCRYPTO_ALG_AES_GCM       "AES-GCM"
 #define WEBCRYPTO_ALG_AES_KW        "AES-KW"
 #define WEBCRYPTO_ALG_SHA1          "SHA-1"
 #define WEBCRYPTO_ALG_SHA256        "SHA-256"
 #define WEBCRYPTO_ALG_SHA384        "SHA-384"
 #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"
 
 // WebCrypto key formats
 #define WEBCRYPTO_KEY_FORMAT_RAW    "raw"
 #define WEBCRYPTO_KEY_FORMAT_PKCS8  "pkcs8"
 #define WEBCRYPTO_KEY_FORMAT_SPKI   "spki"
@@ -176,37 +176,66 @@ MapAlgorithmNameToMechanism(const nsStri
   } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
     mechanism = CKM_SHA256;
   } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA384)) {
     mechanism = CKM_SHA384;
   } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA512)) {
     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)) {
     mechanism = CKM_RSA_PKCS_OAEP;
   } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
     mechanism = CKM_ECDH1_DERIVE;
   }
 
   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;
   }
 
   return true;
 }
 
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -6,26 +6,19 @@
 
 #include "pk11pub.h"
 #include "cryptohi.h"
 #include "secerr.h"
 #include "ScopedNSSTypes.h"
 
 #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"
 
 namespace mozilla {
 namespace dom {
 
 // Pre-defined identifiers for telemetry histograms
@@ -49,17 +42,17 @@ enum TelemetryAlgorithm {
   // Please make additions at the end of the list,
   // to preserve comparability of histograms over time
   TA_UNKNOWN         = 0,
   // encrypt / decrypt
   TA_AES_CBC         = 1,
   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,
   TA_RSA_PSS         = 8,
   TA_HMAC_SHA_1      = 9,
   TA_HMAC_SHA_224    = 10,
   TA_HMAC_SHA_256    = 11,
   TA_HMAC_SHA_384    = 12,
@@ -94,19 +87,17 @@ enum TelemetryAlgorithm {
 #define ATTEMPT_BUFFER_ASSIGN(dst, src) \
   if (!dst.Assign(src)) { \
     return NS_ERROR_DOM_UNKNOWN_ERR; \
   }
 
 // 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; \
     } \
   }
 
 class ClearException
 {
 public:
@@ -132,52 +123,25 @@ GetAlgorithmName(JSContext* aCx, const O
   if (aAlgorithm.IsString()) {
     // If string, then treat as algorithm name
     aName.Assign(aAlgorithm.GetAsString());
   } else {
     // Coerce to algorithm and extract name
     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;
 }
 
 template<class T, class OOS>
 static nsresult
 Coerce(JSContext* aCx, T& aTarget, const OOS& aAlgorithm)
@@ -225,47 +189,46 @@ GetKeyLengthForAlgorithm(JSContext* aCx,
   }
 
   // Read AES key length from given algorithm object.
   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)) {
     RootedDictionary<AesDerivedKeyParams> 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;
   }
 
   // Read HMAC key length from given algorithm object or
   // determine key length as the block size of the given hash.
   if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
     RootedDictionary<HmacDerivedKeyParams> 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;
     }
 
     // Return the passed length, if any.
     if (params.mLength.WasPassed()) {
       aLength = params.mLength.Value();
       return NS_OK;
     }
 
     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;
     }
 
     // Return the given hash algorithm's block size as the key length.
     size_t length = MapHashAlgorithmNameToBlockSize(hashName);
     if (length == 0) {
       return NS_ERROR_DOM_SYNTAX_ERR;
     }
@@ -313,17 +276,16 @@ CloneData(JSContext* aCx, CryptoBuffer& 
   RootedTypedArray<ArrayBufferView> abv(aCx);
   if (abv.Init(aSrc)) {
     return !!aDst.Assign(abv);
   }
 
   return false;
 }
 
-
 // Implementation of WebCryptoTask methods
 
 void
 WebCryptoTask::FailWithError(nsresult aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, false);
 
@@ -459,59 +421,58 @@ public:
     TelemetryAlgorithm telemetryAlg;
     if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) {
       CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_CBC);
 
       mMechanism = CKM_AES_CBC_PAD;
       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;
       }
     } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) {
       CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_AES_CTR);
 
       mMechanism = CKM_AES_CTR;
       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);
 
       mMechanism = CKM_AES_GCM;
       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())
       }
 
       // 32, 64, 96, 104, 112, 120 or 128
       mTagLength = 128;
       if (params.mTagLength.WasPassed()) {
@@ -738,114 +699,16 @@ private:
       }
       ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(unwrappedKey));
     }
 
     return rv;
   }
 };
 
-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
 {
 public:
   RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
               CryptoKey& aKey, bool aEncrypt)
     : mPrivKey(aKey.GetPrivateKey())
     , mPubKey(aKey.GetPublicKey())
@@ -891,30 +754,27 @@ public:
     if (!aAlgorithm.IsString()) {
       RootedDictionary<RsaOaepParams> params(aCx);
       mEarlyRv = Coerce(aCx, params, aAlgorithm);
       if (NS_FAILED(mEarlyRv)) {
         mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
         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
 
     // Look up the MGF based on the KeyAlgorithm.
     // 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<RsaHashedKeyAlgorithm> rsaAlg =
-      static_cast<RsaHashedKeyAlgorithm*>(aKey.Algorithm());
-    mHashMechanism = rsaAlg->Hash()->Mechanism();
+    mHashMechanism = KeyAlgorithmProxy::GetMechanism(aKey.Algorithm().mRsa.mHash);
 
     switch (mHashMechanism) {
       case CKM_SHA_1:
         mMgfMechanism = CKG_MGF1_SHA1; break;
       case CKM_SHA256:
         mMgfMechanism = CKG_MGF1_SHA256; break;
       case CKM_SHA384:
         mMgfMechanism = CKG_MGF1_SHA384; break;
@@ -991,17 +851,17 @@ private:
 class HmacTask : public WebCryptoTask
 {
 public:
   HmacTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
            CryptoKey& aKey,
            const CryptoOperationData& aSignature,
            const CryptoOperationData& aData,
            bool aSign)
-    : mMechanism(aKey.Algorithm()->Mechanism())
+    : mMechanism(aKey.Algorithm().Mechanism())
     , mSymKey(aKey.GetSymKey())
     , mSign(aSign)
   {
     CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_HMAC);
 
     ATTEMPT_BUFFER_INIT(mData, aData);
     if (!aSign) {
       ATTEMPT_BUFFER_INIT(mSignature, aSignature);
@@ -1115,20 +975,20 @@ public:
     if (!aSign) {
       ATTEMPT_BUFFER_INIT(mSignature, aSignature);
     }
 
     // Look up the SECOidTag based on the KeyAlgorithm
     // 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<RsaHashedKeyAlgorithm> rsaAlg = static_cast<RsaHashedKeyAlgorithm*>(aKey.Algorithm());
-    nsRefPtr<KeyAlgorithm> hashAlg = rsaAlg->Hash();
-
-    switch (hashAlg->Mechanism()) {
+    CK_MECHANISM_TYPE mech;
+    mech = KeyAlgorithmProxy::GetMechanism(aKey.Algorithm().mRsa.mHash);
+
+    switch (mech) {
       case CKM_SHA_1:
         mOidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break;
       case CKM_SHA256:
         mOidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break;
       case CKM_SHA384:
         mOidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break;
       case CKM_SHA512:
         mOidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break;
@@ -1315,17 +1175,17 @@ public:
     // Check 'ext'
     if (aKey->Extractable() &&
         aJwk.mExt.WasPassed() && !aJwk.mExt.Value()) {
       return false;
     }
 
     // Check 'alg'
     if (aJwk.mAlg.WasPassed() &&
-        aJwk.mAlg.Value() != aKey->Algorithm()->ToJwkAlg()) {
+        aJwk.mAlg.Value() != aKey->Algorithm().JwkAlg()) {
       return false;
     }
 
     // Check 'key_ops'
     if (aJwk.mKey_ops.WasPassed()) {
       nsTArray<nsString> usages;
       aKey->GetUsages(usages);
       for (size_t i = 0; i < usages.Length(); ++i) {
@@ -1344,16 +1204,17 @@ public:
     // and if that fails, try to initialize a JWK
     if (CloneData(aCx, mKeyData, aKeyData)) {
       mDataIsJwk = false;
 
       if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
         SetJwkFromKeyData();
       }
     } else {
+      ClearException ce(aCx);
       JS::RootedValue value(aCx, JS::ObjectValue(*aKeyData));
       if (!mJwk.Init(aCx, value)) {
         return;
       }
       mDataIsJwk = true;
     }
   }
 
@@ -1424,37 +1285,41 @@ public:
       const Sequence<nsString>& aKeyUsages)
   {
     Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
     if (NS_FAILED(mEarlyRv)) {
       return;
     }
 
     SetKeyData(aCx, aKeyData);
+    if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
+      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
+      return;
+    }
   }
 
   void Init(JSContext* aCx,
       const nsAString& aFormat,
       const ObjectOrString& aAlgorithm, bool aExtractable,
       const Sequence<nsString>& aKeyUsages)
   {
     ImportKeyTask::Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
     if (NS_FAILED(mEarlyRv)) {
       return;
     }
 
     // If this is an HMAC key, import the hash name
     if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
       RootedDictionary<HmacImportParams> 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;
       }
     }
   }
 
   virtual nsresult BeforeCrypto() MOZ_OVERRIDE
@@ -1476,18 +1341,16 @@ public:
 
     // Check that we have valid key data.
     if (mKeyData.Length() == 0) {
       return NS_ERROR_DOM_DATA_ERR;
     }
 
     // Construct an appropriate KeyAlorithm,
     // and verify that usages are appropriate
-    nsRefPtr<KeyAlgorithm> 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) ||
         mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
         mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
       if (mKey->HasUsageOtherThan(CryptoKey::ENCRYPT | CryptoKey::DECRYPT |
                                   CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) {
         return NS_ERROR_DOM_DATA_ERR;
@@ -1496,62 +1359,59 @@ public:
       if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) &&
           mKey->HasUsageOtherThan(CryptoKey::WRAPKEY | CryptoKey::UNWRAPKEY)) {
         return NS_ERROR_DOM_DATA_ERR;
       }
 
       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
         return NS_ERROR_DOM_DATA_ERR;
       };
     } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
       if (mKey->HasUsageOtherThan(CryptoKey::SIGN | CryptoKey::VERIFY)) {
         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;
       }
 
       if (mDataIsJwk && mJwk.mUse.WasPassed() &&
           !mJwk.mUse.Value().EqualsLiteral(JWK_USE_SIG)) {
         return NS_ERROR_DOM_DATA_ERR;
       }
     } else {
       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;
   }
 
 private:
   nsString mHashName;
 };
 
 class ImportRsaKeyTask : public ImportKeyTask
@@ -1571,16 +1431,20 @@ public:
       const Sequence<nsString>& aKeyUsages)
   {
     Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
     if (NS_FAILED(mEarlyRv)) {
       return;
     }
 
     SetKeyData(aCx, aKeyData);
+    if (mDataIsJwk && !mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
+      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
+      return;
+    }
   }
 
   void Init(JSContext* aCx,
       const nsAString& aFormat,
       const ObjectOrString& aAlgorithm, bool aExtractable,
       const Sequence<nsString>& aKeyUsages)
   {
     ImportKeyTask::Init(aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
@@ -1588,26 +1452,34 @@ public:
       return;
     }
 
     // If this is RSA with a hash, cache the hash name
     if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
         mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
       RootedDictionary<RsaHashedImportParams> 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;
     }
   }
 
 private:
   nsString mHashName;
   uint32_t mModulusLength;
   CryptoBuffer mPublicExponent;
 
@@ -1664,51 +1536,35 @@ private:
     mPublicExponent.Assign(&pubKey->u.rsa.publicExponent);
 
     return NS_OK;
   }
 
   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 &&
            mKey->HasUsageOtherThan(CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY))) {
         return NS_ERROR_DOM_DATA_ERR;
       }
     } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
       if ((mKey->GetKeyType() == CryptoKey::PUBLIC &&
            mKey->HasUsageOtherThan(CryptoKey::VERIFY)) ||
           (mKey->GetKeyType() == CryptoKey::PRIVATE &&
            mKey->HasUsageOtherThan(CryptoKey::SIGN))) {
         return NS_ERROR_DOM_DATA_ERR;
       }
     }
 
-    // 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<RsaHashedKeyAlgorithm> 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;
     }
 
     return NS_OK;
   }
 };
@@ -1788,34 +1644,33 @@ private:
       mKey->SetPublicKey(pubKey.get());
       mKey->SetType(CryptoKey::PUBLIC);
     } else {
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
 
     // 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;
       }
     }
 
     return NS_OK;
   }
 
   virtual nsresult AfterCrypto() MOZ_OVERRIDE
   {
     // Check permissions for the requested operation
     if (mKey->GetKeyType() == CryptoKey::PRIVATE &&
         mKey->HasUsageOtherThan(CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY)) {
       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;
     }
 
     return NS_OK;
   }
 };
@@ -1825,23 +1680,18 @@ class ExportKeyTask : public WebCryptoTa
 public:
   ExportKeyTask(const nsAString& aFormat, CryptoKey& aKey)
     : mFormat(aFormat)
     , mSymKey(aKey.GetSymKey())
     , mPrivateKey(aKey.GetPrivateKey())
     , 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);
   }
 
 
 protected:
   nsString mFormat;
   CryptoBuffer mSymKey;
   ScopedSECKEYPrivateKey mPrivateKey;
@@ -1892,17 +1742,17 @@ private:
     } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
       if (mKeyType == CryptoKey::SECRET) {
         nsString k;
         nsresult rv = mSymKey.ToJwkBase64(k);
         if (NS_FAILED(rv)) {
           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;
         }
 
         nsresult rv = CryptoKey::PublicKeyToJwk(mPublicKey, mJwk, locker);
         if (NS_FAILED(rv)) {
           return NS_ERROR_DOM_OPERATION_ERR;
@@ -1970,74 +1820,73 @@ public:
     nsString algName;
     mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
     if (NS_FAILED(mEarlyRv)) {
       mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
       return;
     }
 
     // Construct an appropriate KeyAlorithm
-    nsRefPtr<KeyAlgorithm> algorithm;
     uint32_t allowedUsages = 0;
     if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
         algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
         algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
         algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
       mEarlyRv = GetKeyLengthForAlgorithm(aCx, aAlgorithm, mLength);
       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<HmacKeyGenParams> 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;
       }
 
       if (params.mLength.WasPassed()) {
         mLength = params.mLength.Value();
       } else {
         mLength = MapHashAlgorithmNameToBlockSize(hashName);
       }
 
       if (mLength == 0) {
         mEarlyRv = NS_ERROR_DOM_DATA_ERR;
         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;
       return;
     }
 
     // Add key usages
     mKey->ClearUsages();
     for (uint32_t i = 0; i < aKeyUsages.Length(); ++i) {
       mEarlyRv = mKey->AddUsageIntersecting(aKeyUsages[i], allowedUsages);
       if (NS_FAILED(mEarlyRv)) {
         return;
       }
     }
 
     mLength = mLength >> 3; // bits to bytes
-    mMechanism = algorithm->Mechanism();
-    mKey->SetAlgorithm(algorithm);
+    mMechanism = mKey->Algorithm().Mechanism();
     // SetSymKey done in Resolve, after we've done the keygen
   }
 
 private:
   nsRefPtr<CryptoKey> mKey;
   size_t mLength;
   CK_MECHANISM_TYPE mMechanism;
   CryptoBuffer mKeyData;
@@ -2084,154 +1933,133 @@ public:
   {
     nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
     if (!global) {
       mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
       return;
     }
 
     // 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;
     mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
     if (NS_FAILED(mEarlyRv)) {
       mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
       return;
     }
 
     // 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<RsaHashedKeyGenParams> 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<RsaKeyGenParams> 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
       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_ECDH)) {
       RootedDictionary<EcKeyGenParams> 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;
       return;
     }
 
     // Set key usages.
     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)) {
       privateAllowedUsages = CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS;
       publicAllowedUsages = 0;
     }
 
-    mKeyPair->PrivateKey()->SetExtractable(aExtractable);
-    mKeyPair->PrivateKey()->SetType(CryptoKey::PRIVATE);
-
-    mKeyPair->PublicKey()->SetExtractable(true);
-    mKeyPair->PublicKey()->SetType(CryptoKey::PUBLIC);
-
-    mKeyPair->PrivateKey()->ClearUsages();
-    mKeyPair->PublicKey()->ClearUsages();
+    mKeyPair.mPrivateKey.get()->SetExtractable(aExtractable);
+    mKeyPair.mPrivateKey.get()->SetType(CryptoKey::PRIVATE);
+
+    mKeyPair.mPublicKey.get()->SetExtractable(true);
+    mKeyPair.mPublicKey.get()->SetType(CryptoKey::PUBLIC);
+
+    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<CryptoKeyPair> mKeyPair;
+  CryptoKeyPair mKeyPair;
   CK_MECHANISM_TYPE mMechanism;
   PK11RSAGenParams mRsaParams;
   ScopedSECKEYPublicKey mPublicKey;
   ScopedSECKEYPrivateKey mPrivateKey;
   nsString mNamedCurve;
 
   virtual void ReleaseNSSResources() MOZ_OVERRIDE
   {
@@ -2270,30 +2098,25 @@ private:
     SECKEYPublicKey* pubKey = nullptr;
     mPrivateKey = PK11_GenerateKeyPair(slot.get(), mMechanism, param, &pubKey,
                                        PR_FALSE, PR_FALSE, nullptr);
     mPublicKey = pubKey;
     if (!mPrivateKey.get() || !mPublicKey.get()) {
       return NS_ERROR_DOM_UNKNOWN_ERR;
     }
 
-    mKeyPair->PrivateKey()->SetPrivateKey(mPrivateKey);
-    mKeyPair->PublicKey()->SetPublicKey(mPublicKey);
+    mKeyPair.mPrivateKey.get()->SetPrivateKey(mPrivateKey);
+    mKeyPair.mPublicKey.get()->SetPublicKey(mPublicKey);
     return NS_OK;
   }
 
   virtual void Resolve() MOZ_OVERRIDE
   {
     mResultPromise->MaybeResolve(mKeyPair);
   }
-
-  virtual void Cleanup() MOZ_OVERRIDE
-  {
-    mKeyPair = nullptr;
-  }
 };
 
 class DerivePbkdfBitsTask : public ReturnArrayBufferViewTask
 {
 public:
   DerivePbkdfBitsTask(JSContext* aCx,
       const ObjectOrString& aAlgorithm, CryptoKey& aKey, uint32_t aLength)
     : mSymKey(aKey.GetSymKey())
@@ -2321,50 +2144,49 @@ public:
     // Check that we got a symmetric key
     if (mSymKey.Length() == 0) {
       mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
       return;
     }
 
     RootedDictionary<Pbkdf2Params> 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;
     }
 
     // length must be a multiple of 8 bigger than zero.
     if (aLength == 0 || aLength % 8) {
       mEarlyRv = NS_ERROR_DOM_DATA_ERR;
       return;
     }
 
     // Extract the hash algorithm.
     nsString hashName;
-    mEarlyRv = GetAlgorithmName(aCx, params.mHash.Value(), hashName);
+    mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName);
     if (NS_FAILED(mEarlyRv)) {
       return;
     }
 
     // Check the given hash algorithm.
     switch (MapAlgorithmNameToMechanism(hashName)) {
       case CKM_SHA_1: mHashOidTag = SEC_OID_HMAC_SHA1; break;
       case CKM_SHA256: mHashOidTag = SEC_OID_HMAC_SHA256; break;
       case CKM_SHA384: mHashOidTag = SEC_OID_HMAC_SHA384; break;
       case CKM_SHA512: mHashOidTag = SEC_OID_HMAC_SHA512; break;
       default: {
         mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
         return;
       }
     }
 
-    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:
   size_t mLength;
   size_t mIterations;
   CryptoBuffer mSalt;
   CryptoBuffer mSymKey;
   SECOidTag mHashOidTag;
@@ -2489,35 +2311,33 @@ public:
       return;
     }
 
     mLength = mLength >> 3; // bits to bytes
 
     // Retrieve the peer's public key.
     RootedDictionary<EcdhKeyDeriveParams> 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<KeyAlgorithm> 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<EcKeyAlgorithm*>(aKey.Algorithm())->GetNamedCurve(curve1);
-    static_cast<EcKeyAlgorithm*>(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;
       return;
     }
   }
 
 private:
@@ -2640,182 +2460,268 @@ private:
       mTask->Skip();
     }
     mTask = nullptr;
   }
 };
 
 // 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());
 
+  // 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);
   }
 
-  // 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);
-  }
-
   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);
   }
 
   return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
 
 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());
 
+  // 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);
   }
 
-  // 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);
-  }
-
   if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
     return new HmacTask(aCx, aAlgorithm, aKey, aSignature, aData, aSign);
   } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
     return new RsassaPkcs1Task(aCx, aAlgorithm, aKey, aSignature, aData, aSign);
   }
 
   return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
 
 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<JSObject*> aKeyData,
-                             const ObjectOrString& aAlgorithm,
-                             bool aExtractable,
-                             const Sequence<nsString>& aKeyUsages)
-{
-  Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_IMPORTKEY);
-  Telemetry::Accumulate(Telemetry::WEBCRYPTO_EXTRACTABLE_IMPORT, aExtractable);
 
   nsString algName;
   nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
   if (NS_FAILED(rv)) {
     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<JSObject*> aKeyData,
+                                   const ObjectOrString& aAlgorithm,
+                                   bool aExtractable,
+                                   const Sequence<nsString>& 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) ||
       algName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW) ||
       algName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2) ||
       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);
   } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
     return new ImportEcKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
                                aExtractable, aKeyUsages);
   } else {
     return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   }
 }
 
 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<nsString>& aKeyUsages)
+                                     const ObjectOrString& aAlgorithm,
+                                     bool aExtractable,
+                                     const Sequence<nsString>& 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)) {
     return new FailureTask(rv);
   }
 
   if (algName.EqualsASCII(WEBCRYPTO_ALG_AES_CBC) ||
       algName.EqualsASCII(WEBCRYPTO_ALG_AES_CTR) ||
       algName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) ||
       algName.EqualsASCII(WEBCRYPTO_ALG_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);
   } else {
     return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   }
 }
 
 WebCryptoTask*
 WebCryptoTask::CreateDeriveKeyTask(JSContext* aCx,
-                             const ObjectOrString& aAlgorithm,
-                             CryptoKey& aBaseKey,
-                             const ObjectOrString& aDerivedKeyType,
-                             bool aExtractable,
-                             const Sequence<nsString>& aKeyUsages)
+                                   const ObjectOrString& aAlgorithm,
+                                   CryptoKey& aBaseKey,
+                                   const ObjectOrString& aDerivedKeyType,
+                                   bool aExtractable,
+                                   const Sequence<nsString>& 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)) {
     return new FailureTask(rv);
   }
 
   if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) {
     return new DeriveKeyTask<DerivePbkdfBitsTask>(aCx, aAlgorithm, aBaseKey,
@@ -2829,22 +2735,27 @@ WebCryptoTask::CreateDeriveKeyTask(JSCon
                                                  aKeyUsages);
   }
 
   return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
 
 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)) {
     return new FailureTask(rv);
   }
 
   if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) {
     return new DerivePbkdfBitsTask(aCx, aAlgorithm, aKey, aLength);
@@ -2854,87 +2765,101 @@ WebCryptoTask::CreateDeriveBitsTask(JSCo
     return new DeriveEcdhBitsTask(aCx, aAlgorithm, aKey, aLength);
   }
 
   return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
 
 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)) {
     return new FailureTask(rv);
   }
 
   if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
       wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
       wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
     return new WrapKeyTask<AesTask>(aCx, aFormat, aKey,
                                     aWrappingKey, aWrapAlgorithm);
   } else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
     return new WrapKeyTask<AesKwTask>(aCx, aFormat, aKey,
                                     aWrappingKey, aWrapAlgorithm);
-  } else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) {
-    return new WrapKeyTask<RsaesPkcs1Task>(aCx, aFormat, aKey,
-                                           aWrappingKey, aWrapAlgorithm);
   } else if (wrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
     return new WrapKeyTask<RsaOaepTask>(aCx, aFormat, aKey,
                                         aWrappingKey, aWrapAlgorithm);
   }
 
   return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
 
 WebCryptoTask*
 WebCryptoTask::CreateUnwrapKeyTask(JSContext* aCx,
-                             const nsAString& aFormat,
-                             const ArrayBufferViewOrArrayBuffer& aWrappedKey,
-                             CryptoKey& aUnwrappingKey,
-                             const ObjectOrString& aUnwrapAlgorithm,
-                             const ObjectOrString& aUnwrappedKeyAlgorithm,
-                             bool aExtractable,
-                             const Sequence<nsString>& aKeyUsages)
+                                   const nsAString& aFormat,
+                                   const ArrayBufferViewOrArrayBuffer& aWrappedKey,
+                                   CryptoKey& aUnwrappingKey,
+                                   const ObjectOrString& aUnwrapAlgorithm,
+                                   const ObjectOrString& aUnwrappedKeyAlgorithm,
+                                   bool aExtractable,
+                                   const Sequence<nsString>& aKeyUsages)
 {
   Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_UNWRAPKEY);
 
   // Ensure key is usable for this operation
   if (!aUnwrappingKey.HasUsage(CryptoKey::UNWRAPKEY)) {
     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)) {
     return new FailureTask(rv);
   }
 
   CryptoOperationData dummy;
   nsRefPtr<ImportKeyTask> importTask;
   if (keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_CBC) ||
       keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_CTR) ||
       keyAlgName.EqualsASCII(WEBCRYPTO_ALG_AES_GCM) ||
       keyAlgName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
     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,
                                       aExtractable, aKeyUsages);
   } else {
     return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   }
 
@@ -2948,20 +2873,16 @@ WebCryptoTask::CreateUnwrapKeyTask(JSCon
       unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
     return new UnwrapKeyTask<AesTask>(aCx, aWrappedKey,
                                       aUnwrappingKey, aUnwrapAlgorithm,
                                       importTask);
   } else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_KW)) {
     return new UnwrapKeyTask<AesKwTask>(aCx, aWrappedKey,
                                       aUnwrappingKey, aUnwrapAlgorithm,
                                       importTask);
-  } else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) {
-    return new UnwrapKeyTask<RsaesPkcs1Task>(aCx, aWrappedKey,
-                                      aUnwrappingKey, aUnwrapAlgorithm,
-                                      importTask);
   } else if (unwrapAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
     return new UnwrapKeyTask<RsaOaepTask>(aCx, aWrappedKey,
                                       aUnwrappingKey, aUnwrapAlgorithm,
                                       importTask);
   }
 
   return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
--- a/dom/crypto/moz.build
+++ b/dom/crypto/moz.build
@@ -1,39 +1,26 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 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',
 ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
--- a/dom/crypto/test/test_WebCrypto.html
+++ b/dom/crypto/test/test_WebCrypto.html
@@ -66,31 +66,30 @@ TestArray.addTest(
 TestArray.addTest(
   "Import / export round-trip with 'raw'",
   function() {
     var that = this;
     var alg = "AES-GCM";
 
     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) ||
         (x.type != "secret") ||
         (!x.extractable) ||
         (x.usages.length != 1) ||
         (x.usages[0] != 'encrypt')){
         throw "Invalid key: incorrect key data";
       }
       return crypto.subtle.exportKey("raw", x);
     }
 
     crypto.subtle.importKey("raw", tv.raw, alg, true, ["encrypt"])
-      .then(doExport, error(that))
+      .then(doExport)
       .then(
         memcmp_complete(that, tv.raw),
         error(that)
       );
   }
 );
 
 // -----------------------------------------------------------------------------
@@ -148,17 +147,17 @@ TestArray.addTest(
         (x.usages.length != 1) ||
         (x.usages[0] != 'sign')){
         throw "Invalid key: incorrect key data";
       }
       return crypto.subtle.exportKey("pkcs8", x);
     }
 
     crypto.subtle.importKey("pkcs8", tv.pkcs8, alg, true, ["sign"])
-      .then(doExport, error(that))
+      .then(doExport)
       .then(
         memcmp_complete(that, tv.pkcs8),
         error(that)
       );
   }
 );
 
 // -----------------------------------------------------------------------------
@@ -173,48 +172,54 @@ TestArray.addTest(
   }
 );
 
 // -----------------------------------------------------------------------------
 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),
         error(that)
       );
   }
 );
 
 // -----------------------------------------------------------------------------
 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));
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
@@ -377,54 +382,56 @@ TestArray.addTest(
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "Generate a 1024-bit RSA key",
   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) &&
                (x.publicKey.algorithm.modulusLength == alg.modulusLength) &&
                (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)
     );
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "Fail cleanly when NSS refuses to generate a key pair",
   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) );
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "SHA-256 digest",
   function() {
@@ -450,17 +457,16 @@ TestArray.addTest(
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "AES-CBC encrypt",
   function () {
     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);
     }
 
     crypto.subtle.importKey("raw", tv.aes_cbc_enc.key, "AES-CBC", false, ['encrypt'])
       .then(doEncrypt)
       .then(
@@ -472,17 +478,16 @@ TestArray.addTest(
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "AES-CBC encrypt with wrong IV size",
   function () {
     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);
     }
 
     function doEncrypt(x) {
       return encrypt(x, new Uint8Array(15))
         .then(
@@ -819,187 +824,125 @@ TestArray.addTest(
         error(that),
         complete(that, function(x) { return true; })
       );
   }
 );
 
 // -----------------------------------------------------------------------------
 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",
   function () {
     var that = this;
     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) );
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "RSASSA verification (SHA-1)",
   function () {
     var that = this;
     var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" };
 
     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)
       );
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "RSASSA verification (SHA-1), failing verification",
   function () {
     var that = this;
     var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" };
 
     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)
       );
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "RSASSA/SHA-256 signature",
   function () {
     var that = this;
     var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
 
     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) );
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "RSASSA verification (SHA-256)",
   function () {
     var that = this;
     var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
 
     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)
       );
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "RSASSA verification (SHA-256), failing verification",
   function () {
     var that = this;
     var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
     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)
       );
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "Key wrap known answer, using AES-GCM",
   function () {
@@ -1170,30 +1113,28 @@ TestArray.addTest(
       return crypto.subtle.wrapKey("jwk", originalKey, wrapKey, wrapAlg);
     }
     function doUnwrap(wrappedKey) {
       return crypto.subtle.unwrapKey("jwk", wrappedKey, wrapKey, wrapAlg,
                                      { name: "HMAC", hash: "SHA-384"},
                                      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;
         }),
         error(that)
       );
   }
 );
@@ -1264,19 +1205,19 @@ TestArray.addTest(
       return crypto.subtle.unwrapKey("raw", wrappedKey, wrapKey,
                                      "AES-KW", { name: "HMAC", hash: "SHA-384"},
                                      true, ['sign', 'verify']);
     }
 
     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; })
     ])
       .then(doWrap)
       .then(doUnwrap)
       .then(doExport)
       .then(
         complete(that, function(x) {
@@ -1327,17 +1268,17 @@ TestArray.addTest(
 
     function doGenerateRsaOaepKey() {
       var alg = {
         name: "rsa-OAEP",
         hash: "sha-1",
         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() {
       var alg = { name: "RSASSA-pkcs1-V1_5", hash: "SHA-1" };
       return crypto.subtle.importKey("pkcs8", tv.pkcs8, alg, true, ["sign"]);
     }
 
     crypto.subtle.generateKey(alg, false, ["sign"])
@@ -1359,34 +1300,17 @@ TestArray.addTest(
 
       function doSign(x) {
         return crypto.subtle.sign("RSASSA-PKCS1-v1_5", x, new Uint8Array());
       }
 
       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));
   }
 );
 /*]]>*/</script>
 </head>
 
 <body>
 
 <div id="content">
--- a/dom/crypto/test/test_WebCrypto_ECDH.html
+++ b/dom/crypto/test/test_WebCrypto_ECDH.html
@@ -98,17 +98,17 @@ TestArray.addTest(
 
     function doGenerateRSA() {
       var alg = {
         name: "RSA-OAEP",
         hash: "SHA-256",
         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() {
       var alg = { name: "ECDH", public: pubKey };
       return crypto.subtle.deriveBits(alg, privKey, 16);
     }
 
     doGenerateP256()
@@ -331,22 +331,22 @@ TestArray.addTest(
       var data = crypto.getRandomValues(new Uint8Array(1024));
       return crypto.subtle.sign("HMAC", x, data)
         .then(function (sig) {
           return crypto.subtle.verify("HMAC", x, sig, data);
         });
     }
 
     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));
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "SPKI import/export of public ECDH keys (P-256)",
   function () {
--- a/dom/crypto/test/test_WebCrypto_JWK.html
+++ b/dom/crypto/test/test_WebCrypto_JWK.html
@@ -187,18 +187,16 @@ TestArray.addTest(
     function doExport(k) {
       return crypto.subtle.exportKey("jwk", k);
     }
 
     crypto.subtle.importKey("jwk", jwk, alg, true, ['sign'])
       .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' &&
                  x.alg == 'RS256' &&
                  x.ext &&
                  shallowArrayEquals(x.key_ops, ['sign']) &&
                  x.n  == jwk.n  &&
                  x.e  == jwk.e  &&
--- a/dom/crypto/test/test_WebCrypto_PBKDF2.html
+++ b/dom/crypto/test/test_WebCrypto_PBKDF2.html
@@ -41,47 +41,45 @@ TestArray.addTest(
 TestArray.addTest(
   "Import raw PBKDF2 key and derive bits using HMAC-SHA-1",
   function() {
     var that = this;
     var alg = "PBKDF2";
     var key = tv.pbkdf2_sha1.password;
 
     function doDerive(x) {
-      console.log("deriving");
       if (!hasKeyFields(x)) {
         throw "Invalid key; missing field(s)";
       }
 
       var alg = {
         name: "PBKDF2",
         hash: "SHA-1",
         salt: tv.pbkdf2_sha1.salt,
         iterations: tv.pbkdf2_sha1.iterations
       };
       return crypto.subtle.deriveBits(alg, x, tv.pbkdf2_sha1.length);
     }
     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 );
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "Import raw PBKDF2 key and derive a new key using HMAC-SHA-1",
   function() {
     var that = this;
     var alg = "PBKDF2";
     var key = tv.pbkdf2_sha1.password;
 
     function doDerive(x) {
-      console.log("deriving");
       if (!hasKeyFields(x)) {
         throw "Invalid key; missing field(s)";
       }
 
       var alg = {
         name: "PBKDF2",
         hash: "SHA-1",
         salt: tv.pbkdf2_sha1.salt,
@@ -156,17 +154,16 @@ TestArray.addTest(
 /*TestArray.addTest(
   "Import raw PBKDF2 key and derive bits using HMAC-SHA-256",
   function() {
     var that = this;
     var alg = "PBKDF2";
     var key = tv.pbkdf2_sha256.password;
 
     function doDerive(x) {
-      console.log("deriving");
       if (!hasKeyFields(x)) {
         throw "Invalid key; missing field(s)";
       }
 
       var alg = {
         name: "PBKDF2",
         hash: "SHA-256",
         salt: tv.pbkdf2_sha256.salt,
--- a/dom/crypto/test/test_WebCrypto_RSA_OAEP.html
+++ b/dom/crypto/test/test_WebCrypto_RSA_OAEP.html
@@ -115,22 +115,23 @@ TestArray.addTest(
       hash: "SHA-1",
       modulusLength: 2048,
       publicExponent: new Uint8Array([0x01, 0x00, 0x01])
     };
 
     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))
       .then(error(that), complete(that));
   }
 );
 
 // -----------------------------------------------------------------------------
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -240,18 +240,16 @@ var interfaceNamesInGlobalScope =
     "Controllers",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ConvolverNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "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!
     "CSS2Properties",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSCharsetRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSConditionRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
new file mode 100644
--- /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;
+};
+
--- a/dom/webidl/SubtleCrypto.webidl
+++ b/dom/webidl/SubtleCrypto.webidl
@@ -4,146 +4,107 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://www.w3.org/TR/WebCryptoAPI/
  */
 
 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 {
   [EnforceRange] unsigned long length;
 };
 
 dictionary EcdhKeyDeriveParams : Algorithm {
-  CryptoKey public;
+  required CryptoKey public;
 };
 
 
 /***** JWK *****/
 
 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<DOMString> key_ops;
   DOMString alg;
 
   // The following fields are defined in JSON Web Key Parameters Registration
   boolean ext;
 
   // The following fields are defined in Section 6 of JSON Web Algorithms
@@ -164,24 +125,23 @@ dictionary JsonWebKey {
 
 
 /***** The Main API *****/
 
 [Pref="dom.webcrypto.enabled"]
 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<KeyUsage> 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;
 typedef (ArrayBufferView or ArrayBuffer) CryptoOperationData;
 typedef (object or DOMString) AlgorithmIdentifier;
 
 [Pref="dom.webcrypto.enabled"]
 interface SubtleCrypto {
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -233,16 +233,17 @@ WEBIDL_FILES = [
     'InputEvent.webidl',
     'InputMethod.webidl',
     'InspectorUtils.webidl',
     'InstallEvent.webidl',
     'InstallPhaseEvent.webidl',
     'InterAppConnection.webidl',
     'InterAppConnectionRequest.webidl',
     'InterAppMessagePort.webidl',
+    'KeyAlgorithm.webidl',
     'KeyboardEvent.webidl',
     'KeyEvent.webidl',
     'LegacyQueryInterface.webidl',
     'LinkStyle.webidl',
     'LocalMediaStream.webidl',
     'Location.webidl',
     'MediaElementAudioSourceNode.webidl',
     'MediaError.webidl',