summaryrefslogtreecommitdiff
path: root/test/fixtures/wpt/WebCryptoAPI/import_export/okp_importKey_failures.js
blob: a5cc08a01e9fc1c23c7c8cced51ba02be60b66d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
function run_test(algorithmNames) {
    var subtle = crypto.subtle; // Change to test prefixed implementations

    setup({explicit_timeout: true});

// These tests check that importKey and exportKey throw an error, and that
// the error is of the right type, for a wide set of incorrect parameters.

// Error testing occurs by setting the parameter that should trigger the
// error to an invalid value, then combining that with all valid
// parameters that should be checked earlier by importKey, and all
// valid and invalid parameters that should be checked later by
// importKey.
//
// There are a lot of combinations of possible parameters for both
// success and failure modes, resulting in a very large number of tests
// performed.


    var allTestVectors = [ // Parameters that should work for importKey / exportKey
        {name: "Ed25519", privateUsages: ["sign"], publicUsages: ["verify"]},
        {name: "Ed448", privateUsages: ["sign"], publicUsages: ["verify"]},
        {name: "X25519",  privateUsages: ["deriveKey", "deriveBits"], publicUsages: []},
        {name: "X448",  privateUsages: ["deriveKey", "deriveBits"], publicUsages: []},
    ];

    var testVectors = [];
    if (algorithmNames && !Array.isArray(algorithmNames)) {
        algorithmNames = [algorithmNames];
    };
    allTestVectors.forEach(function(vector) {
        if (!algorithmNames || algorithmNames.includes(vector.name)) {
            testVectors.push(vector);
        }
    });

    function parameterString(format, algorithm, extractable, usages, data) {
        if (typeof algorithm !== "object" && typeof algorithm !== "string") {
            alert(algorithm);
        }

        var jwk_label = "";
        if (format === "jwk")
            jwk_label = data.d === undefined ? " (public) " : "(private)";

        var result = "(" +
                        objectToString(format) + jwk_label + ", " +
                        objectToString(algorithm) + ", " +
                        objectToString(extractable) + ", " +
                        objectToString(usages) +
                     ")";

        return result;
    }

    // Test that a given combination of parameters results in an error,
    // AND that it is the correct kind of error.
    //
    // Expected error is either a number, tested against the error code,
    // or a string, tested against the error name.
    function testError(format, algorithm, keyData, keySize, usages, extractable, expectedError, testTag) {
        promise_test(async() => {
            let key;
            try {
                key = await subtle.importKey(format, keyData, algorithm, extractable, usages);
            } catch(err) {
                let actualError = typeof expectedError === "number" ? err.code : err.name;
                assert_equals(actualError, expectedError, testTag + " not supported.");
            }
            assert_equals(key, undefined, "Operation succeeded, but should not have.");
        }, testTag + ": importKey" + parameterString(format, algorithm, extractable, usages, keyData));
    }

    // Don't create an exhaustive list of all invalid usages,
    // because there would usually be nearly 2**8 of them,
    // way too many to test. Instead, create every singleton
    // of an illegal usage, and "poison" every valid usage
    // with an illegal one.
    function invalidUsages(validUsages, mandatoryUsages) {
        var results = [];

        var illegalUsages = [];
        ["encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) {
            if (!validUsages.includes(usage)) {
                illegalUsages.push(usage);
            }
        });

        var goodUsageCombinations = validUsages.length === 0 ? [] : allValidUsages(validUsages, false, mandatoryUsages);

        illegalUsages.forEach(function(illegalUsage) {
            results.push([illegalUsage]);
            goodUsageCombinations.forEach(function(usageCombination) {
                results.push(usageCombination.concat([illegalUsage]));
            });
        });

        return results;
    }

    function validUsages(usages, format, data) {
        if (format === 'spki' || format === 'raw') return usages.publicUsages
        if (format === 'pkcs8') return usages.privateUsages
        if (format === 'jwk') {
            if (data === undefined)
                return [];
            return data.d === undefined ? usages.publicUsages : usages.privateUsages;
        }
        return [];
    }

// Now test for properly handling errors
// - Unsupported algorithm
// - Bad usages for algorithm
// - Bad key lengths
// - Lack of a mandatory format field
// - Incompatible keys pair

    // Algorithms normalize okay, but usages bad (though not empty).
    // It shouldn't matter what other extractable is. Should fail
    // due to SyntaxError
    testVectors.forEach(function(vector) {
        var name = vector.name;
        validKeyData.forEach(function(test) {
            allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
                invalidUsages(validUsages(vector, test.format, test.data)).forEach(function(usages) {
                    [true, false].forEach(function(extractable) {
                        testError(test.format, algorithm, test.data, name, usages, extractable, "SyntaxError", "Bad usages");
                    });
                });
            });
        });
    });

    // Algorithms normalize okay, usages ok. The length of the key must thouw a DataError exception.
    testVectors.forEach(function(vector) {
        var name = vector.name;
        badKeyLengthData.forEach(function(test) {
            allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
                allValidUsages(validUsages(vector, test.format, test.data)).forEach(function(usages) {
                    [true, false].forEach(function(extractable) {
                        testError(test.format, algorithm, test.data, name, usages, extractable, "DataError", "Bad key length");
                    });
                });
            });
        });
    });

    // Algorithms normalize okay, usages ok and valid key. The lack of the mandatory JWK parameter must throw a syntax error.
    testVectors.forEach(function(vector) {
        var name = vector.name;
        missingJWKFieldKeyData.forEach(function(test) {
            allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
                allValidUsages(validUsages(vector, 'jwk', test.data)).forEach(function(usages) {
                    [true, false].forEach(function(extractable) {
                        testError('jwk', algorithm, test.data, name, usages, extractable, "DataError", "Missing JWK '" + test.param + "' parameter");
                    });
                });
            });
        });
    });

    // Algorithms normalize okay, usages ok and valid key. The public key is not compatible with the private key.
    testVectors.forEach(function(vector) {
        var name = vector.name;
        invalidJWKKeyData.forEach(function(data) {
            allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
                allValidUsages(vector.privateUsages).forEach(function(usages) {
                    [true].forEach(function(extractable) {
                        testError('jwk', algorithm, data, name, usages, extractable, "DataError", "Invalid key pair");
                    });
                });
            });
        });
    });
}