proxygen
CertTest.cpp
Go to the documentation of this file.
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 <gtest/gtest.h>
10 
13 #include <folly/String.h>
14 
15 using namespace folly;
16 using namespace testing;
17 
18 namespace fizz {
19 namespace test {
20 
21 struct RSATest;
22 
23 struct P256Test {
24  static constexpr KeyType Type = KeyType::P256;
25  static constexpr SignatureScheme Scheme =
26  SignatureScheme::ecdsa_secp256r1_sha256;
27 
28  using Invalid = RSATest;
29 };
30 
31 struct P384Test {
32  static constexpr KeyType Type = KeyType::P384;
33  static constexpr SignatureScheme Scheme =
34  SignatureScheme::ecdsa_secp384r1_sha384;
35 
36  using Invalid = RSATest;
37 };
38 
39 struct P521Test {
40  static constexpr KeyType Type = KeyType::P521;
41  static constexpr SignatureScheme Scheme =
42  SignatureScheme::ecdsa_secp521r1_sha512;
43 
44  using Invalid = RSATest;
45 };
46 
47 struct RSATest {
48  static constexpr KeyType Type = KeyType::RSA;
49  static constexpr SignatureScheme Scheme = SignatureScheme::rsa_pss_sha256;
50 
51  using Invalid = P256Test;
52 };
53 
54 template <typename T>
56 
57 template <>
60 }
61 
62 template <>
65 }
66 
67 template <>
70 }
71 
72 template <>
75 }
76 
77 template <typename T>
79 
80 template <>
82  return getPrivateKey(kP256Key);
83 }
84 
85 template <>
87  return getPrivateKey(kP384Key);
88 }
89 
90 template <>
92  return getPrivateKey(kP521Key);
93 }
94 
95 template <>
97  return getPrivateKey(kRSAKey);
98 }
99 
100 template <typename T>
101 class CertTestTyped : public Test {
102  public:
103  void SetUp() override {
104  OpenSSL_add_all_algorithms();
105  }
106 };
107 
108 using KeyTypes = Types<P256Test, P384Test, P521Test, RSATest>;
110 
111 TEST(CertTest, GetIdentity) {
112  auto cert = getCert(kP256Certificate);
113  auto key = getPrivateKey(kP256Key);
114  std::vector<folly::ssl::X509UniquePtr> certs;
115  certs.push_back(std::move(cert));
117  EXPECT_EQ(certificate.getIdentity(), "Fizz");
118  EXPECT_EQ(certificate.getAltIdentities().size(), 0);
119 }
120 
121 TEST(CertTest, GetAltIdentity) {
122  auto cert = getCert(kRSACertificate);
123  auto key = getPrivateKey(kRSAKey);
124  std::vector<folly::ssl::X509UniquePtr> certs;
125  certs.push_back(std::move(cert));
127  EXPECT_EQ(certificate.getIdentity(), "Fizz");
128  auto alts = certificate.getAltIdentities();
129  EXPECT_EQ(alts.size(), 3);
130  EXPECT_EQ(alts[0], "*.fizz.com");
131  EXPECT_EQ(alts[1], "fizz.com");
132  EXPECT_EQ(alts[2], "example.net");
133 }
134 
135 TEST(CertTest, GetCertMessage) {
136  auto cert = getCert(kP256Certificate);
137  auto key = getPrivateKey(kP256Key);
138  std::vector<folly::ssl::X509UniquePtr> certs;
139  certs.push_back(std::move(cert));
141  auto msg = certificate.getCertMessage();
142  ASSERT_EQ(msg.certificate_list.size(), 1);
143  auto& firstCertEntry = msg.certificate_list[0];
144  auto firstCertData = firstCertEntry.cert_data->coalesce();
145  auto firstCertDataPtr = firstCertData.data();
146  folly::ssl::X509UniquePtr firstEncodedCert(
147  d2i_X509(nullptr, &firstCertDataPtr, firstCertData.size()));
148  CHECK(firstEncodedCert);
149 
150  auto certCopy = getCert(kP256Certificate);
151  EXPECT_EQ(X509_cmp(firstEncodedCert.get(), certCopy.get()), 0);
152 }
153 
154 // example taken from https://tlswg.github.io/tls13-spec/#certificate-verify
155 TEST(CertTest, PrepareSignData) {
156  std::array<uint8_t, 32> toBeSigned;
157  memset(toBeSigned.data(), 1, toBeSigned.size());
158  auto out = CertUtils::prepareSignData(
159  CertificateVerifyContext::Server, folly::range(toBeSigned));
160  auto hex = hexlify(out->moveToFbString());
161  std::string expected =
162  "2020202020202020202020202020202020202020202020202020202020202020"
163  "2020202020202020202020202020202020202020202020202020202020202020"
164  "544c5320312e332c207365727665722043657274696669636174655665726966"
165  "79"
166  "00"
167  "0101010101010101010101010101010101010101010101010101010101010101";
168  EXPECT_EQ(hex, expected);
169 }
170 
171 TEST(CertTest, MakePeerCertEmpty) {
172  EXPECT_THROW(
173  CertUtils::makePeerCert(IOBuf::copyBuffer("")), std::runtime_error);
174 }
175 
176 TEST(CertTest, MakePeerCertJunk) {
177  EXPECT_THROW(
178  CertUtils::makePeerCert(IOBuf::copyBuffer("blah")), std::runtime_error);
179 }
180 
181 TEST(CertTest, PeerCertGetX509) {
183  auto x509 = peerCert.getX509();
184  EXPECT_NE(x509.get(), nullptr);
185 }
186 
187 TYPED_TEST(CertTestTyped, MatchingCert) {
188  std::vector<folly::ssl::X509UniquePtr> certs;
189  certs.push_back(getCert<TypeParam>());
191  getKey<TypeParam>(), std::move(certs));
192 }
193 
194 TYPED_TEST(CertTestTyped, MismatchedCert) {
195  std::vector<folly::ssl::X509UniquePtr> certs;
196  certs.push_back(getCert<TypeParam>());
197  EXPECT_THROW(
199  getKey<typename TypeParam::Invalid>(), std::move(certs)),
200  std::runtime_error);
201 }
202 
203 TYPED_TEST(CertTestTyped, SigSchemes) {
204  std::vector<folly::ssl::X509UniquePtr> certs;
205  certs.push_back(getCert<TypeParam>());
207  getKey<TypeParam>(), std::move(certs));
208 
209  std::vector<SignatureScheme> expected{TypeParam::Scheme};
210  EXPECT_EQ(certificate.getSigSchemes(), expected);
211 }
212 
213 TYPED_TEST(CertTestTyped, TestSignVerify) {
214  PeerCertImpl<TypeParam::Type> peerCert(getCert<TypeParam>());
215  std::vector<folly::ssl::X509UniquePtr> certs;
216  certs.push_back(getCert<TypeParam>());
217  SelfCertImpl<TypeParam::Type> selfCert(getKey<TypeParam>(), std::move(certs));
218 
219  StringPiece tbs{"ToBeSigned"};
220  auto sig =
221  selfCert.sign(TypeParam::Scheme, CertificateVerifyContext::Server, tbs);
222  peerCert.verify(
223  TypeParam::Scheme,
224  CertificateVerifyContext::Server,
225  tbs,
226  sig->coalesce());
227 }
228 
229 TYPED_TEST(CertTestTyped, TestSignVerifyBitFlip) {
230  PeerCertImpl<TypeParam::Type> peerCert(getCert<TypeParam>());
231  std::vector<folly::ssl::X509UniquePtr> certs;
232  certs.push_back(getCert<TypeParam>());
233  SelfCertImpl<TypeParam::Type> selfCert(getKey<TypeParam>(), std::move(certs));
234 
235  StringPiece tbs{"ToBeSigned"};
236  auto sig =
237  selfCert.sign(TypeParam::Scheme, CertificateVerifyContext::Server, tbs);
238  sig->writableData()[1] ^= 0x20;
239  EXPECT_THROW(
240  peerCert.verify(
241  TypeParam::Scheme,
242  CertificateVerifyContext::Server,
243  tbs,
244  sig->coalesce()),
245  std::runtime_error);
246 }
247 
248 TYPED_TEST(CertTestTyped, TestSignVerifyWrongSize) {
249  PeerCertImpl<TypeParam::Type> peerCert(getCert<TypeParam>());
250  std::vector<folly::ssl::X509UniquePtr> certs;
251  certs.push_back(getCert<TypeParam>());
252  SelfCertImpl<TypeParam::Type> selfCert(getKey<TypeParam>(), std::move(certs));
253 
254  StringPiece tbs{"ToBeSigned"};
255  auto sig =
256  selfCert.sign(TypeParam::Scheme, CertificateVerifyContext::Server, tbs);
257  sig->prependChain(IOBuf::copyBuffer("x"));
258  EXPECT_THROW(
259  peerCert.verify(
260  TypeParam::Scheme,
261  CertificateVerifyContext::Server,
262  tbs,
263  sig->coalesce()),
264  std::runtime_error);
265 }
266 
267 TYPED_TEST(CertTestTyped, TestVerifyWrongScheme) {
268  PeerCertImpl<TypeParam::Type> peerCert(getCert<TypeParam>());
269  std::vector<folly::ssl::X509UniquePtr> certs;
270  certs.push_back(getCert<TypeParam>());
271  SelfCertImpl<TypeParam::Type> selfCert(getKey<TypeParam>(), std::move(certs));
272 
273  StringPiece tbs{"ToBeSigned"};
274  auto sig =
275  selfCert.sign(TypeParam::Scheme, CertificateVerifyContext::Server, tbs);
276  EXPECT_THROW(
277  peerCert.verify(
278  TypeParam::Invalid::Scheme,
279  CertificateVerifyContext::Server,
280  tbs,
281  sig->coalesce()),
282  std::runtime_error);
283 }
284 
285 TYPED_TEST(CertTestTyped, TestVerifyDecodedCert) {
286  std::vector<folly::ssl::X509UniquePtr> certs;
287  certs.push_back(getCert<TypeParam>());
288  auto msg = CertUtils::getCertMessage(certs, nullptr);
289  SelfCertImpl<TypeParam::Type> selfCert(getKey<TypeParam>(), std::move(certs));
290 
291  auto peerCert = CertUtils::makePeerCert(
292  std::move(msg.certificate_list.front().cert_data));
293 
294  StringPiece tbs{"ToBeSigned"};
295  auto sig =
296  selfCert.sign(TypeParam::Scheme, CertificateVerifyContext::Server, tbs);
297  peerCert->verify(
298  TypeParam::Scheme,
299  CertificateVerifyContext::Server,
300  tbs,
301  sig->coalesce());
302 }
303 } // namespace test
304 } // namespace fizz
ssl::EvpPkeyUniquePtr getKey< RSATest >()
Definition: CertTest.cpp:96
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
constexpr folly::StringPiece kP256Key
Definition: TestUtil.h:18
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
std::unique_ptr< X509, X509Deleter > X509UniquePtr
constexpr folly::StringPiece kRSACertificate
Definition: TestUtil.h:159
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr folly::StringPiece kP384Certificate
Definition: TestUtil.h:74
ssl::X509UniquePtr getCert< P384Test >()
Definition: CertTest.cpp:63
void SetUp() override
Definition: CertTest.cpp:103
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::vector< SignatureScheme > getSigSchemes() const override
SignatureScheme
Definition: Types.h:257
std::unique_ptr< EVP_PKEY, EvpPkeyDeleter > EvpPkeyUniquePtr
TYPED_TEST_CASE(SynchronizedTest, SynchronizedTestTypes)
EvpPkeyUniquePtr getPrivateKey(StringPiece key)
Definition: TestUtil.cpp:21
std::vector< std::string > getAltIdentities() const override
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
KeyType
Definition: Signature.h:17
static ssl::X509UniquePtr getCert()
folly::ssl::X509UniquePtr getCert(folly::StringPiece cert)
Definition: TestUtil.cpp:48
ssl::X509UniquePtr getCert< P521Test >()
Definition: CertTest.cpp:68
ssl::X509UniquePtr getCert< RSATest >()
Definition: CertTest.cpp:73
Buf sign(SignatureScheme scheme, CertificateVerifyContext context, folly::ByteRange toBeSigned) const override
CertificateMsg getCertMessage(Buf certificateRequestContext=nullptr) const override
void verify(SignatureScheme scheme, CertificateVerifyContext context, folly::ByteRange toBeSigned, folly::ByteRange signature) const override
ssl::EvpPkeyUniquePtr getKey< P256Test >()
Definition: CertTest.cpp:81
TYPED_TEST(SynchronizedTest, Basic)
constexpr Range< Iter > range(Iter first, Iter last)
Definition: Range.h:1114
constexpr detail::Sig< Sig > const sig
Definition: Poly.h:1165
Definition: Actions.h:16
ssl::EvpPkeyUniquePtr getKey< P521Test >()
Definition: CertTest.cpp:91
ssl::EvpPkeyUniquePtr getKey< P384Test >()
Definition: CertTest.cpp:86
::testing::Types< P256, P384, P521 > KeyTypes
TrafficKey getKey()
const char * string
Definition: Conv.cpp:212
constexpr folly::StringPiece kRSAKey
Definition: TestUtil.h:129
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
ssl::X509UniquePtr getCert< P256Test >()
Definition: CertTest.cpp:58
folly::ssl::X509UniquePtr getX509() const override
constexpr folly::StringPiece kP521Key
Definition: TestUtil.h:91
bool hexlify(const InputString &input, OutputString &output, bool append_output)
Definition: String-inl.h:596
static std::unique_ptr< IOBuf > copyBuffer(const void *buf, std::size_t size, std::size_t headroom=0, std::size_t minTailroom=0)
Definition: IOBuf.h:1587
constexpr folly::StringPiece kP521Certificate
Definition: TestUtil.h:110
constexpr folly::StringPiece kP384Key
Definition: TestUtil.h:57
TEST(SequencedExecutor, CPUThreadPoolExecutor)
std::string getIdentity() const override
constexpr folly::StringPiece kP256Certificate
Definition: TestUtil.h:41