WebCryptoAPI: test secret/private importKey empty usages rejections (#39868)

diff --git a/WebCryptoAPI/generateKey/failures.js b/WebCryptoAPI/generateKey/failures.js
index c39e4d2..e0f0279 100644
--- a/WebCryptoAPI/generateKey/failures.js
+++ b/WebCryptoAPI/generateKey/failures.js
@@ -204,7 +204,7 @@
     });
 
 
-    // The last thing that should be checked is an empty usages (for secret keys).
+    // The last thing that should be checked is empty usages (disallowed for secret and private keys).
     testVectors.forEach(function(vector) {
         var name = vector.name;
 
diff --git a/WebCryptoAPI/import_export/ec_importKey.https.any.js b/WebCryptoAPI/import_export/ec_importKey.https.any.js
index c70583b..25defa3 100644
--- a/WebCryptoAPI/import_export/ec_importKey.https.any.js
+++ b/WebCryptoAPI/import_export/ec_importKey.https.any.js
@@ -85,13 +85,13 @@
                 });
 
                 // Next, test private keys
-                allValidUsages(vector.privateUsages, []).forEach(function(usages) {
-                    ['pkcs8', 'jwk'].forEach(function(format) {
-                        var algorithm = {name: vector.name, namedCurve: curve};
-                        var data = keyData[curve];
-
+                ['pkcs8', 'jwk'].forEach(function(format) {
+                    var algorithm = {name: vector.name, namedCurve: curve};
+                    var data = keyData[curve];
+                    allValidUsages(vector.privateUsages, []).forEach(function(usages) {
                         testFormat(format, algorithm, data, curve, usages, extractable);
                     });
+                    testEmptyUsages(format, algorithm, data, curve, extractable);
                 });
             });
 
@@ -136,6 +136,21 @@
         }, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, compressed, keyData, algorithm, extractable, usages));
     }
 
+    // Test importKey with a given key format and other parameters but with empty usages.
+    // Should fail with SyntaxError
+    function testEmptyUsages(format, algorithm, data, keySize, extractable) {
+        const keyData = data[format];
+        const usages = [];
+        promise_test(function(test) {
+            return subtle.importKey(format, keyData, algorithm, extractable, usages).
+            then(function(key) {
+                assert_unreached("importKey succeeded but should have failed with SyntaxError");
+            }, function(err) {
+                assert_equals(err.name, "SyntaxError", "Should throw correct error, not " + err.name + ": " + err.message);
+            });
+        }, "Empty Usages: " + keySize.toString() + " bits " + parameterString(format, false, keyData, algorithm, extractable, usages));
+    }
+
 
 
     // Helper methods follow:
diff --git a/WebCryptoAPI/import_export/okp_importKey_failures.js b/WebCryptoAPI/import_export/okp_importKey_failures.js
index a5cc08a..ebdb736 100644
--- a/WebCryptoAPI/import_export/okp_importKey_failures.js
+++ b/WebCryptoAPI/import_export/okp_importKey_failures.js
@@ -132,6 +132,19 @@
         });
     });
 
+    // Algorithms normalize okay, but usages bad (empty).
+    // Should fail due to SyntaxError
+    testVectors.forEach(function(vector) {
+        var name = vector.name;
+        validKeyData.filter((test) => test.format === 'pkcs8' || (test.format === 'jwk' && test.data.d)).forEach(function(test) {
+            allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
+                [true, false].forEach(function(extractable) {
+                    testError(test.format, algorithm, test.data, name, [/* Empty usages */], extractable, "SyntaxError", "Empty usages");
+                });
+            });
+        });
+    });
+
     // Algorithms normalize okay, usages ok. The length of the key must thouw a DataError exception.
     testVectors.forEach(function(vector) {
         var name = vector.name;
diff --git a/WebCryptoAPI/import_export/rsa_importKey.https.any.js b/WebCryptoAPI/import_export/rsa_importKey.https.any.js
index 41d25da..5582b2f 100644
--- a/WebCryptoAPI/import_export/rsa_importKey.https.any.js
+++ b/WebCryptoAPI/import_export/rsa_importKey.https.any.js
@@ -92,13 +92,13 @@
                     });
 
                     // Next, test private keys
