Bug 1564509 - Remove DH from WebCrypto r=kjacobs,bzbarsky,keeler
authorJ.C. Jones <jjones@mozilla.com>
Mon, 11 Nov 2019 21:17:47 +0000
changeset 501755 5d93cdf79d2796c10ea902470cab90b9f903b159
parent 501754 d65ec56af99764c4370edc565668ce1ec638ee01
child 501756 35f2efaaeff6d8c617498ba1958a2409efe1c92c
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskjacobs, bzbarsky, keeler
bugs1564509, 1034856, 1539578
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1564509 - Remove DH from WebCrypto r=kjacobs,bzbarsky,keeler Bug 1034856 added support for DH algorithms to WebCrypto, however the final specification did not choose to include them, making Firefox the only browser with support. Bug 1539578 added telemetry to show usage, and it is extremely low (not appearing on the graphs), which could be expected as Firefox is the only supporting browser. Since DH is an ongoing maintenance burden -- and overall cryptanalysis of DH is progressing -- let's remove it. Notice to unship went to dev-platform on 29 March 2019 with no objections. [0] [0] https://groups.google.com/d/msg/mozilla.dev.platform/Ut3-eQmUdWg/O9w1et1aBgAJ Differential Revision: https://phabricator.services.mozilla.com/D50865
dom/crypto/CryptoKey.cpp
dom/crypto/CryptoKey.h
dom/crypto/KeyAlgorithmProxy.cpp
dom/crypto/KeyAlgorithmProxy.h
dom/crypto/WebCryptoCommon.h
dom/crypto/WebCryptoTask.cpp
dom/crypto/test/browser/browser_WebCrypto_telemetry.js
dom/crypto/test/test-vectors.js
dom/crypto/test/test_WebCrypto.html
dom/crypto/test/test_WebCrypto_DH.html
dom/webidl/SubtleCrypto.webidl
--- a/dom/crypto/CryptoKey.cpp
+++ b/dom/crypto/CryptoKey.cpp
@@ -8,42 +8,16 @@
 
 #include "cryptohi.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/dom/SubtleCryptoBinding.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "nsNSSComponent.h"
 #include "pk11pub.h"
 
-// Templates taken from security/nss/lib/cryptohi/seckey.c
-// These would ideally be exported by NSS and until that
-// happens we have to keep our own copies.
-const SEC_ASN1Template SECKEY_DHPublicKeyTemplate[] = {
-    {
-        SEC_ASN1_INTEGER,
-        offsetof(SECKEYPublicKey, u.dh.publicValue),
-    },
-    {
-        0,
-    }};
-const SEC_ASN1Template SECKEY_DHParamKeyTemplate[] = {
-    {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPublicKey)},
-    {
-        SEC_ASN1_INTEGER,
-        offsetof(SECKEYPublicKey, u.dh.prime),
-    },
-    {
-        SEC_ASN1_INTEGER,
-        offsetof(SECKEYPublicKey, u.dh.base),
-    },
-    {SEC_ASN1_SKIP_REST},
-    {
-        0,
-    }};
-
 namespace mozilla {
 namespace dom {
 
 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
@@ -201,24 +175,16 @@ void CryptoKey::GetAlgorithm(JSContext* 
       if (converted) {
         converted = ToJSValue(cx, rsa, &val);
       }
       break;
     }
     case KeyAlgorithmProxy::EC:
       converted = ToJSValue(cx, mAlgorithm.mEc, &val);
       break;
-    case KeyAlgorithmProxy::DH: {
-      RootedDictionary<DhKeyAlgorithm> dh(cx);
-      converted = mAlgorithm.mDh.ToKeyAlgorithm(cx, dh);
-      if (converted) {
-        converted = ToJSValue(cx, dh, &val);
-      }
-      break;
-    }
   }
   if (!converted) {
     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     return;
   }
 
   aRetVal.set(&val.toObject());
 }
