/*---
includes: [compatNjs.js, compatFs.js, compatWebcrypto.js, runTsuite.js, webCryptoUtils.js, compareArray.js]
flags: [async]
---*/

async function test(params) {
    let key = await crypto.subtle.importKey(params.key.fmt,
                                            params.key.key,
                                            params.key.alg,
                                            params.key.extractable,
                                            params.key.usage);

    if (params.expected && !validate_key(key, params)) {
        throw Error(`failed validate`);
    }

    return 'SUCCESS';
}

function p(args, default_opts) {
    let key, pem;
    let params = merge({}, default_opts);
    params = merge(params, args);

    switch (params.key.fmt) {
    case "spki":
        pem = fs.readFileSync(`test/webcrypto/${params.key.key}`);
        key = pem_to_der(pem, "PUBLIC");
        break;
    case "pkcs8":
        pem = fs.readFileSync(`test/webcrypto/${params.key.key}`);
        key = pem_to_der(pem, "PRIVATE");
        break;
    case "jwk":
        key = load_jwk(params.key.key);
        break;
    case "raw":
        key = Buffer.from(params.key.key, "base64url");
        break;
    default:
        throw Error("Unknown encoding key format");
    }

    params.key.key = key;

    return params;
}

function validate_key(key, params) {
    let expected = params.expected;
    if (expected.algorithm) {
        if (!key.algorithm) {
            throw Error(`missing import key algorithm`);
        }

        if (expected.algorithm.name !== key.algorithm.name) {
            throw Error(`unexpected import key algorithm name: ${key.algorithm.name} != ${expected.algorithm.name}`);
        }

        if (has_njs()
            && expected.algorithm.name == "HMAC"
            && (expected.algorithm.hash !== key.algorithm.hash))
        {
            throw Error(`unexpected import key algorithm hash: ${JSON.stringify(key.algorithm.hash)} != ${expected.algorithm.hash}`);
        }
    }

    if (expected.type !== key.type) {
        throw Error(`unexpected import key type: ${key.type} != ${expected.type}`);
    }

    if (expected.extractable !== key.extractable) {
        throw Error(`unexpected import key extractable: ${key.extractable} != ${expected.extractable}`);
    }

    if (expected.usages && !compareArray(expected.usages, key.usages)) {
        throw Error(`unexpected import key usages: ${key.usages} != ${expected.usages}`);
    }

    return true;
}

