blob: 097f6bcae6ab16903277abf1a4547b3b68d7f5de [file] [log] [blame]
eroman8793ece2014-10-20 20:47:151// 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.
4
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"
17
18namespace content {
19
20namespace webcrypto {
21
22namespace {
23
24bool SupportsRsaPss() {
25#if defined(USE_OPENSSL)
26 return true;
27#else
28 return false;
29#endif
30}
31
32blink::WebCryptoAlgorithm CreateRsaPssAlgorithm(
33 unsigned int salt_length_bytes) {
34 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
35 blink::WebCryptoAlgorithmIdRsaPss,
36 new blink::WebCryptoRsaPssParams(salt_length_bytes));
37}
38
39// Test that no two RSA-PSS signatures are identical, when using a non-zero
40// lengthed salt.
41TEST(WebCryptoRsaPssTest, SignIsRandom) {
42 if (!SupportsRsaPss()) {
43 LOG(WARNING) << "Skipping test because RSA-PSS is not supported";
44 return;
45 }
46
47 // Import public/private key pair.
48 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
49 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
50
51 ImportRsaKeyPair(
52 HexStringToBytes(kPublicKeySpkiDerHex),
53 HexStringToBytes(kPrivateKeyPkcs8DerHex),
54 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
55 blink::WebCryptoAlgorithmIdSha1),
56 true,
57 blink::WebCryptoKeyUsageVerify,
58 blink::WebCryptoKeyUsageSign,
59 &public_key,
60 &private_key);
61
62 // Use a 20-byte length salt.
63 blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(20);
64
65 // Some random message to sign.
66 std::vector<uint8_t> message = HexStringToBytes(kPublicKeySpkiDerHex);
67
68 // Sign twice.
69 std::vector<uint8_t> signature1;
70 std::vector<uint8_t> signature2;
71
72 ASSERT_EQ(Status::Success(),
73 Sign(params, private_key, CryptoData(message), &signature1));
74 ASSERT_EQ(Status::Success(),
75 Sign(params, private_key, CryptoData(message), &signature2));
76
77 // The signatures will be different because of the salt.
78 EXPECT_NE(CryptoData(signature1), CryptoData(signature2));
79
80 // However both signatures should work when verifying.
81 bool is_match = false;
82
83 ASSERT_EQ(Status::Success(),
84 Verify(params,
85 public_key,
86 CryptoData(signature1),
87 CryptoData(message),
88 &is_match));
89 EXPECT_TRUE(is_match);
90
91 ASSERT_EQ(Status::Success(),
92 Verify(params,
93 public_key,
94 CryptoData(signature2),
95 CryptoData(message),
96 &is_match));
97 EXPECT_TRUE(is_match);
98
99 // Corrupt the signature and verification must fail.
100 ASSERT_EQ(Status::Success(),
101 Verify(params,
102 public_key,
103 CryptoData(Corrupted(signature2)),
104 CryptoData(message),
105 &is_match));
106 EXPECT_FALSE(is_match);
107}
108
109// Try signing and verifying when the salt length is 0. The signature in this
110// case is not random.
111TEST(WebCryptoRsaPssTest, SignVerifyNoSalt) {
112 if (!SupportsRsaPss()) {
113 LOG(WARNING) << "Skipping test because RSA-PSS is not supported";
114 return;
115 }
116
117 // Import public/private key pair.
118 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
119 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
120
121 ImportRsaKeyPair(
122 HexStringToBytes(kPublicKeySpkiDerHex),
123 HexStringToBytes(kPrivateKeyPkcs8DerHex),
124 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
125 blink::WebCryptoAlgorithmIdSha1),
126 true,
127 blink::WebCryptoKeyUsageVerify,
128 blink::WebCryptoKeyUsageSign,
129 &public_key,
130 &private_key);
131
132 // Zero-length salt.
133 blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(0);
134
135 // Some random message to sign.
136 std::vector<uint8_t> message = HexStringToBytes(kPublicKeySpkiDerHex);
137
138 // Sign twice.
139 std::vector<uint8_t> signature1;
140 std::vector<uint8_t> signature2;
141
142 ASSERT_EQ(Status::Success(),
143 Sign(params, private_key, CryptoData(message), &signature1));
144 ASSERT_EQ(Status::Success(),
145 Sign(params, private_key, CryptoData(message), &signature2));
146
147 // The signatures will be the same this time.
148 EXPECT_EQ(CryptoData(signature1), CryptoData(signature2));
149
150 // Make sure that verification works.
151 bool is_match = false;
152 ASSERT_EQ(Status::Success(),
153 Verify(params,
154 public_key,
155 CryptoData(signature1),
156 CryptoData(message),
157 &is_match));
158 EXPECT_TRUE(is_match);
159
160 // Corrupt the signature and verification must fail.
161 ASSERT_EQ(Status::Success(),
162 Verify(params,
163 public_key,
164 CryptoData(Corrupted(signature2)),
165 CryptoData(message),
166 &is_match));
167 EXPECT_FALSE(is_match);
168}
169
170TEST(WebCryptoRsaPssTest, SignEmptyMessage) {
171 if (!SupportsRsaPss()) {
172 LOG(WARNING) << "Skipping test because RSA-PSS is not supported";
173 return;
174 }
175
176 // Import public/private key pair.
177 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
178 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
179
180 ImportRsaKeyPair(
181 HexStringToBytes(kPublicKeySpkiDerHex),
182 HexStringToBytes(kPrivateKeyPkcs8DerHex),
183 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss,
184 blink::WebCryptoAlgorithmIdSha1),
185 true,
186 blink::WebCryptoKeyUsageVerify,
187 blink::WebCryptoKeyUsageSign,
188 &public_key,
189 &private_key);
190
191 blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(20);
192 std::vector<uint8_t> message; // Empty message.
193 std::vector<uint8_t> signature;
194
195 ASSERT_EQ(Status::Success(),
196 Sign(params, private_key, CryptoData(message), &signature));
197
198 // Make sure that verification works.
199 bool is_match = false;
200 ASSERT_EQ(Status::Success(),
201 Verify(params,
202 public_key,
203 CryptoData(signature),
204 CryptoData(message),
205 &is_match));
206 EXPECT_TRUE(is_match);
207
208 // Corrupt the signature and verification must fail.
209 ASSERT_EQ(Status::Success(),
210 Verify(params,
211 public_key,
212 CryptoData(Corrupted(signature)),
213 CryptoData(message),
214 &is_match));
215 EXPECT_FALSE(is_match);
216}
217
218// Iterate through known answers and test verification.
219// * Verify over original message should succeed
220// * Verify over corrupted message should fail
221// * Verification with corrupted signature should fail
222TEST(WebCryptoRsaPssTest, VerifyKnownAnswer) {
223 if (!SupportsRsaPss()) {
224 LOG(WARNING) << "Skipping test because RSA-PSS is not supported";
225 return;
226 }
227
228 scoped_ptr<base::DictionaryValue> test_data;
229 ASSERT_TRUE(ReadJsonTestFileToDictionary("rsa_pss.json", &test_data));
230
231 const base::DictionaryValue* keys_dict = NULL;
232 ASSERT_TRUE(test_data->GetDictionary("keys", &keys_dict));
233
234 const base::ListValue* tests = NULL;
235 ASSERT_TRUE(test_data->GetList("tests", &tests));
236
237 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
238 SCOPED_TRACE(test_index);
239
240 const base::DictionaryValue* test;
241 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
242
243 blink::WebCryptoAlgorithm hash = GetDigestAlgorithm(test, "hash");
244
245 std::string key_name;
246 ASSERT_TRUE(test->GetString("key", &key_name));
247
248 // Import the public key.
249 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
250 std::vector<uint8_t> spki_bytes =
251 GetBytesFromHexString(keys_dict, key_name);
252
253 ASSERT_EQ(Status::Success(),
254 ImportKey(blink::WebCryptoKeyFormatSpki,
255 CryptoData(spki_bytes),
256 CreateRsaHashedImportAlgorithm(
257 blink::WebCryptoAlgorithmIdRsaPss, hash.id()),
258 true,
259 blink::WebCryptoKeyUsageVerify,
260 &public_key));
261
262 int saltLength;
263 ASSERT_TRUE(test->GetInteger("saltLength", &saltLength));
264
265 std::vector<uint8_t> message = GetBytesFromHexString(test, "message");
266 std::vector<uint8_t> signature = GetBytesFromHexString(test, "signature");
267
268 // Test that verification returns true when it should.
269 bool is_match = false;
270 ASSERT_EQ(Status::Success(),
271 Verify(CreateRsaPssAlgorithm(saltLength),
272 public_key,
273 CryptoData(signature),
274 CryptoData(message),
275 &is_match));
276 EXPECT_TRUE(is_match);
277
278 // Corrupt the message and make sure that verification fails.
279 ASSERT_EQ(Status::Success(),
280 Verify(CreateRsaPssAlgorithm(saltLength),
281 public_key,
282 CryptoData(signature),
283 CryptoData(Corrupted(message)),
284 &is_match));
285 EXPECT_FALSE(is_match);
286
287 // Corrupt the signature and make sure that verification fails.
288 ASSERT_EQ(Status::Success(),
289 Verify(CreateRsaPssAlgorithm(saltLength),
290 public_key,
291 CryptoData(Corrupted(signature)),
292 CryptoData(message),
293 &is_match));
294 EXPECT_FALSE(is_match);
295 }
296}
297
298} // namespace
299
300} // namespace webcrypto
301
302} // namespace content