@@ -478,32 +444,22 @@ UniqueSECKEYPublicKey CryptoKey::PublicK
   UniqueCERTSubjectPublicKeyInfo spki(
       SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
   if (!spki) {
     return nullptr;
   }
 
   bool isECDHAlgorithm =
       SECITEM_ItemsAreEqual(&SEC_OID_DATA_EC_DH, &spki->algorithm.algorithm);
-  bool isDHAlgorithm = SECITEM_ItemsAreEqual(&SEC_OID_DATA_DH_KEY_AGREEMENT,
-                                             &spki->algorithm.algorithm);
 
-  // Check for |id-ecDH| and |dhKeyAgreement|. Per the WebCrypto spec we must
-  // support these OIDs but NSS does unfortunately not know about them. Let's
-  // change the algorithm to |id-ecPublicKey| or |dhPublicKey| to make NSS
-  // happy.
-  if (isECDHAlgorithm || isDHAlgorithm) {
-    SECOidTag oid = SEC_OID_UNKNOWN;
-    if (isECDHAlgorithm) {
-      oid = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
-    } else if (isDHAlgorithm) {
-      oid = SEC_OID_X942_DIFFIE_HELMAN_KEY;
-    } else {
-      MOZ_ASSERT(false);
-    }
+  // Check for |id-ecDH|. Per the WebCrypto spec we must
+  // support this OID but NSS does unfortunately not know it. Let's
+  // change the algorithm to |id-ecPublicKey| to make NSS happy.
+  if (isECDHAlgorithm) {
+    SECOidTag oid = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
 
     SECOidData* oidData = SECOID_FindOIDByTag(oid);
     if (!oidData) {
       return nullptr;
     }
 
     SECStatus rv = SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm,
                                     &oidData->oid);
@@ -527,96 +483,31 @@ nsresult CryptoKey::PrivateKeyToPkcs8(SE
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
   if (!aRetVal.Assign(pkcs8Item.get())) {
     return NS_ERROR_DOM_OPERATION_ERR;
   }
   return NS_OK;
 }
 
-nsresult PublicDhKeyToSpki(SECKEYPublicKey* aPubKey,
-                           CERTSubjectPublicKeyInfo* aSpki) {
-  SECItem* params = ::SECITEM_AllocItem(aSpki->arena, nullptr, 0);
-  if (!params) {
-    return NS_ERROR_DOM_OPERATION_ERR;
-  }
-
-  SECItem* rvItem = SEC_ASN1EncodeItem(aSpki->arena, params, aPubKey,
-                                       SECKEY_DHParamKeyTemplate);
-  if (!rvItem) {
-    return NS_ERROR_DOM_OPERATION_ERR;
-  }
-
-  SECStatus rv = SECOID_SetAlgorithmID(aSpki->arena, &aSpki->algorithm,
-                                       SEC_OID_X942_DIFFIE_HELMAN_KEY, params);
-  if (rv != SECSuccess) {
-    return NS_ERROR_DOM_OPERATION_ERR;
-  }
-
-  rvItem = SEC_ASN1EncodeItem(aSpki->arena, &aSpki->subjectPublicKey, aPubKey,
-                              SECKEY_DHPublicKeyTemplate);
-  if (!rvItem) {
-    return NS_ERROR_DOM_OPERATION_ERR;
-  }
-
-  // The public value is a BIT_STRING encoded as an INTEGER. After encoding
-  // an INT we need to adjust the length to reflect the number of bits.
-  aSpki->subjectPublicKey.len <<= 3;
-
-  return NS_OK;
-}
-
 nsresult CryptoKey::PublicKeyToSpki(SECKEYPublicKey* aPubKey,
                                     CryptoBuffer& aRetVal) {
   UniqueCERTSubjectPublicKeyInfo spki;
 
-  // NSS doesn't support exporting DH public keys.
-  if (aPubKey->keyType == dhKey) {
-    // Mimic the behavior of SECKEY_CreateSubjectPublicKeyInfo() and create
-    // a new arena for the SPKI object.
-    UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
-    if (!arena) {
-      return NS_ERROR_DOM_OPERATION_ERR;
-    }
-
-    spki.reset(PORT_ArenaZNew(arena.get(), CERTSubjectPublicKeyInfo));
-    if (!spki) {
-      return NS_ERROR_DOM_OPERATION_ERR;
-    }
-
-    // Assign |arena| to |spki| and null the variable afterwards so that the
-    // arena created above that holds the SPKI object is free'd when |spki|
-    // goes out of scope, not when |arena| does.
-    spki->arena = arena.release();
-
-    nsresult rv = PublicDhKeyToSpki(aPubKey, spki.get());
-    NS_ENSURE_SUCCESS(rv, rv);
-  } else {
-    spki.reset(SECKEY_CreateSubjectPublicKeyInfo(aPubKey));
-    if (!spki) {
-      return NS_ERROR_DOM_OPERATION_ERR;
-    }
+  spki.reset(SECKEY_CreateSubjectPublicKeyInfo(aPubKey));
+  if (!spki) {
+    return NS_ERROR_DOM_OPERATION_ERR;
   }
 
   // Per WebCrypto spec we must export ECDH SPKIs with the algorithm OID
-  // id-ecDH (1.3.132.112) and DH SPKIs with OID dhKeyAgreement
-  // (1.2.840.113549.1.3.1). NSS doesn't know about these OIDs and there is
+  // id-ecDH (1.3.132.112). NSS doesn't know about this OID and there is
   // no way to specify the algorithm to use when exporting a public key.
-  if (aPubKey->keyType == ecKey || aPubKey->keyType == dhKey) {
-    const SECItem* oidData = nullptr;
-    if (aPubKey->keyType == ecKey) {
-      oidData = &SEC_OID_DATA_EC_DH;
-    } else if (aPubKey->keyType == dhKey) {
-      oidData = &SEC_OID_DATA_DH_KEY_AGREEMENT;
-    } else {
-      MOZ_ASSERT(false);
-    }
-
-    SECStatus rv =
-        SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm, oidData);
+  if (aPubKey->keyType == ecKey) {
+    SECStatus rv = SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm,
+                                    &SEC_OID_DATA_EC_DH);
     if (rv != SECSuccess) {
       return NS_ERROR_DOM_OPERATION_ERR;
     }
   }
 
   const SEC_ASN1Template* tpl = SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate);
   UniqueSECItem spkiItem(SEC_ASN1EncodeItem(nullptr, nullptr, spki.get(), tpl));
 
@@ -1031,55 +922,16 @@ nsresult CryptoKey::PublicKeyToJwk(SECKE
         return NS_ERROR_DOM_OPERATION_ERR;
       }
       return NS_OK;
     default:
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 }
 
-UniqueSECKEYPublicKey CryptoKey::PublicDhKeyFromRaw(
-    CryptoBuffer& aKeyData, const CryptoBuffer& aPrime,
-    const CryptoBuffer& aGenerator) {
-  UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
-  if (!arena) {
-    return nullptr;
-  }
-
-  SECKEYPublicKey* key = PORT_ArenaZNew(arena.get(), SECKEYPublicKey);
-  if (!key) {
-    return nullptr;
-  }
-
-  key->keyType = dhKey;
-  key->pkcs11Slot = nullptr;
-  key->pkcs11ID = CK_INVALID_HANDLE;
-
-  // Set DH public key params.
-  if (!aPrime.ToSECItem(arena.get(), &key->u.dh.prime) ||
-      !aGenerator.ToSECItem(arena.get(), &key->u.dh.base) ||
-      !aKeyData.ToSECItem(arena.get(), &key->u.dh.publicValue)) {
-    return nullptr;
-  }
-
-  key->u.dh.prime.type = siUnsignedInteger;
-  key->u.dh.base.type = siUnsignedInteger;
-  key->u.dh.publicValue.type = siUnsignedInteger;
-
-  return UniqueSECKEYPublicKey(SECKEY_CopyPublicKey(key));
-}
-
-nsresult CryptoKey::PublicDhKeyToRaw(SECKEYPublicKey* aPubKey,
-                                     CryptoBuffer& aRetVal) {
-  if (!aRetVal.Assign(&aPubKey->u.dh.publicValue)) {
-    return NS_ERROR_DOM_OPERATION_ERR;
-  }
-  return NS_OK;
-}
-
 UniqueSECKEYPublicKey CryptoKey::PublicECKeyFromRaw(
     CryptoBuffer& aKeyData, const nsString& aNamedCurve) {
   UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
   if (!arena) {
     return nullptr;
   }
 
   SECItem rawItem = {siBuffer, nullptr, 0};
--- a/dom/crypto/CryptoKey.h
+++ b/dom/crypto/CryptoKey.h
@@ -145,22 +145,16 @@ class CryptoKey final : public nsISuppor
 
   static UniqueSECKEYPrivateKey PrivateKeyFromJwk(const JsonWebKey& aJwk);
   static nsresult PrivateKeyToJwk(SECKEYPrivateKey* aPrivKey,
                                   JsonWebKey& aRetVal);
 
   static UniqueSECKEYPublicKey PublicKeyFromJwk(const JsonWebKey& aKeyData);
   static nsresult PublicKeyToJwk(SECKEYPublicKey* aPubKey, JsonWebKey& aRetVal);
 
-  static UniqueSECKEYPublicKey PublicDhKeyFromRaw(
-      CryptoBuffer& aKeyData, const CryptoBuffer& aPrime,
-      const CryptoBuffer& aGenerator);
-  static nsresult PublicDhKeyToRaw(SECKEYPublicKey* aPubKey,
-                                   CryptoBuffer& aRetVal);
-
   static UniqueSECKEYPublicKey PublicECKeyFromRaw(CryptoBuffer& aKeyData,
                                                   const nsString& aNamedCurve);
   static nsresult PublicECKeyToRaw(SECKEYPublicKey* aPubKey,
                                    CryptoBuffer& aRetVal);
 
   static bool PublicKeyValid(SECKEYPublicKey* aPubKey);
 
   // Structured clone methods use these to clone keys
--- a/dom/crypto/KeyAlgorithmProxy.cpp
+++ b/dom/crypto/KeyAlgorithmProxy.cpp
@@ -26,20 +26,16 @@ bool KeyAlgorithmProxy::WriteStructuredC
              StructuredCloneHolder::WriteString(aWriter, mHmac.mHash.mName);
     case RSA: {
       return JS_WriteUint32Pair(aWriter, mRsa.mModulusLength, 0) &&
              WriteBuffer(aWriter, mRsa.mPublicExponent) &&
              StructuredCloneHolder::WriteString(aWriter, mRsa.mHash.mName);
     }
     case EC:
       return StructuredCloneHolder::WriteString(aWriter, mEc.mNamedCurve);
-    case DH: {
-      return WriteBuffer(aWriter, mDh.mPrime) &&
-             WriteBuffer(aWriter, mDh.mGenerator);
-    }
   }
 
   return false;
 }
 
 bool KeyAlgorithmProxy::ReadStructuredClone(JSStructuredCloneReader* aReader) {
   uint32_t type, version, dummy;
   if (!StructuredCloneHolder::ReadString(aReader, mName) ||
@@ -89,25 +85,16 @@ bool KeyAlgorithmProxy::ReadStructuredCl
       nsString namedCurve;
       if (!StructuredCloneHolder::ReadString(aReader, mEc.mNamedCurve)) {
         return false;
       }
 
       mEc.mName = mName;
       return true;
     }
-    case DH: {
-      if (!ReadBuffer(aReader, mDh.mPrime) ||
-          !ReadBuffer(aReader, mDh.mGenerator)) {
-        return false;
-      }
-
-      mDh.mName = mName;
-      return true;
-    }
   }
 
   return false;
 }
 
 CK_MECHANISM_TYPE
 KeyAlgorithmProxy::Mechanism() const {
   if (mType == HMAC) {
--- a/dom/crypto/KeyAlgorithmProxy.h
+++ b/dom/crypto/KeyAlgorithmProxy.h
@@ -36,64 +36,34 @@ struct RsaHashedKeyAlgorithmStorage {
     aRsa.mHash.mName = mHash.mName;
     aRsa.mPublicExponent.Init(exponent);
     aRsa.mPublicExponent.ComputeLengthAndData();
 
     return true;
   }
 };
 
-// A heap-safe variant of DhKeyAlgorithm
-// The only difference is that it uses CryptoBuffers instead of Uint8Arrays
-struct DhKeyAlgorithmStorage {
-  nsString mName;
-  CryptoBuffer mPrime;
-  CryptoBuffer mGenerator;
-
-  bool ToKeyAlgorithm(JSContext* aCx, DhKeyAlgorithm& aDh) const {
-    JS::Rooted<JSObject*> prime(aCx, mPrime.ToUint8Array(aCx));
-    if (!prime) {
-      return false;
-    }
-
-    JS::Rooted<JSObject*> generator(aCx, mGenerator.ToUint8Array(aCx));
-    if (!generator) {
-      return false;
-    }
-
-    aDh.mName = mName;
-    aDh.mPrime.Init(prime);
-    aDh.mPrime.ComputeLengthAndData();
-    aDh.mGenerator.Init(generator);
-    aDh.mGenerator.ComputeLengthAndData();
-
-    return true;
-  }
-};
-
 // This class encapuslates a KeyAlgorithm object, and adds several
 // methods that make WebCrypto operations simpler.
 struct KeyAlgorithmProxy {
   enum KeyAlgorithmType {
     AES,
     HMAC,
     RSA,
     EC,
-    DH,
   };
   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;
-  DhKeyAlgorithmStorage mDh;
 
   // 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;
@@ -133,28 +103,14 @@ struct KeyAlgorithmProxy {
   }
 
   void MakeEc(const nsString& aName, const nsString& aNamedCurve) {
     mType = EC;
     mName = aName;
     mEc.mName = aName;
     mEc.mNamedCurve = aNamedCurve;
   }
-
-  bool MakeDh(const nsString& aName, const CryptoBuffer& aPrime,
-              const CryptoBuffer& aGenerator) {
-    mType = DH;
-    mName = aName;
-    mDh.mName = aName;
-    if (!mDh.mPrime.Assign(aPrime)) {
-      return false;
-    }
-    if (!mDh.mGenerator.Assign(aGenerator)) {
-      return false;
-    }
-    return true;
-  }
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_KeyAlgorithmProxy_h
--- a/dom/crypto/WebCryptoCommon.h
+++ b/dom/crypto/WebCryptoCommon.h
@@ -26,17 +26,16 @@
 #define WEBCRYPTO_ALG_HMAC "HMAC"
 #define WEBCRYPTO_ALG_HKDF "HKDF"
 #define WEBCRYPTO_ALG_PBKDF2 "PBKDF2"
 #define WEBCRYPTO_ALG_RSASSA_PKCS1 "RSASSA-PKCS1-v1_5"
 #define WEBCRYPTO_ALG_RSA_OAEP "RSA-OAEP"
 #define WEBCRYPTO_ALG_RSA_PSS "RSA-PSS"
 #define WEBCRYPTO_ALG_ECDH "ECDH"
 #define WEBCRYPTO_ALG_ECDSA "ECDSA"
-#define WEBCRYPTO_ALG_DH "DH"
 
 // WebCrypto key formats
 #define WEBCRYPTO_KEY_FORMAT_RAW "raw"
 #define WEBCRYPTO_KEY_FORMAT_PKCS8 "pkcs8"
 #define WEBCRYPTO_KEY_FORMAT_SPKI "spki"
 #define WEBCRYPTO_KEY_FORMAT_JWK "jwk"
 
 // WebCrypto key types
@@ -105,25 +104,16 @@
 #define UNKNOWN_CK_MECHANISM CKM_VENDOR_DEFINED + 1
 
 // python security/pkix/tools/DottedOIDToCode.py id-ecDH 1.3.132.112
 static const uint8_t id_ecDH[] = {0x2b, 0x81, 0x04, 0x70};
 const SECItem SEC_OID_DATA_EC_DH = {
     siBuffer, (unsigned char*)id_ecDH,
     static_cast<unsigned int>(mozilla::ArrayLength(id_ecDH))};
 
-// clang-format off
-// python security/pkix/tools/DottedOIDToCode.py dhKeyAgreement 1.2.840.113549.1.3.1
-// clang-format on
-static const uint8_t dhKeyAgreement[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
-                                         0x0d, 0x01, 0x03, 0x01};
-const SECItem SEC_OID_DATA_DH_KEY_AGREEMENT = {
-    siBuffer, (unsigned char*)dhKeyAgreement,
-    static_cast<unsigned int>(mozilla::ArrayLength(dhKeyAgreement))};
-
 namespace mozilla {
 namespace dom {
 
 inline bool ReadBuffer(JSStructuredCloneReader* aReader,
                        CryptoBuffer& aBuffer) {
   uint32_t length, zero;
   bool ret = JS_ReadUint32Pair(aReader, &length, &zero);
   if (!ret) {
@@ -178,18 +168,16 @@ inline CK_MECHANISM_TYPE MapAlgorithmNam
   } 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_RSA_PSS)) {
     mechanism = CKM_RSA_PKCS_PSS;
   } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
     mechanism = CKM_ECDH1_DERIVE;
-  } else if (aName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
-    mechanism = CKM_DH_PKCS_DERIVE;
   }
 
   return mechanism;
 }
 
 #define NORMALIZED_EQUALS(aTest, aConst) \
   nsContentUtils::EqualsIgnoreASCIICase(aTest, NS_LITERAL_STRING(aConst))
 
@@ -222,18 +210,16 @@ inline bool NormalizeToken(const nsStrin
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_OAEP)) {
     aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_OAEP);
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_RSA_PSS)) {
     aDest.AssignLiteral(WEBCRYPTO_ALG_RSA_PSS);
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDH)) {
     aDest.AssignLiteral(WEBCRYPTO_ALG_ECDH);
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_ECDSA)) {
     aDest.AssignLiteral(WEBCRYPTO_ALG_ECDSA);
-  } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_ALG_DH)) {
-    aDest.AssignLiteral(WEBCRYPTO_ALG_DH);
     // Named curve values
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P256)) {
     aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P256);
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P384)) {
     aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P384);
   } else if (NORMALIZED_EQUALS(aName, WEBCRYPTO_NAMED_CURVE_P521)) {
     aDest.AssignLiteral(WEBCRYPTO_NAMED_CURVE_P521);
   } else {
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -1875,113 +1875,16 @@ class ImportEcKeyTask : public ImportKey
     if (mDataIsJwk && !JwkCompatible(mJwk, mKey)) {
       return NS_ERROR_DOM_DATA_ERR;
     }
 
     return NS_OK;
   }
 };
 
