blob: f01aab921a1eb53bbf8bd78b1de1d96eb6054548 [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 {
Davide Pesavento0e768ef2022-05-09 20:03:44 -040056 KeyChain::resetDefaultLocators();
Alexander Afanasyev80782e02017-01-04 13:16:54 -080057 }
Yingdi Yufe4733a2015-10-22 14:24:12 -070058};
59
60struct PibPathConfigFileHome
61{
62 const std::string PATH = "build/config-file-home/";
63};
64
65BOOST_FIXTURE_TEST_CASE(ConstructorNormalConfig, TestHomeAndPibFixture<PibPathConfigFileHome>)
66{
67 createClientConf({"pib=pib-memory:", "tpm=tpm-memory:"});
68
Yingdi Yufe4733a2015-10-22 14:24:12 -070069 KeyChain keyChain;
70 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-memory:");
71 BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-memory:");
72 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-memory:");
73}
74
75struct PibPathConfigFileEmptyHome
76{
77 const std::string PATH = "build/config-file-empty-home/";
78};
79
80BOOST_FIXTURE_TEST_CASE(ConstructorEmptyConfig, TestHomeAndPibFixture<PibPathConfigFileEmptyHome>)
81{
82 createClientConf({"pib=pib-memory:"});
83
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050084#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS)
Yingdi Yufe4733a2015-10-22 14:24:12 -070085 std::string oldHOME;
86 if (std::getenv("OLD_HOME"))
87 oldHOME = std::getenv("OLD_HOME");
88
89 std::string HOME;
90 if (std::getenv("HOME"))
91 HOME = std::getenv("HOME");
92
93 if (!oldHOME.empty())
94 setenv("HOME", oldHOME.c_str(), 1);
95 else
96 unsetenv("HOME");
97#endif
98
Yingdi Yufe4733a2015-10-22 14:24:12 -070099 KeyChain keyChain;
100 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-memory:");
101
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -0500102#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700103 BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-osxkeychain:");
104 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-osxkeychain:");
105#else
106 BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-file:");
107 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:");
108#endif
109
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -0500110#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700111 if (!HOME.empty())
112 setenv("HOME", HOME.c_str(), 1);
113 else
114 unsetenv("HOME");
115
116 if (!oldHOME.empty())
117 setenv("OLD_HOME", oldHOME.c_str(), 1);
118 else
119 unsetenv("OLD_HOME");
120#endif
121}
122
123struct PibPathConfigFileEmpty2Home
124{
125 const std::string PATH = "build/config-file-empty2-home/";
126};
127
Davide Pesavento73710362020-12-04 16:10:03 -0500128BOOST_FIXTURE_TEST_CASE(ConstructorEmptyConfig2, TestHomeAndPibFixture<PibPathConfigFileEmpty2Home>)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700129{
130 createClientConf({"tpm=tpm-memory:"});
131
Yingdi Yufe4733a2015-10-22 14:24:12 -0700132 KeyChain keyChain;
133 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:");
134 BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-memory:");
135 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-memory:");
136}
137
138struct PibPathConfigFileMalformedHome
139{
140 const std::string PATH = "build/config-file-malformed-home/";
141};
142
Davide Pesavento73710362020-12-04 16:10:03 -0500143BOOST_FIXTURE_TEST_CASE(ConstructorBadConfig, TestHomeAndPibFixture<PibPathConfigFileMalformedHome>)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700144{
145 createClientConf({"pib=lord", "tpm=ring"});
Davide Pesavento73710362020-12-04 16:10:03 -0500146 BOOST_CHECK_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
Yingdi Yufe4733a2015-10-22 14:24:12 -0700147}
148
149struct PibPathConfigFileMalformed2Home
150{
151 const std::string PATH = "build/config-file-malformed2-home/";
152};
153
Davide Pesavento73710362020-12-04 16:10:03 -0500154BOOST_FIXTURE_TEST_CASE(ConstructorBadConfig2, TestHomeAndPibFixture<PibPathConfigFileMalformed2Home>)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700155{
156 createClientConf({"pib=pib-sqlite3:%PATH%", "tpm=just-wrong"});
Davide Pesavento73710362020-12-04 16:10:03 -0500157 BOOST_CHECK_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
Yingdi Yufe4733a2015-10-22 14:24:12 -0700158}
159
Alexander Afanasyev57d02b62018-06-15 18:19:50 -0400160struct PibPathConfigFileNonCanonicalTpm
161{
162 const std::string PATH = "build/config-file-non-canonical-tpm/";
163};
164
165BOOST_FIXTURE_TEST_CASE(ConstructorNonCanonicalTpm, TestHomeAndPibFixture<PibPathConfigFileNonCanonicalTpm>) // Bug 4297
166{
167 createClientConf({"pib=pib-sqlite3:", "tpm=tpm-file"});
168
169 {
170 KeyChain keyChain;
171 keyChain.createIdentity("/test");
172 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:");
173 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:");
174 }
175
176 {
177 KeyChain keyChain;
178 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-sqlite3:");
179 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-file:");
180 BOOST_CHECK(keyChain.getPib().getIdentities().find("/test") != keyChain.getPib().getIdentities().end());
181 }
182}
183
Yingdi Yufe4733a2015-10-22 14:24:12 -0700184BOOST_AUTO_TEST_CASE(KeyChainWithCustomTpmAndPib)
185{
Yingdi Yufe4733a2015-10-22 14:24:12 -0700186 KeyChain keyChain("pib-memory", "tpm-memory");
187 BOOST_CHECK_EQUAL(keyChain.getPib().getPibLocator(), "pib-memory:");
188 BOOST_CHECK_EQUAL(keyChain.getPib().getTpmLocator(), "tpm-memory:");
189 BOOST_CHECK_EQUAL(keyChain.getTpm().getTpmLocator(), "tpm-memory:");
Davide Pesavento0e768ef2022-05-09 20:03:44 -0400190
191 BOOST_CHECK_NO_THROW(KeyChain("pib-memory:", "tpm-memory:"));
192 BOOST_CHECK_NO_THROW(KeyChain("pib-memory:/something", "tpm-memory:/something"));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700193}
194
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500195BOOST_FIXTURE_TEST_CASE(SigningWithCorruptedPibTpm, KeyChainFixture)
Alexander Afanasyevf601e192020-06-02 16:41:07 -0400196{
197 Identity id = m_keyChain.createIdentity("/test");
198
199 Data data("/foobar");
200 BOOST_CHECK_NO_THROW(m_keyChain.sign(data, signingByIdentity(id)));
201
202 // now, "corrupting TPM"
203 const_cast<Tpm&>(m_keyChain.getTpm()).deleteKey(id.getDefaultKey().getName());
204
205 BOOST_CHECK_NO_THROW(id.getDefaultKey());
206 BOOST_CHECK_THROW(m_keyChain.sign(data, signingByIdentity(id)), KeyChain::InvalidSigningInfoError);
207}
208
Davide Pesavento73710362020-12-04 16:10:03 -0500209BOOST_FIXTURE_TEST_CASE(SigningWithNonExistingIdentity, KeyChainFixture)
210{
211 Data data("/test/data");
212 BOOST_CHECK_THROW(m_keyChain.sign(data, signingByIdentity("/non-existing/identity")),
213 KeyChain::InvalidSigningInfoError);
214}
215
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500216BOOST_FIXTURE_TEST_CASE(Management, KeyChainFixture)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700217{
218 Name identityName("/test/id");
219 Name identity2Name("/test/id2");
220
221 BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 0);
222 BOOST_REQUIRE_THROW(m_keyChain.getPib().getDefaultIdentity(), Pib::Error);
223
224 // Create identity
225 Identity id = m_keyChain.createIdentity(identityName);
226 BOOST_CHECK(id);
227 BOOST_CHECK(m_keyChain.getPib().getIdentities().find(identityName) != m_keyChain.getPib().getIdentities().end());
228 // The first added identity becomes the default identity
laqinfan56a812d2019-06-03 15:33:58 -0500229 BOOST_CHECK_NO_THROW(m_keyChain.getPib().getDefaultIdentity());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700230 // The default key of the added identity must exist
laqinfan56a812d2019-06-03 15:33:58 -0500231 Key key = id.getDefaultKey();
Yingdi Yufe4733a2015-10-22 14:24:12 -0700232 // The default certificate of the default key must exist
laqinfan56a812d2019-06-03 15:33:58 -0500233 BOOST_CHECK_NO_THROW(key.getDefaultCertificate());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700234
235 // Delete key
236 Name key1Name = key.getName();
237 BOOST_CHECK_NO_THROW(id.getKey(key1Name));
238 BOOST_CHECK_EQUAL(id.getKeys().size(), 1);
239 m_keyChain.deleteKey(id, key);
240 // The key instance should not be valid any more
241 BOOST_CHECK(!key);
242 BOOST_CHECK_THROW(id.getKey(key1Name), Pib::Error);
243 BOOST_CHECK_EQUAL(id.getKeys().size(), 0);
244
245 // Create another key
246 m_keyChain.createKey(id);
247 // The added key becomes the default key.
Yingdi Yufe4733a2015-10-22 14:24:12 -0700248 Key key2 = id.getDefaultKey();
249 BOOST_REQUIRE(key2);
250 BOOST_CHECK_NE(key2.getName(), key1Name);
251 BOOST_CHECK_EQUAL(id.getKeys().size(), 1);
laqinfan56a812d2019-06-03 15:33:58 -0500252 BOOST_CHECK_NO_THROW(key2.getDefaultCertificate());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700253
254 // Create the third key
255 Key key3 = m_keyChain.createKey(id);
Junxiao Shi72c0c642018-04-20 15:41:09 +0000256 BOOST_CHECK_NE(key3.getName(), key2.getName());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700257 // The added key will not be the default key, because the default key already exists
Junxiao Shi72c0c642018-04-20 15:41:09 +0000258 BOOST_CHECK_EQUAL(id.getDefaultKey().getName(), key2.getName());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700259 BOOST_CHECK_EQUAL(id.getKeys().size(), 2);
laqinfan56a812d2019-06-03 15:33:58 -0500260 BOOST_CHECK_NO_THROW(key3.getDefaultCertificate());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700261
262 // Delete cert
263 BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1);
264 Certificate key3Cert1 = *key3.getCertificates().begin();
265 Name key3CertName = key3Cert1.getName();
266 m_keyChain.deleteCertificate(key3, key3CertName);
267 BOOST_CHECK_EQUAL(key3.getCertificates().size(), 0);
268 BOOST_REQUIRE_THROW(key3.getDefaultCertificate(), Pib::Error);
269
270 // Add cert
271 m_keyChain.addCertificate(key3, key3Cert1);
272 BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1);
laqinfan56a812d2019-06-03 15:33:58 -0500273 BOOST_CHECK_NO_THROW(key3.getDefaultCertificate());
Alexander Afanasyeva10b2ff2017-01-30 12:44:15 -0800274 m_keyChain.addCertificate(key3, key3Cert1); // overwriting the cert should work
Yingdi Yufe4733a2015-10-22 14:24:12 -0700275 BOOST_CHECK_EQUAL(key3.getCertificates().size(), 1);
276 // Add another cert
277 Certificate key3Cert2 = key3Cert1;
278 Name key3Cert2Name = key3.getName();
279 key3Cert2Name.append("Self");
280 key3Cert2Name.appendVersion();
281 key3Cert2.setName(key3Cert2Name);
282 m_keyChain.addCertificate(key3, key3Cert2);
283 BOOST_CHECK_EQUAL(key3.getCertificates().size(), 2);
Davide Pesavento81bd6962020-06-17 16:03:23 -0400284 // Add empty cert
285 Certificate key3Cert3 = key3Cert1;
286 key3Cert3.unsetContent();
287 BOOST_CHECK_THROW(m_keyChain.addCertificate(key3, key3Cert3), std::invalid_argument);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700288
289 // Default certificate setting
290 BOOST_CHECK_EQUAL(key3.getDefaultCertificate().getName(), key3CertName);
291 m_keyChain.setDefaultCertificate(key3, key3Cert2);
292 BOOST_CHECK_EQUAL(key3.getDefaultCertificate().getName(), key3Cert2Name);
293
294 // Default key setting
295 BOOST_CHECK_EQUAL(id.getDefaultKey().getName(), key2.getName());
296 m_keyChain.setDefaultKey(id, key3);
297 BOOST_CHECK_EQUAL(id.getDefaultKey().getName(), key3.getName());
298
299 // Default identity setting
300 Identity id2 = m_keyChain.createIdentity(identity2Name);
301 BOOST_CHECK_EQUAL(m_keyChain.getPib().getDefaultIdentity().getName(), id.getName());
302 m_keyChain.setDefaultIdentity(id2);
303 BOOST_CHECK_EQUAL(m_keyChain.getPib().getDefaultIdentity().getName(), id2.getName());
304
305 // Delete identity
306 m_keyChain.deleteIdentity(id);
307 // The identity instance should not be valid any more
308 BOOST_CHECK(!id);
Davide Pesavento73710362020-12-04 16:10:03 -0500309 BOOST_CHECK_THROW(m_keyChain.getPib().getIdentity(identityName), Pib::Error);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700310 BOOST_CHECK(m_keyChain.getPib().getIdentities().find(identityName) == m_keyChain.getPib().getIdentities().end());
311}
312
Davide Pesavento73710362020-12-04 16:10:03 -0500313struct DataPkt
Yingdi Yufe4733a2015-10-22 14:24:12 -0700314{
Davide Pesavento73710362020-12-04 16:10:03 -0500315 Data packet{"/data"};
316 SignedInterestFormat sigFormat = SignedInterestFormat::V02; // irrelevant for Data
Yingdi Yufe4733a2015-10-22 14:24:12 -0700317
Davide Pesavento73710362020-12-04 16:10:03 -0500318 SignatureInfo
319 getSignatureInfo() const
320 {
321 return packet.getSignatureInfo();
322 }
323};
laqinfan56a812d2019-06-03 15:33:58 -0500324
Davide Pesavento73710362020-12-04 16:10:03 -0500325struct InterestV02Pkt
326{
Davide Pesaventoaee2ada2022-02-18 14:43:02 -0500327 Interest packet{"/interest02"};
Davide Pesavento73710362020-12-04 16:10:03 -0500328 SignedInterestFormat sigFormat = SignedInterestFormat::V02;
Eric Newberryb74bbda2020-06-18 19:33:58 -0700329
Davide Pesavento73710362020-12-04 16:10:03 -0500330 SignatureInfo
331 getSignatureInfo() const
332 {
333 return SignatureInfo(packet.getName()[signed_interest::POS_SIG_INFO].blockFromValue());
334 }
335};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700336
Davide Pesavento73710362020-12-04 16:10:03 -0500337struct InterestV03Pkt
338{
Davide Pesaventoaee2ada2022-02-18 14:43:02 -0500339 Interest packet{"/interest03"};
Davide Pesavento73710362020-12-04 16:10:03 -0500340 SignedInterestFormat sigFormat = SignedInterestFormat::V03;
Eric Newberryb74bbda2020-06-18 19:33:58 -0700341
Davide Pesavento73710362020-12-04 16:10:03 -0500342 SignatureInfo
343 getSignatureInfo() const
344 {
345 return packet.getSignatureInfo().value(); // use .value() for checked access
346 }
347};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700348
Davide Pesavento73710362020-12-04 16:10:03 -0500349template<typename KeyParams>
350struct DefaultIdentity
351{
352 Identity
353 operator()(KeyChain& keyChain) const
354 {
355 auto id = keyChain.createIdentity("/id", KeyParams());
356 BOOST_ASSERT(keyChain.getPib().getDefaultIdentity() == id);
357 return id;
358 }
359};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700360
Davide Pesavento73710362020-12-04 16:10:03 -0500361template<typename KeyParams>
362struct NonDefaultIdentity
363{
364 Identity
365 operator()(KeyChain& keyChain) const
366 {
367 auto id = keyChain.createIdentity("/id");
368 auto id2 = keyChain.createIdentity("/id2", KeyParams());
369 BOOST_ASSERT(keyChain.getPib().getDefaultIdentity() == id);
370 return id2;
371 }
372};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700373
Davide Pesavento73710362020-12-04 16:10:03 -0500374template<typename KeyParams>
375struct DefaultKey
376{
377 Key
378 operator()(KeyChain&, const Identity& id) const
379 {
380 auto key = id.getDefaultKey();
381 BOOST_ASSERT(key.getKeyType() == KeyParams().getKeyType());
382 return key;
383 }
384};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700385
Davide Pesavento73710362020-12-04 16:10:03 -0500386template<typename KeyParams>
387struct NonDefaultKey
388{
389 Key
390 operator()(KeyChain& keyChain, const Identity& id) const
391 {
392 auto key2 = keyChain.createKey(id, KeyParams());
393 BOOST_ASSERT(id.getDefaultKey() != key2);
394 return key2;
395 }
396};
Eric Newberryb74bbda2020-06-18 19:33:58 -0700397
Davide Pesavento73710362020-12-04 16:10:03 -0500398template<typename PacketType,
399 template<typename> class IdentityMaker = DefaultIdentity,
400 template<typename> class KeyMaker = DefaultKey,
401 typename AsymmetricKeyParams = EcKeyParams,
402 uint32_t SignatureTypeTlvValue = tlv::SignatureSha256WithEcdsa>
403struct AsymmetricSigningBase : protected KeyChainFixture, protected PacketType
404{
405 const Identity id = IdentityMaker<AsymmetricKeyParams>()(m_keyChain);
406 const Key key = KeyMaker<AsymmetricKeyParams>()(m_keyChain, id);
407 const Certificate cert = key.getDefaultCertificate();
408
409 const uint32_t expectedSigType = SignatureTypeTlvValue;
410 const bool shouldHaveKeyLocator = true;
Junxiao Shi7d728682022-04-01 01:21:13 +0000411 const optional<KeyLocator> expectedKeyLocator = cert.getName();
Davide Pesavento73710362020-12-04 16:10:03 -0500412
413 bool
414 verify(const SigningInfo&) const
415 {
416 return verifySignature(this->packet, key);
417 }
418};
419
420template<typename PacketType,
421 typename AsymmetricKeyParams,
422 uint32_t SignatureTypeTlvValue>
423struct AsymmetricSigning : protected AsymmetricSigningBase<PacketType, DefaultIdentity, DefaultKey,
424 AsymmetricKeyParams, SignatureTypeTlvValue>
425{
426 const std::vector<SigningInfo> signingInfos = {
Yingdi Yufe4733a2015-10-22 14:24:12 -0700427 SigningInfo(),
Davide Pesavento73710362020-12-04 16:10:03 -0500428 SigningInfo(""),
Yingdi Yufe4733a2015-10-22 14:24:12 -0700429
Davide Pesavento73710362020-12-04 16:10:03 -0500430 SigningInfo(this->id),
431 SigningInfo(SigningInfo::SIGNER_TYPE_ID, this->id.getName()),
432 SigningInfo("id:" + this->id.getName().toUri()),
433 signingByIdentity(this->id),
434 signingByIdentity(this->id.getName()),
Yingdi Yufe4733a2015-10-22 14:24:12 -0700435
Davide Pesavento73710362020-12-04 16:10:03 -0500436 SigningInfo(this->key),
437 SigningInfo(SigningInfo::SIGNER_TYPE_KEY, this->key.getName()),
438 SigningInfo("key:" + this->key.getName().toUri()),
439 signingByKey(this->key),
440 signingByKey(this->key.getName()),
Alexander Afanasyevd6d78aa2017-01-02 18:14:23 -0800441
Davide Pesavento73710362020-12-04 16:10:03 -0500442 SigningInfo(SigningInfo::SIGNER_TYPE_CERT, this->cert.getName()),
443 SigningInfo("cert:" + this->cert.getName().toUri()),
444 signingByCertificate(this->cert),
445 signingByCertificate(this->cert.getName()),
446 };
447};
Yingdi Yufe4733a2015-10-22 14:24:12 -0700448
Davide Pesavento73710362020-12-04 16:10:03 -0500449template<typename PacketType>
450using RsaSigning = AsymmetricSigning<PacketType, RsaKeyParams, tlv::SignatureSha256WithRsa>;
Alexander Afanasyevd6d78aa2017-01-02 18:14:23 -0800451
Davide Pesavento73710362020-12-04 16:10:03 -0500452template<typename PacketType>
453using EcdsaSigning = AsymmetricSigning<PacketType, EcKeyParams, tlv::SignatureSha256WithEcdsa>;
Yingdi Yufe4733a2015-10-22 14:24:12 -0700454
Davide Pesavento73710362020-12-04 16:10:03 -0500455template<typename PacketType>
456struct SigningWithNonDefaultIdentity : protected AsymmetricSigningBase<PacketType, NonDefaultIdentity>
457{
458 const std::vector<SigningInfo> signingInfos = {
459 signingByIdentity(this->id),
460 signingByIdentity(this->id.getName()),
461 signingByKey(this->key),
462 signingByCertificate(this->cert),
463 };
464};
465
466template<typename PacketType>
467struct SigningWithNonDefaultKey : protected AsymmetricSigningBase<PacketType, NonDefaultIdentity, NonDefaultKey>
468{
469 const std::vector<SigningInfo> signingInfos = {
470 signingByKey(this->key),
471 signingByKey(this->key.getName()),
472 signingByCertificate(this->cert),
473 };
474};
475
476template<typename PacketType,
477 DigestAlgorithm DigestAlgo = DigestAlgorithm::SHA256,
478 uint32_t SignatureTypeTlvValue = tlv::SignatureHmacWithSha256>
479struct HmacSigning : protected KeyChainFixture, protected PacketType
480{
481 const std::vector<SigningInfo> signingInfos = {
482 SigningInfo(SigningInfo::SIGNER_TYPE_HMAC, m_keyChain.createHmacKey()),
laqinfan56a812d2019-06-03 15:33:58 -0500483 SigningInfo("hmac-sha256:QjM3NEEyNkE3MTQ5MDQzN0FBMDI0RTRGQURENUI0OTdGREZGMUE4RUE2RkYxMkY2RkI2NUFGMjcyMEI1OUNDRg=="),
Davide Pesavento73710362020-12-04 16:10:03 -0500484 };
laqinfan56a812d2019-06-03 15:33:58 -0500485
Davide Pesavento73710362020-12-04 16:10:03 -0500486 const uint32_t expectedSigType = SignatureTypeTlvValue;
487 const bool shouldHaveKeyLocator = true;
488 const optional<KeyLocator> expectedKeyLocator = nullopt; // don't check KeyLocator value
489
490 bool
491 verify(const SigningInfo& si) const
492 {
493 return verifySignature(this->packet, m_keyChain.getTpm(), si.getSignerName(), DigestAlgo);
494 }
495};
496
497template<typename PacketType>
498struct Sha256Signing : protected KeyChainFixture, protected PacketType
499{
500 const std::vector<SigningInfo> signingInfos = {
Yingdi Yufe4733a2015-10-22 14:24:12 -0700501 SigningInfo(SigningInfo::SIGNER_TYPE_SHA256),
Davide Pesavento73710362020-12-04 16:10:03 -0500502 SigningInfo("id:" + SigningInfo::getDigestSha256Identity().toUri()),
Yingdi Yufe4733a2015-10-22 14:24:12 -0700503 signingWithSha256()
504 };
505
Davide Pesavento73710362020-12-04 16:10:03 -0500506 const uint32_t expectedSigType = tlv::DigestSha256;
507 const bool shouldHaveKeyLocator = false;
508 const optional<KeyLocator> expectedKeyLocator = nullopt;
Yingdi Yufe4733a2015-10-22 14:24:12 -0700509
Davide Pesavento73710362020-12-04 16:10:03 -0500510 bool
511 verify(const SigningInfo&) const
512 {
Davide Pesavento809f7542021-03-24 18:53:05 -0400513 return verifySignature(this->packet, nullopt);
Davide Pesavento73710362020-12-04 16:10:03 -0500514 }
515};
Yingdi Yufe4733a2015-10-22 14:24:12 -0700516
Davide Pesavento73710362020-12-04 16:10:03 -0500517using SigningTests = boost::mpl::vector<
518 RsaSigning<DataPkt>,
519 RsaSigning<InterestV02Pkt>,
520 RsaSigning<InterestV03Pkt>,
521 EcdsaSigning<DataPkt>,
522 EcdsaSigning<InterestV02Pkt>,
523 EcdsaSigning<InterestV03Pkt>,
Davide Pesavento94dfcf12021-09-26 14:18:45 -0400524#if OPENSSL_VERSION_NUMBER < 0x30000000L // FIXME #5154
Davide Pesavento73710362020-12-04 16:10:03 -0500525 HmacSigning<DataPkt>,
526 HmacSigning<InterestV02Pkt>,
527 HmacSigning<InterestV03Pkt>,
Davide Pesavento94dfcf12021-09-26 14:18:45 -0400528#endif
Davide Pesavento73710362020-12-04 16:10:03 -0500529 Sha256Signing<DataPkt>,
530 Sha256Signing<InterestV02Pkt>,
531 Sha256Signing<InterestV03Pkt>,
532 SigningWithNonDefaultIdentity<DataPkt>,
Davide Pesavento809f7542021-03-24 18:53:05 -0400533 SigningWithNonDefaultIdentity<InterestV03Pkt>,
534 SigningWithNonDefaultKey<DataPkt>,
535 SigningWithNonDefaultKey<InterestV03Pkt>
Davide Pesavento73710362020-12-04 16:10:03 -0500536>;
Eric Newberryb74bbda2020-06-18 19:33:58 -0700537
Davide Pesavento73710362020-12-04 16:10:03 -0500538BOOST_FIXTURE_TEST_CASE_TEMPLATE(SigningInterface, T, SigningTests, T)
539{
540 BOOST_TEST_CONTEXT("Packet = " << this->packet.getName()) {
541 for (auto signingInfo : this->signingInfos) {
542 signingInfo.setSignedInterestFormat(this->sigFormat);
543
544 BOOST_TEST_CONTEXT("SigningInfo = " << signingInfo) {
545 this->m_keyChain.sign(this->packet, signingInfo);
546
547 auto sigInfo = this->getSignatureInfo();
548 BOOST_CHECK_EQUAL(sigInfo.getSignatureType(), this->expectedSigType);
549 BOOST_CHECK_EQUAL(sigInfo.hasKeyLocator(), this->shouldHaveKeyLocator);
550 if (this->expectedKeyLocator) {
551 BOOST_CHECK_EQUAL(sigInfo.getKeyLocator(), *this->expectedKeyLocator);
552 }
553 BOOST_CHECK(this->verify(signingInfo));
Eric Newberryb74bbda2020-06-18 19:33:58 -0700554 }
Yingdi Yufe4733a2015-10-22 14:24:12 -0700555 }
556 }
557}
558
Junxiao Shi9ee770b2022-04-25 23:33:33 +0000559class MakeCertificateFixture : public ClockFixture
560{
561public:
562 MakeCertificateFixture()
563 : requesterKeyChain("pib-memory:", "tpm-memory:")
564 , signerKeyChain("pib-memory:", "tpm-memory:")
565 {
566 m_systemClock->setNow(time::fromIsoString("20091117T203458,651387237").time_since_epoch());
567
568 requester = requesterKeyChain.createIdentity("/requester").getDefaultKey();
569 Name signerIdentityName("/signer");
570 signerKey = signerKeyChain.createIdentity(signerIdentityName).getDefaultKey();
571 signerParams = signingByIdentity(signerIdentityName);
572 }
573
574 void
Davide Pesavento07db0732022-05-06 15:20:26 -0400575 checkKeyLocatorName(const Certificate& cert, const optional<Name>& klName = nullopt) const
Junxiao Shi9ee770b2022-04-25 23:33:33 +0000576 {
577 auto kl = cert.getKeyLocator();
578 if (!kl.has_value()) {
579 BOOST_ERROR("KeyLocator is missing");
580 return;
581 }
Davide Pesavento07db0732022-05-06 15:20:26 -0400582 BOOST_CHECK_EQUAL(kl->getName(), klName.value_or(signerKey.getDefaultCertificate().getName()));
Junxiao Shi9ee770b2022-04-25 23:33:33 +0000583 }
584
585 void
586 checkCertFromDefaults(const Certificate& cert) const
587 {
588 BOOST_CHECK(Certificate::isValidName(cert.getName()));
589 BOOST_CHECK_EQUAL(cert.getKeyName(), requester.getName());
590 BOOST_CHECK_EQUAL(cert.getName()[-2], name::Component("NA"));
591 BOOST_CHECK(cert.getName()[-1].isVersion());
592
593 BOOST_CHECK_EQUAL(cert.getContentType(), tlv::ContentType_Key);
594 BOOST_CHECK_EQUAL(cert.getFreshnessPeriod(), 1_h);
595
Davide Pesavento8e2a61d2022-05-13 18:44:03 -0400596 BOOST_TEST(cert.getPublicKey() == requester.getPublicKey(), boost::test_tools::per_element());
Junxiao Shi9ee770b2022-04-25 23:33:33 +0000597
598 checkKeyLocatorName(cert);
599
600 BOOST_CHECK(cert.isValid());
601 auto vp = cert.getValidityPeriod().getPeriod();
602 BOOST_CHECK_EQUAL(vp.first, time::fromIsoString("20091117T203458"));
603 BOOST_CHECK_EQUAL(vp.second, time::fromIsoString("20101117T203458"));
604
605 auto adBlock = cert.getSignatureInfo().getCustomTlv(tlv::AdditionalDescription);
606 BOOST_CHECK(!adBlock.has_value());
607 }
608
609public:
610 KeyChain requesterKeyChain;
611 pib::Key requester;
612
613 KeyChain signerKeyChain;
614 pib::Key signerKey;
615 Name signerCertificateName;
616 SigningInfo signerParams;
617};
618
619BOOST_FIXTURE_TEST_SUITE(MakeCertificate, MakeCertificateFixture)
620
621BOOST_AUTO_TEST_CASE(DefaultsFromKey)
622{
623 auto cert = signerKeyChain.makeCertificate(requester, signerParams);
624 checkCertFromDefaults(cert);
625}
626
627BOOST_AUTO_TEST_CASE(DefaultsFromCert)
628{
629 auto cert = signerKeyChain.makeCertificate(requester.getDefaultCertificate(), signerParams);
630 checkCertFromDefaults(cert);
631}
632
633BOOST_AUTO_TEST_CASE(Options)
634{
635 MakeCertificateOptions opts;
636 opts.issuerId = name::Component::fromEscapedString("ISSUER");
637 opts.version = 41218268;
638 opts.freshnessPeriod = 321_s;
639 opts.validity.emplace(time::fromIsoString("20060702T150405"),
640 time::fromIsoString("20160702T150405"));
641
642 SignatureInfo sigInfo;
643 sigInfo.setKeyLocator(signerKey.getName());
644 sigInfo.setValidityPeriod(ValidityPeriod(time::fromIsoString("20060102T150405"),
645 time::fromIsoString("20160102T150405")));
646 sigInfo.addCustomTlv(Block(0xF0));
647 signerParams.setSignatureInfo(sigInfo);
648
649 auto cert = signerKeyChain.makeCertificate(requester, signerParams, opts);
650
651 BOOST_CHECK_EQUAL(cert.getName(),
652 Name(requester.getName()).append(PartialName("ISSUER/v=41218268")));
653 BOOST_CHECK_EQUAL(cert.getFreshnessPeriod(), 321_s);
654 checkKeyLocatorName(cert, signerKey.getName());
655
656 auto vp = cert.getValidityPeriod().getPeriod();
657 BOOST_CHECK_EQUAL(vp.first, time::fromIsoString("20060702T150405"));
658 BOOST_CHECK_EQUAL(vp.second, time::fromIsoString("20160702T150405"));
659
660 BOOST_CHECK(cert.getSignatureInfo().getCustomTlv(0xF0).has_value());
661}
662
663BOOST_AUTO_TEST_CASE(ErrSigner)
664{
665 signerParams = signingByIdentity("/nonexistent");
666 BOOST_CHECK_THROW(signerKeyChain.makeCertificate(requester, signerParams), KeyChain::Error);
667}
668
669BOOST_AUTO_TEST_CASE(ErrZeroFreshness)
670{
671 MakeCertificateOptions opts;
672 opts.freshnessPeriod = 0_ms;
673 BOOST_CHECK_THROW(signerKeyChain.makeCertificate(requester, signerParams, opts),
674 std::invalid_argument);
675}
676
677BOOST_AUTO_TEST_CASE(ErrNegativeFreshness)
678{
679 MakeCertificateOptions opts;
680 opts.freshnessPeriod = -1_ms;
681 BOOST_CHECK_THROW(signerKeyChain.makeCertificate(requester, signerParams, opts),
682 std::invalid_argument);
683}
684
685BOOST_AUTO_TEST_CASE(ErrContent)
686{
687 Certificate request(requester.getDefaultCertificate());
Davide Pesavento07db0732022-05-06 15:20:26 -0400688
689 // malformed public key
Junxiao Shi9ee770b2022-04-25 23:33:33 +0000690 const auto& oldContent = request.getContent();
691 std::vector<uint8_t> content(oldContent.value_begin(), oldContent.value_end());
692 content[0] ^= 0x80;
693 request.setContent(content);
694 BOOST_CHECK_THROW(signerKeyChain.makeCertificate(request, signerParams), std::invalid_argument);
Davide Pesavento07db0732022-05-06 15:20:26 -0400695
696 // empty content
697 request.setContent(span<uint8_t>{});
698 BOOST_CHECK_THROW(signerKeyChain.makeCertificate(request, signerParams), std::invalid_argument);
Junxiao Shi9ee770b2022-04-25 23:33:33 +0000699}
700
701BOOST_AUTO_TEST_SUITE_END() // MakeCertificate
702
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500703BOOST_FIXTURE_TEST_CASE(ImportPrivateKey, KeyChainFixture)
laqinfan56a812d2019-06-03 15:33:58 -0500704{
Davide Pesavento765abc92021-12-27 00:44:04 -0500705 const Name keyName("/test/device2");
706 const uint8_t rawKey[] = "nPSNOHyZKsg2WLqHAs7MXGb0sjQb4zCT";
laqinfan56a812d2019-06-03 15:33:58 -0500707 auto key = make_shared<transform::PrivateKey>();
Davide Pesavento765abc92021-12-27 00:44:04 -0500708 key->loadRaw(KeyType::HMAC, rawKey);
laqinfan56a812d2019-06-03 15:33:58 -0500709
710 m_keyChain.importPrivateKey(keyName, key);
711 BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(keyName), true);
712 BOOST_CHECK_THROW(m_keyChain.importPrivateKey(keyName, key), KeyChain::Error);
713}
714
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500715BOOST_FIXTURE_TEST_CASE(ExportImport, KeyChainFixture)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700716{
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500717 Identity id = m_keyChain.createIdentity("/TestKeyChain/ExportIdentity");
Yingdi Yufe4733a2015-10-22 14:24:12 -0700718 Certificate cert = id.getDefaultKey().getDefaultCertificate();
719
720 shared_ptr<SafeBag> exported = m_keyChain.exportSafeBag(cert, "1234", 4);
721 Block block = exported->wireEncode();
722
723 m_keyChain.deleteIdentity(id);
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500724 BOOST_CHECK_THROW(m_keyChain.exportSafeBag(cert, "1234", 4), KeyChain::Error);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700725
726 BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(cert.getKeyName()), false);
727 BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 0);
728
729 SafeBag imported;
730 imported.wireDecode(block);
731 m_keyChain.importSafeBag(imported, "1234", 4);
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500732 BOOST_CHECK_THROW(m_keyChain.importSafeBag(imported, "1234", 4), KeyChain::Error);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700733
734 BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(cert.getKeyName()), true);
735 BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 1);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700736 Identity newId = m_keyChain.getPib().getIdentity(cert.getIdentity());
737 BOOST_CHECK_EQUAL(newId.getKeys().size(), 1);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700738 Key newKey = newId.getKey(cert.getKeyName());
739 BOOST_CHECK_EQUAL(newKey.getCertificates().size(), 1);
laqinfan56a812d2019-06-03 15:33:58 -0500740 BOOST_CHECK_NO_THROW(newKey.getCertificate(cert.getName()));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700741
742 m_keyChain.deleteIdentity(newId);
743 BOOST_CHECK_EQUAL(m_keyChain.getPib().getIdentities().size(), 0);
744 BOOST_CHECK_EQUAL(m_keyChain.getTpm().hasKey(cert.getKeyName()), false);
745}
746
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500747BOOST_FIXTURE_TEST_CASE(SelfSignedCertValidity, KeyChainFixture)
Alexander Afanasyevf8379172017-01-11 16:56:04 -0800748{
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500749 Certificate cert = m_keyChain.createIdentity("/Security/TestKeyChain/SelfSignedCertValidity")
Alexander Afanasyevf8379172017-01-11 16:56:04 -0800750 .getDefaultKey()
751 .getDefaultCertificate();
752 BOOST_CHECK(cert.isValid());
Davide Pesavento0f830802018-01-16 23:58:58 -0500753 BOOST_CHECK(cert.isValid(time::system_clock::now() + 10 * 365_days));
754 BOOST_CHECK_GT(cert.getValidityPeriod().getPeriod().second, time::system_clock::now() + 10 * 365_days);
Alexander Afanasyevf8379172017-01-11 16:56:04 -0800755}
756
Yingdi Yufe4733a2015-10-22 14:24:12 -0700757BOOST_AUTO_TEST_SUITE_END() // TestKeyChain
Yingdi Yufe4733a2015-10-22 14:24:12 -0700758BOOST_AUTO_TEST_SUITE_END() // Security
759
760} // namespace tests
Alexander Afanasyev09236c22020-06-03 13:42:38 -0400761} // inline namespace v2
Yingdi Yufe4733a2015-10-22 14:24:12 -0700762} // namespace security
763} // namespace ndn