forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			216 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
function run_test(algorithmNames) {
 | 
						|
    var subtle = crypto.subtle; // Change to test prefixed implementations
 | 
						|
 | 
						|
    setup({explicit_timeout: true});
 | 
						|
 | 
						|
// These tests check that generateKey throws 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 generateKey, and all
 | 
						|
// valid and invalid parameters that should be checked later by
 | 
						|
// generateKey.
 | 
						|
//
 | 
						|
// There are a lot of combinations of possible parameters for both
 | 
						|
// success and failure modes, resulting in a very large number of tests
 | 
						|
// performed.
 | 
						|
 | 
						|
 | 
						|
// Setup: define the correct behaviors that should be sought, and create
 | 
						|
// helper functions that generate all possible test parameters for
 | 
						|
// different situations.
 | 
						|
 | 
						|
    var allTestVectors = [ // Parameters that should work for generateKey
 | 
						|
        {name: "AES-CTR",  resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
 | 
						|
        {name: "AES-CBC",  resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
 | 
						|
        {name: "AES-GCM",  resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
 | 
						|
        {name: "AES-KW",   resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []},
 | 
						|
        {name: "HMAC",     resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []},
 | 
						|
        {name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
 | 
						|
        {name: "RSA-PSS",  resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
 | 
						|
        {name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
 | 
						|
        {name: "ECDSA",    resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
 | 
						|
        {name: "ECDH",     resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]}
 | 
						|
    ];
 | 
						|
 | 
						|
    var testVectors = [];
 | 
						|
    if (algorithmNames && !Array.isArray(algorithmNames)) {
 | 
						|
        algorithmNames = [algorithmNames];
 | 
						|
    };
 | 
						|
    allTestVectors.forEach(function(vector) {
 | 
						|
        if (!algorithmNames || algorithmNames.includes(vector.name)) {
 | 
						|
            testVectors.push(vector);
 | 
						|
        }
 | 
						|
    });
 | 
						|
 | 
						|
 | 
						|
    function parameterString(algorithm, extractable, usages) {
 | 
						|
        if (typeof algorithm !== "object" && typeof algorithm !== "string") {
 | 
						|
            alert(algorithm);
 | 
						|
        }
 | 
						|
 | 
						|
        var result = "(" +
 | 
						|
                        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(algorithm, extractable, usages, expectedError, testTag) {
 | 
						|
        promise_test(function(test) {
 | 
						|
            return crypto.subtle.generateKey(algorithm, extractable, usages)
 | 
						|
            .then(function(result) {
 | 
						|
                assert_unreached("Operation succeeded, but should not have");
 | 
						|
            }, function(err) {
 | 
						|
                if (typeof expectedError === "number") {
 | 
						|
                    assert_equals(err.code, expectedError, testTag + " not supported");
 | 
						|
                } else {
 | 
						|
                    assert_equals(err.name, expectedError, testTag + " not supported");
 | 
						|
                }
 | 
						|
            });
 | 
						|
        }, testTag + ": generateKey" + parameterString(algorithm, extractable, usages));
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // Given an algorithm name, create several invalid parameters.
 | 
						|
    function badAlgorithmPropertySpecifiersFor(algorithmName) {
 | 
						|
        var results = [];
 | 
						|
 | 
						|
        if (algorithmName.toUpperCase().substring(0, 3) === "AES") {
 | 
						|
            // Specifier properties are name and length
 | 
						|
            [64, 127, 129, 255, 257, 512].forEach(function(length) {
 | 
						|
                results.push({name: algorithmName, length: length});
 | 
						|
            });
 | 
						|
        } else if (algorithmName.toUpperCase().substring(0, 3) === "RSA") {
 | 
						|
            [new Uint8Array([1]), new Uint8Array([1,0,0])].forEach(function(publicExponent) {
 | 
						|
                results.push({name: algorithmName, hash: "SHA-256", modulusLength: 1024, publicExponent: publicExponent});
 | 
						|
            });
 | 
						|
        } else if (algorithmName.toUpperCase().substring(0, 2) === "EC") {
 | 
						|
            ["P-512", "Curve25519"].forEach(function(curveName) {
 | 
						|
                results.push({name: algorithmName, namedCurve: curveName});
 | 
						|
            });
 | 
						|
        }
 | 
						|
 | 
						|
        return results;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    // 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 = allValidUsages(validUsages, false, mandatoryUsages);
 | 
						|
 | 
						|
        illegalUsages.forEach(function(illegalUsage) {
 | 
						|
            results.push([illegalUsage]);
 | 
						|
            goodUsageCombinations.forEach(function(usageCombination) {
 | 
						|
                results.push(usageCombination.concat([illegalUsage]));
 | 
						|
            });
 | 
						|
        });
 | 
						|
 | 
						|
        return results;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
// Now test for properly handling errors
 | 
						|
// - Unsupported algorithm
 | 
						|
// - Bad usages for algorithm
 | 
						|
// - Bad key lengths
 | 
						|
 | 
						|
    // Algorithm normalization should fail with "Not supported"
 | 
						|
    var badAlgorithmNames = [
 | 
						|
        "AES",
 | 
						|
        {name: "AES"},
 | 
						|
        {name: "AES", length: 128},
 | 
						|
        {name: "AES-CMAC", length: 128},    // Removed after CR
 | 
						|
        {name: "AES-CFB", length: 128},      // Removed after CR
 | 
						|
        {name: "HMAC", hash: "MD5"},
 | 
						|
        {name: "RSA", hash: "SHA-256", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
 | 
						|
        {name: "RSA-PSS", hash: "SHA", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
 | 
						|
        {name: "EC", namedCurve: "P521"}
 | 
						|
    ];
 | 
						|
 | 
						|
 | 
						|
    // Algorithm normalization failures should be found first
 | 
						|
    // - all other parameters can be good or bad, should fail
 | 
						|
    //   due to NotSupportedError.
 | 
						|
    badAlgorithmNames.forEach(function(algorithm) {
 | 
						|
        allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used
 | 
						|
        .forEach(function(usages) {
 | 
						|
            [false, true, "RED", 7].forEach(function(extractable){
 | 
						|
                testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm");
 | 
						|
            });
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
 | 
						|
    // 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;
 | 
						|
 | 
						|
        allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
 | 
						|
            invalidUsages(vector.usages, vector.mandatoryUsages).forEach(function(usages) {
 | 
						|
                [true].forEach(function(extractable) {
 | 
						|
                    testError(algorithm, extractable, usages, "SyntaxError", "Bad usages");
 | 
						|
                });
 | 
						|
            });
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
 | 
						|
    // Other algorithm properties should be checked next, so try good
 | 
						|
    // algorithm names and usages, but bad algorithm properties next.
 | 
						|
    // - Special case: normally bad usage [] isn't checked until after properties,
 | 
						|
    //   so it's included in this test case. It should NOT cause an error.
 | 
						|
    testVectors.forEach(function(vector) {
 | 
						|
        var name = vector.name;
 | 
						|
        badAlgorithmPropertySpecifiersFor(name).forEach(function(algorithm) {
 | 
						|
            allValidUsages(vector.usages, true, vector.mandatoryUsages)
 | 
						|
            .forEach(function(usages) {
 | 
						|
                [false, true].forEach(function(extractable) {
 | 
						|
                    if (name.substring(0,2) === "EC") {
 | 
						|
                        testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm property");
 | 
						|
                    } else {
 | 
						|
                        testError(algorithm, extractable, usages, "OperationError", "Bad algorithm property");
 | 
						|
                    }
 | 
						|
                });
 | 
						|
            });
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
 | 
						|
    // The last thing that should be checked is an empty usages (for secret keys).
 | 
						|
    testVectors.forEach(function(vector) {
 | 
						|
        var name = vector.name;
 | 
						|
 | 
						|
        allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
 | 
						|
            var usages = [];
 | 
						|
            [false, true].forEach(function(extractable) {
 | 
						|
                testError(algorithm, extractable, usages, "SyntaxError", "Empty usages");
 | 
						|
            });
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
 | 
						|
}
 |