let aes_tsuite = {
    name: "AES importing",
    skip: () => (!has_webcrypto()),
    T: test,
    prepare_args: p,

    tests: [
      { key: { fmt: "jwk",
               key: { alg: 'A128CBC', ext: true, k: 'AAAAAAAAAAAAAAAAAAAAAA', key_ops: [ 'decrypt', 'encrypt' ], kty: 'oct' },
               alg: { name: "AES-CBC" },
               extractable: true,
               usage: [ "decrypt", "encrypt" ] },
        expected: { algorithm: { name: "AES-CBC" },
                    extractable: true,
                    type: "secret",
                    usages: [ "decrypt", "encrypt" ] } },
      { key: { fmt: "jwk",
               key: { alg: 'A128CBC', ext: true, k: 'AAAAAAAAAAAAAAAAAAAAAA', key_ops: [ 'encrypt' ], kty: 'oct' },
               alg: { name: "AES-CBC" },
               extractable: true,
               usage: [ "encrypt" ] },
        expected: { algorithm: { name: "AES-CBC" },
                    extractable: true,
                    type: "secret",
                    usages: [ "encrypt" ] } },
      { key: { fmt: "jwk",
               key: { alg: 'A128CBC', ext: true, k: 'AAAAAAAAAAAAAAAAAAAAAA', kty: 'oct' },
               alg: { name: "AES-CBC" },
               extractable: true,
               usage: [ "encrypt" ] },
        expected: { algorithm: { name: "AES-CBC" },
                    extractable: true,
                    type: "secret",
                    usages: [ "encrypt" ] } },
      { key: { fmt: "jwk",
               key: { alg: 'A128CBC', k: 'AAAAAAAAAAAAAAAAAAAAAA', kty: 'oct' },
               alg: { name: "AES-CBC" },
               extractable: true,
               usage: [ "encrypt" ] },
        expected: { algorithm: { name: "AES-CBC" },
                    extractable: true,
                    type: "secret",
                    usages: [ "encrypt" ] } },
      { key: { fmt: "raw",
               key: 'AAAAAAAAAAAAAAAAAAAAAA',
               alg: { name: "AES-CBC" },
               extractable: true,
               usage: [ "decrypt", "encrypt" ] },
        expected: { algorithm: { name: "AES-CBC" },
                    extractable: true,
                    type: "secret",
                    usages: [ "decrypt", "encrypt" ] } },
      { key: { fmt: "raw",
               key: 'AAAAAAAAAAAAAAAAAAAAAA',
               alg: { name: "AES-CTR" },
               extractable: false,
               usage: [ "decrypt" ] },
        expected: { algorithm: { name: "AES-CTR" },
                    extractable: false,
                    type: "secret",
                    usages: [ "decrypt" ] } },
      { key: { fmt: "raw",
               key: 'AAAAAAAAAAAAAAAAAAAAAA',
               alg: { name: "AES-GCM" },
               extractable: true,
               usage: [ "decrypt", "encrypt" ] },
        expected: { algorithm: { name: "AES-GCM" },
                    extractable: true,
                    type: "secret",
                    usages: [ "decrypt", "encrypt" ] } },

      { key: { fmt: "raw",
               key: 'AA',
               alg: { name: "AES-CBC" },
               extractable: true,
               usage: [ "decrypt", "encrypt" ] },
        exception: "TypeError: AES Invalid key length" },
      { key: { fmt: "jwk",
               key: { alg: 'A128CBC', ext: true, k: 'AA', key_ops: [ 'encrypt', 'decrypt' ], kty: 'oct' },
               alg: { name: "AES-CBC" },
               usage: [ "encrypt", "decrypt" ] },
        exception: "TypeError: key size and \"alg\" value \"A128CBC\" mismatch" },
      { key: { fmt: "jwk",
               key: { alg: 'A129CBC', ext: true, k: 'AA', key_ops: [ 'encrypt', 'decrypt' ], kty: 'oct' },
               alg: { name: "AES-CBC" },
               usage: [ "encrypt", "decrypt" ] },
        exception: "TypeError: unexpected \"alg\" value \"A129CBC\" for JWK key" },
      { key: { fmt: "jwk",
               key: { alg: 'A128CBC', ext: false, k: 'AAAAAAAAAAAAAAAAAAAAAA', kty: 'oct' },
               alg: { name: "AES-CBC" },
               extractable: true,
               usage: [ "encrypt" ] },
        exception: "TypeError: JWK oct is not extractable" },
      { key: { fmt: "jwk",
               key: { alg: 1, ext: true, k: 'AA', key_ops: ['encrypt', 'decrypt'], kty: 'oct' },
               alg: { name: "AES-CBC" },
               usage: [ "encrypt", "decrypt" ] },
        exception: "TypeError: Invalid JWK oct alg" },
      { key: { fmt: "jwk",
               key: { kty: 'RSA' },
               alg: { name: "AES-CBC" },
               extractable: true,
               usage: [ "encrypt" ] },
        exception: "TypeError: JWK kty \"RSA\" doesn't match algorithm \"AES-CBC\"" },
      { key: { fmt: "jwk",
               key: { kty: 'EC' },
               alg: { name: "AES-GCM" },
               extractable: true,
               usage: [ "encrypt" ] },
        exception: "TypeError: JWK kty \"EC\" doesn't match algorithm \"AES-GCM\"" },
]};

