зеркало из https://github.com/mozilla/gecko-dev.git
370 строки
10 KiB
HTML
370 строки
10 KiB
HTML
<!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>
|