1 /*
2  *  Copyright (c) 2018-present, Facebook, Inc.
3  *  All rights reserved.
4  *
5  *  This source code is licensed under the BSD-style license found in the
6  *  LICENSE file in the root directory of this source tree.
7  */
8 
9 #include <folly/portability/GTest.h>
10 
11 #include <fizz/crypto/signature/Signature.h>
12 #include <fizz/crypto/signature/test/EdSignatureTest.h>
13 #include <fizz/crypto/test/TestUtil.h>
14 #include <folly/String.h>
15 
16 #define ED25519_FIXTURE(num)                                               \
17   Params {                                                                 \
18     kEd25519PrivateKey##num, kEd25519PublicKey##num, kEd25519Message##num, \
19         kEd25519Signature##num                                             \
20   }
21 
22 using namespace folly;
23 
24 namespace fizz {
25 namespace testing {
26 
27 #if FIZZ_OPENSSL_HAS_ED25519
TEST_P(EdDSATest,TestSignature)28 TEST_P(EdDSATest, TestSignature) {
29   auto privateKey = fizz::test::getPrivateKey(GetParam().privateKey);
30   auto message = unhexlify(GetParam().hexMessage);
31   auto generatedSignature =
32       detail::edSign(IOBuf::copyBuffer(message)->coalesce(), privateKey);
33   EXPECT_EQ(hexlify(generatedSignature->coalesce()), GetParam().hexSignature);
34 }
35 
TEST_P(EdDSATest,TestVerify)36 TEST_P(EdDSATest, TestVerify) {
37   auto publicKey = fizz::test::getPublicKey(GetParam().publicKey);
38   auto message = unhexlify(GetParam().hexMessage);
39   auto signature = unhexlify(GetParam().hexSignature);
40 
41   // 1. Verification should pass for the message-signature pair in our fixtures
42   detail::edVerify(
43       IOBuf::copyBuffer(message)->coalesce(),
44       folly::ByteRange(folly::StringPiece(signature)),
45       publicKey);
46 
47   // 2. Verification should fail if the message is modified
48   auto modifiedMessage = modifyMessage(message);
49   EXPECT_THROW(
50       detail::edVerify(
51           IOBuf::copyBuffer(modifiedMessage)->coalesce(),
52           folly::ByteRange(folly::StringPiece(signature)),
53           publicKey),
54       std::runtime_error);
55 
56   // 3. Verification should fail if the signature is modified
57   auto modifiedSignature = modifySignature(signature);
58   EXPECT_THROW(
59       detail::edVerify(
60           IOBuf::copyBuffer(message)->coalesce(),
61           folly::ByteRange(folly::StringPiece(modifiedSignature)),
62           publicKey),
63       std::runtime_error);
64 }
65 
TEST_P(Ed25519Test,TestOpenSSLSignature)66 TEST_P(Ed25519Test, TestOpenSSLSignature) {
67   auto privateKey = fizz::test::getPrivateKey(GetParam().privateKey);
68   auto message = unhexlify(GetParam().hexMessage);
69   auto signature = unhexlify(GetParam().hexSignature);
70 
71   // 1. Test instantiation of OpenSSLSignature for Ed25519
72   OpenSSLSignature<KeyType::ED25519> eddsa;
73 
74   // 2. Test setting key
75   eddsa.setKey(std::move(privateKey));
76 
77   // 3. Test sign method
78   auto generatedSignature = eddsa.sign<SignatureScheme::ed25519>(
79       IOBuf::copyBuffer(message)->coalesce());
80   EXPECT_EQ(hexlify(generatedSignature->coalesce()), GetParam().hexSignature);
81 
82   // 4. Test verify method succeeds when it should
83   eddsa.verify<SignatureScheme::ed25519>(
84       IOBuf::copyBuffer(message)->coalesce(),
85       folly::ByteRange(folly::StringPiece(signature)));
86 
87   // 5. Test verify method fails if the message is modified
88   auto modifiedMessage = modifyMessage(message);
89   EXPECT_THROW(
90       eddsa.verify<SignatureScheme::ed25519>(
91           IOBuf::copyBuffer(modifiedMessage)->coalesce(),
92           folly::ByteRange(folly::StringPiece(signature))),
93       std::runtime_error);
94 
95   // 6. Test verify method fails if the signature is modified
96   auto modifiedSignature = modifySignature(signature);
97   EXPECT_THROW(
98       eddsa.verify<SignatureScheme::ed25519>(
99           IOBuf::copyBuffer(message)->coalesce(),
100           folly::ByteRange(folly::StringPiece(modifiedSignature))),
101       std::runtime_error);
102 }
103 
104 // Test vectors from RFC8032
105 INSTANTIATE_TEST_CASE_P(
106     TestVectors,
107     EdDSATest,
108     ::testing::Values(
109         ED25519_FIXTURE(1),
110         ED25519_FIXTURE(2),
111         ED25519_FIXTURE(3),
112         ED25519_FIXTURE(4),
113         ED25519_FIXTURE(5)));
114 
115 // Test vectors from RFC8032
116 INSTANTIATE_TEST_CASE_P(
117     TestVectors,
118     Ed25519Test,
119     ::testing::Values(
120         ED25519_FIXTURE(1),
121         ED25519_FIXTURE(2),
122         ED25519_FIXTURE(3),
123         ED25519_FIXTURE(4),
124         ED25519_FIXTURE(5)));
125 #endif
126 
modifyMessage(const std::string & input)127 std::string modifyMessage(const std::string& input) {
128   if (input.size() == 0) {
129     return "a";
130   }
131   auto modifiedMessage = std::string(input);
132   modifiedMessage[0] ^= 1; // Flip a  bit in the first character
133   return modifiedMessage;
134 }
135 
modifySignature(const std::string & input)136 std::string modifySignature(const std::string& input) {
137   CHECK_GT(input.size(), 0) << "Signatures should have positive length";
138   auto modifiedMessage = std::string(input);
139   modifiedMessage[0] ^= 1; // Flip a  bit in the first character
140   return modifiedMessage;
141 }
142 } // namespace testing
143 } // namespace fizz
144