let ec_tsuite = {
    name: "EC importing",
    skip: () => (!has_webcrypto()),
    T: test,
    prepare_args: p,

    tests: [
      { key: { fmt: "jwk",
               key: "ec.jwk",
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        expected: { algorithm: { name: "ECDSA", namedCurve: "SHA-256" },
                    extractable: true,
                    type: "private",
                    usages: [ "sign" ] } },
      { key: { fmt: "spki",
               key: "ec.spki",
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "verify" ] },
        expected: { algorithm: { name: "ECDSA", namedCurve: "SHA-256" },
                    extractable: true,
                    type: "public",
                    usages: [ "verify" ] } },
      { key: { fmt: "pkcs8",
               key: "ec.pkcs8",
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        expected: { algorithm: { name: "ECDSA", namedCurve: "SHA-256" },
                    extractable: true,
                    type: "private",
                    usages: [ "sign" ] } },
      { key: { fmt: "raw",
               key: "BHFFLGURrlWEXhok0JfTKke4q-nWSIMPvKTPhdKYSVnc4Nzn_7uNz0AA3U4fhpfVxSD4U5QciGyEoM4r3jC7bjI",
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "verify" ] },
        expected: { algorithm: { name: "ECDSA", namedCurve: "SHA-256" },
                    extractable: true,
                    type: "public",
                    usages: [ "verify" ] } },

      { key: { fmt: "jwk",
               key: "ec.jwk",
               alg: { name: "ECDSA", namedCurve: "P-384" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK EC key" },
      { key: { fmt: "jwk",
               key: 1,
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: invalid JWK key data" },
      { key: { fmt: "jwk",
               key: { kty: "EC" },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK EC key" },
      { key: { fmt: "jwk",
               key: { kty: "EC",
                      x: "cUUsZRGuVYReGiTQl9MqR7ir6dZIgw-8pM-F0phJWdw" },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK EC key" },
      { key: { fmt: "jwk",
               key: { kty: "EC",
                      x: "cUUsZRGuVYReGiTQl9MqR7ir6dZIgw-8pM-F0phJWdw",
                      y: "4Nzn_7uNz0AA3U4fhpfVxSD4U5QciGyEoM4r3jC7bjI" },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK EC key" },
      { key: { fmt: "jwk",
               key: { kty: "EC",
                      x: "cUUsZRGuVYReGiTQl9MqR7ir6dZIgw-8pM-F0phJWdw",
                      y: "4Nzn_7uNz0AA3U4fhpfVxSD4U5QciGyEoM4r3jC7bjI",
                      d: "E2sW0_4a3QXaSTJ0JKbSUbieKTD1UFtr7i_2CuetP6A" },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "JWK EC curve mismatch" },
      { key: { fmt: "jwk",
               key: { kty: "EC",
                      x: "cUUsZRGuVYReGiTQl9MqR7ir6dZIgw-8pM-F0phJWdw",
                      y: "4Nzn_7uNz0AA3U4fhpfVxSD4U5QciGyEoM4r3jC7bjI",
                      d: "E2sW0_4a3QXaSTJ0JKbSUbieKTD1UFtr7i_2CuetP6A",
                      crv: "P-384" },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "JWK EC curve mismatch" },
      { key: { fmt: "jwk",
               key: { kty: "EC",
                      x: "_BROKEN_",
                      y: "4Nzn_7uNz0AA3U4fhpfVxSD4U5QciGyEoM4r3jC7bjI",
                      d: "E2sW0_4a3QXaSTJ0JKbSUbieKTD1UFtr7i_2CuetP6A",
                      crv: "P-256" },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: EC_KEY_set_public_key_affine_coordinates()" },
      { key: { fmt: "jwk",
               key: { kty: "EC",
                      x: "cUUsZRGuVYReGiTQl9MqR7ir6dZIgw-8pM-F0phJWdw",
                      y: "4Nzn_7uNz0AA3U4fhpfVxSD4U5QciGyEoM4r3jC7bjI",
                      d: "E2sW0_4a3QXaSTJ0JKbSUbieKTD1UFtr7i_2CuetP6A",
                      crv: "P-256",
                      key_ops: [ "verify" ] },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Key operations and usage mismatch" },
      { key: { fmt: "jwk",
               key: { kty: "EC",
                      x: "cUUsZRGuVYReGiTQl9MqR7ir6dZIgw-8pM-F0phJWdw",
                      y: "4Nzn_7uNz0AA3U4fhpfVxSD4U5QciGyEoM4r3jC7bjI",
                      d: "E2sW0_4a3QXaSTJ0JKbSUbieKTD1UFtr7i_2CuetP6A",
                      ext: false },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "JWK EC is not extractable" },
      { key: { fmt: "jwk",
               key: { kty: "EC",
                      x: "cUUsZRGuVYReGiTQl9MqR7ir6dZIgw-8pM-F0phJWdw",
                      y: "4Nzn_7uNz0AA3U4fhpfVxSD4U5QciGyEoM4r3jC7bjI",
                      d: "E2sW0_4a3QXaSTJ0JKbSUbieKTD1UFtr7i_2CuetP6A",
                      crv: "P-256" },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign", "verify" ] },
        exception: "TypeError: key usage mismatch for \"ECDSA\" key" },
      { key: { fmt: "pkcs8",
               key: "ec.pkcs8",
               alg: { name: "ECDSA", namedCurve: "unknown_named_curve" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: unknown namedCurve: \"unknown_named_curve\"" },
      { key: { fmt: "spki",
               key: "rsa.spki",
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "verify" ] },
        exception: "TypeError: EC key is not found" },
      { key: { fmt: "spki",
               key: "ec.spki",
               alg: { name: "ECDSA", namedCurve: "P-384" },
               extractable: true,
               usage: [ "verify" ] },
        exception: "TypeError: name curve mismatch" },
      { key: { fmt: "raw",
               key: "CHFFLGURrlWEXhok0JfTKke4q-nWSIMPvKTPhdKYSVnc4Nzn_7uNz0AA3U4fhpfVxSD4U5QciGyEoM4r3jC7bjI",
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "verify" ] },
        exception: "TypeError: EC_POINT_oct2point()" },
      { key: { fmt: "jwk",
               key: { kty: 'oct', k: 'AQIDBAUG', alg: 'HS256' },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: JWK kty \"oct\" doesn't match algorithm \"ECDSA\"" },
      { key: { fmt: "jwk",
               key: { kty: 'oct', k: 'AQIDBAUG', alg: 'HS256' },
               alg: { name: "ECDH", namedCurve: "P-256" },
               extractable: true,
               usage: [ "deriveBits" ] },
        exception: "TypeError: JWK kty \"oct\" doesn't match algorithm \"ECDH\"" },
      { key: { fmt: "jwk",
               key: { kty: 'RSA' },
               alg: { name: "ECDSA", namedCurve: "P-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: JWK kty \"RSA\" doesn't match algorithm \"ECDSA\"" },
]};

let hmac_tsuite = {
    name: "HMAC importing",
    skip: () => (!has_webcrypto()),
    T: test,
    prepare_args: p,

    tests: [
      { key: { fmt: "raw",
               key: "AA",
               alg: { name: "HMAC", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign", "verify" ] },
        expected: { algorithm: { name: "HMAC", hash: "SHA-256" },
                    extractable: true,
                    type: "secret",
                    usages: [ "sign", "verify" ] } },
      { key: { fmt: "raw",
               key: "AA",
               alg: { name: "HMAC", hash: "SHA-384" },
               extractable: true,
               usage: [ "sign", "verify" ] },
        expected: { algorithm: { name: "HMAC", hash: "SHA-384" },
                    extractable: true,
                    type: "secret",
                    usages: [ "sign", "verify" ] } },
      { key: { fmt: "raw",
               key: "AA",
               alg: { name: "HMAC", hash: "SHA-384" },
               extractable: false,
               usage: [ "sign", "verify" ] },
        expected: { algorithm: { name: "HMAC", hash: "SHA-384" },
                    extractable: false,
                    type: "secret",
                    usages: [ "sign", "verify" ] } },

      { key: { fmt: "raw",
               key: "AA",
               alg: { name: "HMAC", hash: "SHA-385" },
               extractable: true,
               usage: [ "sign", "verify" ] },
        exception: "TypeError: unknown hash name: \"SHA-385\"" },
      { key: { fmt: "spki",
               key: "ec.spki",
               alg: { name: "HMAC" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: unsupported key fmt \"spki\" for \"HMAC\" key" },
      { key: { fmt: "raw",
               key: "AA",
               alg: { name: "HMAC", hash: "SHA-384" },
               extractable: true,
               usage: [ "encrypt" ] },
        exception: "TypeError: unsupported key usage for \"HMAC\" key" },
      { key: { fmt: "raw",
               key: "AA",
               alg: { name: "HMAC", hash: "SHA-384" },
               extractable: true,
               usage: [ "invalid_usage" ] },
        exception: "TypeError: unknown key usage: \"invalid_usage\"" },

      { key: { fmt: "jwk",
               key: { alg: 'HS384', ext: true, k: 'AA', key_ops: [ 'sign', 'verify' ], kty: 'oct' },
               alg: { name: "HMAC", hash: "SHA-384" },
               extractable: true,
               usage: [ "sign", "verify" ] },
        expected: { algorithm: { name: "HMAC", hash: "SHA-384" },
                    extractable: true,
                    type: "secret",
                    usages: [ "sign", "verify" ] } },
      { key: { fmt: "jwk",
               key: { alg: 'HS256', ext: true, k: 'AA', key_ops: [ 'sign' ], kty: 'oct' },
               alg: { name: "HMAC", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ]},
        expected: { algorithm: { name: "HMAC", hash: "SHA-256" },
                    extractable: true,
                    type: "secret",
                    usages: [ "sign" ] } },
      { key: { fmt: "jwk",
               key: { alg: 'HS256', k: 'AA', kty: 'oct' },
               alg: { name: "HMAC", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ]},
        expected: { algorithm: { name: "HMAC", hash: "SHA-256" },
                    extractable: true,
                    type: "secret",
                    usages: [ "sign" ] } },

      { key: { fmt: "jwk",
               key: { alg: 'HS385', ext: true, k: 'AA', key_ops: [ 'sign', 'verify' ], kty: 'oct' },
               alg: { name: "HMAC", hash: "SHA-385" },
               extractable: true,
               usage: [ "sign", "verify" ] },
        exception: "TypeError: unexpected \"alg\" value \"HS385\" for JWK key" },
      { key: { fmt: "jwk",
               key: { alg: 'HS384', ext: true, k: 'AA', key_ops: [ 'sign', 'verify' ], kty: 'invalid_kty' },
               alg: { name: "HMAC", hash: "SHA-384" },
               extractable: true,
               usage: [ "sign", "verify" ] },
        exception: "TypeError: invalid JWK key type: \"invalid_kty\"" },
      { key: { fmt: "jwk",
               key: { alg: 'HS256', ext: true, key_ops: [ 'sign' ], kty: 'oct' },
               alg: { name: "HMAC", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ]},
        exception: "TypeError: Invalid JWK oct key" },
      { key: { fmt: "jwk",
               key: { alg: 'HS256', k: 'AA', key_ops: [ 'sign' ], kty: 'oct' },
               alg: { name: "HMAC", hash: "SHA-256" },
               extractable: true,
               usage: [ "verify" ]},
        exception: "TypeError: Key operations and usage mismatch" },
      { key: { fmt: "jwk",
               key: { kty: 'RSA' },
               alg: { name: "HMAC", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: JWK kty \"RSA\" doesn't match algorithm \"HMAC\"" },
      { key: { fmt: "jwk",
               key: { kty: 'EC' },
               alg: { name: "HMAC", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: JWK kty \"EC\" doesn't match algorithm \"HMAC\"" },
]};

let rsa_tsuite = {
    name: "RSA importing",
    skip: () => (!has_webcrypto()),
    T: test,
    prepare_args: p,

    tests: [
      { key: { fmt: "jwk",
               key: "rsa.jwk",
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        expected: { algorithm: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
                    extractable: true,
                    type: "private",
                    usages: [ "sign" ] } },
      { key: { fmt: "pkcs8",
               key: "rsa.pkcs8",
               alg: { name: "RSA-OAEP", hash: "SHA-1" },
               extractable: true,
               usage: [ "decrypt" ] },
        expected: { algorithm: { name: "RSA-OAEP", hash: "SHA-1" },
                    extractable: true,
                    type: "private",
                    usages: [ "decrypt" ] } },
      { key: { fmt: "spki",
               key: "rsa.spki",
               alg: { name: "RSA-OAEP", hash: "SHA-256" },
               extractable: true,
               usage: [ "encrypt" ] },
        expected: { algorithm: { name: "RSA-OAEP", hash: "SHA-256" },
                    extractable: true,
                    type: "public",
                    usages: [ "encrypt" ] } },

      { key: { fmt: "jwk",
               key: 1,
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: invalid JWK key data" },
      { key: { fmt: "jwk",
               key: "rsa.jwk",
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "verify" ] },
        exception: "TypeError: Key operations and usage mismatch" },
      { key: { fmt: "jwk",
               key: { kty: "RSA",
                      n: "yUmxoJC8VAM5hyYZa-XUBZg1N1ywFMPUpWsF1kaSGed98P3XUgPzgX80wpyzd5qdGuALqnf2lMc7O8PrGBtO5YrvQlI96NX0jUo5bc5wz220ob3AUCeQnTfx-UFqM4pCwjoDSo2PlphJdWgFYymGBaBCJgnENQL9H1N_8_yNiN8",
                      e: "AQAB",
                      d: "j06DQyCopFujYoASi0oWmGEUSjUYO8BsrdSzVCnsLLsuZBwlZ4Peouyw4Hl2IIoYniCyzYwZJzVtC5Dh2MjgcrJTG5nX3FfheuabGl4in0583C51ZYWlVpDvBWw8kJTfXjiKH4z6ZA9dWdT5Y3aH_kOf-znUc7eTvuzISs61x_k",
                      alg: "RS256" },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-384" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: RSA JWK hash mismatch" },
      { key: { fmt: "jwk",
               key: { kty: "RSA",
                      n: "yUmxoJC8VAM5hyYZa-XUBZg1N1ywFMPUpWsF1kaSGed98P3XUgPzgX80wpyzd5qdGuALqnf2lMc7O8PrGBtO5YrvQlI96NX0jUo5bc5wz220ob3AUCeQnTfx-UFqM4pCwjoDSo2PlphJdWgFYymGBaBCJgnENQL9H1N_8_yNiN8" },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK RSA key" },
      { key: { fmt: "jwk",
               key: { kty: "RSA",
                      n: "yUmxoJC8VAM5hyYZa-XUBZg1N1ywFMPUpWsF1kaSGed98P3XUgPzgX80wpyzd5qdGuALqnf2lMc7O8PrGBtO5YrvQlI96NX0jUo5bc5wz220ob3AUCeQnTfx-UFqM4pCwjoDSo2PlphJdWgFYymGBaBCJgnENQL9H1N_8_yNiN8",
                      e: "AQAB" },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: key usage mismatch for \"RSASSA-PKCS1-v1_5\" key" },
      { key: { fmt: "jwk",
               key: { kty: "RSA",
                      n: "yUmxoJC8VAM5hyYZa-XUBZg1N1ywFMPUpWsF1kaSGed98P3XUgPzgX80wpyzd5qdGuALqnf2lMc7O8PrGBtO5YrvQlI96NX0jUo5bc5wz220ob3AUCeQnTfx-UFqM4pCwjoDSo2PlphJdWgFYymGBaBCJgnENQL9H1N_8_yNiN8",
                      e: "AQAB",
                      d: "j06DQyCopFujYoASi0oWmGEUSjUYO8BsrdSzVCnsLLsuZBwlZ4Peouyw4Hl2IIoYniCyzYwZJzVtC5Dh2MjgcrJTG5nX3FfheuabGl4in0583C51ZYWlVpDvBWw8kJTfXjiKH4z6ZA9dWdT5Y3aH_kOf-znUc7eTvuzISs61x_k" },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK RSA key" },
      { key: { fmt: "jwk",
               key: { kty: "RSA",
                      n: "yUmxoJC8VAM5hyYZa-XUBZg1N1ywFMPUpWsF1kaSGed98P3XUgPzgX80wpyzd5qdGuALqnf2lMc7O8PrGBtO5YrvQlI96NX0jUo5bc5wz220ob3AUCeQnTfx-UFqM4pCwjoDSo2PlphJdWgFYymGBaBCJgnENQL9H1N_8_yNiN8",
                      e: "AQAB",
                      d: "j06DQyCopFujYoASi0oWmGEUSjUYO8BsrdSzVCnsLLsuZBwlZ4Peouyw4Hl2IIoYniCyzYwZJzVtC5Dh2MjgcrJTG5nX3FfheuabGl4in0583C51ZYWlVpDvBWw8kJTfXjiKH4z6ZA9dWdT5Y3aH_kOf-znUc7eTvuzISs61x_k",
                      p: "9ASb2yw5b8d7unrFuOyy4EDcPbnzEpbuVGASeHPqkORwHsqeGbfwGlhDYSYrY0HCwUsSBSFcO3SDeu0Z0zSvFQ" },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK RSA key" },
      { key: { fmt: "jwk",
               key: { kty: "RSA",
                      n: "yUmxoJC8VAM5hyYZa-XUBZg1N1ywFMPUpWsF1kaSGed98P3XUgPzgX80wpyzd5qdGuALqnf2lMc7O8PrGBtO5YrvQlI96NX0jUo5bc5wz220ob3AUCeQnTfx-UFqM4pCwjoDSo2PlphJdWgFYymGBaBCJgnENQL9H1N_8_yNiN8",
                      e: "AQAB",
                      d: "j06DQyCopFujYoASi0oWmGEUSjUYO8BsrdSzVCnsLLsuZBwlZ4Peouyw4Hl2IIoYniCyzYwZJzVtC5Dh2MjgcrJTG5nX3FfheuabGl4in0583C51ZYWlVpDvBWw8kJTfXjiKH4z6ZA9dWdT5Y3aH_kOf-znUc7eTvuzISs61x_k",
                      p: "9ASb2yw5b8d7unrFuOyy4EDcPbnzEpbuVGASeHPqkORwHsqeGbfwGlhDYSYrY0HCwUsSBSFcO3SDeu0Z0zSvFQ",
                      q: "0yvzzgHo_PGYSlVj-M3965AwQF2wTXz82MZHv6EfcCHKuBfCSecr-igqLHhzfynAQjjf39VrXuPuRL23REF1Iw" },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK RSA key" },
      { key: { fmt: "jwk",
               key: { kty: "RSA",
                      n: "yUmxoJC8VAM5hyYZa-XUBZg1N1ywFMPUpWsF1kaSGed98P3XUgPzgX80wpyzd5qdGuALqnf2lMc7O8PrGBtO5YrvQlI96NX0jUo5bc5wz220ob3AUCeQnTfx-UFqM4pCwjoDSo2PlphJdWgFYymGBaBCJgnENQL9H1N_8_yNiN8",
                      e: "AQAB",
                      d: "j06DQyCopFujYoASi0oWmGEUSjUYO8BsrdSzVCnsLLsuZBwlZ4Peouyw4Hl2IIoYniCyzYwZJzVtC5Dh2MjgcrJTG5nX3FfheuabGl4in0583C51ZYWlVpDvBWw8kJTfXjiKH4z6ZA9dWdT5Y3aH_kOf-znUc7eTvuzISs61x_k",
                      p: "9ASb2yw5b8d7unrFuOyy4EDcPbnzEpbuVGASeHPqkORwHsqeGbfwGlhDYSYrY0HCwUsSBSFcO3SDeu0Z0zSvFQ",
                      q: "0yvzzgHo_PGYSlVj-M3965AwQF2wTXz82MZHv6EfcCHKuBfCSecr-igqLHhzfynAQjjf39VrXuPuRL23REF1Iw",
                      dp: "pUXJ2jSl4lOWNcOZz5phvQmxIg2j2N9pJLS9TeAU63YNio1pb7npYa6OVGpp0JxlsE2MMvVZZtuPgd69MxPn0Q" },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK RSA key" },
      { key: { fmt: "jwk",
               key: { kty: "RSA",
                      n: "yUmxoJC8VAM5hyYZa-XUBZg1N1ywFMPUpWsF1kaSGed98P3XUgPzgX80wpyzd5qdGuALqnf2lMc7O8PrGBtO5YrvQlI96NX0jUo5bc5wz220ob3AUCeQnTfx-UFqM4pCwjoDSo2PlphJdWgFYymGBaBCJgnENQL9H1N_8_yNiN8",
                      e: "AQAB",
                      d: "j06DQyCopFujYoASi0oWmGEUSjUYO8BsrdSzVCnsLLsuZBwlZ4Peouyw4Hl2IIoYniCyzYwZJzVtC5Dh2MjgcrJTG5nX3FfheuabGl4in0583C51ZYWlVpDvBWw8kJTfXjiKH4z6ZA9dWdT5Y3aH_kOf-znUc7eTvuzISs61x_k",
                      p: "9ASb2yw5b8d7unrFuOyy4EDcPbnzEpbuVGASeHPqkORwHsqeGbfwGlhDYSYrY0HCwUsSBSFcO3SDeu0Z0zSvFQ",
                      q: "0yvzzgHo_PGYSlVj-M3965AwQF2wTXz82MZHv6EfcCHKuBfCSecr-igqLHhzfynAQjjf39VrXuPuRL23REF1Iw",
                      dp: "pUXJ2jSl4lOWNcOZz5phvQmxIg2j2N9pJLS9TeAU63YNio1pb7npYa6OVGpp0JxlsE2MMvVZZtuPgd69MxPn0Q",
                      dq: "RZoqDM-iXKTA3ldQ0TQMKnVnAgAfWRsGN-j6wxW3R_1LVOw31KYGX7iXVfsJjnNTdEBMwfkVH7yezzd8zVmJ4w" },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK RSA key" },
      { key: { fmt: "jwk",
               key: { kty: "RSA",
                      n: "yUmxoJC8VAM5hyYZa-XUBZg1N1ywFMPUpWsF1kaSGed98P3XUgPzgX80wpyzd5qdGuALqnf2lMc7O8PrGBtO5YrvQlI96NX0jUo5bc5wz220ob3AUCeQnTfx-UFqM4pCwjoDSo2PlphJdWgFYymGBaBCJgnENQL9H1N_8_yNiN8",
                      e: "AQAB",
                      d: "j06DQyCopFujYoASi0oWmGEUSjUYO8BsrdSzVCnsLLsuZBwlZ4Peouyw4Hl2IIoYniCyzYwZJzVtC5Dh2MjgcrJTG5nX3FfheuabGl4in0583C51ZYWlVpDvBWw8kJTfXjiKH4z6ZA9dWdT5Y3aH_kOf-znUc7eTvuzISs61x_k",
                      p: "9ASb2yw5b8d7unrFuOyy4EDcPbnzEpbuVGASeHPqkORwHsqeGbfwGlhDYSYrY0HCwUsSBSFcO3SDeu0Z0zSvFQ",
                      q: "0yvzzgHo_PGYSlVj-M3965AwQF2wTXz82MZHv6EfcCHKuBfCSecr-igqLHhzfynAQjjf39VrXuPuRL23REF1Iw",
                      dp: "pUXJ2jSl4lOWNcOZz5phvQmxIg2j2N9pJLS9TeAU63YNio1pb7npYa6OVGpp0JxlsE2MMvVZZtuPgd69MxPn0Q",
                      dq: "RZoqDM-iXKTA3ldQ0TQMKnVnAgAfWRsGN-j6wxW3R_1LVOw31KYGX7iXVfsJjnNTdEBMwfkVH7yezzd8zVmJ4w",
                      qi: "2REPnRQIaLsya5wlwFw0whwPaAbTZp2jfguhtg5gou_Yru7Cxz_b83YFPgoI6xuGE1OXsWkRTToS8FuIWCrNBQ",
                      ext: false },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "JWK RSA is not extractable" },
      { key: { fmt: "jwk",
               key: { kty: "RSA" },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: Invalid JWK RSA key" },
      { key: { fmt: "pkcs8",
               key: "ec.pkcs8",
               alg: { name: "RSA-OAEP", hash: "SHA-1" },
               extractable: true,
               usage: [ "decrypt" ] },
        exception: "TypeError: RSA key is not found" },
      { key: { fmt: "pkcs8",
               key: "rsa.pkcs8.broken",
               alg: { name: "RSA-OAEP", hash: "SHA-1" },
               extractable: true,
               usage: [ "decrypt" ] },
        exception: "TypeError: d2i_PKCS8_PRIV_KEY_INFO_bio() failed" },
      { key: { fmt: "pkcs8",
               key: "rsa.pkcs8.broken2",
               alg: { name: "RSA-OAEP", hash: "SHA-1" },
               extractable: true,
               usage: [ "decrypt" ] },
        exception: "TypeError: EVP_PKCS82PKEY() failed" },
      { key: { fmt: "pkcs8",
               key: "rsa.pkcs8",
               alg: { name: "RSA-OAEP", hash: "XXX" },
               extractable: true,
               usage: [ "decrypt" ] },
        exception: "TypeError: unknown hash name: \"XXX\"" },
      { key: { fmt: "spki",
               key: "rsa.spki.broken",
               alg: { name: "RSA-OAEP", hash: "SHA-256" },
               extractable: true,
               usage: [ "encrypt" ] },
        exception: "TypeError: d2i_PUBKEY() failed" },
      { key: { fmt: "jwk",
               key: { kty: 'oct', k: 'AQIDBAUG', alg: 'HS256' },
               alg: { name: "RSA-OAEP", hash: "SHA-256" },
               extractable: true,
               usage: [ "encrypt" ] },
        exception: "TypeError: JWK kty \"oct\" doesn't match algorithm \"RSA-OAEP\"" },
      { key: { fmt: "jwk",
               key: { kty: 'EC' },
               alg: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
               extractable: true,
               usage: [ "sign" ] },
        exception: "TypeError: JWK kty \"EC\" doesn't match algorithm \"RSASSA-PKCS1-v1_5\"" },
]};

run([
    aes_tsuite,
    ec_tsuite,
    hmac_tsuite,
    rsa_tsuite,
])
.then($DONE, $DONE);
