rsa_pss_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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.
  4. #include <stddef.h>
  5. #include <stdint.h>
  6. #include "base/strings/string_number_conversions.h"
  7. #include "components/webcrypto/algorithm_dispatch.h"
  8. #include "components/webcrypto/algorithms/test_helpers.h"
  9. #include "components/webcrypto/jwk.h"
  10. #include "components/webcrypto/status.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. #include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
  13. #include "third_party/blink/public/platform/web_crypto_key.h"
  14. #include "third_party/blink/public/platform/web_crypto_key_algorithm.h"
  15. namespace webcrypto {
  16. namespace {
  17. blink::WebCryptoAlgorithm CreateRsaPssAlgorithm(
  18. unsigned int salt_length_bytes) {
  19. return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(
  20. blink::kWebCryptoAlgorithmIdRsaPss,
  21. new blink::WebCryptoRsaPssParams(salt_length_bytes));
  22. }
  23. class WebCryptoRsaPssTest : public WebCryptoTestBase {};
  24. // Test that no two RSA-PSS signatures are identical, when using a non-zero
  25. // lengthed salt.
  26. TEST_F(WebCryptoRsaPssTest, SignIsRandom) {
  27. // Import public/private key pair.
  28. blink::WebCryptoKey public_key = blink::WebCryptoKey::CreateNull();
  29. blink::WebCryptoKey private_key = blink::WebCryptoKey::CreateNull();
  30. ImportRsaKeyPair(
  31. HexStringToBytes(kPublicKeySpkiDerHex),
  32. HexStringToBytes(kPrivateKeyPkcs8DerHex),
  33. CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaPss,
  34. blink::kWebCryptoAlgorithmIdSha1),
  35. true, blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
  36. &public_key, &private_key);
  37. // Use a 20-byte length salt.
  38. blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(20);
  39. // Some random message to sign.
  40. std::vector<uint8_t> message = HexStringToBytes(kPublicKeySpkiDerHex);
  41. // Sign twice.
  42. std::vector<uint8_t> signature1;
  43. std::vector<uint8_t> signature2;
  44. ASSERT_EQ(Status::Success(), Sign(params, private_key, message, &signature1));
  45. ASSERT_EQ(Status::Success(), Sign(params, private_key, message, &signature2));
  46. // The signatures will be different because of the salt.
  47. EXPECT_NE(signature1, signature2);
  48. // However both signatures should work when verifying.
  49. bool is_match = false;
  50. ASSERT_EQ(Status::Success(),
  51. Verify(params, public_key, signature1, message, &is_match));
  52. EXPECT_TRUE(is_match);
  53. ASSERT_EQ(Status::Success(),
  54. Verify(params, public_key, signature2, message, &is_match));
  55. EXPECT_TRUE(is_match);
  56. // Corrupt the signature and verification must fail.
  57. ASSERT_EQ(Status::Success(), Verify(params, public_key, Corrupted(signature2),
  58. message, &is_match));
  59. EXPECT_FALSE(is_match);
  60. }
  61. // Try signing and verifying when the salt length is 0. The signature in this
  62. // case is not random.
  63. TEST_F(WebCryptoRsaPssTest, SignVerifyNoSalt) {
  64. // Import public/private key pair.
  65. blink::WebCryptoKey public_key = blink::WebCryptoKey::CreateNull();
  66. blink::WebCryptoKey private_key = blink::WebCryptoKey::CreateNull();
  67. ImportRsaKeyPair(
  68. HexStringToBytes(kPublicKeySpkiDerHex),
  69. HexStringToBytes(kPrivateKeyPkcs8DerHex),
  70. CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaPss,
  71. blink::kWebCryptoAlgorithmIdSha1),
  72. true, blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
  73. &public_key, &private_key);
  74. // Zero-length salt.
  75. blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(0);
  76. // Some random message to sign.
  77. std::vector<uint8_t> message = HexStringToBytes(kPublicKeySpkiDerHex);
  78. // Sign twice.
  79. std::vector<uint8_t> signature1;
  80. std::vector<uint8_t> signature2;
  81. ASSERT_EQ(Status::Success(), Sign(params, private_key, message, &signature1));
  82. ASSERT_EQ(Status::Success(), Sign(params, private_key, message, &signature2));
  83. // The signatures will be the same this time.
  84. EXPECT_EQ(signature1, signature2);
  85. // Make sure that verification works.
  86. bool is_match = false;
  87. ASSERT_EQ(Status::Success(),
  88. Verify(params, public_key, signature1, message, &is_match));
  89. EXPECT_TRUE(is_match);
  90. // Corrupt the signature and verification must fail.
  91. ASSERT_EQ(Status::Success(), Verify(params, public_key, Corrupted(signature2),
  92. message, &is_match));
  93. EXPECT_FALSE(is_match);
  94. }
  95. TEST_F(WebCryptoRsaPssTest, SignEmptyMessage) {
  96. // Import public/private key pair.
  97. blink::WebCryptoKey public_key = blink::WebCryptoKey::CreateNull();
  98. blink::WebCryptoKey private_key = blink::WebCryptoKey::CreateNull();
  99. ImportRsaKeyPair(
  100. HexStringToBytes(kPublicKeySpkiDerHex),
  101. HexStringToBytes(kPrivateKeyPkcs8DerHex),
  102. CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaPss,
  103. blink::kWebCryptoAlgorithmIdSha1),
  104. true, blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
  105. &public_key, &private_key);
  106. blink::WebCryptoAlgorithm params = CreateRsaPssAlgorithm(20);
  107. std::vector<uint8_t> message; // Empty message.
  108. std::vector<uint8_t> signature;
  109. ASSERT_EQ(Status::Success(), Sign(params, private_key, message, &signature));
  110. // Make sure that verification works.
  111. bool is_match = false;
  112. ASSERT_EQ(Status::Success(),
  113. Verify(params, public_key, signature, message, &is_match));
  114. EXPECT_TRUE(is_match);
  115. // Corrupt the signature and verification must fail.
  116. ASSERT_EQ(Status::Success(), Verify(params, public_key, Corrupted(signature),
  117. message, &is_match));
  118. EXPECT_FALSE(is_match);
  119. }
  120. // RSA-PSS known answer tests:
  121. const char kKey1[] =
  122. "30819F300D06092A864886F70D010101050003818D0030818902818100A56E4A0E70101758"
  123. "9A5187DC7EA841D156F2EC0E36AD52A44DFEB1E61F7AD991D8C51056FFEDB162B4C0F283A1"
  124. "2A88A394DFF526AB7291CBB307CEABFCE0B1DFD5CD9508096D5B2B8B6DF5D671EF6377C092"
  125. "1CB23C270A70E2598E6FF89D19F105ACC2D3F0CB35F29280E1386B6F64C4EF22E1E1F20D0C"
  126. "E8CFFB2249BD9A21370203010001";
  127. const char kKey2[] =
  128. "30819D300D06092A864886F70D010101050003818B0030818702818100BE499B5E7F06C83F"
  129. "A0293E31465C8EB6B58AF920BAE52A7B5B9BFEB7AA72DB1264112EB3FD431D31A2A7E50941"
  130. "566929494A0E891ED5613918B4B51B0D1FB97783B26ACF7D0F384CFB35F4D2824F5DD38062"
  131. "3A26BF180B63961C619DCDB20CAE406F22F6E276C80A37259490CFEB72C1A71A84F1846D33"
  132. "0877BA3E3101EC9C7B020111";
  133. const char kNistTestMessage[] =
  134. "c7f5270fca725f9bd19f519a8d7cca3cc5c079024029f3bae510f9b02140fe238908e4f6c1"
  135. "8f07a89c687c8684669b1f1db2baf9251a3c829faccb493084e16ec9e28d58868074a5d622"
  136. "1667dd6e528d16fe2c9f3db4cfaf6c4dce8c8439af38ceaaaa9ce2ecae7bc8f4a5a55e3bf9"
  137. "6df9cd575c4f9cb327951b8cdfe4087168";
  138. struct RsaPssKnownAnswer {
  139. blink::WebCryptoAlgorithmId hash;
  140. const char* key;
  141. const char* message;
  142. size_t salt_length;
  143. const char* signature;
  144. };
  145. const RsaPssKnownAnswer kRsaPssKnownAnswers[] = {
  146. // Example 1.1 from pss-vect.txt in
  147. // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip
  148. {blink::kWebCryptoAlgorithmIdSha1, kKey1,
  149. "cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d4"
  150. "5ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba9"
  151. "58fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472"
  152. "c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42"
  153. "d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625"
  154. "cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73"
  155. "318b750a0167d0",
  156. 20,
  157. "9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7"
  158. "fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f95"
  159. "79aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb"
  160. "27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c"},
  161. // Example 1.4 from pss-vect.txt in
  162. // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip
  163. {blink::kWebCryptoAlgorithmIdSha1, kKey1, "bc656747fa9eafb3f0", 20,
  164. "4609793b23e9d09362dc21bb47da0b4f3a7622649a47d464019b9aeafe53359c178c91"
  165. "cd58ba6bcb78be0346a7bc637f4b873d4bab38ee661f199634c547a1ad8442e03da015"
  166. "b136e543f7ab07c0c13e4225b8de8cce25d4f6eb8400f81f7e1833b7ee6e334d370964"
  167. "ca79fdb872b4d75223b5eeb08101591fb532d155a6de87"},
  168. // The next three are from SigVerPSS_186-3.rsp in
  169. // http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-2rsatestvectors.zip
  170. {blink::kWebCryptoAlgorithmIdSha256, kKey2, kNistTestMessage, 10,
  171. "11e169f2fd40b07641b9768a2ab19965fb6c27f10fcf0323fcc6d12eb4f1c06b330dda"
  172. "a1ea504407afa29de9ebe0374fe9d1e7d0ffbd5fc1cf3a3446e4145415d2ab24f789b3"
  173. "464c5c43a256bbc1d692cf7f04801dac5bb401a4a03ab7d5728a860c19e1a4dc797ca5"
  174. "42c8203cec2e601eb0c51f567f2eda022b0b9ebddeeefa"},
  175. {blink::kWebCryptoAlgorithmIdSha384, kKey2, kNistTestMessage, 10,
  176. "b281ad934b2775c0cba5fb10aa574d2ed85c7f99b942b78e49702480069362ed394bad"
  177. "ed55e56cfcbe7b0b8d2217a05a60e1acd725cb09060dfac585bc2132b99b41cdbd530c"
  178. "69d17cdbc84bc6b9830fc7dc8e1b2412cfe06dcf8c1a0cc3453f93f25ebf10cb0c9033"
  179. "4fac573f449138616e1a194c67f44efac34cc07a526267"},
  180. {blink::kWebCryptoAlgorithmIdSha512, kKey2, kNistTestMessage, 10,
  181. "8ffc38f9b820ef6b080fd2ec7de5626c658d79056f3edf610a295b7b0546f73e01ffdf4d0"
  182. "070ebf79c33fd86c2d608be9438b3d420d09535b97cd3d846ecaf8f6551cdf93197e9f8fb"
  183. "048044473ab41a801e9f7fc983c62b324361dade9f71a65952bd35c59faaa4d6ff462f68a"
  184. "6c4ec0b428aa47336f2178aeb276136563b7d"},
  185. };
  186. blink::WebCryptoKey RsaPssKeyFromBytes(blink::WebCryptoAlgorithmId hash,
  187. const char* key) {
  188. auto pubkey = blink::WebCryptoKey::CreateNull();
  189. webcrypto::Status result = ImportKey(
  190. blink::kWebCryptoKeyFormatSpki, HexStringToBytes(key),
  191. CreateRsaHashedImportAlgorithm(blink::kWebCryptoAlgorithmIdRsaPss, hash),
  192. true, blink::kWebCryptoKeyUsageVerify, &pubkey);
  193. CHECK(result == Status::Success());
  194. return pubkey;
  195. }
  196. bool VerifySignature(size_t salt_length,
  197. blink::WebCryptoKey pubkey,
  198. const std::vector<uint8_t>& signature,
  199. const std::vector<uint8_t>& message) {
  200. bool is_match = false;
  201. auto result = Verify(CreateRsaPssAlgorithm(salt_length), pubkey, signature,
  202. message, &is_match);
  203. CHECK(result == Status::Success());
  204. return is_match;
  205. }
  206. // Iterate through known answers and test verification.
  207. // * Verify over original message should succeed
  208. // * Verify over corrupted message should fail
  209. // * Verification with corrupted signature should fail
  210. TEST_F(WebCryptoRsaPssTest, VerifyKnownAnswer) {
  211. for (const auto& test : kRsaPssKnownAnswers) {
  212. SCOPED_TRACE(&test - &kRsaPssKnownAnswers[0]);
  213. blink::WebCryptoKey pubkey = RsaPssKeyFromBytes(test.hash, test.key);
  214. std::vector<uint8_t> message = HexStringToBytes(test.message);
  215. std::vector<uint8_t> signature = HexStringToBytes(test.signature);
  216. EXPECT_TRUE(VerifySignature(test.salt_length, pubkey, signature, message));
  217. EXPECT_FALSE(VerifySignature(test.salt_length, pubkey, signature,
  218. Corrupted(message)));
  219. EXPECT_FALSE(VerifySignature(test.salt_length, pubkey, Corrupted(signature),
  220. message));
  221. }
  222. }
  223. } // namespace
  224. } // namespace webcrypto