blob: 4a2e0a9af4fe40a14ac1244c89141021e4ae6893 [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 Pesavento5d2f1512023-08-11 14:50:51 -04003 * Copyright (c) 2014-2023, 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
Davide Pesavento5d2f1512023-08-11 14:50:51 -040033namespace ndn::nac::tests {
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040034
Davide Pesaventoba3f6892020-12-08 22:18:35 -050035class EncryptorStaticDataEnvironment : public IoKeyChainFixture
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040036{
37public:
Alexander Afanasyevda366d82018-06-29 18:18:02 -040038 EncryptorStaticDataEnvironment(bool shouldPublishData)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040039 {
Alexander Afanasyevda366d82018-06-29 18:18:02 -040040 if (shouldPublishData) {
41 publishData();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040042 }
43
Davide Pesaventoba3f6892020-12-08 22:18:35 -050044 auto serveFromIms = [this] (const Name&, const Interest& interest) {
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040045 auto data = m_ims.find(interest);
46 if (data != nullptr) {
Davide Pesaventocab86032020-12-10 20:30:12 -050047 m_imsFace.put(*data);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040048 }
49 };
Davide Pesaventocab86032020-12-10 20:30:12 -050050 m_imsFace.setInterestFilter("/", serveFromIms, [] (auto...) {});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040051 advanceClocks(1_ms, 10);
Alexander Afanasyevda366d82018-06-29 18:18:02 -040052
Davide Pesaventocab86032020-12-10 20:30:12 -050053 m_imsFace.sentData.clear();
54 m_imsFace.sentInterests.clear();
Alexander Afanasyevda366d82018-06-29 18:18:02 -040055 }
56
57 void
58 publishData()
59 {
60 StaticData data;
61 for (const auto& block : data.managerPackets) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -050062 m_ims.insert(*make_shared<Data>(block));
Alexander Afanasyevda366d82018-06-29 18:18:02 -040063 }
64 advanceClocks(1_ms, 10);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040065 }
66
Davide Pesaventocab86032020-12-10 20:30:12 -050067protected:
Davide Pesavento5d2f1512023-08-11 14:50:51 -040068 DummyClientFace m_imsFace{m_io, m_keyChain, {true, true}};
Davide Pesaventocab86032020-12-10 20:30:12 -050069
70private:
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040071 InMemoryStoragePersistent m_ims;
72};
73
Alexander Afanasyevda366d82018-06-29 18:18:02 -040074template<bool shouldPublishData = true>
75class EncryptorFixture : public EncryptorStaticDataEnvironment
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040076{
77public:
78 EncryptorFixture()
Alexander Afanasyevda366d82018-06-29 18:18:02 -040079 : EncryptorStaticDataEnvironment(shouldPublishData)
Davide Pesaventocab86032020-12-10 20:30:12 -050080 , face(m_io, m_keyChain, {true, true})
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040081 , encryptor("/access/policy/identity/NAC/dataset", "/some/ck/prefix", signingWithSha256(),
Alexander Afanasyevda366d82018-06-29 18:18:02 -040082 [=] (const ErrorCode& code, const std::string& error) {
83 onFailure(code, error);
84 },
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040085 validator, m_keyChain, face)
86 {
Davide Pesaventocab86032020-12-10 20:30:12 -050087 face.linkTo(m_imsFace);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040088 advanceClocks(1_ms, 10);
89 }
90
91public:
Davide Pesavento5d2f1512023-08-11 14:50:51 -040092 DummyClientFace face;
Davide Pesavento2e5b7b12022-09-19 23:30:44 -040093 security::ValidatorNull validator;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040094 Encryptor encryptor;
Davide Pesavento5d2f1512023-08-11 14:50:51 -040095 signal::Signal<EncryptorFixture, ErrorCode, std::string> onFailure;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040096};
97
Alexander Afanasyevda366d82018-06-29 18:18:02 -040098BOOST_FIXTURE_TEST_SUITE(TestEncryptor, EncryptorFixture<>)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040099
100BOOST_AUTO_TEST_CASE(EncryptAndPublishedCk)
101{
Alexander Afanasyevc9934282018-07-17 18:41:36 -0400102 encryptor.m_kek.reset();
103 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, false);
104 encryptor.regenerateCk();
105 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, true);
106
Davide Pesavento714dba02022-03-17 20:46:28 -0400107 const std::string plaintext = "Data to encrypt";
108 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400109
110 EncryptedContent content(block);
111 auto ckPrefix = content.getKeyLocator();
112 BOOST_CHECK_EQUAL(ckPrefix.getPrefix(-1), "/some/ck/prefix/CK");
113
114 BOOST_CHECK(content.hasIv());
115 BOOST_CHECK_NE(std::string(reinterpret_cast<const char*>(content.getPayload().value()),
116 content.getPayload().value_size()),
117 plaintext);
118
119 advanceClocks(1_ms, 10);
120
121 // check that KEK interests has been sent
122 BOOST_CHECK_EQUAL(face.sentInterests.at(0).getName().getPrefix(6),
123 Name("/access/policy/identity/NAC/dataset/KEK"));
124
Davide Pesaventocab86032020-12-10 20:30:12 -0500125 auto kek = m_imsFace.sentData.at(0);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400126 BOOST_CHECK_EQUAL(kek.getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
127 BOOST_CHECK_EQUAL(kek.getName().size(), 7);
128
129 face.sentData.clear();
130 face.sentInterests.clear();
131
132 face.receive(Interest(ckPrefix)
133 .setCanBePrefix(true).setMustBeFresh(true));
134 advanceClocks(1_ms, 10);
135
136 auto ckName = face.sentData.at(0).getName();
137 BOOST_CHECK_EQUAL(ckName.getPrefix(4), "/some/ck/prefix/CK");
138 BOOST_CHECK_EQUAL(ckName.get(5), name::Component("ENCRYPTED-BY"));
139
140 auto extractedKek = ckName.getSubName(6);
141 BOOST_CHECK_EQUAL(extractedKek, kek.getName());
Alexander Afanasyevc9934282018-07-17 18:41:36 -0400142
143 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, false);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400144}
145
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400146BOOST_FIXTURE_TEST_CASE(KekRetrievalFailure, EncryptorFixture<false>)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400147{
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400148 size_t nErrors = 0;
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500149 onFailure.connect([&] (auto&&...) { ++nErrors; });
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400150
Davide Pesavento714dba02022-03-17 20:46:28 -0400151 const std::string plaintext = "Data to encrypt";
152 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400153 advanceClocks(1_ms, 10);
154
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400155 // check that KEK interests has been sent
156 BOOST_CHECK_EQUAL(face.sentInterests.at(0).getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
157
158 // and failed
Davide Pesaventocab86032020-12-10 20:30:12 -0500159 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400160
161 advanceClocks(1_s, 13); // 4_s default interest lifetime x 3
162 BOOST_CHECK_EQUAL(nErrors, 1);
Davide Pesaventocab86032020-12-10 20:30:12 -0500163 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400164
165 advanceClocks(1_s, 730); // 60 seconds between attempts + ~12 seconds for each attempt
166 BOOST_CHECK_EQUAL(nErrors, 11);
Davide Pesaventocab86032020-12-10 20:30:12 -0500167 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400168
169 // check recovery
170
171 publishData();
172
173 advanceClocks(1_s, 73);
174
Davide Pesaventocab86032020-12-10 20:30:12 -0500175 auto kek = m_imsFace.sentData.at(0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400176 BOOST_CHECK_EQUAL(kek.getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
177 BOOST_CHECK_EQUAL(kek.getName().size(), 7);
178}
179
180BOOST_AUTO_TEST_CASE(EnumerateDataFromIms)
181{
182 encryptor.regenerateCk();
183 advanceClocks(1_ms, 10);
184
185 encryptor.regenerateCk();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400186 advanceClocks(1_ms, 10);
187
188 BOOST_CHECK_EQUAL(encryptor.size(), 3);
189 size_t nCk = 0;
190 for (const auto& data : encryptor) {
191 BOOST_TEST_MESSAGE(data.getName());
192 if (data.getName().getPrefix(4) == Name("/some/ck/prefix/CK")) {
193 ++nCk;
194 }
195 }
196 BOOST_CHECK_EQUAL(nCk, 3);
197}
198
Davide Pesavento32d1dc22020-12-09 18:01:47 -0500199BOOST_AUTO_TEST_CASE(GenerateTestData,
200 * ut::description("regenerates the static test data used by other test cases")
201 * ut::disabled())
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400202{
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500203 const auto plaintext = "Data to encrypt"s;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400204
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500205 std::cerr << "const std::vector<Block> encryptedBlobs = {\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400206 for (size_t i = 0; i < 3; ++i) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500207 std::cerr << " \"";
Davide Pesavento714dba02022-03-17 20:46:28 -0400208 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
209 printHex(std::cerr, block.wireEncode(), true);
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500210 std::cerr << "\"_block,\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400211
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400212 encryptor.regenerateCk();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400213 advanceClocks(1_ms, 10);
214 }
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500215 std::cerr << "};\n\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400216
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500217 std::cerr << "const std::vector<Block> encryptorPackets = {\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400218 for (const auto& data : encryptor) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500219 std::cerr << " \"";
Davide Pesavento714dba02022-03-17 20:46:28 -0400220 printHex(std::cerr, data.wireEncode(), true);
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500221 std::cerr << "\"_block,\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400222 }
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500223 std::cerr << "};\n\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400224}
225
226BOOST_AUTO_TEST_SUITE_END()
227
Davide Pesavento5d2f1512023-08-11 14:50:51 -0400228} // namespace ndn::nac::tests