blob: d9bafba3b936733b529b5ec31661dcaa00c03293 [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
26#include <iostream>
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
30namespace ndn {
31namespace nac {
32namespace tests {
33
Davide Pesaventoba3f6892020-12-08 22:18:35 -050034class EncryptorStaticDataEnvironment : public IoKeyChainFixture
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040035{
36public:
Alexander Afanasyevda366d82018-06-29 18:18:02 -040037 EncryptorStaticDataEnvironment(bool shouldPublishData)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040038 {
Alexander Afanasyevda366d82018-06-29 18:18:02 -040039 if (shouldPublishData) {
40 publishData();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040041 }
42
Davide Pesaventoba3f6892020-12-08 22:18:35 -050043 auto serveFromIms = [this] (const Name&, const Interest& interest) {
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040044 auto data = m_ims.find(interest);
45 if (data != nullptr) {
Davide Pesaventocab86032020-12-10 20:30:12 -050046 m_imsFace.put(*data);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040047 }
48 };
Davide Pesaventocab86032020-12-10 20:30:12 -050049 m_imsFace.setInterestFilter("/", serveFromIms, [] (auto...) {});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040050 advanceClocks(1_ms, 10);
Alexander Afanasyevda366d82018-06-29 18:18:02 -040051
Davide Pesaventocab86032020-12-10 20:30:12 -050052 m_imsFace.sentData.clear();
53 m_imsFace.sentInterests.clear();
Alexander Afanasyevda366d82018-06-29 18:18:02 -040054 }
55
56 void
57 publishData()
58 {
59 StaticData data;
60 for (const auto& block : data.managerPackets) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -050061 m_ims.insert(*make_shared<Data>(block));
Alexander Afanasyevda366d82018-06-29 18:18:02 -040062 }
63 advanceClocks(1_ms, 10);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040064 }
65
Davide Pesaventocab86032020-12-10 20:30:12 -050066protected:
67 util::DummyClientFace m_imsFace{m_io, m_keyChain, {true, true}};
68
69private:
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040070 InMemoryStoragePersistent m_ims;
71};
72
Alexander Afanasyevda366d82018-06-29 18:18:02 -040073template<bool shouldPublishData = true>
74class EncryptorFixture : public EncryptorStaticDataEnvironment
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040075{
76public:
77 EncryptorFixture()
Alexander Afanasyevda366d82018-06-29 18:18:02 -040078 : EncryptorStaticDataEnvironment(shouldPublishData)
Davide Pesaventocab86032020-12-10 20:30:12 -050079 , face(m_io, m_keyChain, {true, true})
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040080 , encryptor("/access/policy/identity/NAC/dataset", "/some/ck/prefix", signingWithSha256(),
Alexander Afanasyevda366d82018-06-29 18:18:02 -040081 [=] (const ErrorCode& code, const std::string& error) {
82 onFailure(code, error);
83 },
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040084 validator, m_keyChain, face)
85 {
Davide Pesaventocab86032020-12-10 20:30:12 -050086 face.linkTo(m_imsFace);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040087 advanceClocks(1_ms, 10);
88 }
89
90public:
Davide Pesaventocab86032020-12-10 20:30:12 -050091 util::DummyClientFace face;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040092 ValidatorNull validator;
93 Encryptor encryptor;
Alexander Afanasyevda366d82018-06-29 18:18:02 -040094 util::Signal<EncryptorFixture, ErrorCode, std::string> onFailure;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040095};
96
Alexander Afanasyevda366d82018-06-29 18:18:02 -040097BOOST_FIXTURE_TEST_SUITE(TestEncryptor, EncryptorFixture<>)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -040098
99BOOST_AUTO_TEST_CASE(EncryptAndPublishedCk)
100{
Alexander Afanasyevc9934282018-07-17 18:41:36 -0400101 encryptor.m_kek.reset();
102 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, false);
103 encryptor.regenerateCk();
104 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, true);
105
Davide Pesavento714dba02022-03-17 20:46:28 -0400106 const std::string plaintext = "Data to encrypt";
107 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400108
109 EncryptedContent content(block);
110 auto ckPrefix = content.getKeyLocator();
111 BOOST_CHECK_EQUAL(ckPrefix.getPrefix(-1), "/some/ck/prefix/CK");
112
113 BOOST_CHECK(content.hasIv());
114 BOOST_CHECK_NE(std::string(reinterpret_cast<const char*>(content.getPayload().value()),
115 content.getPayload().value_size()),
116 plaintext);
117
118 advanceClocks(1_ms, 10);
119
120 // check that KEK interests has been sent
121 BOOST_CHECK_EQUAL(face.sentInterests.at(0).getName().getPrefix(6),
122 Name("/access/policy/identity/NAC/dataset/KEK"));
123
Davide Pesaventocab86032020-12-10 20:30:12 -0500124 auto kek = m_imsFace.sentData.at(0);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400125 BOOST_CHECK_EQUAL(kek.getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
126 BOOST_CHECK_EQUAL(kek.getName().size(), 7);
127
128 face.sentData.clear();
129 face.sentInterests.clear();
130
131 face.receive(Interest(ckPrefix)
132 .setCanBePrefix(true).setMustBeFresh(true));
133 advanceClocks(1_ms, 10);
134
135 auto ckName = face.sentData.at(0).getName();
136 BOOST_CHECK_EQUAL(ckName.getPrefix(4), "/some/ck/prefix/CK");
137 BOOST_CHECK_EQUAL(ckName.get(5), name::Component("ENCRYPTED-BY"));
138
139 auto extractedKek = ckName.getSubName(6);
140 BOOST_CHECK_EQUAL(extractedKek, kek.getName());
Alexander Afanasyevc9934282018-07-17 18:41:36 -0400141
142 BOOST_CHECK_EQUAL(encryptor.m_isKekRetrievalInProgress, false);
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400143}
144
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400145BOOST_FIXTURE_TEST_CASE(KekRetrievalFailure, EncryptorFixture<false>)
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400146{
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400147 size_t nErrors = 0;
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500148 onFailure.connect([&] (auto&&...) { ++nErrors; });
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400149
Davide Pesavento714dba02022-03-17 20:46:28 -0400150 const std::string plaintext = "Data to encrypt";
151 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400152 advanceClocks(1_ms, 10);
153
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400154 // check that KEK interests has been sent
155 BOOST_CHECK_EQUAL(face.sentInterests.at(0).getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
156
157 // and failed
Davide Pesaventocab86032020-12-10 20:30:12 -0500158 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400159
160 advanceClocks(1_s, 13); // 4_s default interest lifetime x 3
161 BOOST_CHECK_EQUAL(nErrors, 1);
Davide Pesaventocab86032020-12-10 20:30:12 -0500162 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400163
164 advanceClocks(1_s, 730); // 60 seconds between attempts + ~12 seconds for each attempt
165 BOOST_CHECK_EQUAL(nErrors, 11);
Davide Pesaventocab86032020-12-10 20:30:12 -0500166 BOOST_CHECK_EQUAL(m_imsFace.sentData.size(), 0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400167
168 // check recovery
169
170 publishData();
171
172 advanceClocks(1_s, 73);
173
Davide Pesaventocab86032020-12-10 20:30:12 -0500174 auto kek = m_imsFace.sentData.at(0);
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400175 BOOST_CHECK_EQUAL(kek.getName().getPrefix(6), Name("/access/policy/identity/NAC/dataset/KEK"));
176 BOOST_CHECK_EQUAL(kek.getName().size(), 7);
177}
178
179BOOST_AUTO_TEST_CASE(EnumerateDataFromIms)
180{
181 encryptor.regenerateCk();
182 advanceClocks(1_ms, 10);
183
184 encryptor.regenerateCk();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400185 advanceClocks(1_ms, 10);
186
187 BOOST_CHECK_EQUAL(encryptor.size(), 3);
188 size_t nCk = 0;
189 for (const auto& data : encryptor) {
190 BOOST_TEST_MESSAGE(data.getName());
191 if (data.getName().getPrefix(4) == Name("/some/ck/prefix/CK")) {
192 ++nCk;
193 }
194 }
195 BOOST_CHECK_EQUAL(nCk, 3);
196}
197
Davide Pesavento32d1dc22020-12-09 18:01:47 -0500198BOOST_AUTO_TEST_CASE(GenerateTestData,
199 * ut::description("regenerates the static test data used by other test cases")
200 * ut::disabled())
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400201{
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500202 const auto plaintext = "Data to encrypt"s;
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400203
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500204 std::cerr << "const std::vector<Block> encryptedBlobs = {\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400205 for (size_t i = 0; i < 3; ++i) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500206 std::cerr << " \"";
Davide Pesavento714dba02022-03-17 20:46:28 -0400207 auto block = encryptor.encrypt({reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size()});
208 printHex(std::cerr, block.wireEncode(), true);
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500209 std::cerr << "\"_block,\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400210
Alexander Afanasyevda366d82018-06-29 18:18:02 -0400211 encryptor.regenerateCk();
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400212 advanceClocks(1_ms, 10);
213 }
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500214 std::cerr << "};\n\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400215
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500216 std::cerr << "const std::vector<Block> encryptorPackets = {\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400217 for (const auto& data : encryptor) {
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500218 std::cerr << " \"";
Davide Pesavento714dba02022-03-17 20:46:28 -0400219 printHex(std::cerr, data.wireEncode(), true);
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500220 std::cerr << "\"_block,\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400221 }
Davide Pesaventoba3f6892020-12-08 22:18:35 -0500222 std::cerr << "};\n\n";
Alexander Afanasyev1a21e102018-06-13 20:33:21 -0400223}
224
225BOOST_AUTO_TEST_SUITE_END()
226
227} // namespace tests
228} // namespace nac
229} // namespace ndn