-class ImportDhKeyTask : public ImportKeyTask {
- public:
-  ImportDhKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
-                  const nsAString& aFormat, const ObjectOrString& aAlgorithm,
-                  bool aExtractable, const Sequence<nsString>& aKeyUsages) {
-    Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
-  }
-
-  ImportDhKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx,
-                  const nsAString& aFormat, JS::Handle<JSObject*> aKeyData,
-                  const ObjectOrString& aAlgorithm, bool aExtractable,
-                  const Sequence<nsString>& aKeyUsages) {
-    Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable, aKeyUsages);
-    if (NS_SUCCEEDED(mEarlyRv)) {
-      SetKeyData(aCx, aKeyData);
-      NS_ENSURE_SUCCESS_VOID(mEarlyRv);
-    }
-  }
-
-  void Init(nsIGlobalObject* aGlobal, JSContext* aCx, const nsAString& aFormat,
-            const ObjectOrString& aAlgorithm, bool aExtractable,
-            const Sequence<nsString>& aKeyUsages) {
-    ImportKeyTask::Init(aGlobal, aCx, aFormat, aAlgorithm, aExtractable,
-                        aKeyUsages);
-    if (NS_FAILED(mEarlyRv)) {
-      return;
-    }
-
-    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
-      RootedDictionary<DhImportKeyParams> params(aCx);
-      mEarlyRv = Coerce(aCx, params, aAlgorithm);
-      if (NS_FAILED(mEarlyRv)) {
-        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
-        return;
-      }
-
-      CryptoBuffer prime;
-      ATTEMPT_BUFFER_INIT(mPrime, params.mPrime);
-
-      CryptoBuffer generator;
-      ATTEMPT_BUFFER_INIT(mGenerator, params.mGenerator);
-    }
-  }
-
- private:
-  CryptoBuffer mPrime;
-  CryptoBuffer mGenerator;
-
-  virtual nsresult DoCrypto() override {
-    // Import the key data itself
-    UniqueSECKEYPublicKey pubKey;
-
-    if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW) ||
-        mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
-      // Public key import
-      if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
-        pubKey = CryptoKey::PublicDhKeyFromRaw(mKeyData, mPrime, mGenerator);
-      } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
-        pubKey = CryptoKey::PublicKeyFromSpki(mKeyData);
-      } else {
-        MOZ_ASSERT(false);
-      }
-
-      if (!pubKey) {
-        return NS_ERROR_DOM_DATA_ERR;
-      }
-
-      if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
-        ATTEMPT_BUFFER_ASSIGN(mPrime, &pubKey->u.dh.prime);
-        ATTEMPT_BUFFER_ASSIGN(mGenerator, &pubKey->u.dh.base);
-      }
-
-      if (NS_FAILED(mKey->SetPublicKey(pubKey.get()))) {
-        return NS_ERROR_DOM_OPERATION_ERR;
-      }
-
-      mKey->SetType(CryptoKey::PUBLIC);
-    } else {
-      return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-    }
-
-    return NS_OK;
-  }
-
-  virtual nsresult AfterCrypto() override {
-    // Check permissions for the requested operation
-    if (mKey->HasUsageOtherThan(CryptoKey::DERIVEBITS | CryptoKey::DERIVEKEY)) {
-      return NS_ERROR_DOM_DATA_ERR;
-    }
-
-    if (!mKey->Algorithm().MakeDh(mAlgName, mPrime, mGenerator)) {
-      return NS_ERROR_DOM_OPERATION_ERR;
-    }
-    return NS_OK;
-  }
-};
-
 class ExportKeyTask : public WebCryptoTask {
  public:
   ExportKeyTask(const nsAString& aFormat, CryptoKey& aKey)
       : mFormat(aFormat),
         mSymKey(aKey.GetSymKey()),
         mPrivateKey(aKey.GetPrivateKey()),
         mPublicKey(aKey.GetPublicKey()),
         mKeyType(aKey.GetKeyType()),
@@ -2001,21 +1904,17 @@ class ExportKeyTask : public WebCryptoTa
   nsTArray<nsString> mKeyUsages;
   CryptoBuffer mResult;
   JsonWebKey mJwk;
 
  private:
   virtual nsresult DoCrypto() override {
     if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
       if (mPublicKey && mPublicKey->keyType == dhKey) {
-        nsresult rv = CryptoKey::PublicDhKeyToRaw(mPublicKey.get(), mResult);
-        if (NS_FAILED(rv)) {
-          return NS_ERROR_DOM_OPERATION_ERR;
-        }
-        return NS_OK;
+        return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
 
       if (mPublicKey && mPublicKey->keyType == ecKey) {
         nsresult rv = CryptoKey::PublicECKeyToRaw(mPublicKey.get(), mResult);
         if (NS_FAILED(rv)) {
           return NS_ERROR_DOM_OPERATION_ERR;
         }
         return NS_OK;
@@ -2302,65 +2201,31 @@ GenerateAsymmetricKeyTask::GenerateAsymm
       mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       return;
     }
 
     // Create algorithm.
     mKeyPair->mPublicKey.get()->Algorithm().MakeEc(mAlgName, mNamedCurve);
     mKeyPair->mPrivateKey.get()->Algorithm().MakeEc(mAlgName, mNamedCurve);
     mMechanism = CKM_EC_KEY_PAIR_GEN;
-  } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
-    RootedDictionary<DhKeyGenParams> params(aCx);
-    mEarlyRv = Coerce(aCx, params, aAlgorithm);
-    if (NS_FAILED(mEarlyRv)) {
-      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
-      return;
-    }
-
-    CryptoBuffer prime;
-    ATTEMPT_BUFFER_INIT(prime, params.mPrime);
-
-    CryptoBuffer generator;
-    ATTEMPT_BUFFER_INIT(generator, params.mGenerator);
-
-    // Set up params.
-    if (!prime.ToSECItem(mArena.get(), &mDhParams.prime) ||
-        !generator.ToSECItem(mArena.get(), &mDhParams.base)) {
-      mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
-      return;
-    }
-
-    // Create algorithm.
-    if (!mKeyPair->mPublicKey.get()->Algorithm().MakeDh(mAlgName, prime,
-                                                        generator)) {
-      mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
-      return;
-    }
-    if (!mKeyPair->mPrivateKey.get()->Algorithm().MakeDh(mAlgName, prime,
-                                                         generator)) {
-      mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
-      return;
-    }
-    mMechanism = CKM_DH_PKCS_KEY_PAIR_GEN;
   } else {
     mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     return;
   }
 
   // Set key usages.
   if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
       mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS) ||
       mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
     privateAllowedUsages = CryptoKey::SIGN;
     publicAllowedUsages = CryptoKey::VERIFY;
   } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
     privateAllowedUsages = CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY;
     publicAllowedUsages = CryptoKey::ENCRYPT | CryptoKey::WRAPKEY;
