proxygen
AeadTicketCipherTest.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 <gmock/gmock.h>
10 #include <gtest/gtest.h>
11 
13 
15 #include <fizz/crypto/test/Mocks.h>
17 #include <folly/String.h>
18 
19 using namespace fizz::test;
20 using namespace folly;
21 using namespace testing;
22 
23 static constexpr StringPiece ticketSecret1{
24  "90a791cf38c0b5c20447ef029ae1bc4bf3eecc2e85042174497671835ceaccd9"};
25 // secret: 13deec41c45b2f1c4f595ad5972d13047fba09031ba53140c751380e74114cc4
26 // salt: 4444444444444444444444444444444444444444444444444444444444444444
27 // hkdf output: c951156f3dcb1ab243a3f2c8e4346bec92cb25d241ae821484081388
28 static constexpr StringPiece ticket1{
29  "444444444444444444444444444444444444444444444444444444444444444400000000579bb5b10c83d7a581f6b8f7bd25acde3dabfe6f59e5147bde86681831"};
30 static constexpr StringPiece ticket2{
31  "444444444444444444444444444444444444444444444444444444444444444400000001f444b4f0a0d1dd8b26d3a0afa275b4f6956cfdce4857f9ec46177d0ff9"};
32 
33 static constexpr StringPiece ticketSecret2{
34  "04de0343a34c12f17f8b9696443d55e533ca1eef92bdba6634a46b604e51436d"};
35 // secret: d2c07e1107d3024bd08ebf34d59b9726d05bd7082da80cbb1e90b879e0770b5f
36 // salt: 5cef31d266ca1fe1d634de9b95668d3d8895d4837d3ba81787185ff51c056e95
37 // hkdf output: f7d80b07236875b5a48bdc5bd4642a775c05c231b9507285675c1e0b
38 static constexpr StringPiece ticket3{
39  "5cef31d266ca1fe1d634de9b95668d3d8895d4837d3ba81787185ff51c056e95000000005d19a72a3becb5b063346fdf1ec6f9d9d4ddd82cb5f34a8ba0d19e4b69"};
40 
41 // Uses context 'foobar'
42 static constexpr StringPiece ticket4{
43  "5cef31d266ca1fe1d634de9b95668d3d8895d4837d3ba81787185ff51c056e95000000005b2168cc0fda4f9987b5e9d045845ba4809ac5189158c578c0e5d11b00"};
44 
45 static constexpr StringPiece badTicket{
46  "5d19a72a3becb5b061346fdf1ec6f9d9d4ddd82cb5f34a8ba0d19e4b69"};
47 
48 namespace fizz {
49 namespace server {
50 namespace test {
51 
53  public:
56  _decode,
57  ResumptionState(Buf& encoded, const FizzServerContext* context));
58 };
59 
61  public:
62  static constexpr folly::StringPiece Label{"Mock Ticket Codec"};
64  return instance->_encode(state);
65  }
67  return instance->_decode(encoded, context);
68  }
70 };
71 MockTicketCodecInstance* MockTicketCodec::instance;
72 constexpr folly::StringPiece MockTicketCodec::Label;
73 
78 
79 class AeadTicketCipherTest : public Test {
80  public:
81  ~AeadTicketCipherTest() override = default;
82  void SetUp() override {
83  MockTicketCodec::instance = &codec_;
84  }
85 
86  protected:
89 
90  void setTicketSecrets(std::string pskContext = "") {
91  if (!pskContext.empty()) {
92  cipher_ = TestAeadTicketCipher(pskContext);
93  } else {
94  cipher_ = TestAeadTicketCipher();
95  }
96  auto s1 = toIOBuf(ticketSecret1);
97  auto s2 = toIOBuf(ticketSecret2);
98  std::vector<ByteRange> ticketSecrets{{s1->coalesce(), s2->coalesce()}};
99  EXPECT_TRUE(cipher_.setTicketSecrets(std::move(ticketSecrets)));
100  }
101 
102  void expectDecode() {
103  EXPECT_CALL(codec_, _decode(_, _))
104  .WillOnce(
105  Invoke([](Buf& encoded, const FizzServerContext* /*context*/) {
106  EXPECT_TRUE(
107  IOBufEqualTo()(encoded, IOBuf::copyBuffer("encodedticket")));
108  return ResumptionState();
109  }));
110  }
111 
114  EXPECT_FALSE(cipher_.encrypt(std::move(state)).get().hasValue());
115  }
116 };
117 
118 TEST_F(AeadTicketCipherTest, TestEncryptNoTicketSecrets) {
119  checkUnsetEncrypt();
120 }
121 
123  setTicketSecrets();
124  useMockRandom();
125  cipher_.setValidity(std::chrono::seconds(5));
126  EXPECT_CALL(codec_, _encode(_)).WillOnce(InvokeWithoutArgs([]() {
127  return IOBuf::copyBuffer("encodedticket");
128  }));
130  auto result = cipher_.encrypt(std::move(state)).get();
131  EXPECT_TRUE(result.hasValue());
132  EXPECT_TRUE(IOBufEqualTo()(result->first, toIOBuf(ticket1)));
133  EXPECT_EQ(result->second, std::chrono::seconds(5));
134 }
135 
136 TEST_F(AeadTicketCipherTest, TestDecryptNoTicketSecrets) {
137  auto result = cipher_.decrypt(toIOBuf(ticket1)).get();
138  EXPECT_EQ(result.first, PskType::Rejected);
139  EXPECT_FALSE(result.second.hasValue());
140 }
141 
142 TEST_F(AeadTicketCipherTest, TestDecryptFirst) {
143  setTicketSecrets();
144  expectDecode();
145  auto result = cipher_.decrypt(toIOBuf(ticket1)).get();
146  EXPECT_EQ(result.first, PskType::Resumption);
147  EXPECT_TRUE(result.second.hasValue());
148 }
149 
150 TEST_F(AeadTicketCipherTest, TestDecryptSecond) {
151  setTicketSecrets();
152  expectDecode();
153  auto result = cipher_.decrypt(toIOBuf(ticket3)).get();
154  EXPECT_EQ(result.first, PskType::Resumption);
155  EXPECT_TRUE(result.second.hasValue());
156 }
157 
158 TEST_F(AeadTicketCipherTest, TestDecryptWithContext) {
159  setTicketSecrets("foobar");
160  expectDecode();
161  auto result = cipher_.decrypt(toIOBuf(ticket4)).get();
162  EXPECT_EQ(result.first, PskType::Resumption);
163  EXPECT_TRUE(result.second.hasValue());
164 }
165 
166 TEST_F(AeadTicketCipherTest, TestDecryptWithoutContext) {
167  setTicketSecrets();
168  // Ticket 4 needs context 'foobar'
169  auto result = cipher_.decrypt(toIOBuf(ticket4)).get();
170  EXPECT_EQ(result.first, PskType::Rejected);
171  EXPECT_FALSE(result.second.hasValue());
172 }
173 
174 TEST_F(AeadTicketCipherTest, TestDecryptWithWrongContext) {
175  setTicketSecrets("barbaz");
176  // barbaz =/= foobar
177  auto result = cipher_.decrypt(toIOBuf(ticket4)).get();
178  EXPECT_EQ(result.first, PskType::Rejected);
179  EXPECT_FALSE(result.second.hasValue());
180 }
181 
182 TEST_F(AeadTicketCipherTest, TestDecryptWithUnneededContext) {
183  setTicketSecrets("foobar");
184  // Now test that ticket 3 with context 'foobar' doesn't work
185  auto result = cipher_.decrypt(toIOBuf(ticket3)).get();
186  EXPECT_EQ(result.first, PskType::Rejected);
187  EXPECT_FALSE(result.second.hasValue());
188 }
189 
190 TEST_F(AeadTicketCipherTest, TestDecryptSeqNum) {
191  setTicketSecrets();
192  expectDecode();
193  auto result = cipher_.decrypt(toIOBuf(ticket2)).get();
194  EXPECT_EQ(result.first, PskType::Resumption);
195  EXPECT_TRUE(result.second.hasValue());
196 }
197 
198 TEST_F(AeadTicketCipherTest, TestDecryptFailed) {
199  setTicketSecrets();
200  auto result = cipher_.decrypt(toIOBuf(badTicket)).get();
201  EXPECT_EQ(result.first, PskType::Rejected);
202  EXPECT_FALSE(result.second.hasValue());
203 }
204 
205 TEST_F(AeadTicketCipherTest, TestDecryptTooShort) {
206  setTicketSecrets();
207  auto result = cipher_.decrypt(IOBuf::copyBuffer("short")).get();
208  EXPECT_EQ(result.first, PskType::Rejected);
209  EXPECT_FALSE(result.second.hasValue());
210 }
211 
212 TEST_F(AeadTicketCipherTest, TestUnsetTicketSecrets) {
213  setTicketSecrets();
214  EXPECT_TRUE(cipher_.setTicketSecrets(std::vector<ByteRange>()));
215  checkUnsetEncrypt();
216 }
217 
218 TEST_F(AeadTicketCipherTest, TestSetTicketSecretsTooShort) {
219  StringPiece tooShort{"short"};
220  std::vector<ByteRange> ticketSecrets{{tooShort}};
221  EXPECT_FALSE(cipher_.setTicketSecrets(std::move(ticketSecrets)));
222  checkUnsetEncrypt();
223 }
224 } // namespace test
225 } // namespace server
226 } // namespace fizz
#define MOCK_CONST_METHOD1(m,...)
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static constexpr StringPiece ticketSecret1
context
Definition: CMakeCache.txt:563
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
void setTicketSecrets(std::string pskContext="")
static constexpr StringPiece ticket4
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
std::unique_ptr< Codec > codec_
PolymorphicAction< internal::InvokeWithoutArgsAction< FunctionImpl > > InvokeWithoutArgs(FunctionImpl function_impl)
void useMockRandom()
Definition: TestUtil.cpp:69
std::unique_ptr< folly::IOBuf > toIOBuf(std::string hexData, size_t headroom, size_t tailroom)
Definition: TestUtil.cpp:24
static constexpr StringPiece ticket1
bool setTicketSecrets(const std::vector< folly::ByteRange > &ticketSecrets)
PolymorphicAction< internal::InvokeAction< FunctionImpl > > Invoke(FunctionImpl function_impl)
Definition: Actions.h:16
folly::Future< folly::Optional< std::pair< Buf, std::chrono::seconds > > > encrypt(ResumptionState resState) const override
static Buf encode(ResumptionState state)
static MockTicketCodecInstance * instance
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
TEST_F(RSAPSSTest, TestSignVerify)
const char * string
Definition: Conv.cpp:212
std::unique_ptr< folly::IOBuf > Buf
Definition: Types.h:22
#define MOCK_CONST_METHOD2(m,...)
#define EXPECT_CALL(obj, call)
const internal::AnythingMatcher _
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
static constexpr StringPiece badTicket
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
AeadTicketCipher< OpenSSLEVPCipher< AESGCM128 >, MockTicketCodec, HkdfImpl< Sha256 >> TestAeadTicketCipher
static constexpr StringPiece ticket2
static constexpr StringPiece ticket3
static ResumptionState decode(Buf encoded, const FizzServerContext *context)
state
Definition: http_parser.c:272
static constexpr StringPiece ticketSecret2