blob: f4ea7236b4b630ee9aa0252c85192fbfc51b43db [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 Yu281689a2015-06-13 14:32:32 -0700155std::string
156KeyChain::getDefaultPibLocator()
Yingdi Yu41546342014-11-30 23:37:53 -0800157{
Yingdi Yu281689a2015-06-13 14:32:32 -0700158 std::string defaultPibLocator = DEFAULT_PIB_SCHEME + ":";
159 return defaultPibLocator;
160}
Yingdi Yu41546342014-11-30 23:37:53 -0800161
Yingdi Yu281689a2015-06-13 14:32:32 -0700162static inline std::tuple<std::string/*type*/, std::string/*location*/>
163getCanonicalPibLocator(const std::string& pibLocator)
164{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800165 std::string pibScheme, pibLocation;
Yingdi Yu281689a2015-06-13 14:32:32 -0700166 std::tie(pibScheme, pibLocation) = parseUri(pibLocator);
Alexander Afanasyev07113802015-01-15 19:14:36 -0800167
Alexander Afanasyev07113802015-01-15 19:14:36 -0800168 if (pibScheme.empty()) {
169 pibScheme = DEFAULT_PIB_SCHEME;
170 }
Yingdi Yu281689a2015-06-13 14:32:32 -0700171
Alexander Afanasyev07113802015-01-15 19:14:36 -0800172 auto pibFactory = getPibFactories().find(pibScheme);
173 if (pibFactory == getPibFactories().end()) {
Yingdi Yu281689a2015-06-13 14:32:32 -0700174 throw KeyChain::Error("PIB scheme '" + pibScheme + "' is not supported");
Alexander Afanasyev07113802015-01-15 19:14:36 -0800175 }
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800176 pibScheme = pibFactory->second.canonicalName;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800177
Yingdi Yu281689a2015-06-13 14:32:32 -0700178 return std::make_tuple(pibScheme, pibLocation);
179}
180
181unique_ptr<SecPublicInfo>
182KeyChain::createPib(const std::string& pibLocator)
183{
184 BOOST_ASSERT(!getPibFactories().empty());
185
186 std::string pibScheme, pibLocation;
187 std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator);
188 auto pibFactory = getPibFactories().find(pibScheme);
189 BOOST_ASSERT(pibFactory != getPibFactories().end());
190 return pibFactory->second.create(pibLocation);
191}
192
193std::string
194KeyChain::getDefaultTpmLocator()
195{
196 std::string defaultTpmLocator = DEFAULT_TPM_SCHEME + ":";
197 return defaultTpmLocator;
198}
199
200static inline std::tuple<std::string/*type*/, std::string/*location*/>
201getCanonicalTpmLocator(const std::string& tpmLocator)
202{
203 std::string tpmScheme, tpmLocation;
204 std::tie(tpmScheme, tpmLocation) = parseUri(tpmLocator);
205
Alexander Afanasyev07113802015-01-15 19:14:36 -0800206 if (tpmScheme.empty()) {
207 tpmScheme = DEFAULT_TPM_SCHEME;
208 }
209 auto tpmFactory = getTpmFactories().find(tpmScheme);
210 if (tpmFactory == getTpmFactories().end()) {
Yingdi Yu281689a2015-06-13 14:32:32 -0700211 throw KeyChain::Error("TPM scheme '" + tpmScheme + "' is not supported");
Alexander Afanasyev07113802015-01-15 19:14:36 -0800212 }
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800213 tpmScheme = tpmFactory->second.canonicalName;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800214
Yingdi Yu281689a2015-06-13 14:32:32 -0700215 return std::make_tuple(tpmScheme, tpmLocation);
216}
Alexander Afanasyev07113802015-01-15 19:14:36 -0800217
Yingdi Yu281689a2015-06-13 14:32:32 -0700218unique_ptr<SecTpm>
219KeyChain::createTpm(const std::string& tpmLocator)
220{
221 BOOST_ASSERT(!getTpmFactories().empty());
222
223 std::string tpmScheme, tpmLocation;
224 std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator);
225 auto tpmFactory = getTpmFactories().find(tpmScheme);
226 BOOST_ASSERT(tpmFactory != getTpmFactories().end());
227 return tpmFactory->second.create(tpmLocation);
228}
229
230void
231KeyChain::initialize(const std::string& pibLocator,
232 const std::string& tpmLocator,
233 bool allowReset)
234{
235 // PIB Locator
236 std::string pibScheme, pibLocation;
237 std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator);
238 std::string canonicalPibLocator = pibScheme + ":" + pibLocation;
239
240 // Create PIB
241 m_pib = createPib(canonicalPibLocator);
242
243 // TPM Locator
244 std::string tpmScheme, tpmLocation;
245 std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator);
246 std::string canonicalTpmLocator = tpmScheme + ":" + tpmLocation;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800247
248 // Create TPM, checking that it matches to the previously associated one
Yingdi Yu41546342014-11-30 23:37:53 -0800249 try {
Alexander Afanasyev07113802015-01-15 19:14:36 -0800250 if (!allowReset &&
Yingdi Yu281689a2015-06-13 14:32:32 -0700251 !m_pib->getTpmLocator().empty() && m_pib->getTpmLocator() != canonicalTpmLocator)
Alexander Afanasyev07113802015-01-15 19:14:36 -0800252 // Tpm mismatch, but we do not want to reset PIB
253 throw MismatchError("TPM locator supplied does not match TPM locator in PIB: " +
Yingdi Yu281689a2015-06-13 14:32:32 -0700254 m_pib->getTpmLocator() + " != " + canonicalTpmLocator);
Yingdi Yu41546342014-11-30 23:37:53 -0800255 }
256 catch (SecPublicInfo::Error&) {
257 // TPM locator is not set in PIB yet.
258 }
259
Alexander Afanasyev07113802015-01-15 19:14:36 -0800260 // note that key mismatch may still happen if the TPM locator is initially set to a
261 // wrong one or if the PIB was shared by more than one TPMs before. This is due to the
262 // old PIB does not have TPM info, new pib should not have this problem.
Yingdi Yu281689a2015-06-13 14:32:32 -0700263 m_tpm = createTpm(canonicalTpmLocator);
264 m_pib->setTpmLocator(canonicalTpmLocator);
Yingdi Yu41546342014-11-30 23:37:53 -0800265}
266
Yingdi Yu7036ce22014-06-19 18:53:37 -0700267Name
268KeyChain::createIdentity(const Name& identityName, const KeyParams& params)
269{
270 m_pib->addIdentity(identityName);
271
272 Name keyName;
273 try
274 {
275 keyName = m_pib->getDefaultKeyNameForIdentity(identityName);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700276
277 shared_ptr<PublicKey> key = m_pib->getPublicKey(keyName);
278
279 if (key->getKeyType() != params.getKeyType())
280 {
281 keyName = generateKeyPair(identityName, true, params);
282 m_pib->setDefaultKeyNameForIdentity(keyName);
283 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700284 }
285 catch (SecPublicInfo::Error& e)
286 {
287 keyName = generateKeyPair(identityName, true, params);
288 m_pib->setDefaultKeyNameForIdentity(keyName);
289 }
290
291 Name certName;
292 try
293 {
294 certName = m_pib->getDefaultCertificateNameForKey(keyName);
295 }
296 catch (SecPublicInfo::Error& e)
297 {
298 shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
299 m_pib->addCertificateAsIdentityDefault(*selfCert);
300 certName = selfCert->getName();
301 }
302
303 return certName;
304}
305
306Name
Yingdi Yu41546342014-11-30 23:37:53 -0800307KeyChain::generateRsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
308{
309 RsaKeyParams params(keySize);
310 return generateKeyPair(identityName, isKsk, params);
311}
312
313Name
314KeyChain::generateEcdsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
315{
316 EcdsaKeyParams params(keySize);
317 return generateKeyPair(identityName, isKsk, params);
318}
319
320Name
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700321KeyChain::generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
Yingdi Yu7036ce22014-06-19 18:53:37 -0700322{
323 RsaKeyParams params(keySize);
324
325 Name keyName = generateKeyPair(identityName, isKsk, params);
326
327 m_pib->setDefaultKeyNameForIdentity(keyName);
328
329 return keyName;
330}
331
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700332Name
333KeyChain::generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
334{
335 EcdsaKeyParams params(keySize);
336
337 Name keyName = generateKeyPair(identityName, isKsk, params);
338
339 m_pib->setDefaultKeyNameForIdentity(keyName);
340
341 return keyName;
342}
343
344
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700345shared_ptr<IdentityCertificate>
346KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
347 const Name& signingIdentity,
348 const time::system_clock::TimePoint& notBefore,
349 const time::system_clock::TimePoint& notAfter,
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700350 const std::vector<CertificateSubjectDescription>& subjectDescription,
351 const Name& certPrefix)
352{
353 shared_ptr<PublicKey> publicKey;
354 try
355 {
356 publicKey = m_pib->getPublicKey(keyName);
357 }
358 catch (SecPublicInfo::Error& e)
359 {
360 return shared_ptr<IdentityCertificate>();
361 }
362
363 return prepareUnsignedIdentityCertificate(keyName, *publicKey, signingIdentity,
364 notBefore, notAfter,
365 subjectDescription, certPrefix);
366}
367
368shared_ptr<IdentityCertificate>
369KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
370 const PublicKey& publicKey,
371 const Name& signingIdentity,
372 const time::system_clock::TimePoint& notBefore,
373 const time::system_clock::TimePoint& notAfter,
374 const std::vector<CertificateSubjectDescription>& subjectDescription,
375 const Name& certPrefix)
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700376{
377 if (keyName.size() < 1)
378 return shared_ptr<IdentityCertificate>();
379
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700380 std::string keyIdPrefix = keyName.get(-1).toUri().substr(0, 4);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700381 if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
382 return shared_ptr<IdentityCertificate>();
383
384 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
385 Name certName;
386
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700387 if (certPrefix == KeyChain::DEFAULT_PREFIX)
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700388 {
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700389 // No certificate prefix hint, infer the prefix
390 if (signingIdentity.isPrefixOf(keyName))
391 certName.append(signingIdentity)
392 .append("KEY")
393 .append(keyName.getSubName(signingIdentity.size()))
394 .append("ID-CERT")
395 .appendVersion();
396 else
397 certName.append(keyName.getPrefix(-1))
398 .append("KEY")
399 .append(keyName.get(-1))
400 .append("ID-CERT")
401 .appendVersion();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700402 }
403 else
404 {
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700405 // cert prefix hint is supplied, determine the cert name.
406 if (certPrefix.isPrefixOf(keyName) && certPrefix != keyName)
407 certName.append(certPrefix)
408 .append("KEY")
409 .append(keyName.getSubName(certPrefix.size()))
410 .append("ID-CERT")
411 .appendVersion();
412 else
413 return shared_ptr<IdentityCertificate>();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700414 }
415
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700416
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700417 certificate->setName(certName);
418 certificate->setNotBefore(notBefore);
419 certificate->setNotAfter(notAfter);
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700420 certificate->setPublicKeyInfo(publicKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700421
422 if (subjectDescription.empty())
423 {
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700424 CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri());
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700425 certificate->addSubjectDescription(subjectName);
426 }
427 else
428 {
429 std::vector<CertificateSubjectDescription>::const_iterator sdIt =
430 subjectDescription.begin();
431 std::vector<CertificateSubjectDescription>::const_iterator sdEnd =
432 subjectDescription.end();
433 for(; sdIt != sdEnd; sdIt++)
434 certificate->addSubjectDescription(*sdIt);
435 }
436
437 certificate->encode();
438
439 return certificate;
440}
441
442Signature
443KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
444{
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700445 shared_ptr<IdentityCertificate> certificate = m_pib->getCertificate(certificateName);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700446
Yingdi Yu4a557052014-07-09 16:40:37 -0700447 KeyLocator keyLocator(certificate->getName().getPrefix(-1));
448 shared_ptr<Signature> sig =
449 determineSignatureWithPublicKey(keyLocator, certificate->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");
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700453
Yingdi Yu4a557052014-07-09 16:40:37 -0700454
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700455 // For temporary usage, we support SHA256 only, but will support more.
456 sig->setValue(m_tpm->signInTpm(buffer, bufferLength,
457 certificate->getPublicKeyName(),
458 DIGEST_ALGORITHM_SHA256));
459
460 return *sig;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700461}
462
463shared_ptr<IdentityCertificate>
464KeyChain::selfSign(const Name& keyName)
465{
466 shared_ptr<PublicKey> pubKey;
467 try
468 {
469 pubKey = m_pib->getPublicKey(keyName); // may throw an exception.
470 }
471 catch (SecPublicInfo::Error& e)
472 {
473 return shared_ptr<IdentityCertificate>();
474 }
475
476 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
477
478 Name certificateName = keyName.getPrefix(-1);
479 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
480
481 certificate->setName(certificateName);
482 certificate->setNotBefore(time::system_clock::now());
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700483 certificate->setNotAfter(time::system_clock::now() + time::days(7300)); // ~20 years
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700484 certificate->setPublicKeyInfo(*pubKey);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700485 certificate->addSubjectDescription(CertificateSubjectDescription(oid::ATTRIBUTE_NAME,
486 keyName.toUri()));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700487 certificate->encode();
488
489 selfSign(*certificate);
490 return certificate;
491}
492
493void
494KeyChain::selfSign(IdentityCertificate& cert)
495{
496 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(cert.getName());
497 if (!m_tpm->doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700498 throw SecTpm::Error("Private key does not exist");
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700499
Yingdi Yu4a557052014-07-09 16:40:37 -0700500
501 KeyLocator keyLocator(cert.getName().getPrefix(-1));
502 shared_ptr<Signature> sig =
503 determineSignatureWithPublicKey(keyLocator, cert.getPublicKeyInfo().getKeyType());
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700504
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700505 if (!static_cast<bool>(sig))
506 throw SecTpm::Error("unknown key type");
507
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700508 signPacketWrapper(cert, *sig, keyName, DIGEST_ALGORITHM_SHA256);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700509}
510
511shared_ptr<SecuredBag>
512KeyChain::exportIdentity(const Name& identity, const std::string& passwordStr)
513{
514 if (!m_pib->doesIdentityExist(identity))
Yingdi Yu7036ce22014-06-19 18:53:37 -0700515 throw SecPublicInfo::Error("Identity does not exist");
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700516
517 Name keyName = m_pib->getDefaultKeyNameForIdentity(identity);
518
519 ConstBufferPtr pkcs5;
520 try
521 {
522 pkcs5 = m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, passwordStr);
523 }
524 catch (SecTpm::Error& e)
525 {
526 throw SecPublicInfo::Error("Fail to export PKCS5 of private key");
527 }
528
529 shared_ptr<IdentityCertificate> cert;
530 try
531 {
532 cert = m_pib->getCertificate(m_pib->getDefaultCertificateNameForKey(keyName));
533 }
534 catch (SecPublicInfo::Error& e)
535 {
536 cert = selfSign(keyName);
537 m_pib->addCertificateAsIdentityDefault(*cert);
538 }
539
Alexander Afanasyevb67090a2014-04-29 22:31:01 -0700540 // make_shared on OSX 10.9 has some strange problem here
541 shared_ptr<SecuredBag> secureBag(new SecuredBag(*cert, pkcs5));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700542
543 return secureBag;
544}
545
546void
547KeyChain::importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
548{
549 Name certificateName = securedBag.getCertificate().getName();
550 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
551 Name identity = keyName.getPrefix(-1);
552
553 // Add identity
554 m_pib->addIdentity(identity);
555
556 // Add key
557 m_tpm->importPrivateKeyPkcs5IntoTpm(keyName,
558 securedBag.getKey()->buf(),
559 securedBag.getKey()->size(),
560 passwordStr);
561
562 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
563 // HACK! We should set key type according to the pkcs8 info.
Yingdi Yu41546342014-11-30 23:37:53 -0800564 m_pib->addKey(keyName, *pubKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700565 m_pib->setDefaultKeyNameForIdentity(keyName);
566
567 // Add cert
568 m_pib->addCertificateAsIdentityDefault(securedBag.getCertificate());
569}
570
Yingdi Yu4a557052014-07-09 16:40:37 -0700571shared_ptr<Signature>
572KeyChain::determineSignatureWithPublicKey(const KeyLocator& keyLocator,
573 KeyType keyType, DigestAlgorithm digestAlgorithm)
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700574{
575 switch (keyType)
576 {
577 case KEY_TYPE_RSA:
578 {
579 // For temporary usage, we support SHA256 only, but will support more.
580 if (digestAlgorithm != DIGEST_ALGORITHM_SHA256)
Yingdi Yu4a557052014-07-09 16:40:37 -0700581 return shared_ptr<Signature>();
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700582
Yingdi Yu4a557052014-07-09 16:40:37 -0700583 return make_shared<SignatureSha256WithRsa>(keyLocator);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700584 }
585 case KEY_TYPE_ECDSA:
586 {
587 // For temporary usage, we support SHA256 only, but will support more.
588 if (digestAlgorithm != DIGEST_ALGORITHM_SHA256)
Yingdi Yu4a557052014-07-09 16:40:37 -0700589 return shared_ptr<Signature>();
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700590
Yingdi Yu4a557052014-07-09 16:40:37 -0700591 return make_shared<SignatureSha256WithEcdsa>(keyLocator);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700592 }
593 default:
Yingdi Yu4a557052014-07-09 16:40:37 -0700594 return shared_ptr<Signature>();
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700595 }
596}
597
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700598void
599KeyChain::setDefaultCertificateInternal()
600{
601 m_pib->refreshDefaultCertificate();
602
Alexander Afanasyevaab79662014-07-07 17:35:34 -0700603 if (!static_cast<bool>(m_pib->getDefaultCertificate()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700604 {
605 Name defaultIdentity;
606 try
607 {
608 defaultIdentity = m_pib->getDefaultIdentity();
609 }
610 catch (SecPublicInfo::Error& e)
611 {
612 uint32_t random = random::generateWord32();
613 defaultIdentity.append("tmp-identity")
614 .append(reinterpret_cast<uint8_t*>(&random), 4);
615 }
616 createIdentity(defaultIdentity);
617 m_pib->setDefaultIdentity(defaultIdentity);
618 m_pib->refreshDefaultCertificate();
619 }
620}
621
Yingdi Yu7036ce22014-06-19 18:53:37 -0700622Name
623KeyChain::generateKeyPair(const Name& identityName, bool isKsk, const KeyParams& params)
624{
625 Name keyName = m_pib->getNewKeyName(identityName, isKsk);
626
627 m_tpm->generateKeyPairInTpm(keyName.toUri(), params);
628
629 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
630 m_pib->addKey(keyName, *pubKey);
631
632 return keyName;
633}
634
635void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700636KeyChain::signPacketWrapper(Data& data, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700637 const Name& keyName, DigestAlgorithm digestAlgorithm)
638{
639 data.setSignature(signature);
640
641 EncodingBuffer encoder;
642 data.wireEncode(encoder, true);
643
644 Block signatureValue = m_tpm->signInTpm(encoder.buf(), encoder.size(),
645 keyName, digestAlgorithm);
646 data.wireEncode(encoder, signatureValue);
647}
648
649void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700650KeyChain::signPacketWrapper(Interest& interest, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700651 const Name& keyName, DigestAlgorithm digestAlgorithm)
652{
653 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
654 if (timestamp <= m_lastTimestamp)
655 {
656 timestamp = m_lastTimestamp + time::milliseconds(1);
657 }
658
659 Name signedName = interest.getName();
660 signedName
661 .append(name::Component::fromNumber(timestamp.count())) // timestamp
662 .append(name::Component::fromNumber(random::generateWord64())) // nonce
663 .append(signature.getInfo()); // signatureInfo
664
665 Block sigValue = m_tpm->signInTpm(signedName.wireEncode().value(),
666 signedName.wireEncode().value_size(),
667 keyName,
668 digestAlgorithm);
669 sigValue.encode();
670 signedName.append(sigValue); // signatureValue
671 interest.setName(signedName);
672}
673
674Signature
675KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
676{
677 Name signingCertificateName;
678 try
679 {
680 signingCertificateName = m_pib->getDefaultCertificateNameForIdentity(identityName);
681 }
682 catch (SecPublicInfo::Error& e)
683 {
684 signingCertificateName = createIdentity(identityName);
685 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which
686 // is a fatal error.
687 }
688
689 // We either get or create the signing certificate, sign data! (no exception unless fatal error
690 // in TPM)
691 return sign(buffer, bufferLength, signingCertificateName);
692}
693
694void
695KeyChain::signWithSha256(Data& data)
696{
697 DigestSha256 sig;
698 data.setSignature(sig);
699
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600700 Block sigValue(tlv::SignatureValue,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700701 crypto::sha256(data.wireEncode().value(),
702 data.wireEncode().value_size() -
703 data.getSignature().getValue().size()));
704 data.setSignatureValue(sigValue);
705}
706
707void
Yingdi Yu6ab67812014-11-27 15:00:34 -0800708KeyChain::signWithSha256(Interest& interest)
709{
710 DigestSha256 sig;
711
712 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
713 if (timestamp <= m_lastTimestamp)
714 timestamp = m_lastTimestamp + time::milliseconds(1);
715
716 Name signedName = interest.getName();
717 signedName
718 .append(name::Component::fromNumber(timestamp.count())) // timestamp
719 .append(name::Component::fromNumber(random::generateWord64())) // nonce
720 .append(sig.getInfo()); // signatureInfo
721
722 Block sigValue(tlv::SignatureValue,
723 crypto::sha256(signedName.wireEncode().value(),
724 signedName.wireEncode().value_size()));
725
726 sigValue.encode();
727 signedName.append(sigValue); // signatureValue
728 interest.setName(signedName);
729}
730
731void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700732KeyChain::deleteCertificate(const Name& certificateName)
733{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700734 m_pib->deleteCertificateInfo(certificateName);
735}
736
737void
738KeyChain::deleteKey(const Name& keyName)
739{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700740 m_pib->deletePublicKeyInfo(keyName);
741 m_tpm->deleteKeyPairInTpm(keyName);
742}
743
744void
745KeyChain::deleteIdentity(const Name& identity)
746{
Yingdi Yu6147ef42014-12-08 17:48:32 -0800747 std::vector<Name> keyNames;
748 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, true);
749 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, false);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700750
751 m_pib->deleteIdentityInfo(identity);
752
Yingdi Yu6147ef42014-12-08 17:48:32 -0800753 for (const auto& keyName : keyNames)
754 m_tpm->deleteKeyPairInTpm(keyName);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700755}
756
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700757}