test_WebCrypto_JWK.html (10693B)
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <title>WebCrypto Test Suite</title> 6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> 7 <link rel="stylesheet" href="./test_WebCrypto.css"/> 8 <script src="/tests/SimpleTest/SimpleTest.js"></script> 9 10 <!-- Utilities for manipulating ABVs --> 11 <script src="util.js"></script> 12 13 <!-- A simple wrapper around IndexedDB --> 14 <script src="simpledb.js"></script> 15 16 <!-- Test vectors drawn from the literature --> 17 <script src="./test-vectors.js"></script> 18 19 <!-- General testing framework --> 20 <script src="./test-array.js"></script> 21 22 <script>/* <![CDATA[*/ 23 "use strict"; 24 25 // ----------------------------------------------------------------------------- 26 TestArray.addTest( 27 "JWK import and use of an AES-GCM key", 28 function() { 29 var that = this; 30 31 function doEncrypt(x) { 32 return crypto.subtle.encrypt( 33 { 34 name: "AES-GCM", 35 iv: tv.aes_gcm_enc.iv, 36 additionalData: tv.aes_gcm_enc.adata, 37 tagLength: 128, 38 }, 39 x, tv.aes_gcm_enc.data); 40 } 41 42 crypto.subtle.importKey("jwk", tv.aes_gcm_enc.key_jwk, "AES-GCM", false, ["encrypt"]) 43 .then(doEncrypt) 44 .then( 45 memcmp_complete(that, tv.aes_gcm_enc.result), 46 error(that) 47 ); 48 } 49 ); 50 51 // ----------------------------------------------------------------------------- 52 TestArray.addTest( 53 "JWK import and use of an RSASSA-PKCS1-v1_5 private key", 54 function() { 55 var that = this; 56 var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; 57 58 function doSign(x) { 59 return crypto.subtle.sign(alg.name, x, tv.rsassa.data); 60 } 61 function fail(x) { console.log(x); error(that); } 62 63 crypto.subtle.importKey("jwk", tv.rsassa.jwk_priv, alg, false, ["sign"]) 64 .then( doSign, fail ) 65 .then( memcmp_complete(that, tv.rsassa.sig256), fail ); 66 } 67 ); 68 69 // ----------------------------------------------------------------------------- 70 TestArray.addTest( 71 "JWK import and use of an RSASSA-PKCS1-v1_5 public key", 72 function() { 73 var that = this; 74 var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; 75 76 function doVerify(x) { 77 return crypto.subtle.verify(alg.name, x, tv.rsassa.sig256, tv.rsassa.data); 78 } 79 function fail() { error(that); } 80 81 crypto.subtle.importKey("jwk", tv.rsassa.jwk_pub, alg, false, ["verify"]) 82 .then( doVerify, fail ) 83 .then( 84 complete(that, function(x) { return x; }), 85 fail 86 ); 87 }); 88 89 // ----------------------------------------------------------------------------- 90 TestArray.addTest( 91 "JWK import failure on incomplete RSA private key (missing 'qi')", 92 function() { 93 var that = this; 94 var alg = { name: "RSA-OAEP", hash: "SHA-256" }; 95 var jwk = { 96 kty: "RSA", 97 n: tv.rsassa.jwk_priv.n, 98 e: tv.rsassa.jwk_priv.e, 99 d: tv.rsassa.jwk_priv.d, 100 p: tv.rsassa.jwk_priv.p, 101 q: tv.rsassa.jwk_priv.q, 102 dp: tv.rsassa.jwk_priv.dp, 103 dq: tv.rsassa.jwk_priv.dq, 104 }; 105 106 crypto.subtle.importKey("jwk", jwk, alg, true, ["encrypt", "decrypt"]) 107 .then( error(that), complete(that) ); 108 } 109 ); 110 111 // ----------------------------------------------------------------------------- 112 TestArray.addTest( 113 "JWK import failure on algorithm mismatch", 114 function() { 115 var that = this; 116 var alg = "AES-GCM"; 117 var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", alg: "A256GCM" }; 118 119 crypto.subtle.importKey("jwk", jwk, alg, true, ["encrypt", "decrypt"]) 120 .then( error(that), complete(that) ); 121 } 122 ); 123 124 // ----------------------------------------------------------------------------- 125 TestArray.addTest( 126 "JWK import failure on usages mismatch", 127 function() { 128 var that = this; 129 var alg = "AES-GCM"; 130 var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", key_ops: ["encrypt"] }; 131 132 crypto.subtle.importKey("jwk", jwk, alg, true, ["encrypt", "decrypt"]) 133 .then( error(that), complete(that) ); 134 } 135 ); 136 137 // ----------------------------------------------------------------------------- 138 TestArray.addTest( 139 "JWK import failure on extractable mismatch", 140 function() { 141 var that = this; 142 var alg = "AES-GCM"; 143 var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", ext: false }; 144 145 crypto.subtle.importKey("jwk", jwk, alg, true, ["encrypt"]) 146 .then( error(that), complete(that) ); 147 } 148 ); 149 150 // ----------------------------------------------------------------------------- 151 TestArray.addTest( 152 "JWK export of a symmetric key", 153 function() { 154 var that = this; 155 var alg = "AES-GCM"; 156 var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", kty: "oct" }; 157 158 function doExport(k) { 159 return crypto.subtle.exportKey("jwk", k); 160 } 161 162 crypto.subtle.importKey("jwk", jwk, alg, true, ["encrypt", "decrypt"]) 163 .then(doExport) 164 .then( 165 complete(that, function(x) { 166 return hasBaseJwkFields(x) && 167 hasFields(x, ["k"]) && 168 x.kty == "oct" && 169 x.alg == "A128GCM" && 170 x.ext && 171 shallowArrayEquals(x.key_ops, ["encrypt", "decrypt"]) && 172 x.k == jwk.k; 173 }), 174 error(that) 175 ); 176 } 177 ); 178 179 // ----------------------------------------------------------------------------- 180 TestArray.addTest( 181 "JWK import/export of an RSA private key", 182 function() { 183 var jwk = tv.rsassa.jwk_priv; 184 185 var that = this; 186 var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; 187 188 function doExport(k) { 189 return crypto.subtle.exportKey("jwk", k); 190 } 191 192 crypto.subtle.importKey("jwk", jwk, alg, true, ["sign"]) 193 .then(doExport) 194 .then( 195 complete(that, function(x) { 196 return hasBaseJwkFields(x) && 197 hasFields(x, ["n", "e", "d", "p", "q", "dp", "dq", "qi"]) && 198 x.kty == "RSA" && 199 x.alg == "RS256" && 200 x.ext && 201 shallowArrayEquals(x.key_ops, ["sign"]) && 202 x.n == jwk.n && 203 x.e == jwk.e && 204 x.d == jwk.d && 205 x.p == jwk.p && 206 x.q == jwk.q && 207 x.dp == jwk.dp && 208 x.dq == jwk.dq && 209 x.qi == jwk.qi; 210 }), 211 error(that) 212 ); 213 } 214 ); 215 216 // ----------------------------------------------------------------------------- 217 TestArray.addTest( 218 "JWK import/export of an RSA private key where p < q", 219 function() { 220 var jwk = tv.rsassa.jwk_priv_pLTq; 221 222 var that = this; 223 var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; 224 225 function doExport(k) { 226 return crypto.subtle.exportKey("jwk", k); 227 } 228 229 crypto.subtle.importKey("jwk", jwk, alg, true, ["sign"]) 230 .then(doExport) 231 .then( 232 complete(that, function(x) { 233 return hasBaseJwkFields(x) && 234 hasFields(x, ["n", "e", "d", "p", "q", "dp", "dq", "qi"]) && 235 x.kty == "RSA" && 236 x.alg == "RS256" && 237 x.ext && 238 shallowArrayEquals(x.key_ops, ["sign"]) && 239 x.n == jwk.n && 240 x.e == jwk.e && 241 x.d == jwk.d && 242 x.p == jwk.p && 243 x.q == jwk.q && 244 x.dp == jwk.dp && 245 x.dq == jwk.dq && 246 x.qi == jwk.qi; 247 }), 248 error(that) 249 ); 250 } 251 ); 252 253 // ----------------------------------------------------------------------------- 254 TestArray.addTest( 255 "JWK export of an RSA public key", 256 function() { 257 var that = this; 258 var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; 259 var jwk = tv.rsassa.jwk_pub; 260 261 function doExport(k) { 262 return crypto.subtle.exportKey("jwk", k); 263 } 264 265 crypto.subtle.importKey("jwk", jwk, alg, true, ["verify"]) 266 .then(doExport) 267 .then( 268 complete(that, function(x) { 269 window.jwk_pub = x; 270 return hasBaseJwkFields(x) && 271 hasFields(x, ["n", "e"]) && 272 x.kty == "RSA" && 273 x.alg == "RS256" && 274 x.ext && 275 shallowArrayEquals(x.key_ops, ["verify"]) && 276 x.n == jwk.n && 277 x.e == jwk.e; 278 }), 279 error(that) 280 ); 281 } 282 ); 283 284 // -------- 285 TestArray.addTest( 286 "Check JWK parameters on generated ECDSA key pair", 287 function() { 288 crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"]) 289 .then(pair => Promise.all([ 290 crypto.subtle.exportKey("jwk", pair.privateKey), 291 crypto.subtle.exportKey("jwk", pair.publicKey), 292 ])) 293 .then( 294 complete(this, function(x) { 295 var priv = x[0]; 296 var pub = x[1]; 297 var pubIsSubsetOfPriv = Object.keys(pub) 298 .filter(k => k !== "key_ops") // key_ops is the only complex attr 299 .reduce((all, k) => all && pub[k] === priv[k], true); 300 // Can't use hasBaseJwkFields() because EC keys don't get "alg": 301 // "alg" matches curve to hash, but WebCrypto keys are more flexible. 302 return hasFields(pub, ["kty", "crv", "key_ops", "ext"]) && 303 pub.kty === "EC" && 304 pub.crv === "P-256" && 305 pub.ext && 306 typeof(pub.x) === "string" && 307 typeof(pub.y) === "string" && 308 shallowArrayEquals(pub.key_ops, ["verify"]) && 309 pubIsSubsetOfPriv && 310 shallowArrayEquals(priv.key_ops, ["sign"]) && 311 typeof(priv.d) === "string"; 312 }), 313 error(this)); 314 } 315 ); 316 317 // -------- 318 TestArray.addTest( 319 "Check key_ops parameter on an unusable RSA public key", 320 function() { 321 var parameters = { 322 name: "RSASSA-PKCS1-v1_5", 323 modulusLength: 1024, 324 publicExponent: new Uint8Array([1, 0, 1]), 325 hash: "SHA-256", 326 }; 327 // The public key generated here will have no usages and will therefore 328 // have an empty key_ops list. 329 crypto.subtle.generateKey(parameters, true, ["sign"]) 330 .then(pair => crypto.subtle.exportKey("jwk", pair.publicKey)) 331 .then(complete(this, x => x.key_ops.length === 0), 332 error(this)); 333 } 334 ); 335 /* ]]>*/</script> 336 </head> 337 338 <body> 339 340 <div id="content"> 341 <div id="head"> 342 <b>Web</b>Crypto<br> 343 </div> 344 345 <div id="start" onclick="start();">RUN ALL</div> 346 347 <div id="resultDiv" class="content"> 348 Summary: 349 <span class="pass"><span id="passN">0</span> passed, </span> 350 <span class="fail"><span id="failN">0</span> failed, </span> 351 <span class="pending"><span id="pendingN">0</span> pending.</span> 352 <br/> 353 <br/> 354 355 <table id="results"> 356 <tr> 357 <th>Test</th> 358 <th>Result</th> 359 <th>Time</th> 360 </tr> 361 </table> 362 363 </div> 364 365 <div id="foot"></div> 366 </div> 367 368 </body> 369 </html>