-  } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
-             mAlgName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
+  } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
     privateAllowedUsages = CryptoKey::DERIVEKEY | CryptoKey::DERIVEBITS;
     publicAllowedUsages = 0;
   } else {
     MOZ_ASSERT(false);  // This shouldn't happen.
   }
 
   mKeyPair->mPrivateKey.get()->SetExtractable(aExtractable);
   mKeyPair->mPrivateKey.get()->SetType(CryptoKey::PRIVATE);
@@ -2867,111 +2732,16 @@ class DeriveEcdhBitsTask : public Return
     if (!mResult.SetLength(mLength, fallible)) {
       return NS_ERROR_DOM_UNKNOWN_ERR;
     }
 
     return NS_OK;
   }
 };
 
-class DeriveDhBitsTask : public ReturnArrayBufferViewTask {
- public:
-  DeriveDhBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
-                   CryptoKey& aKey, uint32_t aLength)
-      : mLength(aLength), mPrivKey(aKey.GetPrivateKey()) {
-    Init(aCx, aAlgorithm, aKey);
-  }
-
-  DeriveDhBitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
-                   CryptoKey& aKey, const ObjectOrString& aTargetAlgorithm)
-      : mPrivKey(aKey.GetPrivateKey()) {
-    mEarlyRv = GetKeyLengthForAlgorithm(aCx, aTargetAlgorithm, mLength);
-    if (NS_SUCCEEDED(mEarlyRv)) {
-      Init(aCx, aAlgorithm, aKey);
-    }
-  }
-
-  void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey) {
-    Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_DH);
-    CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_DH);
-
-    // Check that we have a private key.
-    if (!mPrivKey) {
-      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
-      return;
-    }
-
-    mLength = mLength >> 3;  // bits to bytes
-
-    // Retrieve the peer's public key.
-    RootedDictionary<DhKeyDeriveParams> params(aCx);
-    mEarlyRv = Coerce(aCx, params, aAlgorithm);
-    if (NS_FAILED(mEarlyRv)) {
-      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
-      return;
-    }
-
-    CryptoKey* publicKey = params.mPublic;
-    mPubKey = publicKey->GetPublicKey();
-    if (!mPubKey) {
-      mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
-      return;
-    }
-
-    KeyAlgorithmProxy alg1 = publicKey->Algorithm();
-    CHECK_KEY_ALGORITHM(alg1, WEBCRYPTO_ALG_DH);
-
-    // Both keys must use the same prime and generator.
-    KeyAlgorithmProxy alg2 = aKey.Algorithm();
-    if (alg1.mDh.mPrime != alg2.mDh.mPrime ||
-        alg1.mDh.mGenerator != alg2.mDh.mGenerator) {
-      mEarlyRv = NS_ERROR_DOM_DATA_ERR;
-      return;
-    }
-  }
-
- private:
-  size_t mLength;
-  UniqueSECKEYPrivateKey mPrivKey;
-  UniqueSECKEYPublicKey mPubKey;
-
-  virtual nsresult DoCrypto() override {
-    // CKM_SHA512_HMAC and CKA_SIGN are key type and usage attributes of the
-    // derived symmetric key and don't matter because we ignore them anyway.
-    UniquePK11SymKey symKey(
-        PK11_PubDeriveWithKDF(mPrivKey.get(), mPubKey.get(), PR_FALSE, nullptr,
-                              nullptr, CKM_DH_PKCS_DERIVE, CKM_SHA512_HMAC,
-                              CKA_SIGN, 0, CKD_NULL, nullptr, nullptr));
-
-    if (!symKey.get()) {
-      return NS_ERROR_DOM_OPERATION_ERR;
-    }
-
-    nsresult rv = MapSECStatus(PK11_ExtractKeyValue(symKey.get()));
-    if (NS_FAILED(rv)) {
-      return NS_ERROR_DOM_OPERATION_ERR;
-    }
-
-    // This doesn't leak, because the SECItem* returned by PK11_GetKeyData
-    // just refers to a buffer managed by symKey. The assignment copies the
-    // data, so mResult manages one copy, while symKey manages another.
-    ATTEMPT_BUFFER_ASSIGN(mResult, PK11_GetKeyData(symKey.get()));
-
-    if (mLength > mResult.Length()) {
-      return NS_ERROR_DOM_DATA_ERR;
-    }
-
-    if (!mResult.SetLength(mLength, fallible)) {
-      return NS_ERROR_DOM_UNKNOWN_ERR;
-    }
-
-    return NS_OK;
-  }
-};
-
 template <class KeyEncryptTask>
 class WrapKeyTask : public ExportKeyTask {
  public:
   WrapKeyTask(JSContext* aCx, const nsAString& aFormat, CryptoKey& aKey,
               CryptoKey& aWrappingKey, const ObjectOrString& aWrapAlgorithm)
       : ExportKeyTask(aFormat, aKey) {
     if (NS_FAILED(mEarlyRv)) {
       return;
@@ -3172,19 +2942,16 @@ WebCryptoTask* WebCryptoTask::CreateImpo
              algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
              algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
     return new ImportRsaKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm,
                                 aExtractable, aKeyUsages);
   } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
              algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
     return new ImportEcKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm,
                                aExtractable, aKeyUsages);
