blob: 9f496a1711e95b24f5fe037c1b51e9f99c6f6bd8 [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/*
Yingdi Yufe4733a2015-10-22 14:24:12 -07003 * Copyright (c) 2013-2017 Regents of the University of California.
4 *
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
119 return s_defaultPibLocator;
120}
121
122const std::string&
123KeyChain::getDefaultTpmLocator()
124{
125 if (!s_defaultTpmLocator.empty())
126 return s_defaultTpmLocator;
127
128 if (getenv("NDN_CLIENT_TPM") != nullptr) {
129 s_defaultTpmLocator = getenv("NDN_CLIENT_TPM");
130 }
131 else {
132 ConfigFile config;
133 s_defaultTpmLocator = config.getParsedConfiguration().get<std::string>("tpm", getDefaultTpmScheme() + ":");
134 }
135
136 return s_defaultTpmLocator;
137}
138
139
140// Other defaults
141
142const SigningInfo&
143KeyChain::getDefaultSigningInfo()
144{
145 static SigningInfo signingInfo;
146 return signingInfo;
147}
148
149const KeyParams&
150KeyChain::getDefaultKeyParams()
151{
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700152 static EcKeyParams keyParams;
Yingdi Yufe4733a2015-10-22 14:24:12 -0700153 return keyParams;
154}
155
156//
157
158KeyChain::KeyChain()
159 : KeyChain(getDefaultPibLocator(), getDefaultTpmLocator(), true)
160{
161}
162
163KeyChain::KeyChain(const std::string& pibLocator, const std::string& tpmLocator, bool allowReset)
164{
165 // PIB Locator
166 std::string pibScheme, pibLocation;
167 std::tie(pibScheme, pibLocation) = parseAndCheckPibLocator(pibLocator);
168 std::string canonicalPibLocator = pibScheme + ":" + pibLocation;
169
170 // Create PIB
171 m_pib = createPib(canonicalPibLocator);
172 std::string oldTpmLocator;
173 try {
174 oldTpmLocator = m_pib->getTpmLocator();
175 }
176 catch (const Pib::Error&) {
177 // TPM locator is not set in PIB yet.
178 }
179
180 // TPM Locator
181 std::string tpmScheme, tpmLocation;
182 std::tie(tpmScheme, tpmLocation) = parseAndCheckTpmLocator(tpmLocator);
183 std::string canonicalTpmLocator = tpmScheme + ":" + tpmLocation;
184
185 if (canonicalPibLocator == getDefaultPibLocator()) {
186 // Default PIB must use default TPM
187 if (!oldTpmLocator.empty() && oldTpmLocator != getDefaultTpmLocator()) {
188 m_pib->reset();
189 canonicalTpmLocator = getDefaultTpmLocator();
190 }
191 }
192 else {
193 // non-default PIB check consistency
194 if (!oldTpmLocator.empty() && oldTpmLocator != canonicalTpmLocator) {
195 if (allowReset)
196 m_pib->reset();
197 else
198 BOOST_THROW_EXCEPTION(LocatorMismatchError("TPM locator supplied does not match TPM locator in PIB: " +
199 oldTpmLocator + " != " + canonicalTpmLocator));
200 }
201 }
202
203 // note that key mismatch may still happen if the TPM locator is initially set to a
204 // wrong one or if the PIB was shared by more than one TPMs before. This is due to the
205 // old PIB does not have TPM info, new pib should not have this problem.
206 m_tpm = createTpm(canonicalTpmLocator);
207 m_pib->setTpmLocator(canonicalTpmLocator);
208}
209
210KeyChain::~KeyChain() = default;
211
212// public: management
213
214Identity
215KeyChain::createIdentity(const Name& identityName, const KeyParams& params)
216{
217 Identity id = m_pib->addIdentity(identityName);
218
219 Key key;
220 try {
221 key = id.getDefaultKey();
222 }
223 catch (const Pib::Error&) {
224 key = createKey(id, params);
225 }
226
227 try {
228 key.getDefaultCertificate();
229 }
230 catch (const Pib::Error&) {
Alexander Afanasyev83eb1cc2017-01-04 17:34:34 -0800231 NDN_LOG_DEBUG("No default cert for " << key.getName() << ", requesting self-signing");
Yingdi Yufe4733a2015-10-22 14:24:12 -0700232 selfSign(key);
233 }
234
235 return id;
236}
237
238void
239KeyChain::deleteIdentity(const Identity& identity)
240{
241 BOOST_ASSERT(static_cast<bool>(identity));
242
243 Name identityName = identity.getName();
244
245 for (const auto& key : identity.getKeys()) {
246 m_tpm->deleteKey(key.getName());
247 }
248
249 m_pib->removeIdentity(identityName);
250}
251
252void
253KeyChain::setDefaultIdentity(const Identity& identity)
254{
255 BOOST_ASSERT(static_cast<bool>(identity));
256
257 m_pib->setDefaultIdentity(identity.getName());
258}
259
260Key
261KeyChain::createKey(const Identity& identity, const KeyParams& params)
262{
263 BOOST_ASSERT(static_cast<bool>(identity));
264
265 // create key in TPM
266 Name keyName = m_tpm->createKey(identity.getName(), params);
267
268 // set up key info in PIB
269 ConstBufferPtr pubKey = m_tpm->getPublicKey(keyName);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400270 Key key = identity.addKey(pubKey->data(), pubKey->size(), keyName);
Alexander Afanasyev83eb1cc2017-01-04 17:34:34 -0800271
272 NDN_LOG_DEBUG("Requesting self-signing for newly created key " << key.getName());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700273 selfSign(key);
274
275 return key;
276}
277
278void
279KeyChain::deleteKey(const Identity& identity, const Key& key)
280{
281 BOOST_ASSERT(static_cast<bool>(identity));
282 BOOST_ASSERT(static_cast<bool>(key));
283
284 Name keyName = key.getName();
285 if (identity.getName() != key.getIdentity()) {
286 BOOST_THROW_EXCEPTION(std::invalid_argument("Identity `" + identity.getName().toUri() + "` "
Muktadir Chowdhurycab16962017-06-12 12:19:43 -0500287 "does not match key `" + keyName.toUri() + "`"));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700288 }
289
290 identity.removeKey(keyName);
291 m_tpm->deleteKey(keyName);
292}
293
294void
295KeyChain::setDefaultKey(const Identity& identity, const Key& key)
296{
297 BOOST_ASSERT(static_cast<bool>(identity));
298 BOOST_ASSERT(static_cast<bool>(key));
299
300 if (identity.getName() != key.getIdentity())
301 BOOST_THROW_EXCEPTION(std::invalid_argument("Identity `" + identity.getName().toUri() + "` "
Muktadir Chowdhurycab16962017-06-12 12:19:43 -0500302 "does not match key `" + key.getName().toUri() + "`"));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700303
304 identity.setDefaultKey(key.getName());
305}
306
307void
308KeyChain::addCertificate(const Key& key, const Certificate& certificate)
309{
310 BOOST_ASSERT(static_cast<bool>(key));
311
312 if (key.getName() != certificate.getKeyName() ||
313 !std::equal(certificate.getContent().value_begin(), certificate.getContent().value_end(),
314 key.getPublicKey().begin()))
315 BOOST_THROW_EXCEPTION(std::invalid_argument("Key `" + key.getName().toUri() + "` "
Muktadir Chowdhurycab16962017-06-12 12:19:43 -0500316 "does not match certificate `" + certificate.getName().toUri() + "`"));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700317
318 key.addCertificate(certificate);
319}
320
321void
322KeyChain::deleteCertificate(const Key& key, const Name& certificateName)
323{
324 BOOST_ASSERT(static_cast<bool>(key));
325
326 if (!Certificate::isValidName(certificateName)) {
327 BOOST_THROW_EXCEPTION(std::invalid_argument("Wrong certificate name `" + certificateName.toUri() + "`"));
328 }
329
330 key.removeCertificate(certificateName);
331}
332
333void
334KeyChain::setDefaultCertificate(const Key& key, const Certificate& cert)
335{
336 BOOST_ASSERT(static_cast<bool>(key));
337
Davide Pesavento3ce6d4e2017-10-05 01:48:24 -0400338 addCertificate(key, cert);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700339 key.setDefaultCertificate(cert.getName());
340}
341
342shared_ptr<SafeBag>
343KeyChain::exportSafeBag(const Certificate& certificate, const char* pw, size_t pwLen)
344{
345 Name identity = certificate.getIdentity();
346 Name keyName = certificate.getKeyName();
347
348 ConstBufferPtr encryptedKey;
349 try {
350 encryptedKey = m_tpm->exportPrivateKey(keyName, pw, pwLen);
351 }
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500352 catch (const tpm::BackEnd::Error& e) {
353 BOOST_THROW_EXCEPTION(Error("Failed to export private key `" + keyName.toUri() + "`: " + e.what()));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700354 }
355
356 return make_shared<SafeBag>(certificate, *encryptedKey);
357}
358
359void
360KeyChain::importSafeBag(const SafeBag& safeBag, const char* pw, size_t pwLen)
361{
362 Data certData = safeBag.getCertificate();
363 Certificate cert(std::move(certData));
364 Name identity = cert.getIdentity();
365 Name keyName = cert.getKeyName();
366 const Buffer publicKeyBits = cert.getPublicKey();
367
368 if (m_tpm->hasKey(keyName)) {
369 BOOST_THROW_EXCEPTION(Error("Private key `" + keyName.toUri() + "` already exists"));
370 }
371
372 try {
373 Identity existingId = m_pib->getIdentity(identity);
374 existingId.getKey(keyName);
375 BOOST_THROW_EXCEPTION(Error("Public key `" + keyName.toUri() + "` already exists"));
376 }
377 catch (const Pib::Error&) {
378 // Either identity or key doesn't exist. OK to import.
379 }
380
381 try {
382 m_tpm->importPrivateKey(keyName,
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400383 safeBag.getEncryptedKeyBag().data(), safeBag.getEncryptedKeyBag().size(),
Yingdi Yufe4733a2015-10-22 14:24:12 -0700384 pw, pwLen);
385 }
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500386 catch (const tpm::BackEnd::Error& e) {
387 BOOST_THROW_EXCEPTION(Error("Failed to import private key `" + keyName.toUri() + "`: " + e.what()));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700388 }
389
390 // check the consistency of private key and certificate
391 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
392 ConstBufferPtr sigBits;
393 try {
394 sigBits = m_tpm->sign(content, 4, keyName, DigestAlgorithm::SHA256);
395 }
396 catch (const std::runtime_error&) {
397 m_tpm->deleteKey(keyName);
398 BOOST_THROW_EXCEPTION(Error("Invalid private key `" + keyName.toUri() + "`"));
399 }
400 bool isVerified = false;
401 {
402 using namespace transform;
403 PublicKey publicKey;
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400404 publicKey.loadPkcs8(publicKeyBits.data(), publicKeyBits.size());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700405 bufferSource(content, sizeof(content)) >> verifierFilter(DigestAlgorithm::SHA256, publicKey,
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400406 sigBits->data(), sigBits->size())
Yingdi Yufe4733a2015-10-22 14:24:12 -0700407 >> boolSink(isVerified);
408 }
409 if (!isVerified) {
410 m_tpm->deleteKey(keyName);
411 BOOST_THROW_EXCEPTION(Error("Certificate `" + cert.getName().toUri() + "` "
412 "and private key `" + keyName.toUri() + "` do not match"));
413 }
414
415 Identity id = m_pib->addIdentity(identity);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400416 Key key = id.addKey(cert.getPublicKey().data(), cert.getPublicKey().size(), keyName);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700417 key.addCertificate(cert);
418}
419
Yingdi Yufe4733a2015-10-22 14:24:12 -0700420// public: signing
421
422void
423KeyChain::sign(Data& data, const SigningInfo& params)
424{
425 Name keyName;
426 SignatureInfo sigInfo;
427 std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
428
429 data.setSignature(Signature(sigInfo));
430
431 EncodingBuffer encoder;
432 data.wireEncode(encoder, true);
433
434 Block sigValue = sign(encoder.buf(), encoder.size(), keyName, params.getDigestAlgorithm());
435
436 data.wireEncode(encoder, sigValue);
437}
438
439void
440KeyChain::sign(Interest& interest, const SigningInfo& params)
441{
442 Name keyName;
443 SignatureInfo sigInfo;
444 std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
445
446 Name signedName = interest.getName();
447 signedName.append(sigInfo.wireEncode()); // signatureInfo
448
449 Block sigValue = sign(signedName.wireEncode().value(), signedName.wireEncode().value_size(),
450 keyName, params.getDigestAlgorithm());
451
452 sigValue.encode();
453 signedName.append(sigValue); // signatureValue
454 interest.setName(signedName);
455}
456
457Block
458KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params)
459{
460 Name keyName;
461 SignatureInfo sigInfo;
462 std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
463
464 return sign(buffer, bufferLength, keyName, params.getDigestAlgorithm());
465}
466
467// public: PIB/TPM creation helpers
468
469static inline std::tuple<std::string/*type*/, std::string/*location*/>
470parseLocatorUri(const std::string& uri)
471{
472 size_t pos = uri.find(':');
473 if (pos != std::string::npos) {
474 return std::make_tuple(uri.substr(0, pos), uri.substr(pos + 1));
475 }
476 else {
477 return std::make_tuple(uri, "");
478 }
479}
480
481std::tuple<std::string/*type*/, std::string/*location*/>
482KeyChain::parseAndCheckPibLocator(const std::string& pibLocator)
483{
484 std::string pibScheme, pibLocation;
485 std::tie(pibScheme, pibLocation) = parseLocatorUri(pibLocator);
486
487 if (pibScheme.empty()) {
488 pibScheme = getDefaultPibScheme();
489 }
490
491 auto pibFactory = getPibFactories().find(pibScheme);
492 if (pibFactory == getPibFactories().end()) {
493 BOOST_THROW_EXCEPTION(KeyChain::Error("PIB scheme `" + pibScheme + "` is not supported"));
494 }
495
496 return std::make_tuple(pibScheme, pibLocation);
497}
498
499unique_ptr<Pib>
500KeyChain::createPib(const std::string& pibLocator)
501{
502 std::string pibScheme, pibLocation;
503 std::tie(pibScheme, pibLocation) = parseAndCheckPibLocator(pibLocator);
504 auto pibFactory = getPibFactories().find(pibScheme);
505 BOOST_ASSERT(pibFactory != getPibFactories().end());
506 return unique_ptr<Pib>(new Pib(pibScheme, pibLocation, pibFactory->second(pibLocation)));
507}
508
509std::tuple<std::string/*type*/, std::string/*location*/>
510KeyChain::parseAndCheckTpmLocator(const std::string& tpmLocator)
511{
512 std::string tpmScheme, tpmLocation;
513 std::tie(tpmScheme, tpmLocation) = parseLocatorUri(tpmLocator);
514
515 if (tpmScheme.empty()) {
516 tpmScheme = getDefaultTpmScheme();
517 }
518 auto tpmFactory = getTpmFactories().find(tpmScheme);
519 if (tpmFactory == getTpmFactories().end()) {
520 BOOST_THROW_EXCEPTION(KeyChain::Error("TPM scheme `" + tpmScheme + "` is not supported"));
521 }
522
523 return std::make_tuple(tpmScheme, tpmLocation);
524}
525
526unique_ptr<Tpm>
527KeyChain::createTpm(const std::string& tpmLocator)
528{
529 std::string tpmScheme, tpmLocation;
530 std::tie(tpmScheme, tpmLocation) = parseAndCheckTpmLocator(tpmLocator);
531 auto tpmFactory = getTpmFactories().find(tpmScheme);
532 BOOST_ASSERT(tpmFactory != getTpmFactories().end());
533 return unique_ptr<Tpm>(new Tpm(tpmScheme, tpmLocation, tpmFactory->second(tpmLocation)));
534}
535
536// private: signing
537
538Certificate
539KeyChain::selfSign(Key& key)
540{
541 Certificate certificate;
542
543 // set name
544 Name certificateName = key.getName();
545 certificateName
546 .append("self")
547 .appendVersion();
548 certificate.setName(certificateName);
549
550 // set metainfo
551 certificate.setContentType(tlv::ContentType_Key);
552 certificate.setFreshnessPeriod(time::hours(1));
553
554 // set content
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400555 certificate.setContent(key.getPublicKey().data(), key.getPublicKey().size());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700556
557 // set signature-info
Alexander Afanasyev83eb1cc2017-01-04 17:34:34 -0800558 SignatureInfo signatureInfo;
Alexander Afanasyevf8379172017-01-11 16:56:04 -0800559 // Note time::system_clock::max() or other NotAfter date results in incorrect encoded value
560 // because of overflow during conversion to boost::posix_time::ptime (bug #3915).
561 signatureInfo.setValidityPeriod(ValidityPeriod(time::system_clock::TimePoint(),
562 time::system_clock::now() + time::days(20 * 365)));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700563
Alexander Afanasyev83eb1cc2017-01-04 17:34:34 -0800564 sign(certificate, SigningInfo(key).setSignatureInfo(signatureInfo));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700565
566 key.addCertificate(certificate);
567 return certificate;
568}
569
570std::tuple<Name, SignatureInfo>
571KeyChain::prepareSignatureInfo(const SigningInfo& params)
572{
573 SignatureInfo sigInfo = params.getSignatureInfo();
574
575 Name identityName;
576 name::Component keyId;
577 Name certificateName;
578
579 pib::Identity identity;
580 pib::Key key;
581
582 switch (params.getSignerType()) {
583 case SigningInfo::SIGNER_TYPE_NULL: {
584 try {
585 identity = m_pib->getDefaultIdentity();
586 }
587 catch (const Pib::Error&) { // no default identity, use sha256 for signing.
588 sigInfo.setSignatureType(tlv::DigestSha256);
589 return std::make_tuple(SigningInfo::getDigestSha256Identity(), sigInfo);
590 }
591 break;
592 }
593 case SigningInfo::SIGNER_TYPE_ID: {
Junxiao Shife1239a2017-01-27 20:36:12 +0000594 identity = params.getPibIdentity();
595 if (!identity) {
596 try {
597 identity = m_pib->getIdentity(params.getSignerName());
598 }
599 catch (const Pib::Error&) {
600 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Signing identity `" +
601 params.getSignerName().toUri() + "` does not exist"));
602 }
Yingdi Yufe4733a2015-10-22 14:24:12 -0700603 }
604 break;
605 }
606 case SigningInfo::SIGNER_TYPE_KEY: {
Junxiao Shife1239a2017-01-27 20:36:12 +0000607 key = params.getPibKey();
608 if (!key) {
609 Name identityName = extractIdentityFromKeyName(params.getSignerName());
Yingdi Yufe4733a2015-10-22 14:24:12 -0700610
Junxiao Shife1239a2017-01-27 20:36:12 +0000611 try {
612 identity = m_pib->getIdentity(identityName);
613 key = identity.getKey(params.getSignerName());
614 identity = Identity(); // we will use the PIB key instance, so reset identity;
615 }
616 catch (const Pib::Error&) {
617 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Signing key `" +
618 params.getSignerName().toUri() + "` does not exist"));
619 }
Yingdi Yufe4733a2015-10-22 14:24:12 -0700620 }
621 break;
622 }
623 case SigningInfo::SIGNER_TYPE_CERT: {
624 Name identityName = extractIdentityFromCertName(params.getSignerName());
625 Name keyName = extractKeyNameFromCertName(params.getSignerName());
626
627 try {
628 identity = m_pib->getIdentity(identityName);
629 key = identity.getKey(keyName);
630 }
631 catch (const Pib::Error&) {
632 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Signing certificate `" +
633 params.getSignerName().toUri() + "` does not exist"));
634 }
635
636 break;
637 }
638 case SigningInfo::SIGNER_TYPE_SHA256: {
639 sigInfo.setSignatureType(tlv::DigestSha256);
640 return std::make_tuple(SigningInfo::getDigestSha256Identity(), sigInfo);
641 }
Yingdi Yufe4733a2015-10-22 14:24:12 -0700642 default: {
643 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Unrecognized signer type " +
644 boost::lexical_cast<std::string>(params.getSignerType())));
645 }
646 }
647
648 if (!identity && !key) {
649 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Cannot determine signing parameters"));
650 }
651
652 if (identity && !key) {
653 try {
654 key = identity.getDefaultKey();
655 }
656 catch (const Pib::Error&) {
657 BOOST_THROW_EXCEPTION(InvalidSigningInfoError("Signing identity `" + identity.getName().toUri() +
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500658 "` does not have a default certificate"));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700659 }
660 }
661
662 BOOST_ASSERT(key);
663
664 sigInfo.setSignatureType(getSignatureType(key.getKeyType(), params.getDigestAlgorithm()));
665 sigInfo.setKeyLocator(KeyLocator(key.getName()));
Alexander Afanasyev7e721412017-01-11 13:36:08 -0800666
667 NDN_LOG_TRACE("Prepared signature info: " << sigInfo);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700668 return std::make_tuple(key.getName(), sigInfo);
669}
670
671Block
672KeyChain::sign(const uint8_t* buf, size_t size,
673 const Name& keyName, DigestAlgorithm digestAlgorithm) const
674{
675 if (keyName == SigningInfo::getDigestSha256Identity())
Davide Pesavento10b24be2017-07-12 23:23:46 -0400676 return Block(tlv::SignatureValue, util::Sha256::computeDigest(buf, size));
Yingdi Yufe4733a2015-10-22 14:24:12 -0700677
678 return Block(tlv::SignatureValue, m_tpm->sign(buf, size, keyName, digestAlgorithm));
679}
680
681tlv::SignatureTypeValue
682KeyChain::getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm)
683{
684 switch (keyType) {
685 case KeyType::RSA:
686 return tlv::SignatureSha256WithRsa;
687 case KeyType::EC:
688 return tlv::SignatureSha256WithEcdsa;
689 default:
690 BOOST_THROW_EXCEPTION(Error("Unsupported key types"));
691 }
692}
693
694} // namespace v2
695} // namespace security
696} // namespace ndn