blob: 3a1cbdaee9cd41159a672f7f2bf8ba30f4938e3d [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 {
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
Alexander Afanasyev34a37632015-01-16 17:37:36 -080065template<class T>
66struct Factory
67{
68 Factory(const std::string& canonicalName, const T& create)
69 : canonicalName(canonicalName)
70 , create(create)
71 {
72 }
73
74 std::string canonicalName;
75 T create;
76};
77typedef Factory<KeyChain::PibCreateFunc> PibFactory;
78typedef Factory<KeyChain::TpmCreateFunc> TpmFactory;
79
80static std::map<std::string, PibFactory>&
Alexander Afanasyev07113802015-01-15 19:14:36 -080081getPibFactories()
82{
Alexander Afanasyev34a37632015-01-16 17:37:36 -080083 static std::map<std::string, PibFactory> pibFactories;
Alexander Afanasyev07113802015-01-15 19:14:36 -080084 return pibFactories;
85}
86
Alexander Afanasyev34a37632015-01-16 17:37:36 -080087static std::map<std::string, TpmFactory>&
Alexander Afanasyev07113802015-01-15 19:14:36 -080088getTpmFactories()
89{
Alexander Afanasyev34a37632015-01-16 17:37:36 -080090 static std::map<std::string, TpmFactory> tpmFactories;
Alexander Afanasyev07113802015-01-15 19:14:36 -080091 return tpmFactories;
92}
93
94void
Alexander Afanasyev34a37632015-01-16 17:37:36 -080095KeyChain::registerPibImpl(const std::string& canonicalName,
96 std::initializer_list<std::string> aliases,
Alexander Afanasyev07113802015-01-15 19:14:36 -080097 KeyChain::PibCreateFunc createFunc)
98{
Alexander Afanasyev34a37632015-01-16 17:37:36 -080099 for (const std::string& alias : aliases) {
100 getPibFactories().insert(make_pair(alias, PibFactory(canonicalName, createFunc)));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800101 }
102}
103
104void
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800105KeyChain::registerTpmImpl(const std::string& canonicalName,
106 std::initializer_list<std::string> aliases,
Alexander Afanasyev07113802015-01-15 19:14:36 -0800107 KeyChain::TpmCreateFunc createFunc)
108{
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800109 for (const std::string& alias : aliases) {
110 getTpmFactories().insert(make_pair(alias, TpmFactory(canonicalName, createFunc)));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800111 }
112}
113
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700114KeyChain::KeyChain()
Yingdi Yu41546342014-11-30 23:37:53 -0800115 : m_pib(nullptr)
116 , m_tpm(nullptr)
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700117 , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700118{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800119 ConfigFile config;
120 const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700121
Alexander Afanasyev07113802015-01-15 19:14:36 -0800122 std::string pibLocator = parsed.get<std::string>("pib", "");
123 std::string tpmLocator = parsed.get<std::string>("tpm", "");
124
125 initialize(pibLocator, tpmLocator, false);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700126}
127
128KeyChain::KeyChain(const std::string& pibName,
Yingdi Yu41546342014-11-30 23:37:53 -0800129 const std::string& tpmName,
130 bool allowReset)
131 : m_pib(nullptr)
132 , m_tpm(nullptr)
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700133 , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700134{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800135 initialize(pibName, tpmName, allowReset);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700136}
137
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700138KeyChain::~KeyChain()
139{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800140}
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700141
Alexander Afanasyev07113802015-01-15 19:14:36 -0800142static inline std::tuple<std::string/*type*/, std::string/*location*/>
143parseUri(const std::string& uri)
144{
145 size_t pos = uri.find(':');
146 if (pos != std::string::npos) {
147 return std::make_tuple(uri.substr(0, pos),
148 uri.substr(pos + 1));
149 }
150 else {
151 return std::make_tuple(uri, "");
152 }
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700153}
154
Yingdi Yu41546342014-11-30 23:37:53 -0800155void
Alexander Afanasyev07113802015-01-15 19:14:36 -0800156KeyChain::initialize(const std::string& pibLocatorUri,
157 const std::string& tpmLocatorUri,
Yingdi Yu41546342014-11-30 23:37:53 -0800158 bool allowReset)
159{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800160 BOOST_ASSERT(!getPibFactories().empty());
161 BOOST_ASSERT(!getTpmFactories().empty());
Yingdi Yu41546342014-11-30 23:37:53 -0800162
Alexander Afanasyev07113802015-01-15 19:14:36 -0800163 std::string pibScheme, pibLocation;
164 std::tie(pibScheme, pibLocation) = parseUri(pibLocatorUri);
165
166 std::string tpmScheme, tpmLocation;
167 std::tie(tpmScheme, tpmLocation) = parseUri(tpmLocatorUri);
168
169 // Find PIB and TPM factories
170 if (pibScheme.empty()) {
171 pibScheme = DEFAULT_PIB_SCHEME;
172 }
173 auto pibFactory = getPibFactories().find(pibScheme);
174 if (pibFactory == getPibFactories().end()) {
175 throw Error("PIB scheme '" + pibScheme + "' is not supported");
176 }
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800177 pibScheme = pibFactory->second.canonicalName;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800178
179 if (tpmScheme.empty()) {
180 tpmScheme = DEFAULT_TPM_SCHEME;
181 }
182 auto tpmFactory = getTpmFactories().find(tpmScheme);
183 if (tpmFactory == getTpmFactories().end()) {
184 throw Error("TPM scheme '" + tpmScheme + "' is not supported");
185 }
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800186 tpmScheme = tpmFactory->second.canonicalName;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800187
188 // Create PIB
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800189 m_pib = pibFactory->second.create(pibLocation);
Alexander Afanasyev07113802015-01-15 19:14:36 -0800190
191 std::string actualTpmLocator = tpmScheme + ":" + tpmLocation;
192
193 // Create TPM, checking that it matches to the previously associated one
Yingdi Yu41546342014-11-30 23:37:53 -0800194 try {
Alexander Afanasyev07113802015-01-15 19:14:36 -0800195 if (!allowReset &&
196 !m_pib->getTpmLocator().empty() && m_pib->getTpmLocator() != actualTpmLocator)
197 // Tpm mismatch, but we do not want to reset PIB
198 throw MismatchError("TPM locator supplied does not match TPM locator in PIB: " +
199 m_pib->getTpmLocator() + " != " + actualTpmLocator);
Yingdi Yu41546342014-11-30 23:37:53 -0800200 }
201 catch (SecPublicInfo::Error&) {
202 // TPM locator is not set in PIB yet.
203 }
204
Alexander Afanasyev07113802015-01-15 19:14:36 -0800205 // note that key mismatch may still happen if the TPM locator is initially set to a
206 // wrong one or if the PIB was shared by more than one TPMs before. This is due to the
207 // old PIB does not have TPM info, new pib should not have this problem.
Yingdi Yu41546342014-11-30 23:37:53 -0800208
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800209 m_tpm = tpmFactory->second.create(tpmLocation);
Alexander Afanasyev07113802015-01-15 19:14:36 -0800210 m_pib->setTpmLocator(actualTpmLocator);
Yingdi Yu41546342014-11-30 23:37:53 -0800211}
212
Yingdi Yu7036ce22014-06-19 18:53:37 -0700213Name
214KeyChain::createIdentity(const Name& identityName, const KeyParams& params)
215{
216 m_pib->addIdentity(identityName);
217
218 Name keyName;
219 try
220 {
221 keyName = m_pib->getDefaultKeyNameForIdentity(identityName);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700222
223 shared_ptr<PublicKey> key = m_pib->getPublicKey(keyName);
224
225 if (key->getKeyType() != params.getKeyType())
226 {
227 keyName = generateKeyPair(identityName, true, params);
228 m_pib->setDefaultKeyNameForIdentity(keyName);
229 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700230 }
231 catch (SecPublicInfo::Error& e)
232 {
233 keyName = generateKeyPair(identityName, true, params);
234 m_pib->setDefaultKeyNameForIdentity(keyName);
235 }
236
237 Name certName;
238 try
239 {
240 certName = m_pib->getDefaultCertificateNameForKey(keyName);
241 }
242 catch (SecPublicInfo::Error& e)
243 {
244 shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
245 m_pib->addCertificateAsIdentityDefault(*selfCert);
246 certName = selfCert->getName();
247 }
248
249 return certName;
250}
251
252Name
Yingdi Yu41546342014-11-30 23:37:53 -0800253KeyChain::generateRsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
254{
255 RsaKeyParams params(keySize);
256 return generateKeyPair(identityName, isKsk, params);
257}
258
259Name
260KeyChain::generateEcdsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
261{
262 EcdsaKeyParams params(keySize);
263 return generateKeyPair(identityName, isKsk, params);
264}
265
266Name
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700267KeyChain::generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
Yingdi Yu7036ce22014-06-19 18:53:37 -0700268{
269 RsaKeyParams params(keySize);
270
271 Name keyName = generateKeyPair(identityName, isKsk, params);
272
273 m_pib->setDefaultKeyNameForIdentity(keyName);
274
275 return keyName;
276}
277
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700278Name
279KeyChain::generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
280{
281 EcdsaKeyParams params(keySize);
282
283 Name keyName = generateKeyPair(identityName, isKsk, params);
284
285 m_pib->setDefaultKeyNameForIdentity(keyName);
286
287 return keyName;
288}
289
290
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700291shared_ptr<IdentityCertificate>
292KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
293 const Name& signingIdentity,
294 const time::system_clock::TimePoint& notBefore,
295 const time::system_clock::TimePoint& notAfter,
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700296 const std::vector<CertificateSubjectDescription>& subjectDescription,
297 const Name& certPrefix)
298{
299 shared_ptr<PublicKey> publicKey;
300 try
301 {
302 publicKey = m_pib->getPublicKey(keyName);
303 }
304 catch (SecPublicInfo::Error& e)
305 {
306 return shared_ptr<IdentityCertificate>();
307 }
308
309 return prepareUnsignedIdentityCertificate(keyName, *publicKey, signingIdentity,
310 notBefore, notAfter,
311 subjectDescription, certPrefix);
312}
313
314shared_ptr<IdentityCertificate>
315KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
316 const PublicKey& publicKey,
317 const Name& signingIdentity,
318 const time::system_clock::TimePoint& notBefore,
319 const time::system_clock::TimePoint& notAfter,
320 const std::vector<CertificateSubjectDescription>& subjectDescription,
321 const Name& certPrefix)
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700322{
323 if (keyName.size() < 1)
324 return shared_ptr<IdentityCertificate>();
325
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700326 std::string keyIdPrefix = keyName.get(-1).toUri().substr(0, 4);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700327 if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
328 return shared_ptr<IdentityCertificate>();
329
330 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
331 Name certName;
332
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700333 if (certPrefix == KeyChain::DEFAULT_PREFIX)
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700334 {
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700335 // No certificate prefix hint, infer the prefix
336 if (signingIdentity.isPrefixOf(keyName))
337 certName.append(signingIdentity)
338 .append("KEY")
339 .append(keyName.getSubName(signingIdentity.size()))
340 .append("ID-CERT")
341 .appendVersion();
342 else
343 certName.append(keyName.getPrefix(-1))
344 .append("KEY")
345 .append(keyName.get(-1))
346 .append("ID-CERT")
347 .appendVersion();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700348 }
349 else
350 {
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700351 // cert prefix hint is supplied, determine the cert name.
352 if (certPrefix.isPrefixOf(keyName) && certPrefix != keyName)
353 certName.append(certPrefix)
354 .append("KEY")
355 .append(keyName.getSubName(certPrefix.size()))
356 .append("ID-CERT")
357 .appendVersion();
358 else
359 return shared_ptr<IdentityCertificate>();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700360 }
361
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700362
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700363 certificate->setName(certName);
364 certificate->setNotBefore(notBefore);
365 certificate->setNotAfter(notAfter);
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700366 certificate->setPublicKeyInfo(publicKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700367
368 if (subjectDescription.empty())
369 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700370 CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri());
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700371 certificate->addSubjectDescription(subjectName);
372 }
373 else
374 {
375 std::vector<CertificateSubjectDescription>::const_iterator sdIt =
376 subjectDescription.begin();
377 std::vector<CertificateSubjectDescription>::const_iterator sdEnd =
378 subjectDescription.end();
379 for(; sdIt != sdEnd; sdIt++)
380 certificate->addSubjectDescription(*sdIt);
381 }
382
383 certificate->encode();
384
385 return certificate;
386}
387
388Signature
389KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
390{
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700391 shared_ptr<IdentityCertificate> certificate = m_pib->getCertificate(certificateName);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700392
Yingdi Yu4a557052014-07-09 16:40:37 -0700393 KeyLocator keyLocator(certificate->getName().getPrefix(-1));
394 shared_ptr<Signature> sig =
395 determineSignatureWithPublicKey(keyLocator, certificate->getPublicKeyInfo().getKeyType());
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700396
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700397 if (!static_cast<bool>(sig))
398 throw SecTpm::Error("unknown key type");
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700399
Yingdi Yu4a557052014-07-09 16:40:37 -0700400
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700401 // For temporary usage, we support SHA256 only, but will support more.
402 sig->setValue(m_tpm->signInTpm(buffer, bufferLength,
403 certificate->getPublicKeyName(),
404 DIGEST_ALGORITHM_SHA256));
405
406 return *sig;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700407}
408
409shared_ptr<IdentityCertificate>
410KeyChain::selfSign(const Name& keyName)
411{
412 shared_ptr<PublicKey> pubKey;
413 try
414 {
415 pubKey = m_pib->getPublicKey(keyName); // may throw an exception.
416 }
417 catch (SecPublicInfo::Error& e)
418 {
419 return shared_ptr<IdentityCertificate>();
420 }
421
422 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
423
424 Name certificateName = keyName.getPrefix(-1);
425 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
426
427 certificate->setName(certificateName);
428 certificate->setNotBefore(time::system_clock::now());
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700429 certificate->setNotAfter(time::system_clock::now() + time::days(7300)); // ~20 years
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700430 certificate->setPublicKeyInfo(*pubKey);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700431 certificate->addSubjectDescription(CertificateSubjectDescription(oid::ATTRIBUTE_NAME,
432 keyName.toUri()));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700433 certificate->encode();
434
435 selfSign(*certificate);
436 return certificate;
437}
438
439void
440KeyChain::selfSign(IdentityCertificate& cert)
441{
442 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(cert.getName());
443 if (!m_tpm->doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700444 throw SecTpm::Error("Private key does not exist");
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700445
Yingdi Yu4a557052014-07-09 16:40:37 -0700446
447 KeyLocator keyLocator(cert.getName().getPrefix(-1));
448 shared_ptr<Signature> sig =
449 determineSignatureWithPublicKey(keyLocator, cert.getPublicKeyInfo().getKeyType());
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700450
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700451 if (!static_cast<bool>(sig))
452 throw SecTpm::Error("unknown key type");
453
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700454 signPacketWrapper(cert, *sig, keyName, DIGEST_ALGORITHM_SHA256);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700455}
456
457shared_ptr<SecuredBag>
458KeyChain::exportIdentity(const Name& identity, const std::string& passwordStr)
459{
460 if (!m_pib->doesIdentityExist(identity))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700461 throw SecPublicInfo::Error("Identity does not exist");
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700462
463 Name keyName = m_pib->getDefaultKeyNameForIdentity(identity);
464
465 ConstBufferPtr pkcs5;
466 try
467 {
468 pkcs5 = m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, passwordStr);
469 }
470 catch (SecTpm::Error& e)
471 {
472 throw SecPublicInfo::Error("Fail to export PKCS5 of private key");
473 }
474
475 shared_ptr<IdentityCertificate> cert;
476 try
477 {
478 cert = m_pib->getCertificate(m_pib->getDefaultCertificateNameForKey(keyName));
479 }
480 catch (SecPublicInfo::Error& e)
481 {
482 cert = selfSign(keyName);
483 m_pib->addCertificateAsIdentityDefault(*cert);
484 }
485
Alexander Afanasyevb67090a2014-04-29 22:31:01 -0700486 // make_shared on OSX 10.9 has some strange problem here
487 shared_ptr<SecuredBag> secureBag(new SecuredBag(*cert, pkcs5));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700488
489 return secureBag;
490}
491
492void
493KeyChain::importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
494{
495 Name certificateName = securedBag.getCertificate().getName();
496 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
497 Name identity = keyName.getPrefix(-1);
498
499 // Add identity
500 m_pib->addIdentity(identity);
501
502 // Add key
503 m_tpm->importPrivateKeyPkcs5IntoTpm(keyName,
504 securedBag.getKey()->buf(),
505 securedBag.getKey()->size(),
506 passwordStr);
507
508 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
509 // HACK! We should set key type according to the pkcs8 info.
Yingdi Yu41546342014-11-30 23:37:53 -0800510 m_pib->addKey(keyName, *pubKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700511 m_pib->setDefaultKeyNameForIdentity(keyName);
512
513 // Add cert
514 m_pib->addCertificateAsIdentityDefault(securedBag.getCertificate());
515}
516
Yingdi Yu4a557052014-07-09 16:40:37 -0700517shared_ptr<Signature>
518KeyChain::determineSignatureWithPublicKey(const KeyLocator& keyLocator,
519 KeyType keyType, DigestAlgorithm digestAlgorithm)
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700520{
521 switch (keyType)
522 {
523 case KEY_TYPE_RSA:
524 {
525 // For temporary usage, we support SHA256 only, but will support more.
526 if (digestAlgorithm != DIGEST_ALGORITHM_SHA256)
Yingdi Yu4a557052014-07-09 16:40:37 -0700527 return shared_ptr<Signature>();
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700528
Yingdi Yu4a557052014-07-09 16:40:37 -0700529 return make_shared<SignatureSha256WithRsa>(keyLocator);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700530 }
531 case KEY_TYPE_ECDSA:
532 {
533 // For temporary usage, we support SHA256 only, but will support more.
534 if (digestAlgorithm != DIGEST_ALGORITHM_SHA256)
Yingdi Yu4a557052014-07-09 16:40:37 -0700535 return shared_ptr<Signature>();
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700536
Yingdi Yu4a557052014-07-09 16:40:37 -0700537 return make_shared<SignatureSha256WithEcdsa>(keyLocator);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700538 }
539 default:
Yingdi Yu4a557052014-07-09 16:40:37 -0700540 return shared_ptr<Signature>();
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700541 }
542}
543
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700544void
545KeyChain::setDefaultCertificateInternal()
546{
547 m_pib->refreshDefaultCertificate();
548
Alexander Afanasyevaab79662014-07-07 17:35:34 -0700549 if (!static_cast<bool>(m_pib->getDefaultCertificate()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700550 {
551 Name defaultIdentity;
552 try
553 {
554 defaultIdentity = m_pib->getDefaultIdentity();
555 }
556 catch (SecPublicInfo::Error& e)
557 {
558 uint32_t random = random::generateWord32();
559 defaultIdentity.append("tmp-identity")
560 .append(reinterpret_cast<uint8_t*>(&random), 4);
561 }
562 createIdentity(defaultIdentity);
563 m_pib->setDefaultIdentity(defaultIdentity);
564 m_pib->refreshDefaultCertificate();
565 }
566}
567
Yingdi Yu7036ce22014-06-19 18:53:37 -0700568Name
569KeyChain::generateKeyPair(const Name& identityName, bool isKsk, const KeyParams& params)
570{
571 Name keyName = m_pib->getNewKeyName(identityName, isKsk);
572
573 m_tpm->generateKeyPairInTpm(keyName.toUri(), params);
574
575 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
576 m_pib->addKey(keyName, *pubKey);
577
578 return keyName;
579}
580
581void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700582KeyChain::signPacketWrapper(Data& data, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700583 const Name& keyName, DigestAlgorithm digestAlgorithm)
584{
585 data.setSignature(signature);
586
587 EncodingBuffer encoder;
588 data.wireEncode(encoder, true);
589
590 Block signatureValue = m_tpm->signInTpm(encoder.buf(), encoder.size(),
591 keyName, digestAlgorithm);
592 data.wireEncode(encoder, signatureValue);
593}
594
595void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700596KeyChain::signPacketWrapper(Interest& interest, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700597 const Name& keyName, DigestAlgorithm digestAlgorithm)
598{
599 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
600 if (timestamp <= m_lastTimestamp)
601 {
602 timestamp = m_lastTimestamp + time::milliseconds(1);
603 }
604
605 Name signedName = interest.getName();
606 signedName
607 .append(name::Component::fromNumber(timestamp.count())) // timestamp
608 .append(name::Component::fromNumber(random::generateWord64())) // nonce
609 .append(signature.getInfo()); // signatureInfo
610
611 Block sigValue = m_tpm->signInTpm(signedName.wireEncode().value(),
612 signedName.wireEncode().value_size(),
613 keyName,
614 digestAlgorithm);
615 sigValue.encode();
616 signedName.append(sigValue); // signatureValue
617 interest.setName(signedName);
618}
619
620Signature
621KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
622{
623 Name signingCertificateName;
624 try
625 {
626 signingCertificateName = m_pib->getDefaultCertificateNameForIdentity(identityName);
627 }
628 catch (SecPublicInfo::Error& e)
629 {
630 signingCertificateName = createIdentity(identityName);
631 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which
632 // is a fatal error.
633 }
634
635 // We either get or create the signing certificate, sign data! (no exception unless fatal error
636 // in TPM)
637 return sign(buffer, bufferLength, signingCertificateName);
638}
639
640void
641KeyChain::signWithSha256(Data& data)
642{
643 DigestSha256 sig;
644 data.setSignature(sig);
645
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600646 Block sigValue(tlv::SignatureValue,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700647 crypto::sha256(data.wireEncode().value(),
648 data.wireEncode().value_size() -
649 data.getSignature().getValue().size()));
650 data.setSignatureValue(sigValue);
651}
652
653void
Yingdi Yu6ab67812014-11-27 15:00:34 -0800654KeyChain::signWithSha256(Interest& interest)
655{
656 DigestSha256 sig;
657
658 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
659 if (timestamp <= m_lastTimestamp)
660 timestamp = m_lastTimestamp + time::milliseconds(1);
661
662 Name signedName = interest.getName();
663 signedName
664 .append(name::Component::fromNumber(timestamp.count())) // timestamp
665 .append(name::Component::fromNumber(random::generateWord64())) // nonce
666 .append(sig.getInfo()); // signatureInfo
667
668 Block sigValue(tlv::SignatureValue,
669 crypto::sha256(signedName.wireEncode().value(),
670 signedName.wireEncode().value_size()));
671
672 sigValue.encode();
673 signedName.append(sigValue); // signatureValue
674 interest.setName(signedName);
675}
676
677void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700678KeyChain::deleteCertificate(const Name& certificateName)
679{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700680 m_pib->deleteCertificateInfo(certificateName);
681}
682
683void
684KeyChain::deleteKey(const Name& keyName)
685{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700686 m_pib->deletePublicKeyInfo(keyName);
687 m_tpm->deleteKeyPairInTpm(keyName);
688}
689
690void
691KeyChain::deleteIdentity(const Name& identity)
692{
Yingdi Yu6147ef42014-12-08 17:48:32 -0800693 std::vector<Name> keyNames;
694 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, true);
695 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, false);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700696
697 m_pib->deleteIdentityInfo(identity);
698
Yingdi Yu6147ef42014-12-08 17:48:32 -0800699 for (const auto& keyName : keyNames)
700 m_tpm->deleteKeyPairInTpm(keyName);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700701}
702
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700703}