-                    allValidUsages(vector.privateUsages, []).forEach(function(usages) {
-                        ['pkcs8', 'jwk'].forEach(function(format) {
-                            var algorithm = {name: vector.name, hash: hash};
-                            var data = keyData[size];
-
+                    ['pkcs8', 'jwk'].forEach(function(format) {
+                        var algorithm = {name: vector.name, hash: hash};
+                        var data = keyData[size];
+                        allValidUsages(vector.privateUsages, []).forEach(function(usages) {
                             testFormat(format, algorithm, data, size, usages, extractable);
                         });
+                        testEmptyUsages(format, algorithm, data, size, extractable);
                     });
                 });
             });
@@ -135,6 +135,20 @@
         }, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, keyData[format], algorithm, extractable, usages));
     }
 
+    // Test importKey with a given key format and other parameters but with empty usages.
+    // Should fail with SyntaxError
+    function testEmptyUsages(format, algorithm, keyData, keySize, extractable) {
+        const usages = [];
+        promise_test(function(test) {
+            return subtle.importKey(format, keyData[format], algorithm, extractable, usages).
+            then(function(key) {
+                assert_unreached("importKey succeeded but should have failed with SyntaxError");
+            }, function(err) {
+                assert_equals(err.name, "SyntaxError", "Should throw correct error, not " + err.name + ": " + err.message);
+            });
+        }, "Empty Usages: " + keySize.toString() + " bits " + parameterString(format, keyData, algorithm, extractable, usages));
+    }
+
 
 
     // Helper methods follow:
diff --git a/WebCryptoAPI/import_export/symmetric_importKey.https.any.js b/WebCryptoAPI/import_export/symmetric_importKey.https.any.js
index 404b66a..a9ce9be 100644
--- a/WebCryptoAPI/import_export/symmetric_importKey.https.any.js
+++ b/WebCryptoAPI/import_export/symmetric_importKey.https.any.js
@@ -41,17 +41,18 @@
         }
 
         rawKeyData.forEach(function(keyData) {
-            // Generate all combinations of valid usages for testing
-            allValidUsages(vector.legalUsages, []).forEach(function(usages) {
-                // Try each legal value of the extractable parameter
-                vector.extractable.forEach(function(extractable) {
-                    vector.formats.forEach(function(format) {
-                        var data = keyData;
-                        if (format === "jwk") {
-                            data = jwkData(keyData, algorithm);
-                        }
+            // Try each legal value of the extractable parameter
+            vector.extractable.forEach(function(extractable) {
+                vector.formats.forEach(function(format) {
+                    var data = keyData;
+                    if (format === "jwk") {
+                        data = jwkData(keyData, algorithm);
+                    }
+                    // Generate all combinations of valid usages for testing
+                    allValidUsages(vector.legalUsages, []).forEach(function(usages) {
                         testFormat(format, algorithm, data, keyData.length * 8, usages, extractable);
                     });
+                    testEmptyUsages(format, algorithm, data, keyData.length * 8, extractable);
                 });
             });
 
@@ -90,6 +91,20 @@
         }, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, keyData, algorithm, extractable, usages));
     }
 
+    // Test importKey with a given key format and other parameters but with empty usages.
+    // Should fail with SyntaxError
+    function testEmptyUsages(format, algorithm, keyData, keySize, extractable) {
+        const usages = [];
+        promise_test(function(test) {
+            return subtle.importKey(format, keyData, algorithm, extractable, usages).
+            then(function(key) {
+                assert_unreached("importKey succeeded but should have failed with SyntaxError");
+            }, function(err) {
+                assert_equals(err.name, "SyntaxError", "Should throw correct error, not " + err.name + ": " + err.message);
+            });
+        }, "Empty Usages: " + keySize.toString() + " bits " + parameterString(format, keyData, algorithm, extractable, usages));
+    }
+
 
 
     // Helper methods follow: