cfrg_curves_bits.js (13119B)
1 function define_tests_25519() { 2 return define_tests("X25519"); 3 } 4 5 function define_tests_448() { 6 return define_tests("X448"); 7 } 8 9 function define_tests(algorithmName) { 10 // May want to test prefixed implementations. 11 var subtle = self.crypto.subtle; 12 13 // Verify the derive functions perform checks against the all-zero value results, 14 // ensuring small-order points are rejected. 15 // https://www.rfc-editor.org/rfc/rfc7748#section-6.1 16 { 17 kSmallOrderPoint[algorithmName].forEach(function(test) { 18 promise_test(async() => { 19 let derived; 20 let privateKey; 21 let publicKey; 22 try { 23 privateKey = await subtle.importKey("pkcs8", pkcs8[algorithmName], 24 {name: algorithmName}, 25 false, ["deriveBits", "deriveKey"]); 26 publicKey = await subtle.importKey("spki", test.vector, 27 {name: algorithmName}, 28 false, []) 29 derived = await subtle.deriveBits({name: algorithmName, public: publicKey}, privateKey, 8 * sizes[algorithmName]); 30 } catch (err) { 31 assert_true(privateKey !== undefined, "Private key should be valid."); 32 assert_true(publicKey !== undefined, "Public key should be valid."); 33 assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message + "."); 34 } 35 assert_equals(derived, undefined, "Operation succeeded, but should not have."); 36 }, algorithmName + " key derivation checks for all-zero value result with a key of order " + test.order); 37 }); 38 } 39 40 return importKeys(pkcs8, spki, sizes) 41 .then(function(results) { 42 publicKeys = results.publicKeys; 43 privateKeys = results.privateKeys; 44 noDeriveBitsKeys = results.noDeriveBitsKeys; 45 ecdhKeys = results.ecdhKeys; 46 47 { 48 // Basic success case 49 promise_test(function(test) { 50 return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName]) 51 .then(function(derivation) { 52 assert_true(equalBuffers(derivation, derivations[algorithmName]), "Derived correct bits"); 53 }, function(err) { 54 assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); 55 }); 56 }, algorithmName + " good parameters"); 57 58 // Case insensitivity check 59 promise_test(function(test) { 60 return subtle.deriveBits({name: algorithmName.toLowerCase(), public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName]) 61 .then(function(derivation) { 62 assert_true(equalBuffers(derivation, derivations[algorithmName]), "Derived correct bits"); 63 }, function(err) { 64 assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); 65 }); 66 }, algorithmName + " mixed case parameters"); 67 68 // Shorter than entire derivation per algorithm 69 promise_test(function(test) { 70 return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] - 32) 71 .then(function(derivation) { 72 assert_true(equalBuffers(derivation, derivations[algorithmName], 8 * sizes[algorithmName] - 32), "Derived correct bits"); 73 }, function(err) { 74 assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); 75 }); 76 }, algorithmName + " short result"); 77 78 // Non-multiple of 8 79 promise_test(function(test) { 80 return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] - 11) 81 .then(function(derivation) { 82 assert_true(equalBuffers(derivation, derivations[algorithmName], 8 * sizes[algorithmName] - 11), "Derived correct bits"); 83 }, function(err) { 84 assert_unreached("deriveBits failed with error " + err.name + ": " + err.message); 85 }); 86 }, algorithmName + " non-multiple of 8 bits"); 87 88 // Errors to test: 89 90 // - missing public property TypeError 91 promise_test(function(test) { 92 return subtle.deriveBits({name: algorithmName}, privateKeys[algorithmName], 8 * sizes[algorithmName]) 93 .then(function(derivation) { 94 assert_unreached("deriveBits succeeded but should have failed with TypeError"); 95 }, function(err) { 96 assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); 97 }); 98 }, algorithmName + " missing public property"); 99 100 // - Non CryptoKey public property TypeError 101 promise_test(function(test) { 102 return subtle.deriveBits({name: algorithmName, public: {message: "Not a CryptoKey"}}, privateKeys[algorithmName], 8 * sizes[algorithmName]) 103 .then(function(derivation) { 104 assert_unreached("deriveBits succeeded but should have failed with TypeError"); 105 }, function(err) { 106 assert_equals(err.name, "TypeError", "Should throw correct error, not " + err.name + ": " + err.message); 107 }); 108 }, algorithmName + " public property of algorithm is not a CryptoKey"); 109 110 // - wrong algorithm 111 promise_test(function(test) { 112 return subtle.deriveBits({name: algorithmName, public: ecdhKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName]) 113 .then(function(derivation) { 114 assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); 115 }, function(err) { 116 assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); 117 }); 118 }, algorithmName + " mismatched algorithms"); 119 120 // - No deriveBits usage in baseKey InvalidAccessError 121 promise_test(function(test) { 122 return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, noDeriveBitsKeys[algorithmName], 8 * sizes[algorithmName]) 123 .then(function(derivation) { 124 assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); 125 }, function(err) { 126 assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); 127 }); 128 }, algorithmName + " no deriveBits usage for base key"); 129 130 // - Use public key for baseKey InvalidAccessError 131 promise_test(function(test) { 132 return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, publicKeys[algorithmName], 8 * sizes[algorithmName]) 133 .then(function(derivation) { 134 assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); 135 }, function(err) { 136 assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); 137 }); 138 }, algorithmName + " base key is not a private key"); 139 140 // - Use private key for public property InvalidAccessError 141 promise_test(function(test) { 142 return subtle.deriveBits({name: algorithmName, public: privateKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName]) 143 .then(function(derivation) { 144 assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); 145 }, function(err) { 146 assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); 147 }); 148 }, algorithmName + " public property value is a private key"); 149 150 // - Use secret key for public property InvalidAccessError 151 promise_test(function(test) { 152 return subtle.generateKey({name: "AES-CBC", length: 128}, true, ["encrypt", "decrypt"]) 153 .then(function(secretKey) { 154 return subtle.deriveBits({name: algorithmName, public: secretKey}, privateKeys[algorithmName], 8 * sizes[algorithmName]) 155 .then(function(derivation) { 156 assert_unreached("deriveBits succeeded but should have failed with InvalidAccessError"); 157 }, function(err) { 158 assert_equals(err.name, "InvalidAccessError", "Should throw correct error, not " + err.name + ": " + err.message); 159 }); 160 }); 161 }, algorithmName + " public property value is a secret key"); 162 163 // - Length greater than possible for particular curves OperationError 164 promise_test(function(test) { 165 return subtle.deriveBits({name: algorithmName, public: publicKeys[algorithmName]}, privateKeys[algorithmName], 8 * sizes[algorithmName] + 8) 166 .then(function(derivation) { 167 assert_unreached("deriveBits succeeded but should have failed with OperationError"); 168 }, function(err) { 169 assert_equals(err.name, "OperationError", "Should throw correct error, not " + err.name + ": " + err.message); 170 }); 171 }, algorithmName + " asking for too many bits"); 172 } 173 }); 174 175 function importKeys(pkcs8, spki, sizes) { 176 var privateKeys = {}; 177 var publicKeys = {}; 178 var noDeriveBitsKeys = {}; 179 var ecdhPublicKeys = {}; 180 181 var promises = []; 182 { 183 var operation = subtle.importKey("pkcs8", pkcs8[algorithmName], 184 {name: algorithmName}, 185 false, ["deriveBits", "deriveKey"]) 186 .then(function(key) { 187 privateKeys[algorithmName] = key; 188 }, function (err) { 189 privateKeys[algorithmName] = null; 190 }); 191 promises.push(operation); 192 } 193 { 194 var operation = subtle.importKey("pkcs8", pkcs8[algorithmName], 195 {name: algorithmName}, 196 false, ["deriveKey"]) 197 .then(function(key) { 198 noDeriveBitsKeys[algorithmName] = key; 199 }, function (err) { 200 noDeriveBitsKeys[algorithmName] = null; 201 }); 202 promises.push(operation); 203 } 204 { 205 var operation = subtle.importKey("spki", spki[algorithmName], 206 {name: algorithmName}, 207 false, []) 208 .then(function(key) { 209 publicKeys[algorithmName] = key; 210 }, function (err) { 211 publicKeys[algorithmName] = null; 212 }); 213 promises.push(operation); 214 } 215 { 216 var operation = subtle.importKey("spki", ecSPKI, 217 {name: "ECDH", namedCurve: "P-256"}, 218 false, []) 219 .then(function(key) { 220 ecdhPublicKeys[algorithmName] = key; 221 }); 222 } 223 return Promise.all(promises) 224 .then(function(results) {return {privateKeys: privateKeys, publicKeys: publicKeys, noDeriveBitsKeys: noDeriveBitsKeys, ecdhKeys: ecdhPublicKeys}}); 225 } 226 227 // Compares two ArrayBuffer or ArrayBufferView objects. If bitCount is 228 // omitted, the two values must be the same length and have the same contents 229 // in every byte. If bitCount is included, only that leading number of bits 230 // have to match. 231 function equalBuffers(a, b, bitCount) { 232 var remainder; 233 234 if (typeof bitCount === "undefined" && a.byteLength !== b.byteLength) { 235 return false; 236 } 237 238 var aBytes = new Uint8Array(a); 239 var bBytes = new Uint8Array(b); 240 241 var length = a.byteLength; 242 if (typeof bitCount !== "undefined") { 243 length = Math.floor(bitCount / 8); 244 } 245 246 for (var i=0; i<length; i++) { 247 if (aBytes[i] !== bBytes[i]) { 248 return false; 249 } 250 } 251 252 if (typeof bitCount !== "undefined") { 253 remainder = bitCount % 8; 254 return aBytes[length] >> (8 - remainder) === bBytes[length] >> (8 - remainder); 255 } 256 257 return true; 258 } 259 260 }