blob: 5017ae24818304f757e61f53d36b9fbc772da85e [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/values.h"
#include "components/webcrypto/algorithm_dispatch.h"
#include "components/webcrypto/algorithms/test_helpers.h"
#include "components/webcrypto/crypto_data.h"
#include "components/webcrypto/status.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
#include "third_party/blink/public/platform/web_crypto_key.h"
#include "third_party/blink/public/platform/web_crypto_key_algorithm.h"
namespace webcrypto {
namespace {
// Helper for ImportJwkRsaFailures. Restores the JWK JSON
// dictionary to a good state
void RestoreJwkRsaDictionary(base::DictionaryValue* dict) {
dict->Clear();
dict->SetString("kty", "RSA");
dict->SetString("alg", "RS256");
dict->SetString("use", "sig");
dict->SetBoolean("ext", false);
dict->SetString(
"n",
"qLOyhK-OtQs4cDSoYPFGxJGfMYdjzWxVmMiuSBGh4KvEx-CwgtaTpef87Wdc9GaFEncsDLxk"
"p0LGxjD1M8jMcvYq6DPEC_JYQumEu3i9v5fAEH1VvbZi9cTg-rmEXLUUjvc5LdOq_5OuHmtm"
"e7PUJHYW1PW6ENTP0ibeiNOfFvs");
dict->SetString("e", "AQAB");
}
class WebCryptoRsaSsaTest : public WebCryptoTestBase {};
TEST_F(WebCryptoRsaSsaTest, ImportExportSpki) {
// Passing case: Import a valid RSA key in SPKI format.
blink::WebCryptoKey key;
ASSERT_EQ(Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true, blink::kWebCryptoKeyUsageVerify, &key));
EXPECT_TRUE(key.Handle());
EXPECT_EQ(blink::kWebCryptoKeyTypePublic, key.GetType());
EXPECT_TRUE(key.Extractable());
EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, key.Usages());
EXPECT_EQ(kModulusLengthBits,
key.Algorithm().RsaHashedParams()->ModulusLengthBits());
EXPECT_BYTES_EQ_HEX(
"010001",
CryptoData(key.Algorithm().RsaHashedParams()->PublicExponent()));
// Failing case: Import RSA key but provide an inconsistent input algorithm.
EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
blink::kWebCryptoKeyUsageEncrypt, &key));
// Passing case: Export a previously imported RSA public key in SPKI format
// and compare to original data.
std::vector<uint8_t> output;
ASSERT_EQ(Status::Success(),
ExportKey(blink::kWebCryptoKeyFormatSpki, key, &output));
EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, output);
// Failing case: Try to export a previously imported RSA public key in raw
// format (not allowed for a public key).
EXPECT_EQ(Status::ErrorUnsupportedExportKeyFormat(),
ExportKey(blink::kWebCryptoKeyFormatRaw, key, &output));
// Failing case: Try to export a non-extractable key
ASSERT_EQ(Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
false, blink::kWebCryptoKeyUsageVerify, &key));
EXPECT_TRUE(key.Handle());
EXPECT_FALSE(key.Extractable());
EXPECT_EQ(Status::ErrorKeyNotExtractable(),
ExportKey(blink::kWebCryptoKeyFormatSpki, key, &output));
// TODO(eroman): Failing test: Import a SPKI with an unrecognized hash OID
// TODO(eroman): Failing test: Import a SPKI with invalid algorithm params
// TODO(eroman): Failing test: Import a SPKI with inconsistent parameters
// (e.g. SHA-1 in OID, SHA-256 in params)
// TODO(eroman): Failing test: Import a SPKI for RSA-SSA, but with params
// as OAEP/PSS
}
TEST_F(WebCryptoRsaSsaTest, ImportExportPkcs8) {
// Passing case: Import a valid RSA key in PKCS#8 format.
blink::WebCryptoKey key;
ASSERT_EQ(Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha1),
true, blink::kWebCryptoKeyUsageSign, &key));
EXPECT_TRUE(key.Handle());
EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, key.GetType());
EXPECT_TRUE(key.Extractable());
EXPECT_EQ(blink::kWebCryptoKeyUsageSign, key.Usages());
EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
key.Algorithm().RsaHashedParams()->GetHash().Id());
EXPECT_EQ(kModulusLengthBits,
key.Algorithm().RsaHashedParams()->ModulusLengthBits());
EXPECT_BYTES_EQ_HEX(
"010001",
CryptoData(key.Algorithm().RsaHashedParams()->PublicExponent()));
std::vector<uint8_t> exported_key;
ASSERT_EQ(Status::Success(),
ExportKey(blink::kWebCryptoKeyFormatPkcs8, key, &exported_key));
EXPECT_BYTES_EQ_HEX(kPrivateKeyPkcs8DerHex, exported_key);
// Failing case: Import RSA key but provide an inconsistent input algorithm
// and usage. Several issues here:
// * AES-CBC doesn't support PKCS8 key format
// * AES-CBC doesn't support "sign" usage
EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
blink::kWebCryptoKeyUsageSign, &key));
}
// Tests JWK import and export by doing a roundtrip key conversion and ensuring
// it was lossless:
//
// PKCS8 --> JWK --> PKCS8
TEST_F(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkToPkcs8RoundTrip) {
blink::WebCryptoKey key;
ASSERT_EQ(Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha1),
true, blink::kWebCryptoKeyUsageSign, &key));
std::vector<uint8_t> exported_key_jwk;
ASSERT_EQ(Status::Success(),
ExportKey(blink::kWebCryptoKeyFormatJwk, key, &exported_key_jwk));
// All of the optional parameters (p, q, dp, dq, qi) should be present in the
// output.
const char* expected_jwk =
"{\"alg\":\"RS1\",\"d\":\"M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
"kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
"GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU\",\"dp\":"
"\"KPoTk4ZVvh-"
"KFZy6ylpy6hkMMAieGc0nSlVvNsT24Z9VSzTAd3kEJ7vdjdPt4kSDKPOF2Bsw6OQ7L_-"
"gJ4YZeQ\",\"dq\":\"Gos485j6cSBJiY1_t57gp3ZoeRKZzfoJ78DlB6yyHtdDAe9b_Ui-"
"RV6utuFnglWCdYCo5OjhQVHRUQqCo_LnKQ\",\"e\":\"AQAB\",\"ext\":true,\"key_"
"ops\":[\"sign\"],\"kty\":\"RSA\",\"n\":"
"\"pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
"1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
"DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc\",\"p\":\"5-"
"iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31WhU1vZs8w0Fg"
"s7bc0-2o5kQw\",\"q\":\"tp3KHPfU1-yB51uQ_MqHSrzeEj_"
"ScAGAqpBHm25I3o1n7ST58Z2FuidYdPVCzSDccj5pYzZKH5QlRSsmmmeZ_Q\",\"qi\":"
"\"JxVqukEm0kqB86Uoy_sn9WiG-"
"ECp9uhuF6RLlP6TGVhLjiL93h5aLjvYqluo2FhBlOshkKz4MrhH8To9JKefTQ\"}";
ASSERT_EQ(CryptoData(std::string(expected_jwk)),
CryptoData(exported_key_jwk));
ASSERT_EQ(
Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(exported_key_jwk),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha1),
true, blink::kWebCryptoKeyUsageSign, &key));
std::vector<uint8_t> exported_key_pkcs8;
ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatPkcs8, key,
&exported_key_pkcs8));
ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CryptoData(exported_key_pkcs8));
}
// Tests importing multiple RSA private keys from JWK, and then exporting to
// PKCS8.
//
// This is a regression test for http://crbug.com/378315, for which importing
// a sequence of keys from JWK could yield the wrong key. The first key would
// be imported correctly, however every key after that would actually import
// the first key.
TEST_F(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) {
std::unique_ptr<base::ListValue> key_list;
ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
// For this test to be meaningful the keys MUST be kept alive before importing
// new keys.
std::vector<blink::WebCryptoKey> live_keys;
for (size_t key_index = 0; key_index < key_list->GetSize(); ++key_index) {
SCOPED_TRACE(key_index);
base::DictionaryValue* key_values;
ASSERT_TRUE(key_list->GetDictionary(key_index, &key_values));
// Get the JWK representation of the key.
base::DictionaryValue* key_jwk;
ASSERT_TRUE(key_values->GetDictionary("jwk", &key_jwk));
// Get the PKCS8 representation of the key.
std::string pkcs8_hex_string;
ASSERT_TRUE(key_values->GetString("pkcs8", &pkcs8_hex_string));
std::vector<uint8_t> pkcs8_bytes = HexStringToBytes(pkcs8_hex_string);
// Get the modulus length for the key.
int modulus_length_bits = 0;
ASSERT_TRUE(key_values->GetInteger("modulusLength", &modulus_length_bits));
blink::WebCryptoKey private_key;
// Import the key from JWK.
ASSERT_EQ(Status::Success(),
ImportKeyJwkFromDict(
*key_jwk,
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true, blink::kWebCryptoKeyUsageSign, &private_key));
live_keys.push_back(private_key);
EXPECT_EQ(
modulus_length_bits,
static_cast<int>(
private_key.Algorithm().RsaHashedParams()->ModulusLengthBits()));
// Export to PKCS8 and verify that it matches expectation.
std::vector<uint8_t> exported_key_pkcs8;
ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatPkcs8,
private_key, &exported_key_pkcs8));
EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8);
}
}
// Import an RSA private key using JWK. Next import a JWK containing the same
// modulus, but mismatched parameters for the rest. It should NOT be possible
// that the second import retrieves the first key. See http://crbug.com/378315
// for how that could happen.
TEST_F(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
std::unique_ptr<base::ListValue> key_list;
ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
// Import a 1024-bit private key.
base::DictionaryValue* key1_props;
ASSERT_TRUE(key_list->GetDictionary(1, &key1_props));
base::DictionaryValue* key1_jwk;
ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk));
blink::WebCryptoKey key1;
ASSERT_EQ(
Status::Success(),
ImportKeyJwkFromDict(*key1_jwk,
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true, blink::kWebCryptoKeyUsageSign, &key1));
ASSERT_EQ(1024u, key1.Algorithm().RsaHashedParams()->ModulusLengthBits());
// Construct a JWK using the modulus of key1, but all the other fields from
// another key (also a 1024-bit private key).
base::DictionaryValue* key2_props;
ASSERT_TRUE(key_list->GetDictionary(5, &key2_props));
base::DictionaryValue* key2_jwk;
ASSERT_TRUE(key2_props->GetDictionary("jwk", &key2_jwk));
std::string modulus;
key1_jwk->GetString("n", &modulus);
key2_jwk->SetString("n", modulus);
// This should fail, as the n,e,d parameters are not consistent. It MUST NOT
// somehow return the key created earlier.
blink::WebCryptoKey key2;
ASSERT_EQ(
Status::OperationError(),
ImportKeyJwkFromDict(*key2_jwk,
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true, blink::kWebCryptoKeyUsageSign, &key2));
}
TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
// Note: using unrealistic short key lengths here to avoid bogging down tests.
// Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha256)
const unsigned int modulus_length = 256;
const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256, modulus_length, public_exponent);
bool extractable = true;
const blink::WebCryptoKeyUsageMask public_usages =
blink::kWebCryptoKeyUsageVerify;
const blink::WebCryptoKeyUsageMask private_usages =
blink::kWebCryptoKeyUsageSign;
const blink::WebCryptoKeyUsageMask usages = public_usages | private_usages;
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, extractable, usages,
&public_key, &private_key));
ASSERT_FALSE(public_key.IsNull());
ASSERT_FALSE(private_key.IsNull());
EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key.GetType());
EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key.GetType());
EXPECT_EQ(modulus_length,
public_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
EXPECT_EQ(modulus_length,
private_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
public_key.Algorithm().RsaHashedParams()->GetHash().Id());
EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
private_key.Algorithm().RsaHashedParams()->GetHash().Id());
EXPECT_TRUE(public_key.Extractable());
EXPECT_EQ(extractable, private_key.Extractable());
EXPECT_EQ(public_usages, public_key.Usages());
EXPECT_EQ(private_usages, private_key.Usages());
// Try exporting the generated key pair, and then re-importing to verify that
// the exported data was valid.
std::vector<uint8_t> public_key_spki;
EXPECT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatSpki,
public_key, &public_key_spki));
public_key = blink::WebCryptoKey::CreateNull();
ASSERT_EQ(
Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatSpki, CryptoData(public_key_spki),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true, public_usages, &public_key));
EXPECT_EQ(modulus_length,
public_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
std::vector<uint8_t> private_key_pkcs8;
EXPECT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatPkcs8,
private_key, &private_key_pkcs8));
private_key = blink::WebCryptoKey::CreateNull();
ASSERT_EQ(
Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatPkcs8, CryptoData(private_key_pkcs8),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true, private_usages, &private_key));
EXPECT_EQ(modulus_length,
private_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
// Fail with bad modulus.
algorithm = CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256, 0, public_exponent);
EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
GenerateKeyPair(algorithm, extractable, usages, &public_key,
&private_key));
// Fail with bad exponent: larger than unsigned long.
unsigned int exponent_length = sizeof(unsigned long) + 1; // NOLINT
const std::vector<uint8_t> long_exponent(exponent_length, 0x01);
algorithm = CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256, modulus_length, long_exponent);
EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
GenerateKeyPair(algorithm, extractable, usages, &public_key,
&private_key));
// Fail with bad exponent: empty.
const std::vector<uint8_t> empty_exponent;
algorithm = CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256, modulus_length, empty_exponent);
EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
GenerateKeyPair(algorithm, extractable, usages, &public_key,
&private_key));
// Fail with bad exponent: all zeros.
std::vector<uint8_t> exponent_with_leading_zeros(15, 0x00);
algorithm = CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256, modulus_length,
exponent_with_leading_zeros);
EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
GenerateKeyPair(algorithm, extractable, usages, &public_key,
&private_key));
// Key generation success using exponent with leading zeros.
exponent_with_leading_zeros.insert(exponent_with_leading_zeros.end(),
public_exponent.begin(),
public_exponent.end());
algorithm = CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256, modulus_length,
exponent_with_leading_zeros);
EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, extractable, usages,
&public_key, &private_key));
EXPECT_FALSE(public_key.IsNull());
EXPECT_FALSE(private_key.IsNull());
EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key.GetType());
EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key.GetType());
EXPECT_TRUE(public_key.Extractable());
EXPECT_EQ(extractable, private_key.Extractable());
EXPECT_EQ(public_usages, public_key.Usages());
EXPECT_EQ(private_usages, private_key.Usages());
// Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha1)
algorithm = CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha1, modulus_length, public_exponent);
EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, false, usages,
&public_key, &private_key));
EXPECT_FALSE(public_key.IsNull());
EXPECT_FALSE(private_key.IsNull());
EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key.GetType());
EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key.GetType());
EXPECT_EQ(modulus_length,
public_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
EXPECT_EQ(modulus_length,
private_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
public_key.Algorithm().RsaHashedParams()->GetHash().Id());
EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
private_key.Algorithm().RsaHashedParams()->GetHash().Id());
// Even though "extractable" was set to false, the public key remains
// extractable.
EXPECT_TRUE(public_key.Extractable());
EXPECT_FALSE(private_key.Extractable());
EXPECT_EQ(public_usages, public_key.Usages());
EXPECT_EQ(private_usages, private_key.Usages());
// Exporting a private key as SPKI format doesn't make sense. However this
// will first fail because the key is not extractable.
std::vector<uint8_t> output;
EXPECT_EQ(Status::ErrorKeyNotExtractable(),
ExportKey(blink::kWebCryptoKeyFormatSpki, private_key, &output));
// Re-generate an extractable private_key and try to export it as SPKI format.
// This should fail since spki is for public keys.
EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, true, usages,
&public_key, &private_key));
EXPECT_EQ(Status::ErrorUnexpectedKeyType(),
ExportKey(blink::kWebCryptoKeyFormatSpki, private_key, &output));
}
TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadModulusLength) {
const unsigned int kBadModulusBits[] = {
0,
248, // Too small.
257, // Not a multiple of 8.
1023, // Not a multiple of 8.
0xFFFFFFFF, // Too big.
16384 + 8, // 16384 is the maxmimum length that NSS succeeds for.
};
const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
for (size_t i = 0; i < base::size(kBadModulusBits); ++i) {
const unsigned int modulus_length_bits = kBadModulusBits[i];
blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256, modulus_length_bits,
public_exponent);
bool extractable = true;
const blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageSign;
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
GenerateKeyPair(algorithm, extractable, usages, &public_key,
&private_key));
}
}
// Try generating RSA key pairs using unsupported public exponents. Only
// exponents of 3 and 65537 are supported. Although OpenSSL can support other
// values, it can also hang when given invalid exponents. To avoid hanging, use
// a whitelist of known safe exponents.
TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadExponent) {
const unsigned int modulus_length = 1024;
const char* const kPublicExponents[] = {
"11", // 17 - This is a valid public exponent, but currently disallowed.
"00",
"01",
"02",
"010000", // 65536
};
for (size_t i = 0; i < base::size(kPublicExponents); ++i) {
SCOPED_TRACE(i);
blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256, modulus_length,
HexStringToBytes(kPublicExponents[i]));
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
GenerateKeyPair(algorithm, true, blink::kWebCryptoKeyUsageSign,
&public_key, &private_key));
}
}
TEST_F(WebCryptoRsaSsaTest, SignVerifyFailures) {
// Import a key pair.
blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha1);
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
HexStringToBytes(kPublicKeySpkiDerHex),
HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
&public_key, &private_key));
blink::WebCryptoAlgorithm algorithm =
CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
std::vector<uint8_t> signature;
bool signature_match;
// Compute a signature.
const std::vector<uint8_t> data = HexStringToBytes("010203040506070809");
ASSERT_EQ(Status::Success(),
Sign(algorithm, private_key, CryptoData(data), &signature));
// Ensure truncated signature does not verify by passing one less byte.
EXPECT_EQ(Status::Success(),
Verify(algorithm, public_key,
CryptoData(signature.data(),
static_cast<unsigned int>(signature.size()) - 1),
CryptoData(data), &signature_match));
EXPECT_FALSE(signature_match);
// Ensure truncated signature does not verify by passing no bytes.
EXPECT_EQ(Status::Success(), Verify(algorithm, public_key, CryptoData(),
CryptoData(data), &signature_match));
EXPECT_FALSE(signature_match);
// Ensure corrupted signature does not verify.
std::vector<uint8_t> corrupt_sig = signature;
corrupt_sig[corrupt_sig.size() / 2] ^= 0x1;
EXPECT_EQ(Status::Success(),
Verify(algorithm, public_key, CryptoData(corrupt_sig),
CryptoData(data), &signature_match));
EXPECT_FALSE(signature_match);
// Ensure signatures that are greater than the modulus size fail.
const unsigned int long_message_size_bytes = 1024;
DCHECK_GT(long_message_size_bytes, kModulusLengthBits / 8);
const unsigned char kLongSignature[long_message_size_bytes] = {0};
EXPECT_EQ(Status::Success(),
Verify(algorithm, public_key,
CryptoData(kLongSignature, sizeof(kLongSignature)),
CryptoData(data), &signature_match));
EXPECT_FALSE(signature_match);
// Ensure that signing and verifying with an incompatible algorithm fails.
algorithm = CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep);
EXPECT_EQ(Status::ErrorUnexpected(),
Sign(algorithm, private_key, CryptoData(data), &signature));
EXPECT_EQ(Status::ErrorUnexpected(),
Verify(algorithm, public_key, CryptoData(signature),
CryptoData(data), &signature_match));
// Some crypto libraries (NSS) can automatically select the RSA SSA inner hash
// based solely on the contents of the input signature data. In the Web Crypto
// implementation, the inner hash should be specified uniquely by the key
// algorithm parameter. To validate this behavior, call Verify with a computed
// signature that used one hash type (SHA-1), but pass in a key with a
// different inner hash type (SHA-256). If the hash type is determined by the
// signature itself (undesired), the verify will pass, while if the hash type
// is specified by the key algorithm (desired), the verify will fail.
// Compute a signature using SHA-1 as the inner hash.
EXPECT_EQ(Status::Success(),
Sign(CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
private_key, CryptoData(data), &signature));
blink::WebCryptoKey public_key_256;
EXPECT_EQ(Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true, blink::kWebCryptoKeyUsageVerify, &public_key_256));
// Now verify using an algorithm whose inner hash is SHA-256, not SHA-1. The
// signature should not verify.
// NOTE: public_key was produced by generateKey, and so its associated
// algorithm has WebCryptoRsaKeyGenParams and not WebCryptoRsaSsaParams. Thus
// it has no inner hash to conflict with the input algorithm.
EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
private_key.Algorithm().RsaHashedParams()->GetHash().Id());
EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
public_key_256.Algorithm().RsaHashedParams()->GetHash().Id());
bool is_match;
EXPECT_EQ(Status::Success(),
Verify(CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
public_key_256, CryptoData(signature), CryptoData(data),
&is_match));
EXPECT_FALSE(is_match);
}
TEST_F(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
std::unique_ptr<base::ListValue> tests;
ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests));
// Import the key pair.
blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha1);
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
HexStringToBytes(kPublicKeySpkiDerHex),
HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
&public_key, &private_key));
blink::WebCryptoAlgorithm algorithm =
CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
// Validate the signatures are computed and verified as expected.
std::vector<uint8_t> signature;
for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
SCOPED_TRACE(test_index);
base::DictionaryValue* test;
ASSERT_TRUE(tests->GetDictionary(test_index, &test));
std::vector<uint8_t> test_message =
GetBytesFromHexString(test, "message_hex");
std::vector<uint8_t> test_signature =
GetBytesFromHexString(test, "signature_hex");
signature.clear();
ASSERT_EQ(Status::Success(), Sign(algorithm, private_key,
CryptoData(test_message), &signature));
EXPECT_BYTES_EQ(test_signature, signature);
bool is_match = false;
ASSERT_EQ(Status::Success(),
Verify(algorithm, public_key, CryptoData(test_signature),
CryptoData(test_message), &is_match));
EXPECT_TRUE(is_match);
}
}
// Try importing an RSA-SSA public key with unsupported key usages using SPKI
// format. RSA-SSA public keys only support the 'verify' usage.
TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_SPKI) {
const blink::WebCryptoAlgorithm algorithm = CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256);
blink::WebCryptoKeyUsageMask bad_usages[] = {
blink::kWebCryptoKeyUsageSign,
blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
blink::kWebCryptoKeyUsageEncrypt,
blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
};
for (size_t i = 0; i < base::size(bad_usages); ++i) {
SCOPED_TRACE(i);
blink::WebCryptoKey public_key;
ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
algorithm, false, bad_usages[i], &public_key));
}
}
// Try importing an RSA-SSA public key with unsupported key usages using JWK
// format. RSA-SSA public keys only support the 'verify' usage.
TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_JWK) {
const blink::WebCryptoAlgorithm algorithm = CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256);
blink::WebCryptoKeyUsageMask bad_usages[] = {
blink::kWebCryptoKeyUsageSign,
blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
blink::kWebCryptoKeyUsageEncrypt,
blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
};
base::DictionaryValue dict;
RestoreJwkRsaDictionary(&dict);
dict.Remove("use", nullptr);
dict.SetString("alg", "RS256");
for (size_t i = 0; i < base::size(bad_usages); ++i) {
SCOPED_TRACE(i);
blink::WebCryptoKey public_key;
ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
ImportKeyJwkFromDict(dict, algorithm, false, bad_usages[i],
&public_key));
}
}
// Generate an RSA-SSA key pair with invalid usages. RSA-SSA supports:
// 'sign', 'verify'
TEST_F(WebCryptoRsaSsaTest, GenerateKeyBadUsages) {
blink::WebCryptoKeyUsageMask bad_usages[] = {
blink::kWebCryptoKeyUsageDecrypt,
blink::kWebCryptoKeyUsageVerify | blink::kWebCryptoKeyUsageDecrypt,
blink::kWebCryptoKeyUsageWrapKey,
};
const unsigned int modulus_length = 256;
const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
for (size_t i = 0; i < base::size(bad_usages); ++i) {
SCOPED_TRACE(i);
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256,
modulus_length, public_exponent),
true, bad_usages[i], &public_key, &private_key));
}
}
// Generate an RSA-SSA key pair. The public and private keys should select the
// key usages which are applicable, and not have the exact same usages as was
// specified to GenerateKey
TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairIntersectUsages) {
const unsigned int modulus_length = 256;
const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_EQ(
Status::Success(),
GenerateKeyPair(
CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256, modulus_length,
public_exponent),
true, blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
&public_key, &private_key));
EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, public_key.Usages());
EXPECT_EQ(blink::kWebCryptoKeyUsageSign, private_key.Usages());
// Try again but this time without the Verify usages.
ASSERT_EQ(Status::Success(),
GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256,
modulus_length, public_exponent),
true, blink::kWebCryptoKeyUsageSign, &public_key,
&private_key));
EXPECT_EQ(0, public_key.Usages());
EXPECT_EQ(blink::kWebCryptoKeyUsageSign, private_key.Usages());
}
TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairEmptyUsages) {
const unsigned int modulus_length = 256;
const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256,
modulus_length, public_exponent),
true, 0, &public_key, &private_key));
}
TEST_F(WebCryptoRsaSsaTest, ImportKeyEmptyUsages) {
blink::WebCryptoKey public_key;
blink::WebCryptoKey private_key;
// Public without usage does not throw an error.
ASSERT_EQ(Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true, 0, &public_key));
EXPECT_EQ(0, public_key.Usages());
// Private empty usage will throw an error.
ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha1),
true, 0, &private_key));
std::vector<uint8_t> public_jwk;
ASSERT_EQ(Status::Success(),
ExportKey(blink::kWebCryptoKeyFormatJwk, public_key, &public_jwk));
ASSERT_EQ(Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(public_jwk),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true, 0, &public_key));
EXPECT_EQ(0, public_key.Usages());
// With correct usage to get correct imported private_key
std::vector<uint8_t> private_jwk;
ImportKey(blink::kWebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha1),
true, blink::kWebCryptoKeyUsageSign, &private_key);
ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatJwk,
private_key, &private_jwk));
ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(private_jwk),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha1),
true, 0, &private_key));
}
TEST_F(WebCryptoRsaSsaTest, ImportExportJwkRsaPublicKey) {
struct TestCase {
const blink::WebCryptoAlgorithmId hash;
const blink::WebCryptoKeyUsageMask usage;
const char* const jwk_alg;
};
const TestCase kTests[] = {{blink::kWebCryptoAlgorithmIdSha1,
blink::kWebCryptoKeyUsageVerify, "RS1"},
{blink::kWebCryptoAlgorithmIdSha256,
blink::kWebCryptoKeyUsageVerify, "RS256"},
{blink::kWebCryptoAlgorithmIdSha384,
blink::kWebCryptoKeyUsageVerify, "RS384"},
{blink::kWebCryptoAlgorithmIdSha512,
blink::kWebCryptoKeyUsageVerify, "RS512"}};
for (size_t test_index = 0; test_index < base::size(kTests); ++test_index) {
SCOPED_TRACE(test_index);
const TestCase& test = kTests[test_index];
const blink::WebCryptoAlgorithm import_algorithm =
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5, test.hash);
// Import the spki to create a public key
blink::WebCryptoKey public_key;
ASSERT_EQ(Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatSpki,
CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
import_algorithm, true, test.usage, &public_key));
// Export the public key as JWK and verify its contents
std::vector<uint8_t> jwk;
ASSERT_EQ(Status::Success(),
ExportKey(blink::kWebCryptoKeyFormatJwk, public_key, &jwk));
EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, kPublicKeyModulusHex,
kPublicKeyExponentHex, test.usage));
// Import the JWK back in to create a new key
blink::WebCryptoKey public_key2;
ASSERT_EQ(Status::Success(),
ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(jwk),
import_algorithm, true, test.usage, &public_key2));
ASSERT_TRUE(public_key2.Handle());
EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key2.GetType());
EXPECT_TRUE(public_key2.Extractable());
EXPECT_EQ(import_algorithm.Id(), public_key2.Algorithm().Id());
// Export the new key as spki and compare to the original.
std::vector<uint8_t> spki;
ASSERT_EQ(Status::Success(),
ExportKey(blink::kWebCryptoKeyFormatSpki, public_key2, &spki));
EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, CryptoData(spki));
}
}
TEST_F(WebCryptoRsaSsaTest, ImportJwkRsaFailures) {
base::DictionaryValue dict;
RestoreJwkRsaDictionary(&dict);
blink::WebCryptoAlgorithm algorithm = CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256);
blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageVerify;
blink::WebCryptoKey key;
// An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent)
// entry, while an RSA private key must have those plus at least a "d"
// (private exponent) entry.
// See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
// section 6.3.
// Baseline pass.
EXPECT_EQ(Status::Success(),
ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
EXPECT_EQ(algorithm.Id(), key.Algorithm().Id());
EXPECT_FALSE(key.Extractable());
EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, key.Usages());
EXPECT_EQ(blink::kWebCryptoKeyTypePublic, key.GetType());
// The following are specific failure cases for when kty = "RSA".
// Fail if either "n" or "e" is not present or malformed.
const std::string kKtyParmName[] = {"n", "e"};
for (size_t idx = 0; idx < base::size(kKtyParmName); ++idx) {
// Fail on missing parameter.
dict.Remove(kKtyParmName[idx], nullptr);
EXPECT_NE(Status::Success(),
ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
RestoreJwkRsaDictionary(&dict);
// Fail on bad b64 parameter encoding.
dict.SetString(kKtyParmName[idx], "Qk3f0DsytU8lfza2au #$% Htaw2xpop9yTuH0");
EXPECT_NE(Status::Success(),
ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
RestoreJwkRsaDictionary(&dict);
// Fail on empty parameter.
dict.SetString(kKtyParmName[idx], "");
EXPECT_EQ(Status::ErrorJwkEmptyBigInteger(kKtyParmName[idx]),
ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
RestoreJwkRsaDictionary(&dict);
}
}
// Try importing an RSA-SSA key from JWK format, having specified both Sign and
// Verify usage, AND an invalid JWK.
//
// Parsing the invalid JWK will fail before the usage check is done.
TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaJwkBadUsageAndData) {
std::string bad_data = "hello";
blink::WebCryptoKey key;
ASSERT_EQ(
Status::ErrorJwkNotDictionary(),
ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(bad_data),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true,
blink::kWebCryptoKeyUsageVerify | blink::kWebCryptoKeyUsageSign,
&key));
}
// Imports invalid JWK/SPKI/PKCS8 data and verifies that it fails as expected.
TEST_F(WebCryptoRsaSsaTest, ImportInvalidKeyData) {
std::unique_ptr<base::ListValue> tests;
ASSERT_TRUE(ReadJsonTestFileToList("bad_rsa_keys.json", &tests));
for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
SCOPED_TRACE(test_index);
const base::DictionaryValue* test;
ASSERT_TRUE(tests->GetDictionary(test_index, &test));
blink::WebCryptoKeyFormat key_format = GetKeyFormatFromJsonTestCase(test);
std::vector<uint8_t> key_data =
GetKeyDataFromJsonTestCase(test, key_format);
std::string test_error;
ASSERT_TRUE(test->GetString("error", &test_error));
blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageSign;
if (key_format == blink::kWebCryptoKeyFormatSpki)
usages = blink::kWebCryptoKeyUsageVerify;
blink::WebCryptoKey key;
Status status = ImportKey(key_format, CryptoData(key_data),
CreateRsaHashedImportAlgorithm(
blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::kWebCryptoAlgorithmIdSha256),
true, usages, &key);
EXPECT_EQ(test_error, StatusToString(status));
}
}
} // namespace
} // namespace webcrypto