blob: ebfb89c1549311411fb5525f75c4c8569b1741e3 [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 Pesavento2e5b7b12022-09-19 23:30:44 -040027#include <ndn-cxx/security/validator-null.hpp>
Davide Pesaventocab86032020-12-10 20:30:12 -050028#include <ndn-cxx/util/dummy-client-face.hpp>
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040029#include <ndn-cxx/util/string-helper.hpp>
30
Davide Pesaventobde084f2022-04-17 00:21:35 -040031#include <iostream>
32
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040033namespace ndn {
34namespace nac {
35namespace tests {
36
Davide Pesaventoba3f6892020-12-08 22:18:35 -050037class EncryptorStaticDataEnvironment : public IoKeyChainFixture
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040038{
39public:
Alexander Afanasyevda366d82018-06-29 18:18:02 -040040 EncryptorStaticDataEnvironment(bool shouldPublishData)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040041 {
Alexander Afanasyevda366d82018-06-29 18:18:02 -040042 if (shouldPublishData) {
43 publishData();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040044 }
45
Davide Pesaventoba3f6892020-12-08 22:18:35 -050046 auto serveFromIms = [this] (const Name&, const Interest& interest) {
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040047 auto data = m_ims.find(interest);
48 if (data != nullptr) {
Davide Pesaventocab86032020-12-10 20:30:12 -050049 m_imsFace.put(*data);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040050 }
51 };
Davide Pesaventocab86032020-12-10 20:30:12 -050052 m_imsFace.setInterestFilter("/", serveFromIms, [] (auto...) {});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040053 advanceClocks(1_ms, 10);
Alexander Afanasyevda366d82018-06-29 18:18:02 -040054
Davide Pesaventocab86032020-12-10 20:30:12 -050055 m_imsFace.sentData.clear();
56 m_imsFace.sentInterests.clear();
Alexander Afanasyevda366d82018-06-29 18:18:02 -040057 }
58
59 void
60 publishData()
61 {
62 StaticData data;
63 for (const auto& block : data.managerPackets) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -050064 m_ims.insert(*make_shared<Data>(block));
Alexander Afanasyevda366d82018-06-29 18:18:02 -040065 }
66 advanceClocks(1_ms, 10);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040067 }
68
Davide Pesaventocab86032020-12-10 20:30:12 -050069protected:
70 util::DummyClientFace m_imsFace{m_io, m_keyChain, {true, true}};
71
72private:
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040073 InMemoryStoragePersistent m_ims;
74};
75
Alexander Afanasyevda366d82018-06-29 18:18:02 -040076template<bool shouldPublishData = true>
77class EncryptorFixture : public EncryptorStaticDataEnvironment
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040078{
79public:
80 EncryptorFixture()
Alexander Afanasyevda366d82018-06-29 18:18:02 -040081 : EncryptorStaticDataEnvironment(shouldPublishData)
Davide Pesaventocab86032020-12-10 20:30:12 -050082 , face(m_io, m_keyChain, {true, true})
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040083 , encryptor("/access/policy/identity/NAC/dataset", "/some/ck/prefix", signingWithSha256(),
Alexander Afanasyevda366d82018-06-29 18:18:02 -040084 [=] (const ErrorCode& code, const std::string& error) {
85 onFailure(code, error);
86 },
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040087 validator, m_keyChain, face)
88 {
Davide Pesaventocab86032020-12-10 20:30:12 -050089 face.linkTo(m_imsFace);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040090 advanceClocks(1_ms, 10);
91 }
92
93public:
Davide Pesaventocab86032020-12-10 20:30:12 -050094 util::DummyClientFace face;
Davide Pesavento2e5b7b12022-09-19 23:30:44 -040095 security::ValidatorNull validator;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040096 Encryptor encryptor;
Alexander Afanasyevda366d82018-06-29 18:18:02 -040097 util::Signal<EncryptorFixture, ErrorCode, std::string> onFailure;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040098};
99
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400100BOOST_FIXTURE_TEST_SUITE(TestEncryptor, EncryptorFixture<>)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400101
102BOOST_AUTO_TEST_CASE(EncryptAndPublishedCk)
103{
Alexander Afanasyevc9934282018-07-17 18:41:36 -0400104 encryptor.m_kek.reset();
105 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, false);
106 encryptor.regenerateCk();
107 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, true);
108
Davide Pesavento714dba02022-03-17 20:46:28 -0400109 const std::string plaintext = "Data to encrypt";
110 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400111
112 EncryptedContent content(block);
113 auto ckPrefix = content.getKeyLocator();
114 BOOST_CHECK_EQUAL(ckPrefix.getPrefix(-1), "/some/ck/prefix/CK");
115
116 BOOST_CHECK(content.hasIv());
117 BOOST_CHECK_NE(std::string(reinterpret_cast<const char*>(content.getPayload().value()),
118 content.getPayload().value_size()),
119 plaintext);
120
121 advanceClocks(1_ms, 10);
122
123 // check that KEK interests has been sent
124 BOOST_CHECK_EQUAL(face.sentInterests.at(0).getName().getPrefix(6),
125 Name("/access/policy/identity/NAC/dataset/KEK"));
126
Davide Pesaventocab86032020-12-10 20:30:12 -0500127 auto kek = m_imsFace.sentData.at(0);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400128 BOOST_CHECK_EQUAL(kek.getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
129 BOOST_CHECK_EQUAL(kek.getName().size(), 7);
130
131 face.sentData.clear();
132 face.sentInterests.clear();
133
134 face.receive(Interest(ckPrefix)
135 .setCanBePrefix(true).setMustBeFresh(true));
136 advanceClocks(1_ms, 10);
137
138 auto ckName = face.sentData.at(0).getName();
139 BOOST_CHECK_EQUAL(ckName.getPrefix(4), "/some/ck/prefix/CK");
140 BOOST_CHECK_EQUAL(ckName.get(5), name::Component("ENCRYPTED-BY"));
141
142 auto extractedKek = ckName.getSubName(6);
143 BOOST_CHECK_EQUAL(extractedKek, kek.getName());
Alexander Afanasyevc9934282018-07-17 18:41:36 -0400144
145 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, false);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400146}
147
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400148BOOST_FIXTURE_TEST_CASE(KekRetrievalFailure, EncryptorFixture<false>)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400149{
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400150 size_t nErrors = 0;
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500151 onFailure.connect([&] (auto&&...) { ++nErrors; });
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400152
Davide Pesavento714dba02022-03-17 20:46:28 -0400153 const std::string plaintext = "Data to encrypt";
154 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400155 advanceClocks(1_ms, 10);
156
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400157 // check that KEK interests has been sent
158 BOOST_CHECK_EQUAL(face.sentInterests.at(0).getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
159
160 // and failed
Davide Pesaventocab86032020-12-10 20:30:12 -0500161 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400162
163 advanceClocks(1_s, 13); // 4_s default interest lifetime x 3
164 BOOST_CHECK_EQUAL(nErrors, 1);
Davide Pesaventocab86032020-12-10 20:30:12 -0500165 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400166
167 advanceClocks(1_s, 730); // 60 seconds between attempts + ~12 seconds for each attempt
168 BOOST_CHECK_EQUAL(nErrors, 11);
Davide Pesaventocab86032020-12-10 20:30:12 -0500169 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400170
171 // check recovery
172
173 publishData();
174
175 advanceClocks(1_s, 73);
176
Davide Pesaventocab86032020-12-10 20:30:12 -0500177 auto kek = m_imsFace.sentData.at(0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400178 BOOST_CHECK_EQUAL(kek.getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
179 BOOST_CHECK_EQUAL(kek.getName().size(), 7);
180}
181
182BOOST_AUTO_TEST_CASE(EnumerateDataFromIms)
183{
184 encryptor.regenerateCk();
185 advanceClocks(1_ms, 10);
186
187 encryptor.regenerateCk();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400188 advanceClocks(1_ms, 10);
189
190 BOOST_CHECK_EQUAL(encryptor.size(), 3);
191 size_t nCk = 0;
192 for (const auto& data : encryptor) {
193 BOOST_TEST_MESSAGE(data.getName());
194 if (data.getName().getPrefix(4) == Name("/some/ck/prefix/CK")) {
195 ++nCk;
196 }
197 }
198 BOOST_CHECK_EQUAL(nCk, 3);
199}
200
Davide Pesavento32d1dc22020-12-09 18:01:47 -0500201BOOST_AUTO_TEST_CASE(GenerateTestData,
202 * ut::description("regenerates the static test data used by other test cases")
203 * ut::disabled())
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400204{
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500205 const auto plaintext = "Data to encrypt"s;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400206
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500207 std::cerr << "const std::vector<Block> encryptedBlobs = {\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400208 for (size_t i = 0; i < 3; ++i) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500209 std::cerr << " \"";
Davide Pesavento714dba02022-03-17 20:46:28 -0400210 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
211 printHex(std::cerr, block.wireEncode(), true);
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500212 std::cerr << "\"_block,\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400213
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400214 encryptor.regenerateCk();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400215 advanceClocks(1_ms, 10);
216 }
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500217 std::cerr << "};\n\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400218
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500219 std::cerr << "const std::vector<Block> encryptorPackets = {\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400220 for (const auto& data : encryptor) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500221 std::cerr << " \"";
Davide Pesavento714dba02022-03-17 20:46:28 -0400222 printHex(std::cerr, data.wireEncode(), true);
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500223 std::cerr << "\"_block,\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400224 }
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500225 std::cerr << "};\n\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400226}
227
228BOOST_AUTO_TEST_SUITE_END()
229
230} // namespace tests
231} // namespace nac
232} // namespace ndn