blob: 02ae88b87bdeae8565336bcc4ab0c513781798ac [file] [log] [blame]
Alexander Afanasyev1a21e102018-06-13 20:33:21 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento9062a502020-01-04 17:14:04 -05002/*
Davide Pesavento714dba02022-03-17 20:46:28 -04003 * Copyright (c) 2014-2022, Regents of the University of California
Alexander Afanasyev1a21e102018-06-13 20:33:21 -04004 *
5 * NAC library is free software: you can redistribute it and/or modify it under the
6 * terms of the GNU Lesser General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option) any later version.
8 *
9 * NAC library is distributed in the hope that it will be useful, but WITHOUT ANY
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 *
13 * You should have received copies of the GNU General Public License and GNU Lesser
14 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
15 * <http://www.gnu.org/licenses/>.
16 *
17 * See AUTHORS.md for complete list of NAC library authors and contributors.
18 */
19
20#include "encryptor.hpp"
21
Davide Pesaventoba3f6892020-12-08 22:18:35 -050022#include "tests/boost-test.hpp"
Davide Pesaventoba3f6892020-12-08 22:18:35 -050023#include "tests/io-key-chain-fixture.hpp"
24#include "tests/unit/static-data.hpp"
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040025
Davide Pesaventobde084f2022-04-17 00:21:35 -040026#include <ndn-cxx/security/signing-helpers.hpp>
Davide Pesaventocab86032020-12-10 20:30:12 -050027#include <ndn-cxx/util/dummy-client-face.hpp>
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040028#include <ndn-cxx/util/string-helper.hpp>
29
Davide Pesaventobde084f2022-04-17 00:21:35 -040030#include <iostream>
31
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040032namespace ndn {
33namespace nac {
34namespace tests {
35
Davide Pesaventoba3f6892020-12-08 22:18:35 -050036class EncryptorStaticDataEnvironment : public IoKeyChainFixture
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040037{
38public:
Alexander Afanasyevda366d82018-06-29 18:18:02 -040039 EncryptorStaticDataEnvironment(bool shouldPublishData)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040040 {
Alexander Afanasyevda366d82018-06-29 18:18:02 -040041 if (shouldPublishData) {
42 publishData();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040043 }
44
Davide Pesaventoba3f6892020-12-08 22:18:35 -050045 auto serveFromIms = [this] (const Name&, const Interest& interest) {
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040046 auto data = m_ims.find(interest);
47 if (data != nullptr) {
Davide Pesaventocab86032020-12-10 20:30:12 -050048 m_imsFace.put(*data);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040049 }
50 };
Davide Pesaventocab86032020-12-10 20:30:12 -050051 m_imsFace.setInterestFilter("/", serveFromIms, [] (auto...) {});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040052 advanceClocks(1_ms, 10);
Alexander Afanasyevda366d82018-06-29 18:18:02 -040053
Davide Pesaventocab86032020-12-10 20:30:12 -050054 m_imsFace.sentData.clear();
55 m_imsFace.sentInterests.clear();
Alexander Afanasyevda366d82018-06-29 18:18:02 -040056 }
57
58 void
59 publishData()
60 {
61 StaticData data;
62 for (const auto& block : data.managerPackets) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -050063 m_ims.insert(*make_shared<Data>(block));
Alexander Afanasyevda366d82018-06-29 18:18:02 -040064 }
65 advanceClocks(1_ms, 10);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040066 }
67
Davide Pesaventocab86032020-12-10 20:30:12 -050068protected:
69 util::DummyClientFace m_imsFace{m_io, m_keyChain, {true, true}};
70
71private:
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040072 InMemoryStoragePersistent m_ims;
73};
74
Alexander Afanasyevda366d82018-06-29 18:18:02 -040075template<bool shouldPublishData = true>
76class EncryptorFixture : public EncryptorStaticDataEnvironment
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040077{
78public:
79 EncryptorFixture()
Alexander Afanasyevda366d82018-06-29 18:18:02 -040080 : EncryptorStaticDataEnvironment(shouldPublishData)
Davide Pesaventocab86032020-12-10 20:30:12 -050081 , face(m_io, m_keyChain, {true, true})
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040082 , encryptor("/access/policy/identity/NAC/dataset", "/some/ck/prefix", signingWithSha256(),
Alexander Afanasyevda366d82018-06-29 18:18:02 -040083 [=] (const ErrorCode& code, const std::string& error) {
84 onFailure(code, error);
85 },
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040086 validator, m_keyChain, face)
87 {
Davide Pesaventocab86032020-12-10 20:30:12 -050088 face.linkTo(m_imsFace);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040089 advanceClocks(1_ms, 10);
90 }
91
92public:
Davide Pesaventocab86032020-12-10 20:30:12 -050093 util::DummyClientFace face;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040094 ValidatorNull validator;
95 Encryptor encryptor;
Alexander Afanasyevda366d82018-06-29 18:18:02 -040096 util::Signal<EncryptorFixture, ErrorCode, std::string> onFailure;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040097};
98
Alexander Afanasyevda366d82018-06-29 18:18:02 -040099BOOST_FIXTURE_TEST_SUITE(TestEncryptor, EncryptorFixture<>)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400100
101BOOST_AUTO_TEST_CASE(EncryptAndPublishedCk)
102{
Alexander Afanasyevc9934282018-07-17 18:41:36 -0400103 encryptor.m_kek.reset();
104 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, false);
105 encryptor.regenerateCk();
106 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, true);
107
Davide Pesavento714dba02022-03-17 20:46:28 -0400108 const std::string plaintext = "Data to encrypt";
109 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400110
111 EncryptedContent content(block);
112 auto ckPrefix = content.getKeyLocator();
113 BOOST_CHECK_EQUAL(ckPrefix.getPrefix(-1), "/some/ck/prefix/CK");
114
115 BOOST_CHECK(content.hasIv());
116 BOOST_CHECK_NE(std::string(reinterpret_cast<const char*>(content.getPayload().value()),
117 content.getPayload().value_size()),
118 plaintext);
119
120 advanceClocks(1_ms, 10);
121
122 // check that KEK interests has been sent
123 BOOST_CHECK_EQUAL(face.sentInterests.at(0).getName().getPrefix(6),
124 Name("/access/policy/identity/NAC/dataset/KEK"));
125
Davide Pesaventocab86032020-12-10 20:30:12 -0500126 auto kek = m_imsFace.sentData.at(0);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400127 BOOST_CHECK_EQUAL(kek.getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
128 BOOST_CHECK_EQUAL(kek.getName().size(), 7);
129
130 face.sentData.clear();
131 face.sentInterests.clear();
132
133 face.receive(Interest(ckPrefix)
134 .setCanBePrefix(true).setMustBeFresh(true));
135 advanceClocks(1_ms, 10);
136
137 auto ckName = face.sentData.at(0).getName();
138 BOOST_CHECK_EQUAL(ckName.getPrefix(4), "/some/ck/prefix/CK");
139 BOOST_CHECK_EQUAL(ckName.get(5), name::Component("ENCRYPTED-BY"));
140
141 auto extractedKek = ckName.getSubName(6);
142 BOOST_CHECK_EQUAL(extractedKek, kek.getName());
Alexander Afanasyevc9934282018-07-17 18:41:36 -0400143
144 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, false);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400145}
146
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400147BOOST_FIXTURE_TEST_CASE(KekRetrievalFailure, EncryptorFixture<false>)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400148{
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400149 size_t nErrors = 0;
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500150 onFailure.connect([&] (auto&&...) { ++nErrors; });
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400151
Davide Pesavento714dba02022-03-17 20:46:28 -0400152 const std::string plaintext = "Data to encrypt";
153 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400154 advanceClocks(1_ms, 10);
155
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400156 // check that KEK interests has been sent
157 BOOST_CHECK_EQUAL(face.sentInterests.at(0).getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
158
159 // and failed
Davide Pesaventocab86032020-12-10 20:30:12 -0500160 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400161
162 advanceClocks(1_s, 13); // 4_s default interest lifetime x 3
163 BOOST_CHECK_EQUAL(nErrors, 1);
Davide Pesaventocab86032020-12-10 20:30:12 -0500164 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400165
166 advanceClocks(1_s, 730); // 60 seconds between attempts + ~12 seconds for each attempt
167 BOOST_CHECK_EQUAL(nErrors, 11);
Davide Pesaventocab86032020-12-10 20:30:12 -0500168 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400169
170 // check recovery
171
172 publishData();
173
174 advanceClocks(1_s, 73);
175
Davide Pesaventocab86032020-12-10 20:30:12 -0500176 auto kek = m_imsFace.sentData.at(0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400177 BOOST_CHECK_EQUAL(kek.getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
178 BOOST_CHECK_EQUAL(kek.getName().size(), 7);
179}
180
181BOOST_AUTO_TEST_CASE(EnumerateDataFromIms)
182{
183 encryptor.regenerateCk();
184 advanceClocks(1_ms, 10);
185
186 encryptor.regenerateCk();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400187 advanceClocks(1_ms, 10);
188
189 BOOST_CHECK_EQUAL(encryptor.size(), 3);
190 size_t nCk = 0;
191 for (const auto& data : encryptor) {
192 BOOST_TEST_MESSAGE(data.getName());
193 if (data.getName().getPrefix(4) == Name("/some/ck/prefix/CK")) {
194 ++nCk;
195 }
196 }
197 BOOST_CHECK_EQUAL(nCk, 3);
198}
199
Davide Pesavento32d1dc22020-12-09 18:01:47 -0500200BOOST_AUTO_TEST_CASE(GenerateTestData,
201 * ut::description("regenerates the static test data used by other test cases")
202 * ut::disabled())
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400203{
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500204 const auto plaintext = "Data to encrypt"s;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400205
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500206 std::cerr << "const std::vector<Block> encryptedBlobs = {\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400207 for (size_t i = 0; i < 3; ++i) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500208 std::cerr << " \"";
Davide Pesavento714dba02022-03-17 20:46:28 -0400209 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
210 printHex(std::cerr, block.wireEncode(), true);
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500211 std::cerr << "\"_block,\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400212
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400213 encryptor.regenerateCk();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400214 advanceClocks(1_ms, 10);
215 }
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500216 std::cerr << "};\n\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400217
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500218 std::cerr << "const std::vector<Block> encryptorPackets = {\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400219 for (const auto& data : encryptor) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500220 std::cerr << " \"";
Davide Pesavento714dba02022-03-17 20:46:28 -0400221 printHex(std::cerr, data.wireEncode(), true);
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500222 std::cerr << "\"_block,\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400223 }
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500224 std::cerr << "};\n\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400225}
226
227BOOST_AUTO_TEST_SUITE_END()
228
229} // namespace tests
230} // namespace nac
231} // namespace ndn