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 "components/webcrypto/algorithm_dispatch.h"
8 #include "components/webcrypto/crypto_data.h"
9 #include "components/webcrypto/jwk.h"
10 #include "components/webcrypto/status.h"
11 #include "components/webcrypto/test/test_helpers.h"
12 #include "components/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"
22 bool SupportsRsaPss() {
23 #if defined(USE_OPENSSL)
30 blink::WebCryptoAlgorithm
CreateRsaPssAlgorithm(
31 unsigned int salt_length_bytes
) {
32 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
33 blink::WebCryptoAlgorithmIdRsaPss
,
34 new blink::WebCryptoRsaPssParams(salt_length_bytes
));
37 // Test that no two RSA-PSS signatures are identical, when using a non-zero
39 TEST(WebCryptoRsaPssTest
, SignIsRandom
) {
40 if (!SupportsRsaPss()) {
41 LOG(WARNING
) << "Skipping test because RSA-PSS is not supported";
45 // Import public/private key pair.
46 blink::WebCryptoKey public_key
= blink::WebCryptoKey::createNull();
47 blink::WebCryptoKey private_key
= blink::WebCryptoKey::createNull();
50 HexStringToBytes(kPublicKeySpkiDerHex
),
51 HexStringToBytes(kPrivateKeyPkcs8DerHex
),
52 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss
,
53 blink::WebCryptoAlgorithmIdSha1
),
54 true, blink::WebCryptoKeyUsageVerify
, blink::WebCryptoKeyUsageSign
,
55 &public_key
, &private_key
);
57 // Use a 20-byte length salt.
58 blink::WebCryptoAlgorithm params
= CreateRsaPssAlgorithm(20);
60 // Some random message to sign.
61 std::vector
<uint8_t> message
= HexStringToBytes(kPublicKeySpkiDerHex
);
64 std::vector
<uint8_t> signature1
;
65 std::vector
<uint8_t> signature2
;
67 ASSERT_EQ(Status::Success(),
68 Sign(params
, private_key
, CryptoData(message
), &signature1
));
69 ASSERT_EQ(Status::Success(),
70 Sign(params
, private_key
, CryptoData(message
), &signature2
));
72 // The signatures will be different because of the salt.
73 EXPECT_NE(CryptoData(signature1
), CryptoData(signature2
));
75 // However both signatures should work when verifying.
76 bool is_match
= false;
78 ASSERT_EQ(Status::Success(),
79 Verify(params
, public_key
, CryptoData(signature1
),
80 CryptoData(message
), &is_match
));
81 EXPECT_TRUE(is_match
);
83 ASSERT_EQ(Status::Success(),
84 Verify(params
, public_key
, CryptoData(signature2
),
85 CryptoData(message
), &is_match
));
86 EXPECT_TRUE(is_match
);
88 // Corrupt the signature and verification must fail.
89 ASSERT_EQ(Status::Success(),
90 Verify(params
, public_key
, CryptoData(Corrupted(signature2
)),
91 CryptoData(message
), &is_match
));
92 EXPECT_FALSE(is_match
);
95 // Try signing and verifying when the salt length is 0. The signature in this
96 // case is not random.
97 TEST(WebCryptoRsaPssTest
, SignVerifyNoSalt
) {
98 if (!SupportsRsaPss()) {
99 LOG(WARNING
) << "Skipping test because RSA-PSS is not supported";
103 // Import public/private key pair.
104 blink::WebCryptoKey public_key
= blink::WebCryptoKey::createNull();
105 blink::WebCryptoKey private_key
= blink::WebCryptoKey::createNull();
108 HexStringToBytes(kPublicKeySpkiDerHex
),
109 HexStringToBytes(kPrivateKeyPkcs8DerHex
),
110 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss
,
111 blink::WebCryptoAlgorithmIdSha1
),
112 true, blink::WebCryptoKeyUsageVerify
, blink::WebCryptoKeyUsageSign
,
113 &public_key
, &private_key
);
116 blink::WebCryptoAlgorithm params
= CreateRsaPssAlgorithm(0);
118 // Some random message to sign.
119 std::vector
<uint8_t> message
= HexStringToBytes(kPublicKeySpkiDerHex
);
122 std::vector
<uint8_t> signature1
;
123 std::vector
<uint8_t> signature2
;
125 ASSERT_EQ(Status::Success(),
126 Sign(params
, private_key
, CryptoData(message
), &signature1
));
127 ASSERT_EQ(Status::Success(),
128 Sign(params
, private_key
, CryptoData(message
), &signature2
));
130 // The signatures will be the same this time.
131 EXPECT_EQ(CryptoData(signature1
), CryptoData(signature2
));
133 // Make sure that verification works.
134 bool is_match
= false;
135 ASSERT_EQ(Status::Success(),
136 Verify(params
, public_key
, CryptoData(signature1
),
137 CryptoData(message
), &is_match
));
138 EXPECT_TRUE(is_match
);
140 // Corrupt the signature and verification must fail.
141 ASSERT_EQ(Status::Success(),
142 Verify(params
, public_key
, CryptoData(Corrupted(signature2
)),
143 CryptoData(message
), &is_match
));
144 EXPECT_FALSE(is_match
);
147 TEST(WebCryptoRsaPssTest
, SignEmptyMessage
) {
148 if (!SupportsRsaPss()) {
149 LOG(WARNING
) << "Skipping test because RSA-PSS is not supported";
153 // Import public/private key pair.
154 blink::WebCryptoKey public_key
= blink::WebCryptoKey::createNull();
155 blink::WebCryptoKey private_key
= blink::WebCryptoKey::createNull();
158 HexStringToBytes(kPublicKeySpkiDerHex
),
159 HexStringToBytes(kPrivateKeyPkcs8DerHex
),
160 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaPss
,
161 blink::WebCryptoAlgorithmIdSha1
),
162 true, blink::WebCryptoKeyUsageVerify
, blink::WebCryptoKeyUsageSign
,
163 &public_key
, &private_key
);
165 blink::WebCryptoAlgorithm params
= CreateRsaPssAlgorithm(20);
166 std::vector
<uint8_t> message
; // Empty message.
167 std::vector
<uint8_t> signature
;
169 ASSERT_EQ(Status::Success(),
170 Sign(params
, private_key
, CryptoData(message
), &signature
));
172 // Make sure that verification works.
173 bool is_match
= false;
174 ASSERT_EQ(Status::Success(), Verify(params
, public_key
, CryptoData(signature
),
175 CryptoData(message
), &is_match
));
176 EXPECT_TRUE(is_match
);
178 // Corrupt the signature and verification must fail.
179 ASSERT_EQ(Status::Success(),
180 Verify(params
, public_key
, CryptoData(Corrupted(signature
)),
181 CryptoData(message
), &is_match
));
182 EXPECT_FALSE(is_match
);
185 // Iterate through known answers and test verification.
186 // * Verify over original message should succeed
187 // * Verify over corrupted message should fail
188 // * Verification with corrupted signature should fail
189 TEST(WebCryptoRsaPssTest
, VerifyKnownAnswer
) {
190 if (!SupportsRsaPss()) {
191 LOG(WARNING
) << "Skipping test because RSA-PSS is not supported";
195 scoped_ptr
<base::DictionaryValue
> test_data
;
196 ASSERT_TRUE(ReadJsonTestFileToDictionary("rsa_pss.json", &test_data
));
198 const base::DictionaryValue
* keys_dict
= NULL
;
199 ASSERT_TRUE(test_data
->GetDictionary("keys", &keys_dict
));
201 const base::ListValue
* tests
= NULL
;
202 ASSERT_TRUE(test_data
->GetList("tests", &tests
));
204 for (size_t test_index
= 0; test_index
< tests
->GetSize(); ++test_index
) {
205 SCOPED_TRACE(test_index
);
207 const base::DictionaryValue
* test
;
208 ASSERT_TRUE(tests
->GetDictionary(test_index
, &test
));
210 blink::WebCryptoAlgorithm hash
= GetDigestAlgorithm(test
, "hash");
212 std::string key_name
;
213 ASSERT_TRUE(test
->GetString("key", &key_name
));
215 // Import the public key.
216 blink::WebCryptoKey public_key
= blink::WebCryptoKey::createNull();
217 std::vector
<uint8_t> spki_bytes
=
218 GetBytesFromHexString(keys_dict
, key_name
);
220 ASSERT_EQ(Status::Success(),
221 ImportKey(blink::WebCryptoKeyFormatSpki
, CryptoData(spki_bytes
),
222 CreateRsaHashedImportAlgorithm(
223 blink::WebCryptoAlgorithmIdRsaPss
, hash
.id()),
224 true, blink::WebCryptoKeyUsageVerify
, &public_key
));
227 ASSERT_TRUE(test
->GetInteger("saltLength", &saltLength
));
229 std::vector
<uint8_t> message
= GetBytesFromHexString(test
, "message");
230 std::vector
<uint8_t> signature
= GetBytesFromHexString(test
, "signature");
232 // Test that verification returns true when it should.
233 bool is_match
= false;
234 ASSERT_EQ(Status::Success(),
235 Verify(CreateRsaPssAlgorithm(saltLength
), public_key
,
236 CryptoData(signature
), CryptoData(message
), &is_match
));
237 EXPECT_TRUE(is_match
);
239 // Corrupt the message and make sure that verification fails.
240 ASSERT_EQ(Status::Success(),
241 Verify(CreateRsaPssAlgorithm(saltLength
), public_key
,
242 CryptoData(signature
), CryptoData(Corrupted(message
)),
244 EXPECT_FALSE(is_match
);
246 // Corrupt the signature and make sure that verification fails.
247 ASSERT_EQ(Status::Success(),
248 Verify(CreateRsaPssAlgorithm(saltLength
), public_key
,
249 CryptoData(Corrupted(signature
)), CryptoData(message
),
251 EXPECT_FALSE(is_match
);
257 } // namespace webcrypto