Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- Manifest: dom/crypto/test/mochitest.toml
<!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() { 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>