blob: 2ac2e9972d765e214522b21596b7a7db7917740b [file] [log] [blame]
Yingdi Yufe4733a2015-10-22 14:24:12 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento10b24be2017-07-12 23:23:46 -04002/*
Davide Pesavento0f830802018-01-16 23:58:58 -05003 * Copyright (c) 2013-2018 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
22#include "key-chain.hpp"
23
24#include "../../util/config-file.hpp"
Alexander Afanasyev83eb1cc2017-01-04 17:34:34 -080025#include "../../util/logger.hpp"
Junxiao Shi6938e342017-07-25 21:56:58 +000026#include "../../util/sha256.hpp"
Yingdi Yufe4733a2015-10-22 14:24:12 -070027
28#include "../pib/pib-sqlite3.hpp"
29#include "../pib/pib-memory.hpp"
30
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050031#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS
Yingdi Yufe4733a2015-10-22 14:24:12 -070032#include "../tpm/back-end-osx.hpp"
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050033#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS
Yingdi Yufe4733a2015-10-22 14:24:12 -070034
35#include "../tpm/back-end-file.hpp"
36#include "../tpm/back-end-mem.hpp"
37
38#include "../transform/bool-sink.hpp"
39#include "../transform/buffer-source.hpp"
40#include "../transform/private-key.hpp"
Davide Pesavento8aad3722017-09-16 20:57:28 -040041#include "../transform/public-key.hpp"
Yingdi Yufe4733a2015-10-22 14:24:12 -070042#include "../transform/verifier-filter.hpp"
43#include "../../encoding/buffer-stream.hpp"
Yingdi Yufe4733a2015-10-22 14:24:12 -070044
45#include <boost/lexical_cast.hpp>
46
47namespace ndn {
48namespace security {
49
50// When static library is used, not everything is compiled into the resulting binary.
51// Therefore, the following standard PIB and TPMs need to be registered here.
52// http://stackoverflow.com/q/9459980/2150331
53
Yingdi Yufe4733a2015-10-22 14:24:12 -070054namespace pib {
55NDN_CXX_V2_KEYCHAIN_REGISTER_PIB_BACKEND(PibSqlite3);
56NDN_CXX_V2_KEYCHAIN_REGISTER_PIB_BACKEND(PibMemory);
57} // namespace pib
58
Yingdi Yufe4733a2015-10-22 14:24:12 -070059namespace tpm {
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050060#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) && defined(NDN_CXX_WITH_OSX_KEYCHAIN)
Yingdi Yufe4733a2015-10-22 14:24:12 -070061NDN_CXX_V2_KEYCHAIN_REGISTER_TPM_BACKEND(BackEndOsx);
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050062#endif // defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) && defined(NDN_CXX_WITH_OSX_KEYCHAIN)
Yingdi Yufe4733a2015-10-22 14:24:12 -070063
64NDN_CXX_V2_KEYCHAIN_REGISTER_TPM_BACKEND(BackEndFile);
65NDN_CXX_V2_KEYCHAIN_REGISTER_TPM_BACKEND(BackEndMem);
66} // namespace tpm
67
68namespace v2 {
69
Alexander Afanasyev83eb1cc2017-01-04 17:34:34 -080070NDN_LOG_INIT(ndn.security.v2.KeyChain);
71
Yingdi Yufe4733a2015-10-22 14:24:12 -070072std::string KeyChain::s_defaultPibLocator;
73std::string KeyChain::s_defaultTpmLocator;
74
75KeyChain::PibFactories&
76KeyChain::getPibFactories()
77{
78 static PibFactories pibFactories;
79 return pibFactories;
80}
81
82KeyChain::TpmFactories&
83KeyChain::getTpmFactories()
84{
85 static TpmFactories tpmFactories;
86 return tpmFactories;
87}
88
89const std::string&
90KeyChain::getDefaultPibScheme()
91{
92 return pib::PibSqlite3::getScheme();;
93}
94
95const std::string&
96KeyChain::getDefaultTpmScheme()
97{
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050098#if defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) && defined(NDN_CXX_WITH_OSX_KEYCHAIN)
Yingdi Yufe4733a2015-10-22 14:24:12 -070099 return tpm::BackEndOsx::getScheme();;
100#else
101 return tpm::BackEndFile::getScheme();
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -0500102#endif // defined(NDN_CXX_HAVE_OSX_FRAMEWORKS) && defined(NDN_CXX_WITH_OSX_KEYCHAIN)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700103}
104
105const std::string&
106KeyChain::getDefaultPibLocator()
107{
108 if (!s_defaultPibLocator.empty())
109 return s_defaultPibLocator;
110
111 if (getenv("NDN_CLIENT_PIB") != nullptr) {
112 s_defaultPibLocator = getenv("NDN_CLIENT_PIB");
113 }
114 else {
115 ConfigFile config;
116 s_defaultPibLocator = config.getParsedConfiguration().get<std::string>("pib", getDefaultPibScheme() + ":");
117 }
118
Alexander Afanasyev57d02b62018-06-15 18:19:50 -0400119 std::string pibScheme, pibLocation;
120 std::tie(pibScheme, pibLocation) = parseAndCheckPibLocator(s_defaultPibLocator);
121 s_defaultPibLocator = pibScheme + ":" + pibLocation;
122
Yingdi Yufe4733a2015-10-22 14:24:12 -0700123 return s_defaultPibLocator;
124}
125
126const std::string&
127KeyChain::getDefaultTpmLocator()
128{
129 if (!s_defaultTpmLocator.empty())
130 return s_defaultTpmLocator;
131
132 if (getenv("NDN_CLIENT_TPM") != nullptr) {
133 s_defaultTpmLocator = getenv("NDN_CLIENT_TPM");
134 }
135 else {
136 ConfigFile config;
137 s_defaultTpmLocator = config.getParsedConfiguration().get<std::string>("tpm", getDefaultTpmScheme() + ":");
138 }
139
Alexander Afanasyev57d02b62018-06-15 18:19:50 -0400140 std::string tpmScheme, tpmLocation;
141 std::tie(tpmScheme, tpmLocation) = parseAndCheckTpmLocator(s_defaultTpmLocator);
142 s_defaultTpmLocator = tpmScheme + ":" + tpmLocation;
143
Yingdi Yufe4733a2015-10-22 14:24:12 -0700144 return s_defaultTpmLocator;
145}
146
147
148// Other defaults
149
150const SigningInfo&
151KeyChain::getDefaultSigningInfo()
152{
153 static SigningInfo signingInfo;
154 return signingInfo;
155}
156
157const KeyParams&
158KeyChain::getDefaultKeyParams()
159{
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700160 static EcKeyParams keyParams;
Yingdi Yufe4733a2015-10-22 14:24:12 -0700161 return keyParams;
162}
163
164//
165
166KeyChain::KeyChain()
167 : KeyChain(getDefaultPibLocator(), getDefaultTpmLocator(), true)
168{
169}
170
171KeyChain::KeyChain(const std::string& pibLocator, const std::string& tpmLocator, bool allowReset)
172{
173 // PIB Locator
174 std::string pibScheme, pibLocation;
175 std::tie(pibScheme, pibLocation) = parseAndCheckPibLocator(pibLocator);
176 std::string canonicalPibLocator = pibScheme + ":" + pibLocation;
177
178 // Create PIB
179 m_pib = createPib(canonicalPibLocator);
180 std::string oldTpmLocator;
181 try {
182 oldTpmLocator = m_pib->getTpmLocator();
183 }
184 catch (const Pib::Error&) {
185 // TPM locator is not set in PIB yet.
186 }
187
188 // TPM Locator
189 std::string tpmScheme, tpmLocation;
190 std::tie(tpmScheme, tpmLocation) = parseAndCheckTpmLocator(tpmLocator);
191 std::string canonicalTpmLocator = tpmScheme + ":" + tpmLocation;
192
193 if (canonicalPibLocator == getDefaultPibLocator()) {
194 // Default PIB must use default TPM
195 if (!oldTpmLocator.empty() && oldTpmLocator != getDefaultTpmLocator()) {
196 m_pib->reset();
197 canonicalTpmLocator = getDefaultTpmLocator();
198 }
199 }
200 else {
201 // non-default PIB check consistency
202 if (!oldTpmLocator.empty() && oldTpmLocator != canonicalTpmLocator) {
203 if (allowReset)
204 m_pib->reset();
205 else
206 BOOST_THROW_EXCEPTION(LocatorMismatchError("TPM locator supplied does not match TPM locator in PIB: " +
207 oldTpmLocator + " != " + canonicalTpmLocator));
208 }
209 }
210
211 // note that key mismatch may still happen if the TPM locator is initially set to a
212 // wrong one or if the PIB was shared by more than one TPMs before. This is due to the
213 // old PIB does not have TPM info, new pib should not have this problem.
214 m_tpm = createTpm(canonicalTpmLocator);
215 m_pib->setTpmLocator(canonicalTpmLocator);
216}
217
218KeyChain::~KeyChain() = default;
219
220// public: management
221
222Identity
223KeyChain::createIdentity(const Name& identityName, const KeyParams& params)
224{
225 Identity id = m_pib->addIdentity(identityName);
226
227 Key key;
228 try {
229 key = id.getDefaultKey();
230 }
231 catch (const Pib::Error&) {
232 key = createKey(id, params);
233 }
234
235 try {
236 key.getDefaultCertificate();
237 }
238 catch (const Pib::Error&) {
Alexander Afanasyev83eb1cc2017-01-04 17:34:34 -0800239 NDN_LOG_DEBUG("No default cert for " << key.getName() << ", requesting self-signing");
Yingdi Yufe4733a2015-10-22 14:24:12 -0700240 selfSign(key);
241 }
242
243 return id;
244}
245
246void
247KeyChain::deleteIdentity(const Identity& identity)
248{
249 BOOST_ASSERT(static_cast<bool>(identity));
250
251 Name identityName = identity.getName();
252
253 for (const auto& key : identity.getKeys()) {
254 m_tpm->deleteKey(key.getName());
255 }
256
257 m_pib->removeIdentity(identityName);
258}
259
260void
261KeyChain::setDefaultIdentity(const Identity& identity)
262{
263 BOOST_ASSERT(static_cast<bool>(identity));
264
265 m_pib->setDefaultIdentity(identity.getName());
266}
267
268Key
269KeyChain::createKey(const Identity& identity, const KeyParams& params)
270{
271 BOOST_ASSERT(static_cast<bool>(identity));
272
273 // create key in TPM
274 Name keyName = m_tpm->createKey(identity.getName(), params);
275
276 // set up key info in PIB
277 ConstBufferPtr pubKey = m_tpm->getPublicKey(keyName);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400278 Key key = identity.addKey(pubKey->data(), pubKey->size(), keyName);
Alexander Afanasyev83eb1cc2017-01-04 17:34:34 -0800279
280 NDN_LOG_DEBUG("Requesting self-signing for newly created key " << key.getName());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700281 selfSign(key);
282
283 return key;
284}
285
286void
287KeyChain::deleteKey(const Identity& identity, const Key& key)
288{
289 BOOST_ASSERT(static_cast<bool>(identity));
290 BOOST_ASSERT(static_cast<bool>(key));
291
292 Name keyName = key.getName();
293 if (identity.getName() != key.getIdentity()) {
294 BOOST_THROW_EXCEPTION(std::invalid_argument("Identity `" + identity.getName().toUri() + "` "
Muktadir Chowdhurycab16962017-06-12 12:19:43 -0500295 "does not match key `" + keyName.toUri() + "`"));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700296 }
297
298 identity.removeKey(keyName);
299 m_tpm->deleteKey(keyName);
300}
301
302void
303KeyChain::setDefaultKey(const Identity& identity, const Key& key)
304{
305 BOOST_ASSERT(static_cast<bool>(identity));
306 BOOST_ASSERT(static_cast<bool>(key));
307
308 if (identity.getName() != key.getIdentity())
309 BOOST_THROW_EXCEPTION(std::invalid_argument("Identity `" + identity.getName().toUri() + "` "
Muktadir Chowdhurycab16962017-06-12 12:19:43 -0500310 "does not match key `" + key.getName().toUri() + "`"));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700311
312 identity.setDefaultKey(key.getName());
313}
314
315void
316KeyChain::addCertificate(const Key& key, const Certificate& certificate)
317{
318 BOOST_ASSERT(static_cast<bool>(key));
319
320 if (key.getName() != certificate.getKeyName() ||
321 !std::equal(certificate.getContent().value_begin(), certificate.getContent().value_end(),
322 key.getPublicKey().begin()))
323 BOOST_THROW_EXCEPTION(std::invalid_argument("Key `" + key.getName().toUri() + "` "
Muktadir Chowdhurycab16962017-06-12 12:19:43 -0500324 "does not match certificate `" + certificate.getName().toUri() + "`"));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700325
326 key.addCertificate(certificate);
327}
328
329void
330KeyChain::deleteCertificate(const Key& key, const Name& certificateName)
331{
332 BOOST_ASSERT(static_cast<bool>(key));
333
334 if (!Certificate::isValidName(certificateName)) {
335 BOOST_THROW_EXCEPTION(std::invalid_argument("Wrong certificate name `" + certificateName.toUri() + "`"));
336 }
337
338 key.removeCertificate(certificateName);
339}
340
341void
342KeyChain::setDefaultCertificate(const Key& key, const Certificate& cert)
343{
344 BOOST_ASSERT(static_cast<bool>(key));
345
Davide Pesavento3ce6d4e2017-10-05 01:48:24 -0400346 addCertificate(key, cert);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700347 key.setDefaultCertificate(cert.getName());
348}
349
350shared_ptr<SafeBag>
351KeyChain::exportSafeBag(const Certificate& certificate, const char* pw, size_t pwLen)
352{
353 Name identity = certificate.getIdentity();
354 Name keyName = certificate.getKeyName();
355
356 ConstBufferPtr encryptedKey;
357 try {
358 encryptedKey = m_tpm->exportPrivateKey(keyName, pw, pwLen);
359 }
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500360 catch (const tpm::BackEnd::Error& e) {
361 BOOST_THROW_EXCEPTION(Error("Failed to export private key `" + keyName.toUri() + "`: " + e.what()));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700362 }
363
364 return make_shared<SafeBag>(certificate, *encryptedKey);
365}
366
367void
368KeyChain::importSafeBag(const SafeBag& safeBag, const char* pw, size_t pwLen)
369{
370 Data certData = safeBag.getCertificate();
371 Certificate cert(std::move(certData));
372 Name identity = cert.getIdentity();
373 Name keyName = cert.getKeyName();
374 const Buffer publicKeyBits = cert.getPublicKey();
375
376 if (m_tpm->hasKey(keyName)) {
377 BOOST_THROW_EXCEPTION(Error("Private key `" + keyName.toUri() + "` already exists"));
378 }
379
380 try {
381 Identity existingId = m_pib->getIdentity(identity);
382 existingId.getKey(keyName);
383 BOOST_THROW_EXCEPTION(Error("Public key `" + keyName.toUri() + "` already exists"));
384 }
385 catch (const Pib::Error&) {
386 // Either identity or key doesn't exist. OK to import.
387 }
388
389 try {
390 m_tpm->importPrivateKey(keyName,
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400391 safeBag.getEncryptedKeyBag().data(), safeBag.getEncryptedKeyBag().size(),
Yingdi Yufe4733a2015-10-22 14:24:12 -0700392 pw, pwLen);
393 }
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500394 catch (const tpm::BackEnd::Error& e) {
395 BOOST_THROW_EXCEPTION(Error("Failed to import private key `" + keyName.toUri() + "`: " + e.what()));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700396 }
397
398 // check the consistency of private key and certificate
399 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
400 ConstBufferPtr sigBits;
401 try {
402 sigBits = m_tpm->sign(content, 4, keyName, DigestAlgorithm::SHA256);
403 }
404 catch (const std::runtime_error&) {
405 m_tpm->deleteKey(keyName);
406 BOOST_THROW_EXCEPTION(Error("Invalid private key `" + keyName.toUri() + "`"));
407 }
408 bool isVerified = false;
409 {
410 using namespace transform;
411 PublicKey publicKey;
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400412 publicKey.loadPkcs8(publicKeyBits.data(), publicKeyBits.size());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700413 bufferSource(content, sizeof(content)) >> verifierFilter(DigestAlgorithm::SHA256, publicKey,
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400414 sigBits->data(), sigBits->size())
Yingdi Yufe4733a2015-10-22 14:24:12 -0700415 >> boolSink(isVerified);
416 }
417 if (!isVerified) {
418 m_tpm->deleteKey(keyName);
419 BOOST_THROW_EXCEPTION(Error("Certificate `" + cert.getName().toUri() + "` "
420 "and private key `" + keyName.toUri() + "` do not match"));
421 }
422
423 Identity id = m_pib->addIdentity(identity);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400424 Key key = id.addKey(cert.getPublicKey().data(), cert.getPublicKey().size(), keyName);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700425 key.addCertificate(cert);
426}
427
Yingdi Yufe4733a2015-10-22 14:24:12 -0700428// public: signing
429
430void
431KeyChain::sign(Data& data, const SigningInfo& params)
432{
433 Name keyName;
434 SignatureInfo sigInfo;
435 std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
436
437 data.setSignature(Signature(sigInfo));
438
439 EncodingBuffer encoder;
440 data.wireEncode(encoder, true);
441
442 Block sigValue = sign(encoder.buf(), encoder.size(), keyName, params.getDigestAlgorithm());
443
444 data.wireEncode(encoder, sigValue);
445}
446
447void
448KeyChain::sign(Interest& interest, const SigningInfo& params)
449{
450 Name keyName;
451 SignatureInfo sigInfo;
452 std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
453
454 Name signedName = interest.getName();
455 signedName.append(sigInfo.wireEncode()); // signatureInfo
456
457 Block sigValue = sign(signedName.wireEncode().value(), signedName.wireEncode().value_size(),
458 keyName, params.getDigestAlgorithm());
459
460 sigValue.encode();
461 signedName.append(sigValue); // signatureValue
462 interest.setName(signedName);
463}
464
465Block
466KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params)
467{
468 Name keyName;
469 SignatureInfo sigInfo;
470 std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
471
472 return sign(buffer, bufferLength, keyName, params.getDigestAlgorithm());
473}
474
475// public: PIB/TPM creation helpers
476
477static inline std::tuple<std::string/*type*/, std::string/*location*/>
478parseLocatorUri(const std::string& uri)
479{
480 size_t pos = uri.find(':');
481 if (pos != std::string::npos) {
482 return std::make_tuple(uri.substr(0, pos), uri.substr(pos + 1));
483 }
484 else {
485 return std::make_tuple(uri, "");
486 }
487}
488
489std::tuple<std::string/*type*/, std::string/*location*/>
490KeyChain::parseAndCheckPibLocator(const std::string& pibLocator)
491{
492 std::string pibScheme, pibLocation;
493 std::tie(pibScheme, pibLocation) = parseLocatorUri(pibLocator);
494
495 if (pibScheme.empty()) {
496 pibScheme = getDefaultPibScheme();
497 }
498
499 auto pibFactory = getPibFactories().find(pibScheme);
500 if (pibFactory == getPibFactories().end()) {
501 BOOST_THROW_EXCEPTION(KeyChain::Error("PIB scheme `" + pibScheme + "` is not supported"));
502 }
503
504 return std::make_tuple(pibScheme, pibLocation);
505}
506
507unique_ptr<Pib>
508KeyChain::createPib(const std::string& pibLocator)
509{
510 std::string pibScheme, pibLocation;
511 std::tie(pibScheme, pibLocation) = parseAndCheckPibLocator(pibLocator);
512 auto pibFactory = getPibFactories().find(pibScheme);
513 BOOST_ASSERT(pibFactory != getPibFactories().end());
514 return unique_ptr<Pib>(new Pib(pibScheme, pibLocation, pibFactory->second(pibLocation)));
515}
516
517std::tuple<std::string/*type*/, std::string/*location*/>
518KeyChain::parseAndCheckTpmLocator(const std::string& tpmLocator)
519{
520 std::string tpmScheme, tpmLocation;
521 std::tie(tpmScheme, tpmLocation) = parseLocatorUri(tpmLocator);
522
523 if (tpmScheme.empty()) {
524 tpmScheme = getDefaultTpmScheme();
525 }
526 auto tpmFactory = getTpmFactories().find(tpmScheme);
527 if (tpmFactory == getTpmFactories().end()) {
528 BOOST_THROW_EXCEPTION(KeyChain::Error("TPM scheme `" + tpmScheme + "` is not supported"));
529 }
530
531 return std::make_tuple(tpmScheme, tpmLocation);
532}
533
534unique_ptr<Tpm>
535KeyChain::createTpm(const std::string& tpmLocator)
536{
537 std::string tpmScheme, tpmLocation;
538 std::tie(tpmScheme, tpmLocation) = parseAndCheckTpmLocator(tpmLocator);
539 auto tpmFactory = getTpmFactories().find(tpmScheme);
540 BOOST_ASSERT(tpmFactory != getTpmFactories().end());
541 return unique_ptr<Tpm>(new Tpm(tpmScheme, tpmLocation, tpmFactory->second(tpmLocation)));
542}
543
544// private: signing
545
546Certificate
547KeyChain::selfSign(Key& key)
548{
549 Certificate certificate;
550
551 // set name
552 Name certificateName = key.getName();
553 certificateName
554 .append("self")
555 .appendVersion();
556 certificate.setName(certificateName);
557
558 // set metainfo
559 certificate.setContentType(tlv::ContentType_Key);
Davide Pesavento0f830802018-01-16 23:58:58 -0500560 certificate.setFreshnessPeriod(1_h);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700561
562 // set content
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400563 certificate.setContent(key.getPublicKey().data(), key.getPublicKey().size());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700564
565 // set signature-info
Alexander Afanasyev83eb1cc2017-01-04 17:34:34 -0800566 SignatureInfo signatureInfo;
Alexander Afanasyevf8379172017-01-11 16:56:04 -0800567 // Note time::system_clock::max() or other NotAfter date results in incorrect encoded value
568 // because of overflow during conversion to boost::posix_time::ptime (bug #3915).
569 signatureInfo.setValidityPeriod(ValidityPeriod(time::system_clock::TimePoint(),
Davide Pesavento0f830802018-01-16 23:58:58 -0500570 time::system_clock::now() + 20 * 365_days));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700571
Alexander Afanasyev83eb1cc2017-01-04 17:34:34 -0800572 sign(certificate, SigningInfo(key).setSignatureInfo(signatureInfo));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700573
574 key.addCertificate(certificate);
575 return certificate;
576}
577
578std::tuple<Name, SignatureInfo>
579KeyChain::prepareSignatureInfo(const SigningInfo& params)
580{
581 SignatureInfo sigInfo = params.getSignatureInfo();
582
583 Name identityName;
584 name::Component keyId;
585 Name certificateName;
586
587 pib::Identity identity;
588 pib::Key key;
589
590 switch (params.getSignerType()) {
591 case SigningInfo::SIGNER_TYPE_NULL: {
592 try {
593 identity = m_pib->getDefaultIdentity();
594 }
595 catch (const Pib::Error&) { // no default identity, use sha256 for signing.
596 sigInfo.setSignatureType(tlv::DigestSha256);
597 return std::make_tuple(SigningInfo::getDigestSha256Identity(), sigInfo);
598 }
599 break;
600 }
601 case SigningInfo::SIGNER_TYPE_ID: {
Junxiao Shife1239a2017-01-27 20:36:12 +0000602 identity = params.getPibIdentity();
603 if (!identity) {
604 try {
605 identity = m_pib->getIdentity(params.getSignerName());
606 }
607 catch (const Pib::Error&) {
608 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Signing identity `" +
609 params.getSignerName().toUri() + "` does not exist"));
610 }
Yingdi Yufe4733a2015-10-22 14:24:12 -0700611 }
612 break;
613 }
614 case SigningInfo::SIGNER_TYPE_KEY: {
Junxiao Shife1239a2017-01-27 20:36:12 +0000615 key = params.getPibKey();
616 if (!key) {
617 Name identityName = extractIdentityFromKeyName(params.getSignerName());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700618
Junxiao Shife1239a2017-01-27 20:36:12 +0000619 try {
620 identity = m_pib->getIdentity(identityName);
621 key = identity.getKey(params.getSignerName());
622 identity = Identity(); // we will use the PIB key instance, so reset identity;
623 }
624 catch (const Pib::Error&) {
625 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Signing key `" +
626 params.getSignerName().toUri() + "` does not exist"));
627 }
Yingdi Yufe4733a2015-10-22 14:24:12 -0700628 }
629 break;
630 }
631 case SigningInfo::SIGNER_TYPE_CERT: {
632 Name identityName = extractIdentityFromCertName(params.getSignerName());
633 Name keyName = extractKeyNameFromCertName(params.getSignerName());
634
635 try {
636 identity = m_pib->getIdentity(identityName);
637 key = identity.getKey(keyName);
638 }
639 catch (const Pib::Error&) {
640 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Signing certificate `" +
641 params.getSignerName().toUri() + "` does not exist"));
642 }
643
644 break;
645 }
646 case SigningInfo::SIGNER_TYPE_SHA256: {
647 sigInfo.setSignatureType(tlv::DigestSha256);
648 return std::make_tuple(SigningInfo::getDigestSha256Identity(), sigInfo);
649 }
Yingdi Yufe4733a2015-10-22 14:24:12 -0700650 default: {
651 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Unrecognized signer type " +
652 boost::lexical_cast<std::string>(params.getSignerType())));
653 }
654 }
655
656 if (!identity && !key) {
657 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Cannot determine signing parameters"));
658 }
659
660 if (identity && !key) {
661 try {
662 key = identity.getDefaultKey();
663 }
664 catch (const Pib::Error&) {
665 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Signing identity `" + identity.getName().toUri() +
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500666 "` does not have a default certificate"));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700667 }
668 }
669
670 BOOST_ASSERT(key);
671
672 sigInfo.setSignatureType(getSignatureType(key.getKeyType(), params.getDigestAlgorithm()));
673 sigInfo.setKeyLocator(KeyLocator(key.getName()));
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800674
675 NDN_LOG_TRACE("Prepared signature info: " << sigInfo);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700676 return std::make_tuple(key.getName(), sigInfo);
677}
678
679Block
680KeyChain::sign(const uint8_t* buf, size_t size,
681 const Name& keyName, DigestAlgorithm digestAlgorithm) const
682{
683 if (keyName == SigningInfo::getDigestSha256Identity())
Davide Pesavento10b24be2017-07-12 23:23:46 -0400684 return Block(tlv::SignatureValue, util::Sha256::computeDigest(buf, size));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700685
686 return Block(tlv::SignatureValue, m_tpm->sign(buf, size, keyName, digestAlgorithm));
687}
688
689tlv::SignatureTypeValue
690KeyChain::getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm)
691{
692 switch (keyType) {
693 case KeyType::RSA:
694 return tlv::SignatureSha256WithRsa;
695 case KeyType::EC:
696 return tlv::SignatureSha256WithEcdsa;
697 default:
698 BOOST_THROW_EXCEPTION(Error("Unsupported key types"));
699 }
700}
701
702} // namespace v2
703} // namespace security
704} // namespace ndn