bug 1271350 - Work around PK11_CreatePBEV2AlgorithmID generating a random salt when it shouldn't r=ttaubert a=sylvestre
authorDavid Keeler <dkeeler@mozilla.com>
Thu, 12 May 2016 11:12:57 -0700
changeset 333196 76d7c6af162c72bbc0b8fb4be01159408b9f2ff4
parent 333195 8b7e3ca6ddb7c3d7ad1dfd8b61ab18189e6ca1f3
child 333197 bf4d710c80531aa2c170f076716513e69206b05d
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersttaubert, sylvestre
bugs1271350
milestone48.0a2
bug 1271350 - Work around PK11_CreatePBEV2AlgorithmID generating a random salt when it shouldn't r=ttaubert a=sylvestre
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
@@ -2779,16 +2779,28 @@ private:
   {
     ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
     if (!arena) {
       return NS_ERROR_DOM_OPERATION_ERR;
     }
 
     SECItem salt = { siBuffer, nullptr, 0 };
     ATTEMPT_BUFFER_TO_SECITEM(arena, &salt, mSalt);
+    // PK11_CreatePBEV2AlgorithmID will "helpfully" create PBKDF2 parameters
+    // with a random salt if given a SECItem* that is either null or has a null
+    // data pointer. This obviously isn't what we want, so we have to fake it
+    // out by passing in a SECItem* with a non-null data pointer but with zero
+    // length.
+    if (!salt.data) {
+      MOZ_ASSERT(salt.len == 0);
+      salt.data = reinterpret_cast<unsigned char*>(PORT_ArenaAlloc(arena, 1));
+      if (!salt.data) {
+        return NS_ERROR_DOM_UNKNOWN_ERR;
+      }
+    }
 
     // Always pass in cipherAlg=SEC_OID_HMAC_SHA1 (i.e. PBMAC1) as this
     // parameter is unused for key generation. It is currently only used
     // for PBKDF2 authentication or key (un)wrapping when specifying an
     // encryption algorithm (PBES2).
     ScopedSECAlgorithmID alg_id(PK11_CreatePBEV2AlgorithmID(
       SEC_OID_PKCS5_PBKDF2, SEC_OID_HMAC_SHA1, mHashOidTag,
       mLength, mIterations, &salt));
--- a/dom/crypto/test/test-vectors.js
+++ b/dom/crypto/test/test-vectors.js
@@ -644,16 +644,26 @@ tv = {
     length: 40 * 8,
 
     derived: util.hex2abv(
       "348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1" +
       "c635518c7dac47e9"
     )
   },
 
+  pbkdf2_sha256_no_salt: {
+    password: util.hex2abv(
+      "9c13a23bc58a52be8bb4fa1a2cbdff01747265736f7269745f64625f7265636f72645f6964"),
+    length: 32 * 8,
+    iterations: 1,
+
+    derived: util.hex2abv(
+      "ef29dd382fa66a83a95be7ccfb71f1ccfee494977855a4c260d90c2f8c91e062")
+  },
+
   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
@@ -227,16 +227,45 @@ TestArray.addTest(
     }
     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.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)) {
+        throw "Invalid key; missing field(s)";
+      }
+
+      var deriveAlg = {
+        name: "PBKDF2",
+        hash: "SHA-256",
+        salt: new Uint8Array(0),
+        iterations: tv.pbkdf2_sha256_no_salt.iterations
+      };
+      return crypto.subtle.deriveBits(deriveAlg, x, tv.pbkdf2_sha256_no_salt.length);
+    }
+    function fail(x) { console.log("failing"); error(that)(x); }
+
+    crypto.subtle.importKey("raw", key, importAlg, false, ["deriveBits"])
+      .then( doDerive, fail )
+      .then( memcmp_complete(that, tv.pbkdf2_sha256_no_salt.derived), fail );
+  }
+);
 /*]]>*/</script>
 </head>
 
 <body>
 
 <div id="content">
 	<div id="head">
 		<b>Web</b>Crypto<br>