blob: b7aef11963e8f44853e02ece1350d02b253e9923 [file] [log] [blame]
Yingdi Yufe4733a2015-10-22 14:24:12 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento82d6a4c2017-12-23 19:47:20 -05002/*
Davide Pesaventoaee2ada2022-02-18 14:43:02 -05003 * Copyright (c) 2013-2022 Regents of the University of California.
Yingdi Yufe4733a2015-10-22 14:24:12 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
Alexander Afanasyev09236c22020-06-03 13:42:38 -040022#include "ndn-cxx/security/key-chain.hpp"
Davide Pesavento94dfcf12021-09-26 14:18:45 -040023#include "ndn-cxx/security/impl/openssl.hpp"
laqinfan56a812d2019-06-03 15:33:58 -050024#include "ndn-cxx/security/transform/private-key.hpp"
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050025#include "ndn-cxx/security/verification-helpers.hpp"
Yingdi Yufe4733a2015-10-22 14:24:12 -070026
Davide Pesavento7e780642018-11-24 15:51:34 -050027#include "tests/boost-test.hpp"
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050028#include "tests/key-chain-fixture.hpp"
Junxiao Shi9ee770b2022-04-25 23:33:33 +000029#include "tests/unit/clock-fixture.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050030#include "tests/unit/test-home-env-saver.hpp"
Yingdi Yufe4733a2015-10-22 14:24:12 -070031
Davide Pesavento73710362020-12-04 16:10:03 -050032#include <boost/mpl/vector.hpp>
33
Yingdi Yufe4733a2015-10-22 14:24:12 -070034namespace ndn {
35namespace security {
Alexander Afanasyev09236c22020-06-03 13:42:38 -040036inline namespace v2 {
Yingdi Yufe4733a2015-10-22 14:24:12 -070037namespace tests {
38
39using namespace ndn::tests;
40
41BOOST_AUTO_TEST_SUITE(Security)
Yingdi Yufe4733a2015-10-22 14:24:12 -070042BOOST_FIXTURE_TEST_SUITE(TestKeyChain, TestHomeEnvSaver)
43
44template<class Path>
45class TestHomeAndPibFixture : public TestHomeFixture<Path>
46{
47public:
48 TestHomeAndPibFixture()
49 {
50 unsetenv("NDN_CLIENT_PIB");
51 unsetenv("NDN_CLIENT_TPM");
52 }
Alexander Afanasyev80782e02017-01-04 13:16:54 -080053
54 ~TestHomeAndPibFixture()
55 {
Alexander Afanasyev57d02b62018-06-15 18:19:50 -040056 try {
57 const_cast<std::string&>(KeyChain::getDefaultPibLocator()).clear();
58 }
59 catch (const KeyChain::Error&) {
60 // ignore
61 }
62
63 try {
64 const_cast<std::string&>(KeyChain::getDefaultTpmLocator()).clear();
65 }
66 catch (const KeyChain::Error&) {
67 // ignore
68 }
Alexander Afanasyev80782e02017-01-04 13:16:54 -080069 }
Yingdi Yufe4733a2015-10-22 14:24:12 -070070};
71
72struct PibPathConfigFileHome
73{
74 const std::string PATH = "build/config-file-home/";
75};
76
77BOOST_FIXTURE_TEST_CASE(ConstructorNormalConfig, TestHomeAndPibFixture<PibPathConfigFileHome>)
78{
79 createClientConf({"pib=pib-memory:", "tpm=tpm-memory:"});
80
81 BOOST_REQUIRE_NO_THROW(KeyChain());
82
83 KeyChain keyChain;
84 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-memory:");
85 BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-memory:");
86 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-memory:");
87}
88
89struct PibPathConfigFileEmptyHome
90{
91 const std::string PATH = "build/config-file-empty-home/";
92};
93
94BOOST_FIXTURE_TEST_CASE(ConstructorEmptyConfig, TestHomeAndPibFixture<PibPathConfigFileEmptyHome>)
95{
96 createClientConf({"pib=pib-memory:"});
97
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050098#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS)
Yingdi Yufe4733a2015-10-22 14:24:12 -070099 std::string oldHOME;
100 if (std::getenv("OLD_HOME"))
101 oldHOME = std::getenv("OLD_HOME");
102
103 std::string HOME;
104 if (std::getenv("HOME"))
105 HOME = std::getenv("HOME");
106
107 if (!oldHOME.empty())
108 setenv("HOME", oldHOME.c_str(), 1);
109 else
110 unsetenv("HOME");
111#endif
112
113 BOOST_REQUIRE_NO_THROW(KeyChain());
114 KeyChain keyChain;
115 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-memory:");
116
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -0500117#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700118 BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-osxkeychain:");
119 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-osxkeychain:");
120#else
121 BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-file:");
122 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:");
123#endif
124
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -0500125#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700126 if (!HOME.empty())
127 setenv("HOME", HOME.c_str(), 1);
128 else
129 unsetenv("HOME");
130
131 if (!oldHOME.empty())
132 setenv("OLD_HOME", oldHOME.c_str(), 1);
133 else
134 unsetenv("OLD_HOME");
135#endif
136}
137
138struct PibPathConfigFileEmpty2Home
139{
140 const std::string PATH = "build/config-file-empty2-home/";
141};
142
Davide Pesavento73710362020-12-04 16:10:03 -0500143BOOST_FIXTURE_TEST_CASE(ConstructorEmptyConfig2, TestHomeAndPibFixture<PibPathConfigFileEmpty2Home>)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700144{
145 createClientConf({"tpm=tpm-memory:"});
146
147 BOOST_REQUIRE_NO_THROW(KeyChain());
148
149 KeyChain keyChain;
150 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:");
151 BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-memory:");
152 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-memory:");
153}
154
155struct PibPathConfigFileMalformedHome
156{
157 const std::string PATH = "build/config-file-malformed-home/";
158};
159
Davide Pesavento73710362020-12-04 16:10:03 -0500160BOOST_FIXTURE_TEST_CASE(ConstructorBadConfig, TestHomeAndPibFixture<PibPathConfigFileMalformedHome>)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700161{
162 createClientConf({"pib=lord", "tpm=ring"});
Davide Pesavento73710362020-12-04 16:10:03 -0500163 BOOST_CHECK_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
Yingdi Yufe4733a2015-10-22 14:24:12 -0700164}
165
166struct PibPathConfigFileMalformed2Home
167{
168 const std::string PATH = "build/config-file-malformed2-home/";
169};
170
Davide Pesavento73710362020-12-04 16:10:03 -0500171BOOST_FIXTURE_TEST_CASE(ConstructorBadConfig2, TestHomeAndPibFixture<PibPathConfigFileMalformed2Home>)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700172{
173 createClientConf({"pib=pib-sqlite3:%PATH%", "tpm=just-wrong"});
Davide Pesavento73710362020-12-04 16:10:03 -0500174 BOOST_CHECK_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
Yingdi Yufe4733a2015-10-22 14:24:12 -0700175}
176
Alexander Afanasyev57d02b62018-06-15 18:19:50 -0400177struct PibPathConfigFileNonCanonicalTpm
178{
179 const std::string PATH = "build/config-file-non-canonical-tpm/";
180};
181
182BOOST_FIXTURE_TEST_CASE(ConstructorNonCanonicalTpm, TestHomeAndPibFixture<PibPathConfigFileNonCanonicalTpm>) // Bug 4297
183{
184 createClientConf({"pib=pib-sqlite3:", "tpm=tpm-file"});
185
186 {
187 KeyChain keyChain;
188 keyChain.createIdentity("/test");
189 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:");
190 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:");
191 }
192
193 {
194 KeyChain keyChain;
195 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:");
196 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:");
197 BOOST_CHECK(keyChain.getPib().getIdentities().find("/test") != keyChain.getPib().getIdentities().end());
198 }
199}
200
Yingdi Yufe4733a2015-10-22 14:24:12 -0700201BOOST_AUTO_TEST_CASE(KeyChainWithCustomTpmAndPib)
202{
203 BOOST_REQUIRE_NO_THROW((KeyChain("pib-memory", "tpm-memory")));
204 BOOST_REQUIRE_NO_THROW((KeyChain("pib-memory:", "tpm-memory:")));
205 BOOST_REQUIRE_NO_THROW((KeyChain("pib-memory:/something", "tpm-memory:/something")));
206
207 KeyChain keyChain("pib-memory", "tpm-memory");
208 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-memory:");
209 BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-memory:");
210 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-memory:");
211}
212
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500213BOOST_FIXTURE_TEST_CASE(SigningWithCorruptedPibTpm, KeyChainFixture)
Alexander Afanasyevf601e192020-06-02 16:41:07 -0400214{
215 Identity id = m_keyChain.createIdentity("/test");
216
217 Data data("/foobar");
218 BOOST_CHECK_NO_THROW(m_keyChain.sign(data, signingByIdentity(id)));
219
220 // now, "corrupting TPM"
221 const_cast<Tpm&>(m_keyChain.getTpm()).deleteKey(id.getDefaultKey().getName());
222
223 BOOST_CHECK_NO_THROW(id.getDefaultKey());
224 BOOST_CHECK_THROW(m_keyChain.sign(data, signingByIdentity(id)), KeyChain::InvalidSigningInfoError);
225}
226
Davide Pesavento73710362020-12-04 16:10:03 -0500227BOOST_FIXTURE_TEST_CASE(SigningWithNonExistingIdentity, KeyChainFixture)
228{
229 Data data("/test/data");
230 BOOST_CHECK_THROW(m_keyChain.sign(data, signingByIdentity("/non-existing/identity")),
231 KeyChain::InvalidSigningInfoError);
232}
233
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500234BOOST_FIXTURE_TEST_CASE(Management, KeyChainFixture)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700235{
236 Name identityName("/test/id");
237 Name identity2Name("/test/id2");
238
239 BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 0);
240 BOOST_REQUIRE_THROW(m_keyChain.getPib().getDefaultIdentity(), Pib::Error);
241
242 // Create identity
243 Identity id = m_keyChain.createIdentity(identityName);
244 BOOST_CHECK(id);
245 BOOST_CHECK(m_keyChain.getPib().getIdentities().find(identityName) != m_keyChain.getPib().getIdentities().end());
246 // The first added identity becomes the default identity
laqinfan56a812d2019-06-03 15:33:58 -0500247 BOOST_CHECK_NO_THROW(m_keyChain.getPib().getDefaultIdentity());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700248 // The default key of the added identity must exist
laqinfan56a812d2019-06-03 15:33:58 -0500249 Key key = id.getDefaultKey();
Yingdi Yufe4733a2015-10-22 14:24:12 -0700250 // The default certificate of the default key must exist
laqinfan56a812d2019-06-03 15:33:58 -0500251 BOOST_CHECK_NO_THROW(key.getDefaultCertificate());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700252
253 // Delete key
254 Name key1Name = key.getName();
255 BOOST_CHECK_NO_THROW(id.getKey(key1Name));
256 BOOST_CHECK_EQUAL(id.getKeys().size(), 1);
257 m_keyChain.deleteKey(id, key);
258 // The key instance should not be valid any more
259 BOOST_CHECK(!key);
260 BOOST_CHECK_THROW(id.getKey(key1Name), Pib::Error);
261 BOOST_CHECK_EQUAL(id.getKeys().size(), 0);
262
263 // Create another key
264 m_keyChain.createKey(id);
265 // The added key becomes the default key.
Yingdi Yufe4733a2015-10-22 14:24:12 -0700266 Key key2 = id.getDefaultKey();
267 BOOST_REQUIRE(key2);
268 BOOST_CHECK_NE(key2.getName(), key1Name);
269 BOOST_CHECK_EQUAL(id.getKeys().size(), 1);
laqinfan56a812d2019-06-03 15:33:58 -0500270 BOOST_CHECK_NO_THROW(key2.getDefaultCertificate());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700271
272 // Create the third key
273 Key key3 = m_keyChain.createKey(id);
Junxiao Shi72c0c642018-04-20 15:41:09 +0000274 BOOST_CHECK_NE(key3.getName(), key2.getName());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700275 // The added key will not be the default key, because the default key already exists
Junxiao Shi72c0c642018-04-20 15:41:09 +0000276 BOOST_CHECK_EQUAL(id.getDefaultKey().getName(), key2.getName());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700277 BOOST_CHECK_EQUAL(id.getKeys().size(), 2);
laqinfan56a812d2019-06-03 15:33:58 -0500278 BOOST_CHECK_NO_THROW(key3.getDefaultCertificate());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700279
280 // Delete cert
281 BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1);
282 Certificate key3Cert1 = *key3.getCertificates().begin();
283 Name key3CertName = key3Cert1.getName();
284 m_keyChain.deleteCertificate(key3, key3CertName);
285 BOOST_CHECK_EQUAL(key3.getCertificates().size(), 0);
286 BOOST_REQUIRE_THROW(key3.getDefaultCertificate(), Pib::Error);
287
288 // Add cert
289 m_keyChain.addCertificate(key3, key3Cert1);
290 BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1);
laqinfan56a812d2019-06-03 15:33:58 -0500291 BOOST_CHECK_NO_THROW(key3.getDefaultCertificate());
Alexander Afanasyeva10b2ff2017-01-30 12:44:15 -0800292 m_keyChain.addCertificate(key3, key3Cert1); // overwriting the cert should work
Yingdi Yufe4733a2015-10-22 14:24:12 -0700293 BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1);
294 // Add another cert
295 Certificate key3Cert2 = key3Cert1;
296 Name key3Cert2Name = key3.getName();
297 key3Cert2Name.append("Self");
298 key3Cert2Name.appendVersion();
299 key3Cert2.setName(key3Cert2Name);
300 m_keyChain.addCertificate(key3, key3Cert2);
301 BOOST_CHECK_EQUAL(key3.getCertificates().size(), 2);
Davide Pesavento81bd6962020-06-17 16:03:23 -0400302 // Add empty cert
303 Certificate key3Cert3 = key3Cert1;
304 key3Cert3.unsetContent();
305 BOOST_CHECK_THROW(m_keyChain.addCertificate(key3, key3Cert3), std::invalid_argument);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700306
307 // Default certificate setting
308 BOOST_CHECK_EQUAL(key3.getDefaultCertificate().getName(), key3CertName);
309 m_keyChain.setDefaultCertificate(key3, key3Cert2);
310 BOOST_CHECK_EQUAL(key3.getDefaultCertificate().getName(), key3Cert2Name);
311
312 // Default key setting
313 BOOST_CHECK_EQUAL(id.getDefaultKey().getName(), key2.getName());
314 m_keyChain.setDefaultKey(id, key3);
315 BOOST_CHECK_EQUAL(id.getDefaultKey().getName(), key3.getName());
316
317 // Default identity setting
318 Identity id2 = m_keyChain.createIdentity(identity2Name);
319 BOOST_CHECK_EQUAL(m_keyChain.getPib().getDefaultIdentity().getName(), id.getName());
320 m_keyChain.setDefaultIdentity(id2);
321 BOOST_CHECK_EQUAL(m_keyChain.getPib().getDefaultIdentity().getName(), id2.getName());
322
323 // Delete identity
324 m_keyChain.deleteIdentity(id);
325 // The identity instance should not be valid any more
326 BOOST_CHECK(!id);
Davide Pesavento73710362020-12-04 16:10:03 -0500327 BOOST_CHECK_THROW(m_keyChain.getPib().getIdentity(identityName), Pib::Error);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700328 BOOST_CHECK(m_keyChain.getPib().getIdentities().find(identityName) == m_keyChain.getPib().getIdentities().end());
329}
330
Davide Pesavento73710362020-12-04 16:10:03 -0500331struct DataPkt
Yingdi Yufe4733a2015-10-22 14:24:12 -0700332{
Davide Pesavento73710362020-12-04 16:10:03 -0500333 Data packet{"/data"};
334 SignedInterestFormat sigFormat = SignedInterestFormat::V02; // irrelevant for Data
Yingdi Yufe4733a2015-10-22 14:24:12 -0700335
Davide Pesavento73710362020-12-04 16:10:03 -0500336 SignatureInfo
337 getSignatureInfo() const
338 {
339 return packet.getSignatureInfo();
340 }
341};
laqinfan56a812d2019-06-03 15:33:58 -0500342
Davide Pesavento73710362020-12-04 16:10:03 -0500343struct InterestV02Pkt
344{
Davide Pesaventoaee2ada2022-02-18 14:43:02 -0500345 Interest packet{"/interest02"};
Davide Pesavento73710362020-12-04 16:10:03 -0500346 SignedInterestFormat sigFormat = SignedInterestFormat::V02;
Eric Newberryb74bbda2020-06-18 19:33:58 -0700347
Davide Pesavento73710362020-12-04 16:10:03 -0500348 SignatureInfo
349 getSignatureInfo() const
350 {
351 return SignatureInfo(packet.getName()[signed_interest::POS_SIG_INFO].blockFromValue());
352 }
353};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700354
Davide Pesavento73710362020-12-04 16:10:03 -0500355struct InterestV03Pkt
356{
Davide Pesaventoaee2ada2022-02-18 14:43:02 -0500357 Interest packet{"/interest03"};
Davide Pesavento73710362020-12-04 16:10:03 -0500358 SignedInterestFormat sigFormat = SignedInterestFormat::V03;
Eric Newberryb74bbda2020-06-18 19:33:58 -0700359
Davide Pesavento73710362020-12-04 16:10:03 -0500360 SignatureInfo
361 getSignatureInfo() const
362 {
363 return packet.getSignatureInfo().value(); // use .value() for checked access
364 }
365};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700366
Davide Pesavento73710362020-12-04 16:10:03 -0500367template<typename KeyParams>
368struct DefaultIdentity
369{
370 Identity
371 operator()(KeyChain& keyChain) const
372 {
373 auto id = keyChain.createIdentity("/id", KeyParams());
374 BOOST_ASSERT(keyChain.getPib().getDefaultIdentity() == id);
375 return id;
376 }
377};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700378
Davide Pesavento73710362020-12-04 16:10:03 -0500379template<typename KeyParams>
380struct NonDefaultIdentity
381{
382 Identity
383 operator()(KeyChain& keyChain) const
384 {
385 auto id = keyChain.createIdentity("/id");
386 auto id2 = keyChain.createIdentity("/id2", KeyParams());
387 BOOST_ASSERT(keyChain.getPib().getDefaultIdentity() == id);
388 return id2;
389 }
390};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700391
Davide Pesavento73710362020-12-04 16:10:03 -0500392template<typename KeyParams>
393struct DefaultKey
394{
395 Key
396 operator()(KeyChain&, const Identity& id) const
397 {
398 auto key = id.getDefaultKey();
399 BOOST_ASSERT(key.getKeyType() == KeyParams().getKeyType());
400 return key;
401 }
402};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700403
Davide Pesavento73710362020-12-04 16:10:03 -0500404template<typename KeyParams>
405struct NonDefaultKey
406{
407 Key
408 operator()(KeyChain& keyChain, const Identity& id) const
409 {
410 auto key2 = keyChain.createKey(id, KeyParams());
411 BOOST_ASSERT(id.getDefaultKey() != key2);
412 return key2;
413 }
414};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700415
Davide Pesavento73710362020-12-04 16:10:03 -0500416template<typename PacketType,
417 template<typename> class IdentityMaker = DefaultIdentity,
418 template<typename> class KeyMaker = DefaultKey,
419 typename AsymmetricKeyParams = EcKeyParams,
420 uint32_t SignatureTypeTlvValue = tlv::SignatureSha256WithEcdsa>
421struct AsymmetricSigningBase : protected KeyChainFixture, protected PacketType
422{
423 const Identity id = IdentityMaker<AsymmetricKeyParams>()(m_keyChain);
424 const Key key = KeyMaker<AsymmetricKeyParams>()(m_keyChain, id);
425 const Certificate cert = key.getDefaultCertificate();
426
427 const uint32_t expectedSigType = SignatureTypeTlvValue;
428 const bool shouldHaveKeyLocator = true;
Junxiao Shi7d728682022-04-01 01:21:13 +0000429 const optional<KeyLocator> expectedKeyLocator = cert.getName();
Davide Pesavento73710362020-12-04 16:10:03 -0500430
431 bool
432 verify(const SigningInfo&) const
433 {
434 return verifySignature(this->packet, key);
435 }
436};
437
438template<typename PacketType,
439 typename AsymmetricKeyParams,
440 uint32_t SignatureTypeTlvValue>
441struct AsymmetricSigning : protected AsymmetricSigningBase<PacketType, DefaultIdentity, DefaultKey,
442 AsymmetricKeyParams, SignatureTypeTlvValue>
443{
444 const std::vector<SigningInfo> signingInfos = {
Yingdi Yufe4733a2015-10-22 14:24:12 -0700445 SigningInfo(),
Davide Pesavento73710362020-12-04 16:10:03 -0500446 SigningInfo(""),
Yingdi Yufe4733a2015-10-22 14:24:12 -0700447
Davide Pesavento73710362020-12-04 16:10:03 -0500448 SigningInfo(this->id),
449 SigningInfo(SigningInfo::SIGNER_TYPE_ID, this->id.getName()),
450 SigningInfo("id:" + this->id.getName().toUri()),
451 signingByIdentity(this->id),
452 signingByIdentity(this->id.getName()),
Yingdi Yufe4733a2015-10-22 14:24:12 -0700453
Davide Pesavento73710362020-12-04 16:10:03 -0500454 SigningInfo(this->key),
455 SigningInfo(SigningInfo::SIGNER_TYPE_KEY, this->key.getName()),
456 SigningInfo("key:" + this->key.getName().toUri()),
457 signingByKey(this->key),
458 signingByKey(this->key.getName()),
Alexander Afanasyevd6d78aa2017-01-02 18:14:23 -0800459
Davide Pesavento73710362020-12-04 16:10:03 -0500460 SigningInfo(SigningInfo::SIGNER_TYPE_CERT, this->cert.getName()),
461 SigningInfo("cert:" + this->cert.getName().toUri()),
462 signingByCertificate(this->cert),
463 signingByCertificate(this->cert.getName()),
464 };
465};
Yingdi Yufe4733a2015-10-22 14:24:12 -0700466
Davide Pesavento73710362020-12-04 16:10:03 -0500467template<typename PacketType>
468using RsaSigning = AsymmetricSigning<PacketType, RsaKeyParams, tlv::SignatureSha256WithRsa>;
Alexander Afanasyevd6d78aa2017-01-02 18:14:23 -0800469
Davide Pesavento73710362020-12-04 16:10:03 -0500470template<typename PacketType>
471using EcdsaSigning = AsymmetricSigning<PacketType, EcKeyParams, tlv::SignatureSha256WithEcdsa>;
Yingdi Yufe4733a2015-10-22 14:24:12 -0700472
Davide Pesavento73710362020-12-04 16:10:03 -0500473template<typename PacketType>
474struct SigningWithNonDefaultIdentity : protected AsymmetricSigningBase<PacketType, NonDefaultIdentity>
475{
476 const std::vector<SigningInfo> signingInfos = {
477 signingByIdentity(this->id),
478 signingByIdentity(this->id.getName()),
479 signingByKey(this->key),
480 signingByCertificate(this->cert),
481 };
482};
483
484template<typename PacketType>
485struct SigningWithNonDefaultKey : protected AsymmetricSigningBase<PacketType, NonDefaultIdentity, NonDefaultKey>
486{
487 const std::vector<SigningInfo> signingInfos = {
488 signingByKey(this->key),
489 signingByKey(this->key.getName()),
490 signingByCertificate(this->cert),
491 };
492};
493
494template<typename PacketType,
495 DigestAlgorithm DigestAlgo = DigestAlgorithm::SHA256,
496 uint32_t SignatureTypeTlvValue = tlv::SignatureHmacWithSha256>
497struct HmacSigning : protected KeyChainFixture, protected PacketType
498{
499 const std::vector<SigningInfo> signingInfos = {
500 SigningInfo(SigningInfo::SIGNER_TYPE_HMAC, m_keyChain.createHmacKey()),
laqinfan56a812d2019-06-03 15:33:58 -0500501 SigningInfo("hmac-sha256:QjM3NEEyNkE3MTQ5MDQzN0FBMDI0RTRGQURENUI0OTdGREZGMUE4RUE2RkYxMkY2RkI2NUFGMjcyMEI1OUNDRg=="),
Davide Pesavento73710362020-12-04 16:10:03 -0500502 };
laqinfan56a812d2019-06-03 15:33:58 -0500503
Davide Pesavento73710362020-12-04 16:10:03 -0500504 const uint32_t expectedSigType = SignatureTypeTlvValue;
505 const bool shouldHaveKeyLocator = true;
506 const optional<KeyLocator> expectedKeyLocator = nullopt; // don't check KeyLocator value
507
508 bool
509 verify(const SigningInfo& si) const
510 {
511 return verifySignature(this->packet, m_keyChain.getTpm(), si.getSignerName(), DigestAlgo);
512 }
513};
514
515template<typename PacketType>
516struct Sha256Signing : protected KeyChainFixture, protected PacketType
517{
518 const std::vector<SigningInfo> signingInfos = {
Yingdi Yufe4733a2015-10-22 14:24:12 -0700519 SigningInfo(SigningInfo::SIGNER_TYPE_SHA256),
Davide Pesavento73710362020-12-04 16:10:03 -0500520 SigningInfo("id:" + SigningInfo::getDigestSha256Identity().toUri()),
Yingdi Yufe4733a2015-10-22 14:24:12 -0700521 signingWithSha256()
522 };
523
Davide Pesavento73710362020-12-04 16:10:03 -0500524 const uint32_t expectedSigType = tlv::DigestSha256;
525 const bool shouldHaveKeyLocator = false;
526 const optional<KeyLocator> expectedKeyLocator = nullopt;
Yingdi Yufe4733a2015-10-22 14:24:12 -0700527
Davide Pesavento73710362020-12-04 16:10:03 -0500528 bool
529 verify(const SigningInfo&) const
530 {
Davide Pesavento809f7542021-03-24 18:53:05 -0400531 return verifySignature(this->packet, nullopt);
Davide Pesavento73710362020-12-04 16:10:03 -0500532 }
533};
Yingdi Yufe4733a2015-10-22 14:24:12 -0700534
Davide Pesavento73710362020-12-04 16:10:03 -0500535using SigningTests = boost::mpl::vector<
536 RsaSigning<DataPkt>,
537 RsaSigning<InterestV02Pkt>,
538 RsaSigning<InterestV03Pkt>,
539 EcdsaSigning<DataPkt>,
540 EcdsaSigning<InterestV02Pkt>,
541 EcdsaSigning<InterestV03Pkt>,
Davide Pesavento94dfcf12021-09-26 14:18:45 -0400542#if OPENSSL_VERSION_NUMBER < 0x30000000L // FIXME #5154
Davide Pesavento73710362020-12-04 16:10:03 -0500543 HmacSigning<DataPkt>,
544 HmacSigning<InterestV02Pkt>,
545 HmacSigning<InterestV03Pkt>,
Davide Pesavento94dfcf12021-09-26 14:18:45 -0400546#endif
Davide Pesavento73710362020-12-04 16:10:03 -0500547 Sha256Signing<DataPkt>,
548 Sha256Signing<InterestV02Pkt>,
549 Sha256Signing<InterestV03Pkt>,
550 SigningWithNonDefaultIdentity<DataPkt>,
Davide Pesavento809f7542021-03-24 18:53:05 -0400551 SigningWithNonDefaultIdentity<InterestV03Pkt>,
552 SigningWithNonDefaultKey<DataPkt>,
553 SigningWithNonDefaultKey<InterestV03Pkt>
Davide Pesavento73710362020-12-04 16:10:03 -0500554>;
Eric Newberryb74bbda2020-06-18 19:33:58 -0700555
Davide Pesavento73710362020-12-04 16:10:03 -0500556BOOST_FIXTURE_TEST_CASE_TEMPLATE(SigningInterface, T, SigningTests, T)
557{
558 BOOST_TEST_CONTEXT("Packet = " << this->packet.getName()) {
559 for (auto signingInfo : this->signingInfos) {
560 signingInfo.setSignedInterestFormat(this->sigFormat);
561
562 BOOST_TEST_CONTEXT("SigningInfo = " << signingInfo) {
563 this->m_keyChain.sign(this->packet, signingInfo);
564
565 auto sigInfo = this->getSignatureInfo();
566 BOOST_CHECK_EQUAL(sigInfo.getSignatureType(), this->expectedSigType);
567 BOOST_CHECK_EQUAL(sigInfo.hasKeyLocator(), this->shouldHaveKeyLocator);
568 if (this->expectedKeyLocator) {
569 BOOST_CHECK_EQUAL(sigInfo.getKeyLocator(), *this->expectedKeyLocator);
570 }
571 BOOST_CHECK(this->verify(signingInfo));
Eric Newberryb74bbda2020-06-18 19:33:58 -0700572 }
Yingdi Yufe4733a2015-10-22 14:24:12 -0700573 }
574 }
575}
576
Junxiao Shi9ee770b2022-04-25 23:33:33 +0000577class MakeCertificateFixture : public ClockFixture
578{
579public:
580 MakeCertificateFixture()
581 : requesterKeyChain("pib-memory:", "tpm-memory:")
582 , signerKeyChain("pib-memory:", "tpm-memory:")
583 {
584 m_systemClock->setNow(time::fromIsoString("20091117T203458,651387237").time_since_epoch());
585
586 requester = requesterKeyChain.createIdentity("/requester").getDefaultKey();
587 Name signerIdentityName("/signer");
588 signerKey = signerKeyChain.createIdentity(signerIdentityName).getDefaultKey();
589 signerParams = signingByIdentity(signerIdentityName);
590 }
591
592 void
593 checkKeyLocatorName(const Certificate& cert, optional<Name> klName = nullopt) const
594 {
595 auto kl = cert.getKeyLocator();
596 if (!kl.has_value()) {
597 BOOST_ERROR("KeyLocator is missing");
598 return;
599 }
600 BOOST_CHECK_EQUAL(kl->getName(),
601 klName.value_or(signerKey.getDefaultCertificate().getName()));
602 }
603
604 void
605 checkCertFromDefaults(const Certificate& cert) const
606 {
607 BOOST_CHECK(Certificate::isValidName(cert.getName()));
608 BOOST_CHECK_EQUAL(cert.getKeyName(), requester.getName());
609 BOOST_CHECK_EQUAL(cert.getName()[-2], name::Component("NA"));
610 BOOST_CHECK(cert.getName()[-1].isVersion());
611
612 BOOST_CHECK_EQUAL(cert.getContentType(), tlv::ContentType_Key);
613 BOOST_CHECK_EQUAL(cert.getFreshnessPeriod(), 1_h);
614
615 BOOST_TEST(cert.getContent().value_bytes() == requester.getPublicKey(),
616 boost::test_tools::per_element());
617
618 checkKeyLocatorName(cert);
619
620 BOOST_CHECK(cert.isValid());
621 auto vp = cert.getValidityPeriod().getPeriod();
622 BOOST_CHECK_EQUAL(vp.first, time::fromIsoString("20091117T203458"));
623 BOOST_CHECK_EQUAL(vp.second, time::fromIsoString("20101117T203458"));
624
625 auto adBlock = cert.getSignatureInfo().getCustomTlv(tlv::AdditionalDescription);
626 BOOST_CHECK(!adBlock.has_value());
627 }
628
629public:
630 KeyChain requesterKeyChain;
631 pib::Key requester;
632
633 KeyChain signerKeyChain;
634 pib::Key signerKey;
635 Name signerCertificateName;
636 SigningInfo signerParams;
637};
638
639BOOST_FIXTURE_TEST_SUITE(MakeCertificate, MakeCertificateFixture)
640
641BOOST_AUTO_TEST_CASE(DefaultsFromKey)
642{
643 auto cert = signerKeyChain.makeCertificate(requester, signerParams);
644 checkCertFromDefaults(cert);
645}
646
647BOOST_AUTO_TEST_CASE(DefaultsFromCert)
648{
649 auto cert = signerKeyChain.makeCertificate(requester.getDefaultCertificate(), signerParams);
650 checkCertFromDefaults(cert);
651}
652
653BOOST_AUTO_TEST_CASE(Options)
654{
655 MakeCertificateOptions opts;
656 opts.issuerId = name::Component::fromEscapedString("ISSUER");
657 opts.version = 41218268;
658 opts.freshnessPeriod = 321_s;
659 opts.validity.emplace(time::fromIsoString("20060702T150405"),
660 time::fromIsoString("20160702T150405"));
661
662 SignatureInfo sigInfo;
663 sigInfo.setKeyLocator(signerKey.getName());
664 sigInfo.setValidityPeriod(ValidityPeriod(time::fromIsoString("20060102T150405"),
665 time::fromIsoString("20160102T150405")));
666 sigInfo.addCustomTlv(Block(0xF0));
667 signerParams.setSignatureInfo(sigInfo);
668
669 auto cert = signerKeyChain.makeCertificate(requester, signerParams, opts);
670
671 BOOST_CHECK_EQUAL(cert.getName(),
672 Name(requester.getName()).append(PartialName("ISSUER/v=41218268")));
673 BOOST_CHECK_EQUAL(cert.getFreshnessPeriod(), 321_s);
674 checkKeyLocatorName(cert, signerKey.getName());
675
676 auto vp = cert.getValidityPeriod().getPeriod();
677 BOOST_CHECK_EQUAL(vp.first, time::fromIsoString("20060702T150405"));
678 BOOST_CHECK_EQUAL(vp.second, time::fromIsoString("20160702T150405"));
679
680 BOOST_CHECK(cert.getSignatureInfo().getCustomTlv(0xF0).has_value());
681}
682
683BOOST_AUTO_TEST_CASE(ErrSigner)
684{
685 signerParams = signingByIdentity("/nonexistent");
686 BOOST_CHECK_THROW(signerKeyChain.makeCertificate(requester, signerParams), KeyChain::Error);
687}
688
689BOOST_AUTO_TEST_CASE(ErrZeroFreshness)
690{
691 MakeCertificateOptions opts;
692 opts.freshnessPeriod = 0_ms;
693 BOOST_CHECK_THROW(signerKeyChain.makeCertificate(requester, signerParams, opts),
694 std::invalid_argument);
695}
696
697BOOST_AUTO_TEST_CASE(ErrNegativeFreshness)
698{
699 MakeCertificateOptions opts;
700 opts.freshnessPeriod = -1_ms;
701 BOOST_CHECK_THROW(signerKeyChain.makeCertificate(requester, signerParams, opts),
702 std::invalid_argument);
703}
704
705BOOST_AUTO_TEST_CASE(ErrContent)
706{
707 Certificate request(requester.getDefaultCertificate());
708 const auto& oldContent = request.getContent();
709 std::vector<uint8_t> content(oldContent.value_begin(), oldContent.value_end());
710 content[0] ^= 0x80;
711 request.setContent(content);
712 BOOST_CHECK_THROW(signerKeyChain.makeCertificate(request, signerParams), std::invalid_argument);
713}
714
715BOOST_AUTO_TEST_SUITE_END() // MakeCertificate
716
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500717BOOST_FIXTURE_TEST_CASE(ImportPrivateKey, KeyChainFixture)
laqinfan56a812d2019-06-03 15:33:58 -0500718{
Davide Pesavento765abc92021-12-27 00:44:04 -0500719 const Name keyName("/test/device2");
720 const uint8_t rawKey[] = "nPSNOHyZKsg2WLqHAs7MXGb0sjQb4zCT";
laqinfan56a812d2019-06-03 15:33:58 -0500721 auto key = make_shared<transform::PrivateKey>();
Davide Pesavento765abc92021-12-27 00:44:04 -0500722 key->loadRaw(KeyType::HMAC, rawKey);
laqinfan56a812d2019-06-03 15:33:58 -0500723
724 m_keyChain.importPrivateKey(keyName, key);
725 BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(keyName), true);
726 BOOST_CHECK_THROW(m_keyChain.importPrivateKey(keyName, key), KeyChain::Error);
727}
728
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500729BOOST_FIXTURE_TEST_CASE(ExportImport, KeyChainFixture)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700730{
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500731 Identity id = m_keyChain.createIdentity("/TestKeyChain/ExportIdentity");
Yingdi Yufe4733a2015-10-22 14:24:12 -0700732 Certificate cert = id.getDefaultKey().getDefaultCertificate();
733
734 shared_ptr<SafeBag> exported = m_keyChain.exportSafeBag(cert, "1234", 4);
735 Block block = exported->wireEncode();
736
737 m_keyChain.deleteIdentity(id);
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500738 BOOST_CHECK_THROW(m_keyChain.exportSafeBag(cert, "1234", 4), KeyChain::Error);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700739
740 BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(cert.getKeyName()), false);
741 BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 0);
742
743 SafeBag imported;
744 imported.wireDecode(block);
745 m_keyChain.importSafeBag(imported, "1234", 4);
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500746 BOOST_CHECK_THROW(m_keyChain.importSafeBag(imported, "1234", 4), KeyChain::Error);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700747
748 BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(cert.getKeyName()), true);
749 BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 1);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700750 Identity newId = m_keyChain.getPib().getIdentity(cert.getIdentity());
751 BOOST_CHECK_EQUAL(newId.getKeys().size(), 1);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700752 Key newKey = newId.getKey(cert.getKeyName());
753 BOOST_CHECK_EQUAL(newKey.getCertificates().size(), 1);
laqinfan56a812d2019-06-03 15:33:58 -0500754 BOOST_CHECK_NO_THROW(newKey.getCertificate(cert.getName()));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700755
756 m_keyChain.deleteIdentity(newId);
757 BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 0);
758 BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(cert.getKeyName()), false);
759}
760
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500761BOOST_FIXTURE_TEST_CASE(SelfSignedCertValidity, KeyChainFixture)
Alexander Afanasyevf8379172017-01-11 16:56:04 -0800762{
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500763 Certificate cert = m_keyChain.createIdentity("/Security/TestKeyChain/SelfSignedCertValidity")
Alexander Afanasyevf8379172017-01-11 16:56:04 -0800764 .getDefaultKey()
765 .getDefaultCertificate();
766 BOOST_CHECK(cert.isValid());
Davide Pesavento0f830802018-01-16 23:58:58 -0500767 BOOST_CHECK(cert.isValid(time::system_clock::now() + 10 * 365_days));
768 BOOST_CHECK_GT(cert.getValidityPeriod().getPeriod().second, time::system_clock::now() + 10 * 365_days);
Alexander Afanasyevf8379172017-01-11 16:56:04 -0800769}
770
Yingdi Yufe4733a2015-10-22 14:24:12 -0700771BOOST_AUTO_TEST_SUITE_END() // TestKeyChain
Yingdi Yufe4733a2015-10-22 14:24:12 -0700772BOOST_AUTO_TEST_SUITE_END() // Security
773
774} // namespace tests
Alexander Afanasyev09236c22020-06-03 13:42:38 -0400775} // inline namespace v2
Yingdi Yufe4733a2015-10-22 14:24:12 -0700776} // namespace security
777} // namespace ndn