blob: 4c7d08f7b378b17580e3444bbf26e91449f05ff4 [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 Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 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 {
38
Yingdi Yu0eb5d722014-06-10 15:06:25 -070039// Use a GUID as a magic number of KeyChain::DEFAULT_PREFIX identifier
40const Name KeyChain::DEFAULT_PREFIX("/723821fd-f534-44b3-80d9-44bf5f58bbbb");
41
Yingdi Yu7036ce22014-06-19 18:53:37 -070042const RsaKeyParams KeyChain::DEFAULT_KEY_PARAMS;
43
Alexander Afanasyev07113802015-01-15 19:14:36 -080044const std::string DEFAULT_PIB_SCHEME = "pib-sqlite3";
45
46#if defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
47const std::string DEFAULT_TPM_SCHEME = "tpm-osxkeychain";
48#else
49const std::string DEFAULT_TPM_SCHEME = "tpm-file";
50#endif // defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
51
52// When static library is used, not everything is compiled into the resulting binary.
53// Therefore, the following standard PIB and TPMs need to be registered here.
54// http://stackoverflow.com/q/9459980/2150331
55//
56// Also, cannot use Type::SCHEME, as its value may be uninitialized
57NDN_CXX_KEYCHAIN_REGISTER_PIB(SecPublicInfoSqlite3, "pib-sqlite3", "sqlite3");
58
59#ifdef NDN_CXX_HAVE_OSX_SECURITY
60NDN_CXX_KEYCHAIN_REGISTER_TPM(SecTpmOsx, "tpm-osxkeychain", "osx-keychain");
61#endif // NDN_CXX_HAVE_OSX_SECURITY
62
63NDN_CXX_KEYCHAIN_REGISTER_TPM(SecTpmFile, "tpm-file", "file");
64
65static std::map<std::string, KeyChain::PibCreateFunc>&
66getPibFactories()
67{
68 static std::map<std::string, KeyChain::PibCreateFunc> pibFactories;
69 return pibFactories;
70}
71
72static std::map<std::string, KeyChain::TpmCreateFunc>&
73getTpmFactories()
74{
75 static std::map<std::string, KeyChain::TpmCreateFunc> tpmFactories;
76 return tpmFactories;
77}
78
79void
80KeyChain::registerPibImpl(std::initializer_list<std::string> schemes,
81 KeyChain::PibCreateFunc createFunc)
82{
83 for (const std::string& scheme : schemes) {
84 getPibFactories()[scheme] = createFunc;
85 }
86}
87
88void
89KeyChain::registerTpmImpl(std::initializer_list<std::string> schemes,
90 KeyChain::TpmCreateFunc createFunc)
91{
92 for (const std::string& scheme : schemes) {
93 getTpmFactories()[scheme] = createFunc;
94 }
95}
96
Yingdi Yuf56c68f2014-04-24 21:50:13 -070097KeyChain::KeyChain()
Yingdi Yu41546342014-11-30 23:37:53 -080098 : m_pib(nullptr)
99 , m_tpm(nullptr)
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700100 , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700101{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800102 ConfigFile config;
103 const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700104
Alexander Afanasyev07113802015-01-15 19:14:36 -0800105 std::string pibLocator = parsed.get<std::string>("pib", "");
106 std::string tpmLocator = parsed.get<std::string>("tpm", "");
107
108 initialize(pibLocator, tpmLocator, false);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700109}
110
111KeyChain::KeyChain(const std::string& pibName,
Yingdi Yu41546342014-11-30 23:37:53 -0800112 const std::string& tpmName,
113 bool allowReset)
114 : m_pib(nullptr)
115 , m_tpm(nullptr)
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700116 , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700117{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800118 initialize(pibName, tpmName, allowReset);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700119}
120
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700121KeyChain::~KeyChain()
122{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800123}
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700124
Alexander Afanasyev07113802015-01-15 19:14:36 -0800125static inline std::tuple<std::string/*type*/, std::string/*location*/>
126parseUri(const std::string& uri)
127{
128 size_t pos = uri.find(':');
129 if (pos != std::string::npos) {
130 return std::make_tuple(uri.substr(0, pos),
131 uri.substr(pos + 1));
132 }
133 else {
134 return std::make_tuple(uri, "");
135 }
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700136}
137
Yingdi Yu41546342014-11-30 23:37:53 -0800138void
Alexander Afanasyev07113802015-01-15 19:14:36 -0800139KeyChain::initialize(const std::string& pibLocatorUri,
140 const std::string& tpmLocatorUri,
Yingdi Yu41546342014-11-30 23:37:53 -0800141 bool allowReset)
142{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800143 BOOST_ASSERT(!getPibFactories().empty());
144 BOOST_ASSERT(!getTpmFactories().empty());
Yingdi Yu41546342014-11-30 23:37:53 -0800145
Alexander Afanasyev07113802015-01-15 19:14:36 -0800146 std::string pibScheme, pibLocation;
147 std::tie(pibScheme, pibLocation) = parseUri(pibLocatorUri);
148
149 std::string tpmScheme, tpmLocation;
150 std::tie(tpmScheme, tpmLocation) = parseUri(tpmLocatorUri);
151
152 // Find PIB and TPM factories
153 if (pibScheme.empty()) {
154 pibScheme = DEFAULT_PIB_SCHEME;
155 }
156 auto pibFactory = getPibFactories().find(pibScheme);
157 if (pibFactory == getPibFactories().end()) {
158 throw Error("PIB scheme '" + pibScheme + "' is not supported");
159 }
160
161 if (tpmScheme.empty()) {
162 tpmScheme = DEFAULT_TPM_SCHEME;
163 }
164 auto tpmFactory = getTpmFactories().find(tpmScheme);
165 if (tpmFactory == getTpmFactories().end()) {
166 throw Error("TPM scheme '" + tpmScheme + "' is not supported");
167 }
168
169 // Create PIB
170 m_pib = pibFactory->second(pibLocation);
171
172 std::string actualTpmLocator = tpmScheme + ":" + tpmLocation;
173
174 // Create TPM, checking that it matches to the previously associated one
Yingdi Yu41546342014-11-30 23:37:53 -0800175 try {
Alexander Afanasyev07113802015-01-15 19:14:36 -0800176 if (!allowReset &&
177 !m_pib->getTpmLocator().empty() && m_pib->getTpmLocator() != actualTpmLocator)
178 // Tpm mismatch, but we do not want to reset PIB
179 throw MismatchError("TPM locator supplied does not match TPM locator in PIB: " +
180 m_pib->getTpmLocator() + " != " + actualTpmLocator);
Yingdi Yu41546342014-11-30 23:37:53 -0800181 }
182 catch (SecPublicInfo::Error&) {
183 // TPM locator is not set in PIB yet.
184 }
185
Alexander Afanasyev07113802015-01-15 19:14:36 -0800186 // note that key mismatch may still happen if the TPM locator is initially set to a
187 // wrong one or if the PIB was shared by more than one TPMs before. This is due to the
188 // old PIB does not have TPM info, new pib should not have this problem.
Yingdi Yu41546342014-11-30 23:37:53 -0800189
Alexander Afanasyev07113802015-01-15 19:14:36 -0800190 m_tpm = tpmFactory->second(tpmLocation);
191 m_pib->setTpmLocator(actualTpmLocator);
Yingdi Yu41546342014-11-30 23:37:53 -0800192}
193
Yingdi Yu7036ce22014-06-19 18:53:37 -0700194Name
195KeyChain::createIdentity(const Name& identityName, const KeyParams& params)
196{
197 m_pib->addIdentity(identityName);
198
199 Name keyName;
200 try
201 {
202 keyName = m_pib->getDefaultKeyNameForIdentity(identityName);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700203
204 shared_ptr<PublicKey> key = m_pib->getPublicKey(keyName);
205
206 if (key->getKeyType() != params.getKeyType())
207 {
208 keyName = generateKeyPair(identityName, true, params);
209 m_pib->setDefaultKeyNameForIdentity(keyName);
210 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700211 }
212 catch (SecPublicInfo::Error& e)
213 {
214 keyName = generateKeyPair(identityName, true, params);
215 m_pib->setDefaultKeyNameForIdentity(keyName);
216 }
217
218 Name certName;
219 try
220 {
221 certName = m_pib->getDefaultCertificateNameForKey(keyName);
222 }
223 catch (SecPublicInfo::Error& e)
224 {
225 shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
226 m_pib->addCertificateAsIdentityDefault(*selfCert);
227 certName = selfCert->getName();
228 }
229
230 return certName;
231}
232
233Name
Yingdi Yu41546342014-11-30 23:37:53 -0800234KeyChain::generateRsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
235{
236 RsaKeyParams params(keySize);
237 return generateKeyPair(identityName, isKsk, params);
238}
239
240Name
241KeyChain::generateEcdsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
242{
243 EcdsaKeyParams params(keySize);
244 return generateKeyPair(identityName, isKsk, params);
245}
246
247Name
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700248KeyChain::generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
Yingdi Yu7036ce22014-06-19 18:53:37 -0700249{
250 RsaKeyParams params(keySize);
251
252 Name keyName = generateKeyPair(identityName, isKsk, params);
253
254 m_pib->setDefaultKeyNameForIdentity(keyName);
255
256 return keyName;
257}
258
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700259Name
260KeyChain::generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
261{
262 EcdsaKeyParams params(keySize);
263
264 Name keyName = generateKeyPair(identityName, isKsk, params);
265
266 m_pib->setDefaultKeyNameForIdentity(keyName);
267
268 return keyName;
269}
270
271
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700272shared_ptr<IdentityCertificate>
273KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
274 const Name& signingIdentity,
275 const time::system_clock::TimePoint& notBefore,
276 const time::system_clock::TimePoint& notAfter,
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700277 const std::vector<CertificateSubjectDescription>& subjectDescription,
278 const Name& certPrefix)
279{
280 shared_ptr<PublicKey> publicKey;
281 try
282 {
283 publicKey = m_pib->getPublicKey(keyName);
284 }
285 catch (SecPublicInfo::Error& e)
286 {
287 return shared_ptr<IdentityCertificate>();
288 }
289
290 return prepareUnsignedIdentityCertificate(keyName, *publicKey, signingIdentity,
291 notBefore, notAfter,
292 subjectDescription, certPrefix);
293}
294
295shared_ptr<IdentityCertificate>
296KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
297 const PublicKey& publicKey,
298 const Name& signingIdentity,
299 const time::system_clock::TimePoint& notBefore,
300 const time::system_clock::TimePoint& notAfter,
301 const std::vector<CertificateSubjectDescription>& subjectDescription,
302 const Name& certPrefix)
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700303{
304 if (keyName.size() < 1)
305 return shared_ptr<IdentityCertificate>();
306
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700307 std::string keyIdPrefix = keyName.get(-1).toUri().substr(0, 4);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700308 if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
309 return shared_ptr<IdentityCertificate>();
310
311 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
312 Name certName;
313
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700314 if (certPrefix == KeyChain::DEFAULT_PREFIX)
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700315 {
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700316 // No certificate prefix hint, infer the prefix
317 if (signingIdentity.isPrefixOf(keyName))
318 certName.append(signingIdentity)
319 .append("KEY")
320 .append(keyName.getSubName(signingIdentity.size()))
321 .append("ID-CERT")
322 .appendVersion();
323 else
324 certName.append(keyName.getPrefix(-1))
325 .append("KEY")
326 .append(keyName.get(-1))
327 .append("ID-CERT")
328 .appendVersion();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700329 }
330 else
331 {
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700332 // cert prefix hint is supplied, determine the cert name.
333 if (certPrefix.isPrefixOf(keyName) && certPrefix != keyName)
334 certName.append(certPrefix)
335 .append("KEY")
336 .append(keyName.getSubName(certPrefix.size()))
337 .append("ID-CERT")
338 .appendVersion();
339 else
340 return shared_ptr<IdentityCertificate>();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700341 }
342
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700343
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700344 certificate->setName(certName);
345 certificate->setNotBefore(notBefore);
346 certificate->setNotAfter(notAfter);
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700347 certificate->setPublicKeyInfo(publicKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700348
349 if (subjectDescription.empty())
350 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700351 CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri());
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700352 certificate->addSubjectDescription(subjectName);
353 }
354 else
355 {
356 std::vector<CertificateSubjectDescription>::const_iterator sdIt =
357 subjectDescription.begin();
358 std::vector<CertificateSubjectDescription>::const_iterator sdEnd =
359 subjectDescription.end();
360 for(; sdIt != sdEnd; sdIt++)
361 certificate->addSubjectDescription(*sdIt);
362 }
363
364 certificate->encode();
365
366 return certificate;
367}
368
369Signature
370KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
371{
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700372 shared_ptr<IdentityCertificate> certificate = m_pib->getCertificate(certificateName);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700373
Yingdi Yu4a557052014-07-09 16:40:37 -0700374 KeyLocator keyLocator(certificate->getName().getPrefix(-1));
375 shared_ptr<Signature> sig =
376 determineSignatureWithPublicKey(keyLocator, certificate->getPublicKeyInfo().getKeyType());
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700377
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700378 if (!static_cast<bool>(sig))
379 throw SecTpm::Error("unknown key type");
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700380
Yingdi Yu4a557052014-07-09 16:40:37 -0700381
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700382 // For temporary usage, we support SHA256 only, but will support more.
383 sig->setValue(m_tpm->signInTpm(buffer, bufferLength,
384 certificate->getPublicKeyName(),
385 DIGEST_ALGORITHM_SHA256));
386
387 return *sig;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700388}
389
390shared_ptr<IdentityCertificate>
391KeyChain::selfSign(const Name& keyName)
392{
393 shared_ptr<PublicKey> pubKey;
394 try
395 {
396 pubKey = m_pib->getPublicKey(keyName); // may throw an exception.
397 }
398 catch (SecPublicInfo::Error& e)
399 {
400 return shared_ptr<IdentityCertificate>();
401 }
402
403 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
404
405 Name certificateName = keyName.getPrefix(-1);
406 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
407
408 certificate->setName(certificateName);
409 certificate->setNotBefore(time::system_clock::now());
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700410 certificate->setNotAfter(time::system_clock::now() + time::days(7300)); // ~20 years
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700411 certificate->setPublicKeyInfo(*pubKey);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700412 certificate->addSubjectDescription(CertificateSubjectDescription(oid::ATTRIBUTE_NAME,
413 keyName.toUri()));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700414 certificate->encode();
415
416 selfSign(*certificate);
417 return certificate;
418}
419
420void
421KeyChain::selfSign(IdentityCertificate& cert)
422{
423 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(cert.getName());
424 if (!m_tpm->doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700425 throw SecTpm::Error("Private key does not exist");
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700426
Yingdi Yu4a557052014-07-09 16:40:37 -0700427
428 KeyLocator keyLocator(cert.getName().getPrefix(-1));
429 shared_ptr<Signature> sig =
430 determineSignatureWithPublicKey(keyLocator, cert.getPublicKeyInfo().getKeyType());
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700431
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700432 if (!static_cast<bool>(sig))
433 throw SecTpm::Error("unknown key type");
434
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700435 signPacketWrapper(cert, *sig, keyName, DIGEST_ALGORITHM_SHA256);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700436}
437
438shared_ptr<SecuredBag>
439KeyChain::exportIdentity(const Name& identity, const std::string& passwordStr)
440{
441 if (!m_pib->doesIdentityExist(identity))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700442 throw SecPublicInfo::Error("Identity does not exist");
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700443
444 Name keyName = m_pib->getDefaultKeyNameForIdentity(identity);
445
446 ConstBufferPtr pkcs5;
447 try
448 {
449 pkcs5 = m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, passwordStr);
450 }
451 catch (SecTpm::Error& e)
452 {
453 throw SecPublicInfo::Error("Fail to export PKCS5 of private key");
454 }
455
456 shared_ptr<IdentityCertificate> cert;
457 try
458 {
459 cert = m_pib->getCertificate(m_pib->getDefaultCertificateNameForKey(keyName));
460 }
461 catch (SecPublicInfo::Error& e)
462 {
463 cert = selfSign(keyName);
464 m_pib->addCertificateAsIdentityDefault(*cert);
465 }
466
Alexander Afanasyevb67090a2014-04-29 22:31:01 -0700467 // make_shared on OSX 10.9 has some strange problem here
468 shared_ptr<SecuredBag> secureBag(new SecuredBag(*cert, pkcs5));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700469
470 return secureBag;
471}
472
473void
474KeyChain::importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
475{
476 Name certificateName = securedBag.getCertificate().getName();
477 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
478 Name identity = keyName.getPrefix(-1);
479
480 // Add identity
481 m_pib->addIdentity(identity);
482
483 // Add key
484 m_tpm->importPrivateKeyPkcs5IntoTpm(keyName,
485 securedBag.getKey()->buf(),
486 securedBag.getKey()->size(),
487 passwordStr);
488
489 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
490 // HACK! We should set key type according to the pkcs8 info.
Yingdi Yu41546342014-11-30 23:37:53 -0800491 m_pib->addKey(keyName, *pubKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700492 m_pib->setDefaultKeyNameForIdentity(keyName);
493
494 // Add cert
495 m_pib->addCertificateAsIdentityDefault(securedBag.getCertificate());
496}
497
Yingdi Yu4a557052014-07-09 16:40:37 -0700498shared_ptr<Signature>
499KeyChain::determineSignatureWithPublicKey(const KeyLocator& keyLocator,
500 KeyType keyType, DigestAlgorithm digestAlgorithm)
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700501{
502 switch (keyType)
503 {
504 case KEY_TYPE_RSA:
505 {
506 // For temporary usage, we support SHA256 only, but will support more.
507 if (digestAlgorithm != DIGEST_ALGORITHM_SHA256)
Yingdi Yu4a557052014-07-09 16:40:37 -0700508 return shared_ptr<Signature>();
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700509
Yingdi Yu4a557052014-07-09 16:40:37 -0700510 return make_shared<SignatureSha256WithRsa>(keyLocator);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700511 }
512 case KEY_TYPE_ECDSA:
513 {
514 // For temporary usage, we support SHA256 only, but will support more.
515 if (digestAlgorithm != DIGEST_ALGORITHM_SHA256)
Yingdi Yu4a557052014-07-09 16:40:37 -0700516 return shared_ptr<Signature>();
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700517
Yingdi Yu4a557052014-07-09 16:40:37 -0700518 return make_shared<SignatureSha256WithEcdsa>(keyLocator);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700519 }
520 default:
Yingdi Yu4a557052014-07-09 16:40:37 -0700521 return shared_ptr<Signature>();
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700522 }
523}
524
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700525void
526KeyChain::setDefaultCertificateInternal()
527{
528 m_pib->refreshDefaultCertificate();
529
Alexander Afanasyevaab79662014-07-07 17:35:34 -0700530 if (!static_cast<bool>(m_pib->getDefaultCertificate()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700531 {
532 Name defaultIdentity;
533 try
534 {
535 defaultIdentity = m_pib->getDefaultIdentity();
536 }
537 catch (SecPublicInfo::Error& e)
538 {
539 uint32_t random = random::generateWord32();
540 defaultIdentity.append("tmp-identity")
541 .append(reinterpret_cast<uint8_t*>(&random), 4);
542 }
543 createIdentity(defaultIdentity);
544 m_pib->setDefaultIdentity(defaultIdentity);
545 m_pib->refreshDefaultCertificate();
546 }
547}
548
Yingdi Yu7036ce22014-06-19 18:53:37 -0700549Name
550KeyChain::generateKeyPair(const Name& identityName, bool isKsk, const KeyParams& params)
551{
552 Name keyName = m_pib->getNewKeyName(identityName, isKsk);
553
554 m_tpm->generateKeyPairInTpm(keyName.toUri(), params);
555
556 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
557 m_pib->addKey(keyName, *pubKey);
558
559 return keyName;
560}
561
562void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700563KeyChain::signPacketWrapper(Data& data, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700564 const Name& keyName, DigestAlgorithm digestAlgorithm)
565{
566 data.setSignature(signature);
567
568 EncodingBuffer encoder;
569 data.wireEncode(encoder, true);
570
571 Block signatureValue = m_tpm->signInTpm(encoder.buf(), encoder.size(),
572 keyName, digestAlgorithm);
573 data.wireEncode(encoder, signatureValue);
574}
575
576void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700577KeyChain::signPacketWrapper(Interest& interest, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700578 const Name& keyName, DigestAlgorithm digestAlgorithm)
579{
580 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
581 if (timestamp <= m_lastTimestamp)
582 {
583 timestamp = m_lastTimestamp + time::milliseconds(1);
584 }
585
586 Name signedName = interest.getName();
587 signedName
588 .append(name::Component::fromNumber(timestamp.count())) // timestamp
589 .append(name::Component::fromNumber(random::generateWord64())) // nonce
590 .append(signature.getInfo()); // signatureInfo
591
592 Block sigValue = m_tpm->signInTpm(signedName.wireEncode().value(),
593 signedName.wireEncode().value_size(),
594 keyName,
595 digestAlgorithm);
596 sigValue.encode();
597 signedName.append(sigValue); // signatureValue
598 interest.setName(signedName);
599}
600
601Signature
602KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
603{
604 Name signingCertificateName;
605 try
606 {
607 signingCertificateName = m_pib->getDefaultCertificateNameForIdentity(identityName);
608 }
609 catch (SecPublicInfo::Error& e)
610 {
611 signingCertificateName = createIdentity(identityName);
612 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which
613 // is a fatal error.
614 }
615
616 // We either get or create the signing certificate, sign data! (no exception unless fatal error
617 // in TPM)
618 return sign(buffer, bufferLength, signingCertificateName);
619}
620
621void
622KeyChain::signWithSha256(Data& data)
623{
624 DigestSha256 sig;
625 data.setSignature(sig);
626
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600627 Block sigValue(tlv::SignatureValue,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700628 crypto::sha256(data.wireEncode().value(),
629 data.wireEncode().value_size() -
630 data.getSignature().getValue().size()));
631 data.setSignatureValue(sigValue);
632}
633
634void
Yingdi Yu6ab67812014-11-27 15:00:34 -0800635KeyChain::signWithSha256(Interest& interest)
636{
637 DigestSha256 sig;
638
639 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
640 if (timestamp <= m_lastTimestamp)
641 timestamp = m_lastTimestamp + time::milliseconds(1);
642
643 Name signedName = interest.getName();
644 signedName
645 .append(name::Component::fromNumber(timestamp.count())) // timestamp
646 .append(name::Component::fromNumber(random::generateWord64())) // nonce
647 .append(sig.getInfo()); // signatureInfo
648
649 Block sigValue(tlv::SignatureValue,
650 crypto::sha256(signedName.wireEncode().value(),
651 signedName.wireEncode().value_size()));
652
653 sigValue.encode();
654 signedName.append(sigValue); // signatureValue
655 interest.setName(signedName);
656}
657
658void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700659KeyChain::deleteCertificate(const Name& certificateName)
660{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700661 m_pib->deleteCertificateInfo(certificateName);
662}
663
664void
665KeyChain::deleteKey(const Name& keyName)
666{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700667 m_pib->deletePublicKeyInfo(keyName);
668 m_tpm->deleteKeyPairInTpm(keyName);
669}
670
671void
672KeyChain::deleteIdentity(const Name& identity)
673{
Yingdi Yu6147ef42014-12-08 17:48:32 -0800674 std::vector<Name> keyNames;
675 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, true);
676 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, false);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700677
678 m_pib->deleteIdentityInfo(identity);
679
Yingdi Yu6147ef42014-12-08 17:48:32 -0800680 for (const auto& keyName : keyNames)
681 m_tpm->deleteKeyPairInTpm(keyName);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700682}
683
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700684}