Bug 1500292 p1 - Remove 0-length key checks in ImportSymmetricKeyTask and DerivePbkdfBitsTask. r=jcj
authorEdouard Oger <eoger@fastmail.com>
Tue, 23 Oct 2018 15:43:44 +0000
changeset 490947 4ecb7bf0e6f26af47f48454b7d193c9763e623e4
parent 490946 72cca5ce21f435e245a20dc518f1ffb6f72c748c
child 490948 e9bf22cdf91a5de5cf8ebafe7f43bac7646d6878
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjcj
bugs1500292
milestone65.0a1
Bug 1500292 p1 - Remove 0-length key checks in ImportSymmetricKeyTask and DerivePbkdfBitsTask. r=jcj Differential Revision: https://phabricator.services.mozilla.com/D9285
dom/crypto/WebCryptoTask.cpp
dom/crypto/test/test-vectors.js
dom/crypto/test/test_WebCrypto_PBKDF2.html
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -152,17 +152,17 @@ GetAlgorithmName(JSContext* aCx, const O
     if (!alg.Init(aCx, value)) {
       return NS_ERROR_DOM_SYNTAX_ERR;
     }
 
     aName = alg.mName;
   }
 
   if (!NormalizeToken(aName, aName)) {
-    return NS_ERROR_DOM_SYNTAX_ERR;
+    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 
   return NS_OK;
 }
 
 template<class T, class OOS>
 static nsresult
 Coerce(JSContext* aCx, T& aTarget, const OOS& aAlgorithm)
@@ -1563,19 +1563,18 @@ public:
       }
 
       // Import the key material
       rv = mKeyData.FromJwkBase64(mJwk.mK.Value());
       if (NS_FAILED(rv)) {
         return NS_ERROR_DOM_DATA_ERR;
       }
     }
-
     // Check that we have valid key data.
-    if (mKeyData.Length() == 0) {
+    if (mKeyData.Length() == 0 && !mAlgName.EqualsLiteral(WEBCRYPTO_ALG_PBKDF2)) {
       return NS_ERROR_DOM_DATA_ERR;
     }
 
     // Construct an appropriate KeyAlorithm,
     // and verify that usages are appropriate
     uint32_t length = 8 * mKeyData.Length(); // bytes to bits
     if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
         mAlgName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
@@ -2216,17 +2215,16 @@ public:
     mKey = new CryptoKey(aGlobal);
     mKey->SetExtractable(aExtractable);
     mKey->SetType(CryptoKey::SECRET);
 
     // 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
     uint32_t allowedUsages = 0;
     if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
         algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
         algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM) ||
@@ -2245,17 +2243,16 @@ public:
       if (NS_FAILED(mEarlyRv)) {
         mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
         return;
       }
 
       nsString 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);
       }
@@ -2346,17 +2343,16 @@ GenerateAsymmetricKeyTask::GenerateAsymm
 
   // Create an empty key pair and set easy attributes
   mKeyPair->mPrivateKey = new CryptoKey(aGlobal);
   mKeyPair->mPublicKey = new CryptoKey(aGlobal);
 
   // Extract algorithm name
   mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, mAlgName);
   if (NS_FAILED(mEarlyRv)) {
-    mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
     return;
   }
 
   // Construct an appropriate KeyAlorithm
   uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0;
   if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
       mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP) ||
       mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_PSS)) {
@@ -2369,17 +2365,16 @@ GenerateAsymmetricKeyTask::GenerateAsymm
 
     // Pull relevant info
     uint32_t modulusLength = params.mModulusLength;
     CryptoBuffer publicExponent;
     ATTEMPT_BUFFER_INIT(publicExponent, params.mPublicExponent);
     nsString hashName;
     mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName);
     if (NS_FAILED(mEarlyRv)) {
-      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
       return;
     }
 
     // Create algorithm
     if (!mKeyPair->mPublicKey.get()->Algorithm().MakeRsa(mAlgName,
                                                          modulusLength,
                                                          publicExponent,
                                                          hashName)) {
@@ -2752,32 +2747,26 @@ public:
   }
 
   void Init(JSContext* aCx, const ObjectOrString& aAlgorithm, CryptoKey& aKey,
             uint32_t aLength)
   {
     Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_PBKDF2);
     CHECK_KEY_ALGORITHM(aKey.Algorithm(), WEBCRYPTO_ALG_PBKDF2);
 
-    // 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)) {
       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;
+      mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
       return;
     }
 
     // Extract the hash algorithm.
     nsString hashName;
     mEarlyRv = GetAlgorithmName(aCx, params.mHash, hashName);
     if (NS_FAILED(mEarlyRv)) {
       return;
--- a/dom/crypto/test/test-vectors.js
+++ b/dom/crypto/test/test-vectors.js
@@ -654,16 +654,26 @@ tv = {
       "9c13a23bc58a52be8bb4fa1a2cbdff01747265736f7269745f64625f7265636f72645f6964"),
     length: 32 * 8,
     iterations: 1,
 
     derived: util.hex2abv(
       "ef29dd382fa66a83a95be7ccfb71f1ccfee494977855a4c260d90c2f8c91e062")
   },
 
+  pbkdf2_sha256_no_pwd: {
+    password: new Uint8Array(),
+    salt: new TextEncoder("utf-8").encode("saltSALTsaltSALTsaltSALTsaltSALTsalt"),
+    length: 32 * 8,
+    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" +
--- a/dom/crypto/test/test_WebCrypto_PBKDF2.html
+++ b/dom/crypto/test/test_WebCrypto_PBKDF2.html
@@ -230,16 +230,45 @@ TestArray.addTest(
     crypto.subtle.importKey("raw", key, alg, false, ["deriveBits"])
       .then( doDerive, fail )
       .then( memcmp_complete(that, tv.pbkdf2_sha256.derived), fail );
   }
 );
 
 // -----------------------------------------------------------------------------
 TestArray.addTest(
+  "Import raw PBKDF2 zero-length key and derive bits using HMAC-SHA-256",
+  function() {
+    var that = this;
+    var alg = "PBKDF2";
+    var key = tv.pbkdf2_sha256_no_pwd.password;
+
+    function doDerive(x) {
+      if (!hasKeyFields(x)) {
+        throw "Invalid key; missing field(s)";
+      }
+
+      var alg = {
+        name: "PBKDF2",
+        hash: "SHA-256",
+        salt: tv.pbkdf2_sha256_no_pwd.salt,
+        iterations: tv.pbkdf2_sha256_no_pwd.iterations
+      };
+      return crypto.subtle.deriveBits(alg, x, tv.pbkdf2_sha256_no_pwd.length);
+    }
+    function fail(x) { console.log("failing"); error(that)(x); }
+
+    crypto.subtle.importKey("raw", key, alg, false, ["deriveBits"])
+      .then( doDerive, fail )
+      .then( memcmp_complete(that, tv.pbkdf2_sha256_no_pwd.derived), fail );
+  }
+);
+
+// -----------------------------------------------------------------------------
+TestArray.addTest(
   "Import raw PBKDF2 key and derive bits using HMAC-SHA-256 with zero-length salt",
   function() {
     var that = this;
     var importAlg = { name: "PBKDF2", hash: "SHA-256" };
     var key = tv.pbkdf2_sha256_no_salt.password;
 
     function doDerive(x) {
       if (!hasKeyFields(x)) {