blob: 16bc879fa2e3b74bce2d61435cce7dd23b28508e [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yingdi Yuf56c68f2014-04-24 21:50:13 -07002/**
Alexander Afanasyev34a37632015-01-16 17:37:36 -08003 * Copyright (c) 2013-2015 Regents of the University of California.
Yingdi Yuf56c68f2014-04-24 21:50:13 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Yingdi Yuf56c68f2014-04-24 21:50:13 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * 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.
Yingdi Yuf56c68f2014-04-24 21:50:13 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
22 */
23
24#include "key-chain.hpp"
25
Alexander Afanasyev07113802015-01-15 19:14:36 -080026#include "../util/random.hpp"
27#include "../util/config-file.hpp"
28
Yingdi Yuf56c68f2014-04-24 21:50:13 -070029#include "sec-public-info-sqlite3.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070030
31#ifdef NDN_CXX_HAVE_OSX_SECURITY
32#include "sec-tpm-osx.hpp"
Alexander Afanasyev07113802015-01-15 19:14:36 -080033#endif // NDN_CXX_HAVE_OSX_SECURITY
Yingdi Yuf56c68f2014-04-24 21:50:13 -070034
Alexander Afanasyev07113802015-01-15 19:14:36 -080035#include "sec-tpm-file.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070036
37namespace ndn {
Yingdi Yu1b0311c2015-06-10 14:58:47 -070038namespace security {
Yingdi Yuf56c68f2014-04-24 21:50:13 -070039
Yingdi Yu0eb5d722014-06-10 15:06:25 -070040// Use a GUID as a magic number of KeyChain::DEFAULT_PREFIX identifier
41const Name KeyChain::DEFAULT_PREFIX("/723821fd-f534-44b3-80d9-44bf5f58bbbb");
Yingdi Yu1b0311c2015-06-10 14:58:47 -070042const Name KeyChain::DIGEST_SHA256_IDENTITY("/localhost/identity/digest-sha256");
43
44// Note: cannot use default constructor, as it depends on static variables which may or may not be
45// initialized at this point
46const SigningInfo KeyChain::DEFAULT_SIGNING_INFO(SigningInfo::SIGNER_TYPE_NULL, Name(), SignatureInfo());
Yingdi Yu0eb5d722014-06-10 15:06:25 -070047
Yingdi Yu7036ce22014-06-19 18:53:37 -070048const RsaKeyParams KeyChain::DEFAULT_KEY_PARAMS;
49
Alexander Afanasyev07113802015-01-15 19:14:36 -080050const std::string DEFAULT_PIB_SCHEME = "pib-sqlite3";
51
52#if defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
53const std::string DEFAULT_TPM_SCHEME = "tpm-osxkeychain";
54#else
55const std::string DEFAULT_TPM_SCHEME = "tpm-file";
56#endif // defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
57
58// When static library is used, not everything is compiled into the resulting binary.
59// Therefore, the following standard PIB and TPMs need to be registered here.
60// http://stackoverflow.com/q/9459980/2150331
61//
62// Also, cannot use Type::SCHEME, as its value may be uninitialized
63NDN_CXX_KEYCHAIN_REGISTER_PIB(SecPublicInfoSqlite3, "pib-sqlite3", "sqlite3");
64
65#ifdef NDN_CXX_HAVE_OSX_SECURITY
66NDN_CXX_KEYCHAIN_REGISTER_TPM(SecTpmOsx, "tpm-osxkeychain", "osx-keychain");
67#endif // NDN_CXX_HAVE_OSX_SECURITY
68
69NDN_CXX_KEYCHAIN_REGISTER_TPM(SecTpmFile, "tpm-file", "file");
70
Alexander Afanasyev34a37632015-01-16 17:37:36 -080071template<class T>
72struct Factory
73{
74 Factory(const std::string& canonicalName, const T& create)
75 : canonicalName(canonicalName)
76 , create(create)
77 {
78 }
79
80 std::string canonicalName;
81 T create;
82};
83typedef Factory<KeyChain::PibCreateFunc> PibFactory;
84typedef Factory<KeyChain::TpmCreateFunc> TpmFactory;
85
86static std::map<std::string, PibFactory>&
Alexander Afanasyev07113802015-01-15 19:14:36 -080087getPibFactories()
88{
Alexander Afanasyev34a37632015-01-16 17:37:36 -080089 static std::map<std::string, PibFactory> pibFactories;
Alexander Afanasyev07113802015-01-15 19:14:36 -080090 return pibFactories;
91}
92
Alexander Afanasyev34a37632015-01-16 17:37:36 -080093static std::map<std::string, TpmFactory>&
Alexander Afanasyev07113802015-01-15 19:14:36 -080094getTpmFactories()
95{
Alexander Afanasyev34a37632015-01-16 17:37:36 -080096 static std::map<std::string, TpmFactory> tpmFactories;
Alexander Afanasyev07113802015-01-15 19:14:36 -080097 return tpmFactories;
98}
99
100void
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800101KeyChain::registerPibImpl(const std::string& canonicalName,
102 std::initializer_list<std::string> aliases,
Alexander Afanasyev07113802015-01-15 19:14:36 -0800103 KeyChain::PibCreateFunc createFunc)
104{
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800105 for (const std::string& alias : aliases) {
106 getPibFactories().insert(make_pair(alias, PibFactory(canonicalName, createFunc)));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800107 }
108}
109
110void
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800111KeyChain::registerTpmImpl(const std::string& canonicalName,
112 std::initializer_list<std::string> aliases,
Alexander Afanasyev07113802015-01-15 19:14:36 -0800113 KeyChain::TpmCreateFunc createFunc)
114{
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800115 for (const std::string& alias : aliases) {
116 getTpmFactories().insert(make_pair(alias, TpmFactory(canonicalName, createFunc)));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800117 }
118}
119
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700120KeyChain::KeyChain()
Yingdi Yu41546342014-11-30 23:37:53 -0800121 : m_pib(nullptr)
122 , m_tpm(nullptr)
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700123 , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700124{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800125 ConfigFile config;
126 const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700127
Alexander Afanasyev07113802015-01-15 19:14:36 -0800128 std::string pibLocator = parsed.get<std::string>("pib", "");
129 std::string tpmLocator = parsed.get<std::string>("tpm", "");
130
131 initialize(pibLocator, tpmLocator, false);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700132}
133
134KeyChain::KeyChain(const std::string& pibName,
Yingdi Yu41546342014-11-30 23:37:53 -0800135 const std::string& tpmName,
136 bool allowReset)
137 : m_pib(nullptr)
138 , m_tpm(nullptr)
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700139 , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700140{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800141 initialize(pibName, tpmName, allowReset);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700142}
143
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700144KeyChain::~KeyChain()
145{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800146}
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700147
Alexander Afanasyev07113802015-01-15 19:14:36 -0800148static inline std::tuple<std::string/*type*/, std::string/*location*/>
149parseUri(const std::string& uri)
150{
151 size_t pos = uri.find(':');
152 if (pos != std::string::npos) {
153 return std::make_tuple(uri.substr(0, pos),
154 uri.substr(pos + 1));
155 }
156 else {
157 return std::make_tuple(uri, "");
158 }
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700159}
160
Yingdi Yu281689a2015-06-13 14:32:32 -0700161std::string
162KeyChain::getDefaultPibLocator()
Yingdi Yu41546342014-11-30 23:37:53 -0800163{
Yingdi Yu281689a2015-06-13 14:32:32 -0700164 std::string defaultPibLocator = DEFAULT_PIB_SCHEME + ":";
165 return defaultPibLocator;
166}
Yingdi Yu41546342014-11-30 23:37:53 -0800167
Yingdi Yu281689a2015-06-13 14:32:32 -0700168static inline std::tuple<std::string/*type*/, std::string/*location*/>
169getCanonicalPibLocator(const std::string& pibLocator)
170{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800171 std::string pibScheme, pibLocation;
Yingdi Yu281689a2015-06-13 14:32:32 -0700172 std::tie(pibScheme, pibLocation) = parseUri(pibLocator);
Alexander Afanasyev07113802015-01-15 19:14:36 -0800173
Alexander Afanasyev07113802015-01-15 19:14:36 -0800174 if (pibScheme.empty()) {
175 pibScheme = DEFAULT_PIB_SCHEME;
176 }
Yingdi Yu281689a2015-06-13 14:32:32 -0700177
Alexander Afanasyev07113802015-01-15 19:14:36 -0800178 auto pibFactory = getPibFactories().find(pibScheme);
179 if (pibFactory == getPibFactories().end()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700180 BOOST_THROW_EXCEPTION(KeyChain::Error("PIB scheme '" + pibScheme + "' is not supported"));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800181 }
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800182 pibScheme = pibFactory->second.canonicalName;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800183
Yingdi Yu281689a2015-06-13 14:32:32 -0700184 return std::make_tuple(pibScheme, pibLocation);
185}
186
187unique_ptr<SecPublicInfo>
188KeyChain::createPib(const std::string& pibLocator)
189{
190 BOOST_ASSERT(!getPibFactories().empty());
191
192 std::string pibScheme, pibLocation;
193 std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator);
194 auto pibFactory = getPibFactories().find(pibScheme);
195 BOOST_ASSERT(pibFactory != getPibFactories().end());
196 return pibFactory->second.create(pibLocation);
197}
198
199std::string
200KeyChain::getDefaultTpmLocator()
201{
202 std::string defaultTpmLocator = DEFAULT_TPM_SCHEME + ":";
203 return defaultTpmLocator;
204}
205
206static inline std::tuple<std::string/*type*/, std::string/*location*/>
207getCanonicalTpmLocator(const std::string& tpmLocator)
208{
209 std::string tpmScheme, tpmLocation;
210 std::tie(tpmScheme, tpmLocation) = parseUri(tpmLocator);
211
Alexander Afanasyev07113802015-01-15 19:14:36 -0800212 if (tpmScheme.empty()) {
213 tpmScheme = DEFAULT_TPM_SCHEME;
214 }
215 auto tpmFactory = getTpmFactories().find(tpmScheme);
216 if (tpmFactory == getTpmFactories().end()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700217 BOOST_THROW_EXCEPTION(KeyChain::Error("TPM scheme '" + tpmScheme + "' is not supported"));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800218 }
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800219 tpmScheme = tpmFactory->second.canonicalName;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800220
Yingdi Yu281689a2015-06-13 14:32:32 -0700221 return std::make_tuple(tpmScheme, tpmLocation);
222}
Alexander Afanasyev07113802015-01-15 19:14:36 -0800223
Yingdi Yu281689a2015-06-13 14:32:32 -0700224unique_ptr<SecTpm>
225KeyChain::createTpm(const std::string& tpmLocator)
226{
227 BOOST_ASSERT(!getTpmFactories().empty());
228
229 std::string tpmScheme, tpmLocation;
230 std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator);
231 auto tpmFactory = getTpmFactories().find(tpmScheme);
232 BOOST_ASSERT(tpmFactory != getTpmFactories().end());
233 return tpmFactory->second.create(tpmLocation);
234}
235
236void
237KeyChain::initialize(const std::string& pibLocator,
238 const std::string& tpmLocator,
239 bool allowReset)
240{
241 // PIB Locator
242 std::string pibScheme, pibLocation;
243 std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator);
244 std::string canonicalPibLocator = pibScheme + ":" + pibLocation;
245
246 // Create PIB
247 m_pib = createPib(canonicalPibLocator);
248
249 // TPM Locator
250 std::string tpmScheme, tpmLocation;
251 std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator);
252 std::string canonicalTpmLocator = tpmScheme + ":" + tpmLocation;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800253
254 // Create TPM, checking that it matches to the previously associated one
Yingdi Yu41546342014-11-30 23:37:53 -0800255 try {
Alexander Afanasyev07113802015-01-15 19:14:36 -0800256 if (!allowReset &&
Yingdi Yu281689a2015-06-13 14:32:32 -0700257 !m_pib->getTpmLocator().empty() && m_pib->getTpmLocator() != canonicalTpmLocator)
Alexander Afanasyev07113802015-01-15 19:14:36 -0800258 // Tpm mismatch, but we do not want to reset PIB
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700259 BOOST_THROW_EXCEPTION(MismatchError("TPM locator supplied does not match TPM locator in PIB: "
260 + m_pib->getTpmLocator() + " != " + canonicalTpmLocator));
Yingdi Yu41546342014-11-30 23:37:53 -0800261 }
262 catch (SecPublicInfo::Error&) {
263 // TPM locator is not set in PIB yet.
264 }
265
Alexander Afanasyev07113802015-01-15 19:14:36 -0800266 // note that key mismatch may still happen if the TPM locator is initially set to a
267 // wrong one or if the PIB was shared by more than one TPMs before. This is due to the
268 // old PIB does not have TPM info, new pib should not have this problem.
Yingdi Yu281689a2015-06-13 14:32:32 -0700269 m_tpm = createTpm(canonicalTpmLocator);
270 m_pib->setTpmLocator(canonicalTpmLocator);
Yingdi Yu41546342014-11-30 23:37:53 -0800271}
272
Yingdi Yu7036ce22014-06-19 18:53:37 -0700273Name
274KeyChain::createIdentity(const Name& identityName, const KeyParams& params)
275{
276 m_pib->addIdentity(identityName);
277
278 Name keyName;
279 try
280 {
281 keyName = m_pib->getDefaultKeyNameForIdentity(identityName);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700282
283 shared_ptr<PublicKey> key = m_pib->getPublicKey(keyName);
284
285 if (key->getKeyType() != params.getKeyType())
286 {
287 keyName = generateKeyPair(identityName, true, params);
288 m_pib->setDefaultKeyNameForIdentity(keyName);
289 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700290 }
291 catch (SecPublicInfo::Error& e)
292 {
293 keyName = generateKeyPair(identityName, true, params);
294 m_pib->setDefaultKeyNameForIdentity(keyName);
295 }
296
297 Name certName;
298 try
299 {
300 certName = m_pib->getDefaultCertificateNameForKey(keyName);
301 }
302 catch (SecPublicInfo::Error& e)
303 {
304 shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
305 m_pib->addCertificateAsIdentityDefault(*selfCert);
306 certName = selfCert->getName();
307 }
308
309 return certName;
310}
311
312Name
Yingdi Yu41546342014-11-30 23:37:53 -0800313KeyChain::generateRsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
314{
315 RsaKeyParams params(keySize);
316 return generateKeyPair(identityName, isKsk, params);
317}
318
319Name
320KeyChain::generateEcdsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
321{
322 EcdsaKeyParams params(keySize);
323 return generateKeyPair(identityName, isKsk, params);
324}
325
326Name
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700327KeyChain::generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
Yingdi Yu7036ce22014-06-19 18:53:37 -0700328{
329 RsaKeyParams params(keySize);
330
331 Name keyName = generateKeyPair(identityName, isKsk, params);
332
333 m_pib->setDefaultKeyNameForIdentity(keyName);
334
335 return keyName;
336}
337
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700338Name
339KeyChain::generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
340{
341 EcdsaKeyParams params(keySize);
342
343 Name keyName = generateKeyPair(identityName, isKsk, params);
344
345 m_pib->setDefaultKeyNameForIdentity(keyName);
346
347 return keyName;
348}
349
350
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700351shared_ptr<IdentityCertificate>
352KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
353 const Name& signingIdentity,
354 const time::system_clock::TimePoint& notBefore,
355 const time::system_clock::TimePoint& notAfter,
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700356 const std::vector<CertificateSubjectDescription>& subjectDescription,
357 const Name& certPrefix)
358{
359 shared_ptr<PublicKey> publicKey;
360 try
361 {
362 publicKey = m_pib->getPublicKey(keyName);
363 }
364 catch (SecPublicInfo::Error& e)
365 {
366 return shared_ptr<IdentityCertificate>();
367 }
368
369 return prepareUnsignedIdentityCertificate(keyName, *publicKey, signingIdentity,
370 notBefore, notAfter,
371 subjectDescription, certPrefix);
372}
373
374shared_ptr<IdentityCertificate>
375KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
376 const PublicKey& publicKey,
377 const Name& signingIdentity,
378 const time::system_clock::TimePoint& notBefore,
379 const time::system_clock::TimePoint& notAfter,
380 const std::vector<CertificateSubjectDescription>& subjectDescription,
381 const Name& certPrefix)
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700382{
383 if (keyName.size() < 1)
384 return shared_ptr<IdentityCertificate>();
385
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700386 std::string keyIdPrefix = keyName.get(-1).toUri().substr(0, 4);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700387 if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
388 return shared_ptr<IdentityCertificate>();
389
390 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
391 Name certName;
392
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700393 if (certPrefix == KeyChain::DEFAULT_PREFIX)
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700394 {
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700395 // No certificate prefix hint, infer the prefix
396 if (signingIdentity.isPrefixOf(keyName))
397 certName.append(signingIdentity)
398 .append("KEY")
399 .append(keyName.getSubName(signingIdentity.size()))
400 .append("ID-CERT")
401 .appendVersion();
402 else
403 certName.append(keyName.getPrefix(-1))
404 .append("KEY")
405 .append(keyName.get(-1))
406 .append("ID-CERT")
407 .appendVersion();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700408 }
409 else
410 {
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700411 // cert prefix hint is supplied, determine the cert name.
412 if (certPrefix.isPrefixOf(keyName) && certPrefix != keyName)
413 certName.append(certPrefix)
414 .append("KEY")
415 .append(keyName.getSubName(certPrefix.size()))
416 .append("ID-CERT")
417 .appendVersion();
418 else
419 return shared_ptr<IdentityCertificate>();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700420 }
421
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700422
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700423 certificate->setName(certName);
424 certificate->setNotBefore(notBefore);
425 certificate->setNotAfter(notAfter);
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700426 certificate->setPublicKeyInfo(publicKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700427
428 if (subjectDescription.empty())
429 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700430 CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri());
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700431 certificate->addSubjectDescription(subjectName);
432 }
433 else
434 {
435 std::vector<CertificateSubjectDescription>::const_iterator sdIt =
436 subjectDescription.begin();
437 std::vector<CertificateSubjectDescription>::const_iterator sdEnd =
438 subjectDescription.end();
439 for(; sdIt != sdEnd; sdIt++)
440 certificate->addSubjectDescription(*sdIt);
441 }
442
443 certificate->encode();
444
445 return certificate;
446}
447
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700448std::tuple<Name, SignatureInfo>
449KeyChain::prepareSignatureInfo(const SigningInfo& params)
450{
451 SignatureInfo sigInfo = params.getSignatureInfo();
452
453 shared_ptr<IdentityCertificate> signingCert;
454
455 switch (params.getSignerType()) {
456 case SigningInfo::SIGNER_TYPE_NULL:
457 {
458 if (m_pib->getDefaultCertificate() == nullptr)
459 setDefaultCertificateInternal();
460
461 signingCert = m_pib->getDefaultCertificate();
462 break;
463 }
464 case SigningInfo::SIGNER_TYPE_ID:
465 {
466 Name signingCertName;
467 try {
468 signingCertName = m_pib->getDefaultCertificateNameForIdentity(params.getSignerName());
469 }
470 catch (SecPublicInfo::Error&) {
471 signingCertName = createIdentity(params.getSignerName());
472 }
473
474 signingCert = m_pib->getCertificate(signingCertName);
475
476 break;
477 }
478 case SigningInfo::SIGNER_TYPE_KEY:
479 {
480 Name signingCertName;
481 try {
482 signingCertName = m_pib->getDefaultCertificateNameForKey(params.getSignerName());
483 }
484 catch (SecPublicInfo::Error&) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700485 BOOST_THROW_EXCEPTION(Error("signing certificate does not exist"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700486 }
487
488 signingCert = m_pib->getCertificate(signingCertName);
489
490 break;
491 }
492 case SigningInfo::SIGNER_TYPE_CERT:
493 {
494 signingCert = m_pib->getCertificate(params.getSignerName());
495 if (signingCert == nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700496 BOOST_THROW_EXCEPTION(Error("signing certificate does not exist"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700497
498 break;
499 }
500 case SigningInfo::SIGNER_TYPE_SHA256:
501 {
502 sigInfo.setSignatureType(tlv::DigestSha256);
503 return std::make_tuple(DIGEST_SHA256_IDENTITY, sigInfo);
504 }
505 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700506 BOOST_THROW_EXCEPTION(Error("Unrecognized signer type"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700507 }
508
509 sigInfo.setSignatureType(getSignatureType(signingCert->getPublicKeyInfo().getKeyType(),
510 params.getDigestAlgorithm()));
511 sigInfo.setKeyLocator(KeyLocator(signingCert->getName().getPrefix(-1)));
512
513 return std::make_tuple(signingCert->getPublicKeyName(), sigInfo);
514}
515
516void
517KeyChain::sign(Data& data, const SigningInfo& params)
518{
519 signImpl(data, params);
520}
521
522void
523KeyChain::sign(Interest& interest, const SigningInfo& params)
524{
525 signImpl(interest, params);
526}
527
528Block
529KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params)
530{
531 Name keyName;
532 SignatureInfo sigInfo;
533 std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
534 return pureSign(buffer, bufferLength, keyName, DIGEST_ALGORITHM_SHA256);
535}
536
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700537Signature
538KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
539{
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700540 shared_ptr<IdentityCertificate> certificate = m_pib->getCertificate(certificateName);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700541
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700542 if (certificate == nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700543 BOOST_THROW_EXCEPTION(SecPublicInfo::Error("certificate does not exist"));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700544
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700545 Signature sig;
Yingdi Yu4a557052014-07-09 16:40:37 -0700546
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700547 // For temporary usage, we support SHA256 only, but will support more.
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700548 sig.setValue(m_tpm->signInTpm(buffer, bufferLength,
549 certificate->getPublicKeyName(),
550 DIGEST_ALGORITHM_SHA256));
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700551
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700552 return sig;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700553}
554
555shared_ptr<IdentityCertificate>
556KeyChain::selfSign(const Name& keyName)
557{
558 shared_ptr<PublicKey> pubKey;
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700559 try {
560 pubKey = m_pib->getPublicKey(keyName); // may throw an exception.
561 }
562 catch (SecPublicInfo::Error&) {
563 return shared_ptr<IdentityCertificate>();
564 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700565
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700566 auto certificate = make_shared<IdentityCertificate>();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700567
568 Name certificateName = keyName.getPrefix(-1);
569 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
570
571 certificate->setName(certificateName);
572 certificate->setNotBefore(time::system_clock::now());
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700573 certificate->setNotAfter(time::system_clock::now() + time::days(7300)); // ~20 years
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700574 certificate->setPublicKeyInfo(*pubKey);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700575 certificate->addSubjectDescription(CertificateSubjectDescription(oid::ATTRIBUTE_NAME,
576 keyName.toUri()));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700577 certificate->encode();
578
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700579 certificate->setSignature(Signature(SignatureInfo()));
580
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700581 selfSign(*certificate);
582 return certificate;
583}
584
585void
586KeyChain::selfSign(IdentityCertificate& cert)
587{
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700588 Name keyName = cert.getPublicKeyName();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700589 if (!m_tpm->doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700590 BOOST_THROW_EXCEPTION(SecTpm::Error("Private key does not exist"));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700591
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700592 SignatureInfo sigInfo(cert.getSignature().getInfo());
593 sigInfo.setKeyLocator(KeyLocator(cert.getName().getPrefix(-1)));
594 sigInfo.setSignatureType(getSignatureType(cert.getPublicKeyInfo().getKeyType(),
595 DIGEST_ALGORITHM_SHA256));
Yingdi Yu4a557052014-07-09 16:40:37 -0700596
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700597 signPacketWrapper(cert, Signature(sigInfo), keyName, DIGEST_ALGORITHM_SHA256);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700598}
599
600shared_ptr<SecuredBag>
601KeyChain::exportIdentity(const Name& identity, const std::string& passwordStr)
602{
603 if (!m_pib->doesIdentityExist(identity))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700604 BOOST_THROW_EXCEPTION(SecPublicInfo::Error("Identity does not exist"));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700605
606 Name keyName = m_pib->getDefaultKeyNameForIdentity(identity);
607
608 ConstBufferPtr pkcs5;
609 try
610 {
611 pkcs5 = m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, passwordStr);
612 }
613 catch (SecTpm::Error& e)
614 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700615 BOOST_THROW_EXCEPTION(SecPublicInfo::Error("Fail to export PKCS5 of private key"));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700616 }
617
618 shared_ptr<IdentityCertificate> cert;
619 try
620 {
621 cert = m_pib->getCertificate(m_pib->getDefaultCertificateNameForKey(keyName));
622 }
623 catch (SecPublicInfo::Error& e)
624 {
625 cert = selfSign(keyName);
626 m_pib->addCertificateAsIdentityDefault(*cert);
627 }
628
Alexander Afanasyevb67090a2014-04-29 22:31:01 -0700629 // make_shared on OSX 10.9 has some strange problem here
630 shared_ptr<SecuredBag> secureBag(new SecuredBag(*cert, pkcs5));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700631
632 return secureBag;
633}
634
635void
636KeyChain::importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
637{
638 Name certificateName = securedBag.getCertificate().getName();
639 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
640 Name identity = keyName.getPrefix(-1);
641
642 // Add identity
643 m_pib->addIdentity(identity);
644
645 // Add key
646 m_tpm->importPrivateKeyPkcs5IntoTpm(keyName,
647 securedBag.getKey()->buf(),
648 securedBag.getKey()->size(),
649 passwordStr);
650
651 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
652 // HACK! We should set key type according to the pkcs8 info.
Yingdi Yu41546342014-11-30 23:37:53 -0800653 m_pib->addKey(keyName, *pubKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700654 m_pib->setDefaultKeyNameForIdentity(keyName);
655
656 // Add cert
657 m_pib->addCertificateAsIdentityDefault(securedBag.getCertificate());
658}
659
660void
661KeyChain::setDefaultCertificateInternal()
662{
663 m_pib->refreshDefaultCertificate();
664
Alexander Afanasyevaab79662014-07-07 17:35:34 -0700665 if (!static_cast<bool>(m_pib->getDefaultCertificate()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700666 {
667 Name defaultIdentity;
668 try
669 {
670 defaultIdentity = m_pib->getDefaultIdentity();
671 }
672 catch (SecPublicInfo::Error& e)
673 {
674 uint32_t random = random::generateWord32();
675 defaultIdentity.append("tmp-identity")
676 .append(reinterpret_cast<uint8_t*>(&random), 4);
677 }
678 createIdentity(defaultIdentity);
679 m_pib->setDefaultIdentity(defaultIdentity);
680 m_pib->refreshDefaultCertificate();
681 }
682}
683
Yingdi Yu7036ce22014-06-19 18:53:37 -0700684Name
685KeyChain::generateKeyPair(const Name& identityName, bool isKsk, const KeyParams& params)
686{
687 Name keyName = m_pib->getNewKeyName(identityName, isKsk);
688
689 m_tpm->generateKeyPairInTpm(keyName.toUri(), params);
690
691 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
692 m_pib->addKey(keyName, *pubKey);
693
694 return keyName;
695}
696
697void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700698KeyChain::signPacketWrapper(Data& data, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700699 const Name& keyName, DigestAlgorithm digestAlgorithm)
700{
701 data.setSignature(signature);
702
703 EncodingBuffer encoder;
704 data.wireEncode(encoder, true);
705
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700706 Block sigValue = pureSign(encoder.buf(), encoder.size(), keyName, digestAlgorithm);
707
708 data.wireEncode(encoder, sigValue);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700709}
710
711void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700712KeyChain::signPacketWrapper(Interest& interest, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700713 const Name& keyName, DigestAlgorithm digestAlgorithm)
714{
715 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
716 if (timestamp <= m_lastTimestamp)
717 {
718 timestamp = m_lastTimestamp + time::milliseconds(1);
719 }
720
721 Name signedName = interest.getName();
722 signedName
723 .append(name::Component::fromNumber(timestamp.count())) // timestamp
724 .append(name::Component::fromNumber(random::generateWord64())) // nonce
725 .append(signature.getInfo()); // signatureInfo
726
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700727 Block sigValue = pureSign(signedName.wireEncode().value(),
728 signedName.wireEncode().value_size(),
729 keyName,
730 digestAlgorithm);
731
Yingdi Yu7036ce22014-06-19 18:53:37 -0700732 sigValue.encode();
733 signedName.append(sigValue); // signatureValue
734 interest.setName(signedName);
735}
736
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700737Block
738KeyChain::pureSign(const uint8_t* buf, size_t size,
739 const Name& keyName, DigestAlgorithm digestAlgorithm) const
740{
741 if (keyName == DIGEST_SHA256_IDENTITY)
742 return Block(tlv::SignatureValue, crypto::sha256(buf, size));
743
744 return m_tpm->signInTpm(buf, size, keyName, digestAlgorithm);
745}
746
Yingdi Yu7036ce22014-06-19 18:53:37 -0700747Signature
748KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
749{
750 Name signingCertificateName;
751 try
752 {
753 signingCertificateName = m_pib->getDefaultCertificateNameForIdentity(identityName);
754 }
755 catch (SecPublicInfo::Error& e)
756 {
757 signingCertificateName = createIdentity(identityName);
758 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which
759 // is a fatal error.
760 }
761
762 // We either get or create the signing certificate, sign data! (no exception unless fatal error
763 // in TPM)
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700764 Signature sig;
765
766 // For temporary usage, we support SHA256 only, but will support more.
767 sig.setValue(sign(buffer, bufferLength, SigningInfo(SigningInfo::SIGNER_TYPE_CERT,
768 signingCertificateName)));
769
770 return sig;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700771}
772
773void
774KeyChain::signWithSha256(Data& data)
775{
776 DigestSha256 sig;
777 data.setSignature(sig);
778
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600779 Block sigValue(tlv::SignatureValue,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700780 crypto::sha256(data.wireEncode().value(),
781 data.wireEncode().value_size() -
782 data.getSignature().getValue().size()));
783 data.setSignatureValue(sigValue);
784}
785
786void
Yingdi Yu6ab67812014-11-27 15:00:34 -0800787KeyChain::signWithSha256(Interest& interest)
788{
789 DigestSha256 sig;
790
791 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
792 if (timestamp <= m_lastTimestamp)
793 timestamp = m_lastTimestamp + time::milliseconds(1);
794
795 Name signedName = interest.getName();
796 signedName
797 .append(name::Component::fromNumber(timestamp.count())) // timestamp
798 .append(name::Component::fromNumber(random::generateWord64())) // nonce
799 .append(sig.getInfo()); // signatureInfo
800
801 Block sigValue(tlv::SignatureValue,
802 crypto::sha256(signedName.wireEncode().value(),
803 signedName.wireEncode().value_size()));
804
805 sigValue.encode();
806 signedName.append(sigValue); // signatureValue
807 interest.setName(signedName);
808}
809
810void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700811KeyChain::deleteCertificate(const Name& certificateName)
812{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700813 m_pib->deleteCertificateInfo(certificateName);
814}
815
816void
817KeyChain::deleteKey(const Name& keyName)
818{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700819 m_pib->deletePublicKeyInfo(keyName);
820 m_tpm->deleteKeyPairInTpm(keyName);
821}
822
823void
824KeyChain::deleteIdentity(const Name& identity)
825{
Yingdi Yu6147ef42014-12-08 17:48:32 -0800826 std::vector<Name> keyNames;
827 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, true);
828 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, false);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700829
830 m_pib->deleteIdentityInfo(identity);
831
Yingdi Yu6147ef42014-12-08 17:48:32 -0800832 for (const auto& keyName : keyNames)
833 m_tpm->deleteKeyPairInTpm(keyName);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700834}
835
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700836tlv::SignatureTypeValue
837KeyChain::getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm)
838{
839 switch (keyType) {
840 case KEY_TYPE_RSA:
841 return tlv::SignatureSha256WithRsa;
842 case KEY_TYPE_ECDSA:
843 return tlv::SignatureSha256WithEcdsa;
844 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700845 BOOST_THROW_EXCEPTION(Error("Unsupported key types"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700846 }
847
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700848}
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700849
850} // namespace security
851} // namespace ndn