-  } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
-    return new ImportDhKeyTask(aGlobal, aCx, aFormat, aKeyData, aAlgorithm,
-                               aExtractable, aKeyUsages);
   } else {
     return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   }
 }
 
 WebCryptoTask* WebCryptoTask::CreateExportKeyTask(const nsAString& aFormat,
                                                   CryptoKey& aKey) {
   Telemetry::Accumulate(Telemetry::WEBCRYPTO_METHOD, TM_EXPORTKEY);
@@ -3211,18 +2978,17 @@ WebCryptoTask* WebCryptoTask::CreateExpo
       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_RSA_PSS) ||
       algName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA) ||
-      algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH) ||
-      algName.EqualsLiteral(WEBCRYPTO_ALG_DH)) {
+      algName.EqualsLiteral(WEBCRYPTO_ALG_ECDH)) {
     return new ExportKeyTask(aFormat, aKey);
   }
 
   return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
 
 WebCryptoTask* WebCryptoTask::CreateGenerateKeyTask(
     nsIGlobalObject* aGlobal, JSContext* aCx, const ObjectOrString& aAlgorithm,
@@ -3250,18 +3016,17 @@ WebCryptoTask* WebCryptoTask::CreateGene
       algName.EqualsASCII(WEBCRYPTO_ALG_AES_KW) ||
       algName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
     return new GenerateSymmetricKeyTask(aGlobal, aCx, aAlgorithm, aExtractable,
                                         aKeyUsages);
   } else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
              algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP) ||
              algName.EqualsASCII(WEBCRYPTO_ALG_RSA_PSS) ||
              algName.EqualsASCII(WEBCRYPTO_ALG_ECDH) ||
