bug 1271350 - work around PK11_CreatePBEV2AlgorithmID generating a random salt when it shouldn't r=ttaubert
authorDavid Keeler <dkeeler@mozilla.com>
Thu, 12 May 2016 11:12:57 -0700
changeset 297398 f9e0ca40cb9691f55554ec992817bcfc7defb410
parent 297397 2954496a65104993f18aebd6a19235e0c94f7816
child 297399 a13f0e8cfa3fd03cf2f0934d8886a6a99faf2811
push id76716
push userdkeeler@mozilla.com
push dateFri, 13 May 2016 19:25:27 +0000
treeherdermozilla-inbound@f9e0ca40cb96 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersttaubert
bugs1271350
milestone49.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 1271350 - work around PK11_CreatePBEV2AlgorithmID generating a random salt when it shouldn't r=ttaubert MozReview-Commit-ID: KHjiwPg2SBb
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>