Bug 1241757 - Permit export of JWK with empty key_ops field, r?rbarnes draft
authorMartin Thomson <martin.thomson@gmail.com>
Fri, 22 Jan 2016 18:07:39 +1100
changeset 324263 8f8bead9ae47631a20a8d7b0ed521ec3b545efc0
parent 324262 cb5a01dc56fb199aed6ff627d17ced5bc25342ce
child 513346 b6658c25afccc4425c01c7956e015d2f5e760116
push id9868
push usermartin.thomson@gmail.com
push dateFri, 22 Jan 2016 07:08:05 +0000
reviewersrbarnes
bugs1241757
milestone46.0a1
Bug 1241757 - Permit export of JWK with empty key_ops field, r?rbarnes
dom/crypto/WebCryptoTask.cpp
dom/crypto/test/test_WebCrypto_JWK.html
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -2090,21 +2090,19 @@ private:
       }
 
       if (!mAlg.IsEmpty()) {
         mJwk.mAlg.Construct(mAlg);
       }
 
       mJwk.mExt.Construct(mExtractable);
 
-      if (!mKeyUsages.IsEmpty()) {
-        mJwk.mKey_ops.Construct();
-        if (!mJwk.mKey_ops.Value().AppendElements(mKeyUsages, fallible)) {
-          return NS_ERROR_OUT_OF_MEMORY;
-        }
+      mJwk.mKey_ops.Construct();
+      if (!mJwk.mKey_ops.Value().AppendElements(mKeyUsages, fallible)) {
+        return NS_ERROR_OUT_OF_MEMORY;
       }
 
       return NS_OK;
     }
 
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
--- a/dom/crypto/test/test_WebCrypto_JWK.html
+++ b/dom/crypto/test/test_WebCrypto_JWK.html
@@ -245,16 +245,68 @@ TestArray.addTest(
                  shallowArrayEquals(x.key_ops, ['verify']) &&
                  x.n  == jwk.n  &&
                  x.e  == jwk.e;
           }),
         error(that)
       );
   }
 );
+
+// --------
+TestArray.addTest(
+  "Check JWK parameters on generated ECDSA key pair",
+  function() {
+    crypto.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, ['sign', 'verify'])
+      .then(pair => Promise.all([
+         crypto.subtle.exportKey('jwk', pair.privateKey),
+         crypto.subtle.exportKey('jwk', pair.publicKey)
+      ]))
+      .then(
+        complete(this, function(x) {
+          var priv = x[0];
+          var pub = x[1];
+          var pubIsSubsetOfPriv = Object.keys(pub)
+            .filter(k => k !== 'key_ops') // key_ops is the only complex attr
+            .reduce((all, k) => all && pub[k] === priv[k], true);
+          // Can't use hasBaseJwkFields() because EC keys don't get "alg":
+          // "alg" matches curve to hash, but WebCrypto keys are more flexible.
+          return hasFields(pub, ['kty', 'crv', 'key_ops', 'ext']) &&
+            pub.kty === 'EC' &&
+            pub.crv === 'P-256' &&
+            pub.ext &&
+            typeof(pub.x) === 'string' &&
+            typeof(pub.y) === 'string' &&
+            shallowArrayEquals(pub.key_ops, ['verify']) &&
+            pubIsSubsetOfPriv &&
+            shallowArrayEquals(priv.key_ops, ['sign']) &&
+            typeof(priv.d) === 'string';
+        }),
+        error(this));
+  }
+);
+
+// --------
+TestArray.addTest(
+  "Check key_ops parameter on an unusable RSA public key",
+  function() {
+    var parameters = {
+      name: 'RSASSA-PKCS1-v1_5',
+      modulusLength: 1024,
+      publicExponent: new Uint8Array([1, 0, 1]),
+      hash: 'SHA-256'
+    };
+    // The public key generated here will have no usages and will therefore
+    // have an empty key_ops list.
+    crypto.subtle.generateKey(parameters, true, ['sign'])
+      .then(pair => crypto.subtle.exportKey('jwk', pair.publicKey))
+      .then(complete(this, x => x.key_ops.length === 0),
+            error(this));
+  }
+);
 /*]]>*/</script>
 </head>
 
 <body>
 
 <div id="content">
 	<div id="head">
 		<b>Web</b>Crypto<br>