-             algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA) ||
-             algName.EqualsASCII(WEBCRYPTO_ALG_DH)) {
+             algName.EqualsASCII(WEBCRYPTO_ALG_ECDSA)) {
     return new GenerateAsymmetricKeyTask(aGlobal, aCx, aAlgorithm, aExtractable,
                                          aKeyUsages);
   } else {
     return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   }
 }
 
 WebCryptoTask* WebCryptoTask::CreateDeriveKeyTask(
@@ -3326,20 +3091,16 @@ WebCryptoTask* WebCryptoTask::CreateDeri
   if (algName.EqualsASCII(WEBCRYPTO_ALG_PBKDF2)) {
     return new DerivePbkdfBitsTask(aCx, aAlgorithm, aKey, aLength);
   }
 
   if (algName.EqualsASCII(WEBCRYPTO_ALG_ECDH)) {
     return new DeriveEcdhBitsTask(aCx, aAlgorithm, aKey, aLength);
   }
 
-  if (algName.EqualsASCII(WEBCRYPTO_ALG_DH)) {
-    return new DeriveDhBitsTask(aCx, aAlgorithm, aKey, aLength);
-  }
-
   if (algName.EqualsASCII(WEBCRYPTO_ALG_HKDF)) {
     return new DeriveHkdfBitsTask(aCx, aAlgorithm, aKey, aLength);
   }
 
   return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
 
 WebCryptoTask* WebCryptoTask::CreateWrapKeyTask(
--- a/dom/crypto/test/browser/browser_WebCrypto_telemetry.js
+++ b/dom/crypto/test/browser/browser_WebCrypto_telemetry.js
@@ -27,31 +27,8 @@ add_task(async function ecdh_key() {
     { name: "ECDH", public: x.publicKey },
     x.privateKey,
     128
   );
   is(data.byteLength, 128 / 8, "Should be 16 bytes derived");
 
   TelemetryTestUtils.assertHistogram(hist, 20, 1);
 });
-
-add_task(async function dh_key() {
-  let hist = TelemetryTestUtils.getAndClearHistogram(WEBCRYPTO_ALG_PROBE);
-
-  let alg = {
-    name: "DH",
-    prime: tv.dh.prime,
-    generator: new Uint8Array([0x02]),
-  };
-
-  let x = await crypto.subtle.generateKey(alg, false, [
-    "deriveKey",
-    "deriveBits",
-  ]);
-  let data = await crypto.subtle.deriveBits(
-    { name: "DH", public: x.publicKey },
-    x.privateKey,
-    128
-  );
-  is(data.byteLength, 128 / 8, "Should be 16 bytes derived");
-
-  TelemetryTestUtils.assertHistogram(hist, 24, 1);
-});
--- a/dom/crypto/test/test-vectors.js
+++ b/dom/crypto/test/test-vectors.js
@@ -746,30 +746,51 @@ let tv = {
     iterations: 1,
 
     derived: util.hex2abv(
       "1635fa0f0542cc84f51207ff6cad5284aee3b0264faa55868eca95a7efd2335c"
     ),
   },
 
   broken_pkcs8: {
-    // A DH key with parameters p and g, and a private value.
-    // This currently fails the key import due to the missing public value.
-    // <https://stackoverflow.com/questions/6032675/diffie-hellman-test-vectors>
-    dh: util.hex2abv(
-      "308201340201003082011506072a8648ce3e02013082010802818100da3a8085" +
-        "d372437805de95b88b675122f575df976610c6a844de99f1df82a06848bf7a42" +
-        "f18895c97402e81118e01a00d0855d51922f434c022350861d58ddf60d65bc69" +
-        "41fc6064b147071a4c30426d82fc90d888f94990267c64beef8c304a4b2b26fb" +
-        "93724d6a9472fa16bc50c5b9b8b59afb62cfe9ea3ba042c73a6ade3502818100" +
-        "a51883e9ac0539859df3d25c716437008bb4bd8ec4786eb4bc643299daef5e3e" +
-        "5af5863a6ac40a597b83a27583f6a658d408825105b16d31b6ed088fc623f648" +
-        "fd6d95e9cefcb0745763cddf564c87bcf4ba7928e74fd6a3080481f588d535e4" +
-        "c026b58a21e1e5ec412ff241b436043e29173f1dc6cb943c09742de989547288" +
-        "0416021442c6ee70beb7465928a1efe692d2281b8f7b53d6"
+    // An RSA key that's missing the prime1 value. This currently fails the key
+    // import due that missing value. See this gist for the construction:
+    // <https://gist.github.com/jcjones/79efe5a6fe2aad3145e1d5e6be765893>
+    rsa: util.hex2abv(
+      "30820438020100300d06092a864886f70d0101010500048204223082041e0201000282" +
+        "010100cd5286bf0558a0829d0218ae2912bb1ffb1c0533d42a419076dd777652b6fc61" +
+        "c2deeb0dcb60cbcdce530ebdd0952fef6fb4086575a70318dfa9099284ccb99e0c789c" +
+        "f1f006d371fc2a5644ab5dd3928aaf2b7b046968d3db2b5018c21a56f10f83646f34bc" +
+        "f4bc898e6847d6848e51891f9ff8524aee3e3683a8efe437861db3c0671fa994980774" +
+        "de555ffb70c30bd4341b2c2efe0b5624af52ff371bc11b092309b46fecc428c04e1d10" +
+        "b11c678256c76ef9b3a6aee79b2e795496a31c363454c4fdf239d43b759ac321647a3b" +
+        "4b7c76fe5575183a463cd9ebca2da17a6caac74ac9430ee6fef4cb24ca01d3da7321b1" +
+        "972b97cda536a5e392f64d0cb04902030100010282010036599619928cb7505bc76649" +
+        "13ce45825db2391e53172c6bd54b22884bb4ec71e467a5c8ed011e71c81fec530a97b3" +
+        "2caa60f9a801d0c7dd19b761354bb9f59884ac98bee24eac420c0218fbec70d5c480b9" +
+        "85c4f6920091b3fe6f215ea0224b8553be8e416393552504714e32d6bbe5916ab1a9c5" +
+        "fed7b9d82c59d7c68d7c0e7ed37123e64176aa7d24a52972859b91fee93f25c263f900" +
+        "a1c38764798d0396294c775b65e5563e8d8a6fc519307d14c49bd11a36dcbd05a120d9" +
+        "6e05e47da12051311b4e8b027cce5016b411072927f3846a662b8019cd275430f80646" +
+        "7d531dc595bb4af64136c8aadd9cf3f6c123b0aec69c040a0beb4ee2f023beab915102" +
+        "818100d0e82ca2cd42a550f66b8ebaa6fe0fd51e204a15418a4fc97a8106c4106aee61" +
+        "0b72f794a7e65eea45a44a9e844c36a75436c825349c94c8608b243d54a6835013bd77" +
+        "56f386ea25102398bcbda264f1fea9dc5b415d8d71ee3d4e2c67b0e0c6abc1029bb94b" +
+        "6d70b19cb4cea401dc4a9fdc351463666b8ac43c821672551b9f02818052b9f12d0b99" +
+        "cae194fcb8abc8f21cab920453aded0789ec4f92bdb2b1c0c073d6cb29c089c9ac000a" +
+        "afe2df7633741acea7ff216b4aa5f0c299ede0f713a0bd07a5a1001e730013efdc81c9" +
+        "984d8aba957c5c175a7dff3b17c6e0725604f4c91bd867544f20c2b5f6dd39280a9800" +
+        "4308ef55f20be709e5ebeab4c0dc879fc90281800fa02e26873fe2e9a964e62a23ef80" +
+        "f3a9eb345f5ea59fce2c319675f7dc67b42e8d0ce3bba3499a305757957fc3cb9abc7b" +
+        "d480a3ecca5c2a8c7dcb70977bdef37b0a80207b08ec78c690d81d3f1659db788d18ee" +
+        "4cb715bc822d64b8e4cc0b503181a67037aa19f1cf0cdf1ff95ba6e14a31563311281e" +
+        "1b0b83977639d3750281807759c93656b00d794f68388928309c380b0cfd075baf76c2" +
+        "e37b5bc55409027ed02eb1bb3a2cb12d4fc43a84fdadd5b80216b88545d71559caa3a0" +
+        "1267a3cd07c58230ee477d69a71053a6b6a81e5083f7f0cbc28c3d1eae8a3ceeaf8a75" +
+        "651d0f52db8c79cff223edf4b1d412071b1bedf0d9b05348f39e0b2a89c692886ef3"
     ),
   },
 
   // KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_init.fax [EC]
   // <http://csrc.nist.gov/groups/STM/cavp/documents/keymgmt/kastestvectors.zip>
   ecdh_p256: {
     jwk_pub: {
       kty: "EC",
@@ -989,23 +1010,16 @@ let tv = {
   // RFC 2409 <http://tools.ietf.org/html/rfc2409#section-6.2>
   dh: {
     prime: util.hex2abv(
       "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74" +
         "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437" +
         "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed" +
         "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff"
     ),
-
-    prime2: util.hex2abv(
-      "8b79f180cbd3f282de92e8b8f2d092674ffda61f01ed961f8ef04a1b7a3709ff" +
-        "748c2abf6226cf0c4538e48838193da456e92ee530ef7aa703e741585e475b26" +
-        "cd64fa97819181cef27de2449cd385c49c9b030f89873b5b7eaf063a788f00db" +
-        "3cb670c73846bc4f76af062d672bde8f29806b81548411ab48b99aebfd9c2d09"
-    ),
   },
 
   // KASValidityTest_FFCStatic_NOKC_ZZOnly_resp.fax [FA]
   // <http://csrc.nist.gov/groups/STM/cavp/documents/keymgmt/kastestvectors.zip>
   dh_nist: {
     prime: util.hex2abv(
       "8b79f180cbd3f282de92e8b8f2d092674ffda61f01ed961f8ef04a1b7a3709ff" +
         "748c2abf6226cf0c4538e48838193da456e92ee530ef7aa703e741585e475b26" +
--- a/dom/crypto/test/test_WebCrypto.html
+++ b/dom/crypto/test/test_WebCrypto.html
@@ -1025,20 +1025,19 @@ TestArray.addTest(
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "Ensure that importing an invalid key doesn't crash",
   function() {
     var that = this;
-    // TODO Change the algorithm to "DH" once we support it.
     var alg = {name: "RSA-OAEP", hash: "SHA-1"};
 
-    crypto.subtle.importKey("pkcs8", tv.broken_pkcs8.dh, alg, false, ["decrypt"])
+    crypto.subtle.importKey("pkcs8", tv.broken_pkcs8.rsa, alg, false, ["decrypt"])
       .then(error(that), complete(that));
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "Test that we check keys before using them for encryption/signatures",
   function() {
--- a/dom/crypto/test/test_WebCrypto_DH.html
+++ b/dom/crypto/test/test_WebCrypto_DH.html
@@ -16,234 +16,56 @@
 <!-- Test vectors drawn from the literature -->
 <script src="./test-vectors.js"></script>
 
 <!-- General testing framework -->
 <script src="./test-array.js"></script>
 
 <script>/* <![CDATA[*/
 "use strict";
+// DH is not permitted, so ensure all entry point methods error
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "Generate a DH key",
   function() {
     var that = this;
     var alg = {
       name: "DH",
       prime: tv.dh.prime,
       generator: new Uint8Array([0x02]),
     };
-    crypto.subtle.generateKey(alg, false, ["deriveKey", "deriveBits"]).then(
-      complete(that, function(x) {
-        return exists(x.publicKey) &&
-               (x.publicKey.algorithm.name == alg.name) &&
-               util.memcmp(x.publicKey.algorithm.prime, alg.prime) &&
-               util.memcmp(x.publicKey.algorithm.generator, alg.generator) &&
-               (x.publicKey.type == "public") &&
-               x.publicKey.extractable &&
-               (x.publicKey.usages.length == 0) &&
-               exists(x.privateKey) &&
-               (x.privateKey.algorithm.name == alg.name) &&
-               util.memcmp(x.privateKey.algorithm.prime, alg.prime) &&
-               util.memcmp(x.privateKey.algorithm.generator, alg.generator) &&
-               (x.privateKey.type == "private") &&
-               !x.privateKey.extractable &&
-               (x.privateKey.usages.length == 2) &&
-               (x.privateKey.usages[0] == "deriveKey") &&
-               (x.privateKey.usages[1] == "deriveBits");
-      }),
-      error(that)
-    );
-  }
-);
-
-// -----------------------------------------------------------------------------
-TestArray.addTest(
-  "Derive bits from a DH key",
-  function() {
-    var that = this;
-    var alg = {
-      name: "DH",
-      prime: tv.dh.prime,
-      generator: new Uint8Array([0x02]),
-    };
-
-    function doDerive(x) {
-      return crypto.subtle.deriveBits({ name: "DH", public: x.publicKey }, x.privateKey, 128);
-    }
-
-    crypto.subtle.generateKey(alg, false, ["deriveBits"])
-      .then(doDerive, error(that))
-      .then(complete(that, function(x) {
-        return x.byteLength == 16;
-      }), error(that));
-  }
-);
-
-// -----------------------------------------------------------------------------
-TestArray.addTest(
-  "Test that DH deriveBits() fails when the public key is not a DH key",
-  function() {
-    var that = this;
-    var pubKey, privKey;
-    function setPub(x) { pubKey = x.publicKey; }
-    function setPriv(x) { privKey = x.privateKey; }
-
-    function doGenerateDH() {
-      var alg = {
-        name: "DH",
-        prime: tv.dh.prime,
-        generator: new Uint8Array([0x02]),
-      };
-      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
-    }
-
-    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"]);
-    }
-
-    function doDerive() {
-      var alg = {name: "DH", public: pubKey};
-      return crypto.subtle.deriveBits(alg, privKey, 128);
-    }
-
-    doGenerateDH()
-      .then(setPriv, error(that))
-      .then(doGenerateRSA, error(that))
-      .then(setPub, error(that))
-      .then(doDerive, error(that))
-      .then(error(that), complete(that));
-  }
-);
-
-// -----------------------------------------------------------------------------
-TestArray.addTest(
-  "Test that DH deriveBits() fails when the given keys' primes or bases don't match",
-  function() {
-    var that = this;
-    var pubKey, privKey;
-    function setPub(x) { pubKey = x.publicKey; }
-    function setPriv(x) { privKey = x.privateKey; }
-
-    function doGenerateDH() {
-      var alg = {
-        name: "DH",
-        prime: tv.dh.prime,
-        generator: new Uint8Array([0x02]),
-      };
-      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
-    }
-
-    function doGenerateDH2() {
-      var alg = {
-        name: "DH",
-        prime: tv.dh.prime2,
-        generator: new Uint8Array([0x02]),
-      };
-      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
-    }
-
-    function doGenerateDH3() {
-      var alg = {
-        name: "DH",
-        prime: tv.dh.prime,
-        generator: new Uint8Array([0x03]),
-      };
-      return crypto.subtle.generateKey(alg, false, ["deriveBits"]);
-    }
-
-    function doDerive() {
-      var alg = {name: "DH", public: pubKey};
-      return crypto.subtle.deriveBits(alg, privKey, 128);
-    }
-
-    doGenerateDH()
-      .then(setPriv, error(that))
-      .then(doGenerateDH2, error(that))
-      .then(setPub, error(that))
-      .then(doDerive, error(that))
-      .then(error(that), doGenerateDH3)
-      .then(setPub, error(that))
-      .then(doDerive, error(that))
+    crypto.subtle.generateKey(alg, false, ["deriveKey", "deriveBits"])
       .then(error(that), complete(that));
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "Raw import/export of a public DH key",
   function() {
     var that = this;
     var alg = {
       name: "DH",
       prime: tv.dh_nist.prime,
       generator: tv.dh_nist.gen,
     };
 
-    function doExport(x) {
-      return crypto.subtle.exportKey("raw", x);
-    }
-
     crypto.subtle.importKey("raw", tv.dh_nist.raw, alg, true, ["deriveBits"])
-      .then(doExport)
-      .then(memcmp_complete(that, tv.dh_nist.raw), error(that));
-  }
-);
-
-// -----------------------------------------------------------------------------
-TestArray.addTest(
-  "Derive bits from an imported public and a generated private DH key",
-  function() {
-    var that = this;
-    var alg = {
-      name: "DH",
-      prime: tv.dh_nist.prime,
-      generator: tv.dh_nist.gen,
-    };
-
-    var privKey;
-    function setPriv(x) { privKey = x.privateKey; }
-
-    function doImport() {
-      return crypto.subtle.importKey("raw", tv.dh_nist.raw, alg, true, ["deriveBits"]);
-    }
-
-    function doDerive(pubKey) {
-      return crypto.subtle.deriveBits({name: "DH", public: pubKey}, privKey, 128);
-    }
-
-    crypto.subtle.generateKey(alg, false, ["deriveBits"])
-      .then(setPriv, error(that))
-      .then(doImport, error(that))
-      .then(doDerive, error(that))
-      .then(complete(that, function(x) {
-        return x.byteLength == 16;
-      }), error(that));
+      .then(error(that), complete(that));
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
   "SPKI import/export of a public DH key",
   function() {
     var that = this;
 
-    function doExport(x) {
-      return crypto.subtle.exportKey("spki", x);
-    }
-
     crypto.subtle.importKey("spki", tv.dh_nist.spki, "DH", true, ["deriveBits"])
-      .then(doExport, error(that))
-      .then(memcmp_complete(that, tv.dh_nist.spki), error(that));
+      .then(error(that), complete(that));
   }
 );
 /* ]]>*/</script>
 </head>
 
 <body>
 
 <div id="content">
--- a/dom/webidl/SubtleCrypto.webidl
+++ b/dom/webidl/SubtleCrypto.webidl
@@ -75,22 +75,16 @@ dictionary RsaOaepParams : Algorithm {
 };
 
 [GenerateInit]
 dictionary RsaPssParams : Algorithm {
   required [EnforceRange] unsigned long saltLength;
 };
 
 [GenerateInit]
-dictionary DhKeyGenParams : Algorithm {
-  required BigInteger prime;
-  required BigInteger generator;
-};
-
-[GenerateInit]
 dictionary EcKeyGenParams : Algorithm {
   required NamedCurve namedCurve;
 };
 
 [GenerateInit]
 dictionary AesDerivedKeyParams : Algorithm {
   required [EnforceRange] unsigned long length;
 };
@@ -101,21 +95,16 @@ dictionary HmacDerivedKeyParams : HmacIm
 };
 
 [GenerateInit]
 dictionary EcdhKeyDeriveParams : Algorithm {
   required CryptoKey public;
 };
 
 [GenerateInit]
-dictionary DhKeyDeriveParams : Algorithm {
-  required CryptoKey public;
-};
-
-[GenerateInit]
 dictionary DhImportKeyParams : Algorithm {
   required BigInteger prime;
   required BigInteger generator;
 };
 
 [GenerateInit]
 dictionary EcdsaParams : Algorithm {
   required AlgorithmIdentifier hash;