<!DOCTYPE html> <html> <head> <title>WebCrypto Test Suite</title> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <link rel="stylesheet" href="./test_WebCrypto.css"/> <script src="/tests/SimpleTest/SimpleTest.js"></script> <!-- Utilities for manipulating ABVs --> <script src="util.js"></script> <!-- A simple wrapper around IndexedDB --> <script src="simpledb.js"></script> <!-- Test vectors drawn from the literature --> <script src="./test-vectors.js"></script> <!-- General testing framework --> <script src="./test-array.js"></script> <script>/*<![CDATA[*/ "use strict"; // ----------------------------------------------------------------------------- TestArray.addTest( "JWK import and use of an AES-GCM key", function () { var that = this; function doEncrypt(x) { return crypto.subtle.encrypt( { name: "AES-GCM", iv: tv.aes_gcm_enc.iv, additionalData: tv.aes_gcm_enc.adata, tagLength: 128 }, x, tv.aes_gcm_enc.data); } crypto.subtle.importKey("jwk", tv.aes_gcm_enc.key_jwk, "AES-GCM", false, ['encrypt']) .then(doEncrypt) .then( memcmp_complete(that, tv.aes_gcm_enc.result), error(that) ); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "JWK import and use of an RSASSA-PKCS1-v1_5 private key", function () { var that = this; var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; function doSign(x) { return crypto.subtle.sign(alg.name, x, tv.rsassa.data); } function fail(x) { console.log(x); error(that); } crypto.subtle.importKey("jwk", tv.rsassa.jwk_priv, alg, false, ['sign']) .then( doSign, fail ) .then( memcmp_complete(that, tv.rsassa.sig256), fail ); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "JWK import and use of an RSASSA-PKCS1-v1_5 public key", function () { var that = this; var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; function doVerify(x) { return crypto.subtle.verify(alg.name, x, tv.rsassa.sig256, tv.rsassa.data); } function fail(x) { error(that); } crypto.subtle.importKey("jwk", tv.rsassa.jwk_pub, alg, false, ['verify']) .then( doVerify, fail ) .then( complete(that, function(x) { return x; }), fail ); }); // ----------------------------------------------------------------------------- TestArray.addTest( "JWK import failure on incomplete RSA private key (missing 'qi')", function () { var that = this; var alg = { name: "RSA-OAEP", hash: "SHA-256" }; var jwk = { kty: "RSA", n: tv.rsassa.jwk_priv.n, e: tv.rsassa.jwk_priv.e, d: tv.rsassa.jwk_priv.d, p: tv.rsassa.jwk_priv.p, q: tv.rsassa.jwk_priv.q, dp: tv.rsassa.jwk_priv.dp, dq: tv.rsassa.jwk_priv.dq, }; crypto.subtle.importKey("jwk", jwk, alg, true, ['encrypt', 'decrypt']) .then( error(that), complete(that) ); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "JWK import failure on algorithm mismatch", function () { var that = this; var alg = "AES-GCM"; var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", alg: "A256GCM" }; crypto.subtle.importKey("jwk", jwk, alg, true, ['encrypt', 'decrypt']) .then( error(that), complete(that) ); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "JWK import failure on usages mismatch", function () { var that = this; var alg = "AES-GCM"; var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", key_ops: ['encrypt'] }; crypto.subtle.importKey("jwk", jwk, alg, true, ['encrypt', 'decrypt']) .then( error(that), complete(that) ); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "JWK import failure on extractable mismatch", function () { var that = this; var alg = "AES-GCM"; var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", ext: false }; crypto.subtle.importKey("jwk", jwk, alg, true, ['encrypt']) .then( error(that), complete(that) ); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "JWK export of a symmetric key", function () { var that = this; var alg = "AES-GCM"; var jwk = { k: "c2l4dGVlbiBieXRlIGtleQ", kty: "oct" }; function doExport(k) { return crypto.subtle.exportKey("jwk", k); } crypto.subtle.importKey("jwk", jwk, alg, true, ['encrypt', 'decrypt']) .then(doExport) .then( complete(that, function(x) { return hasBaseJwkFields(x) && hasFields(x, ['k']) && x.kty == 'oct' && x.alg == 'A128GCM' && x.ext && shallowArrayEquals(x.key_ops, ['encrypt','decrypt']) && x.k == jwk.k }), error(that) ); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "JWK import/export of an RSA private key", function () { var jwk = tv.rsassa.jwk_priv; var that = this; var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; function doExport(k) { return crypto.subtle.exportKey("jwk", k); } crypto.subtle.importKey("jwk", jwk, alg, true, ['sign']) .then(doExport) .then( complete(that, function(x) { return hasBaseJwkFields(x) && hasFields(x, ['n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi']) && x.kty == 'RSA' && x.alg == 'RS256' && x.ext && shallowArrayEquals(x.key_ops, ['sign']) && x.n == jwk.n && x.e == jwk.e && x.d == jwk.d && x.p == jwk.p && x.q == jwk.q && x.dp == jwk.dp && x.dq == jwk.dq && x.qi == jwk.qi; }), error(that) ); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "JWK import/export of an RSA private key where p < q", function () { var jwk = tv.rsassa.jwk_priv_pLTq; var that = this; var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; function doExport(k) { return crypto.subtle.exportKey("jwk", k); } crypto.subtle.importKey("jwk", jwk, alg, true, ['sign']) .then(doExport) .then( complete(that, function(x) { return hasBaseJwkFields(x) && hasFields(x, ['n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi']) && x.kty == 'RSA' && x.alg == 'RS256' && x.ext && shallowArrayEquals(x.key_ops, ['sign']) && x.n == jwk.n && x.e == jwk.e && x.d == jwk.d && x.p == jwk.p && x.q == jwk.q && x.dp == jwk.dp && x.dq == jwk.dq && x.qi == jwk.qi; }), error(that) ); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "JWK export of an RSA public key", function () { var that = this; var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }; var jwk = tv.rsassa.jwk_pub; function doExport(k) { return crypto.subtle.exportKey("jwk", k); } crypto.subtle.importKey("jwk", jwk, alg, true, ['verify']) .then(doExport) .then( complete(that, function(x) { window.jwk_pub = x; return hasBaseJwkFields(x) && hasFields(x, ['n', 'e']) && x.kty == 'RSA' && x.alg == 'RS256' && x.ext && 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> </div> <div id="start" onclick="start();">RUN ALL</div> <div id="resultDiv" class="content"> Summary: <span class="pass"><span id="passN">0</span> passed, </span> <span class="fail"><span id="failN">0</span> failed, </span> <span class="pending"><span id="pendingN">0</span> pending.</span> <br/> <br/> <table id="results"> <tr> <th>Test</th> <th>Result</th> <th>Time</th> </tr> </table> </div> <div id="foot"></div> </div> </body> </html>