Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / child / webcrypto / test / rsa_pss_unittest.cc
blobc56acacaad9d0b11608c40b6474d5a5c622b4d49
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/logging.h"
6 #include "base/stl_util.h"
7 #include "content/child/webcrypto/algorithm_dispatch.h"
8 #include "content/child/webcrypto/crypto_data.h"
9 #include "content/child/webcrypto/jwk.h"
10 #include "content/child/webcrypto/status.h"
11 #include "content/child/webcrypto/test/test_helpers.h"
12 #include "content/child/webcrypto/webcrypto_util.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
15 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
16 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
18 namespace content {
20 namespace webcrypto {
22 namespace {
24 bool SupportsRsaPss() {
25 #if defined(USE_OPENSSL)
26 return true;
27 #else
28 return false;
29 #endif
32 blink::WebCryptoAlgorithm CreateRsaPssAlgorithm(
33 unsigned int salt_length_bytes) {
34 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
35 blink::WebCryptoAlgorithmIdRsaPss,
36 new blink::WebCryptoRsaPssParams(salt_length_bytes));
39 // Test that no two RSA-PSS signatures are identical, when using a non-zero
40 // lengthed salt.
41 TEST(WebCryptoRsaPssTest, SignIsRandom) {
42 if (!SupportsRsaPss()) {
43 LOG(WARNING) << "Skipping test because RSA-PSS is not supported";
44 return;
47 // Import public/private key pair.
48 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
49 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
51 ImportRsaKeyPair(
52 HexStringToBytes(kPublicKeySpkiDerHex),
53 HexStringToBytes(kPrivateKeyPkcs8DerHex),
54 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
55 blink::WebCryptoAlgorithmIdSha1),
56 true, blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign,
57 &public_key, &private_key);
59 // Use a 20-byte length salt.
60 blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(20);
62 // Some random message to sign.
63 std::vector<uint8_t> message = HexStringToBytes(kPublicKeySpkiDerHex);
65 // Sign twice.
66 std::vector<uint8_t> signature1;
67 std::vector<uint8_t> signature2;
69 ASSERT_EQ(Status::Success(),
70 Sign(params, private_key, CryptoData(message), &signature1));
71 ASSERT_EQ(Status::Success(),
72 Sign(params, private_key, CryptoData(message), &signature2));
74 // The signatures will be different because of the salt.
75 EXPECT_NE(CryptoData(signature1), CryptoData(signature2));
77 // However both signatures should work when verifying.
78 bool is_match = false;
80 ASSERT_EQ(Status::Success(),
81 Verify(params, public_key, CryptoData(signature1),
82 CryptoData(message), &is_match));
83 EXPECT_TRUE(is_match);
85 ASSERT_EQ(Status::Success(),
86 Verify(params, public_key, CryptoData(signature2),
87 CryptoData(message), &is_match));
88 EXPECT_TRUE(is_match);
90 // Corrupt the signature and verification must fail.
91 ASSERT_EQ(Status::Success(),
92 Verify(params, public_key, CryptoData(Corrupted(signature2)),
93 CryptoData(message), &is_match));
94 EXPECT_FALSE(is_match);
97 // Try signing and verifying when the salt length is 0. The signature in this
98 // case is not random.
99 TEST(WebCryptoRsaPssTest, SignVerifyNoSalt) {
100 if (!SupportsRsaPss()) {
101 LOG(WARNING) << "Skipping test because RSA-PSS is not supported";
102 return;
105 // Import public/private key pair.
106 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
107 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
109 ImportRsaKeyPair(
110 HexStringToBytes(kPublicKeySpkiDerHex),
111 HexStringToBytes(kPrivateKeyPkcs8DerHex),
112 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
113 blink::WebCryptoAlgorithmIdSha1),
114 true, blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign,
115 &public_key, &private_key);
117 // Zero-length salt.
118 blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(0);
120 // Some random message to sign.
121 std::vector<uint8_t> message = HexStringToBytes(kPublicKeySpkiDerHex);
123 // Sign twice.
124 std::vector<uint8_t> signature1;
125 std::vector<uint8_t> signature2;
127 ASSERT_EQ(Status::Success(),
128 Sign(params, private_key, CryptoData(message), &signature1));
129 ASSERT_EQ(Status::Success(),
130 Sign(params, private_key, CryptoData(message), &signature2));
132 // The signatures will be the same this time.
133 EXPECT_EQ(CryptoData(signature1), CryptoData(signature2));
135 // Make sure that verification works.
136 bool is_match = false;
137 ASSERT_EQ(Status::Success(),
138 Verify(params, public_key, CryptoData(signature1),
139 CryptoData(message), &is_match));
140 EXPECT_TRUE(is_match);
142 // Corrupt the signature and verification must fail.
143 ASSERT_EQ(Status::Success(),
144 Verify(params, public_key, CryptoData(Corrupted(signature2)),
145 CryptoData(message), &is_match));
146 EXPECT_FALSE(is_match);
149 TEST(WebCryptoRsaPssTest, SignEmptyMessage) {
150 if (!SupportsRsaPss()) {
151 LOG(WARNING) << "Skipping test because RSA-PSS is not supported";
152 return;
155 // Import public/private key pair.
156 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
157 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
159 ImportRsaKeyPair(
160 HexStringToBytes(kPublicKeySpkiDerHex),
161 HexStringToBytes(kPrivateKeyPkcs8DerHex),
162 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
163 blink::WebCryptoAlgorithmIdSha1),
164 true, blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign,
165 &public_key, &private_key);
167 blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(20);
168 std::vector<uint8_t> message; // Empty message.
169 std::vector<uint8_t> signature;
171 ASSERT_EQ(Status::Success(),
172 Sign(params, private_key, CryptoData(message), &signature));
174 // Make sure that verification works.
175 bool is_match = false;
176 ASSERT_EQ(Status::Success(), Verify(params, public_key, CryptoData(signature),
177 CryptoData(message), &is_match));
178 EXPECT_TRUE(is_match);
180 // Corrupt the signature and verification must fail.
181 ASSERT_EQ(Status::Success(),
182 Verify(params, public_key, CryptoData(Corrupted(signature)),
183 CryptoData(message), &is_match));
184 EXPECT_FALSE(is_match);
187 // Iterate through known answers and test verification.
188 // * Verify over original message should succeed
189 // * Verify over corrupted message should fail
190 // * Verification with corrupted signature should fail
191 TEST(WebCryptoRsaPssTest, VerifyKnownAnswer) {
192 if (!SupportsRsaPss()) {
193 LOG(WARNING) << "Skipping test because RSA-PSS is not supported";
194 return;
197 scoped_ptr<base::DictionaryValue> test_data;
198 ASSERT_TRUE(ReadJsonTestFileToDictionary("rsa_pss.json", &test_data));
200 const base::DictionaryValue* keys_dict = NULL;
201 ASSERT_TRUE(test_data->GetDictionary("keys", &keys_dict));
203 const base::ListValue* tests = NULL;
204 ASSERT_TRUE(test_data->GetList("tests", &tests));
206 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
207 SCOPED_TRACE(test_index);
209 const base::DictionaryValue* test;
210 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
212 blink::WebCryptoAlgorithm hash = GetDigestAlgorithm(test, "hash");
214 std::string key_name;
215 ASSERT_TRUE(test->GetString("key", &key_name));
217 // Import the public key.
218 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
219 std::vector<uint8_t> spki_bytes =
220 GetBytesFromHexString(keys_dict, key_name);
222 ASSERT_EQ(Status::Success(),
223 ImportKey(blink::WebCryptoKeyFormatSpki, CryptoData(spki_bytes),
224 CreateRsaHashedImportAlgorithm(
225 blink::WebCryptoAlgorithmIdRsaPss, hash.id()),
226 true, blink::WebCryptoKeyUsageVerify, &public_key));
228 int saltLength;
229 ASSERT_TRUE(test->GetInteger("saltLength", &saltLength));
231 std::vector<uint8_t> message = GetBytesFromHexString(test, "message");
232 std::vector<uint8_t> signature = GetBytesFromHexString(test, "signature");
234 // Test that verification returns true when it should.
235 bool is_match = false;
236 ASSERT_EQ(Status::Success(),
237 Verify(CreateRsaPssAlgorithm(saltLength), public_key,
238 CryptoData(signature), CryptoData(message), &is_match));
239 EXPECT_TRUE(is_match);
241 // Corrupt the message and make sure that verification fails.
242 ASSERT_EQ(Status::Success(),
243 Verify(CreateRsaPssAlgorithm(saltLength), public_key,
244 CryptoData(signature), CryptoData(Corrupted(message)),
245 &is_match));
246 EXPECT_FALSE(is_match);
248 // Corrupt the signature and make sure that verification fails.
249 ASSERT_EQ(Status::Success(),
250 Verify(CreateRsaPssAlgorithm(saltLength), public_key,
251 CryptoData(Corrupted(signature)), CryptoData(message),
252 &is_match));
253 EXPECT_FALSE(is_match);
257 } // namespace
259 } // namespace webcrypto
261 } // namespace content