blob: c1c605a1a44c5b9122355cbc86489d167e71ed94 [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/**
José Quevedo641de4c2016-01-29 00:11:24 +00003 * Copyright (c) 2013-2016 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"
José Quevedo641de4c2016-01-29 00:11:24 +000025#include "signing-helpers.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070026
Alexander Afanasyev07113802015-01-15 19:14:36 -080027#include "../util/random.hpp"
28#include "../util/config-file.hpp"
29
Yingdi Yuf56c68f2014-04-24 21:50:13 -070030#include "sec-public-info-sqlite3.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070031
32#ifdef NDN_CXX_HAVE_OSX_SECURITY
33#include "sec-tpm-osx.hpp"
Alexander Afanasyev07113802015-01-15 19:14:36 -080034#endif // NDN_CXX_HAVE_OSX_SECURITY
Yingdi Yuf56c68f2014-04-24 21:50:13 -070035
Alexander Afanasyev07113802015-01-15 19:14:36 -080036#include "sec-tpm-file.hpp"
Yingdi Yuf56c68f2014-04-24 21:50:13 -070037
38namespace ndn {
Yingdi Yu1b0311c2015-06-10 14:58:47 -070039namespace security {
Yingdi Yuf56c68f2014-04-24 21:50:13 -070040
Yingdi Yu0eb5d722014-06-10 15:06:25 -070041// Use a GUID as a magic number of KeyChain::DEFAULT_PREFIX identifier
42const Name KeyChain::DEFAULT_PREFIX("/723821fd-f534-44b3-80d9-44bf5f58bbbb");
Yingdi Yu1b0311c2015-06-10 14:58:47 -070043const Name KeyChain::DIGEST_SHA256_IDENTITY("/localhost/identity/digest-sha256");
44
45// Note: cannot use default constructor, as it depends on static variables which may or may not be
46// initialized at this point
47const SigningInfo KeyChain::DEFAULT_SIGNING_INFO(SigningInfo::SIGNER_TYPE_NULL, Name(), SignatureInfo());
Yingdi Yu0eb5d722014-06-10 15:06:25 -070048
Yingdi Yu7036ce22014-06-19 18:53:37 -070049const RsaKeyParams KeyChain::DEFAULT_KEY_PARAMS;
50
Alexander Afanasyev07113802015-01-15 19:14:36 -080051const std::string DEFAULT_PIB_SCHEME = "pib-sqlite3";
52
53#if defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
54const std::string DEFAULT_TPM_SCHEME = "tpm-osxkeychain";
55#else
56const std::string DEFAULT_TPM_SCHEME = "tpm-file";
57#endif // defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
58
59// When static library is used, not everything is compiled into the resulting binary.
60// Therefore, the following standard PIB and TPMs need to be registered here.
61// http://stackoverflow.com/q/9459980/2150331
62//
63// Also, cannot use Type::SCHEME, as its value may be uninitialized
64NDN_CXX_KEYCHAIN_REGISTER_PIB(SecPublicInfoSqlite3, "pib-sqlite3", "sqlite3");
65
66#ifdef NDN_CXX_HAVE_OSX_SECURITY
67NDN_CXX_KEYCHAIN_REGISTER_TPM(SecTpmOsx, "tpm-osxkeychain", "osx-keychain");
68#endif // NDN_CXX_HAVE_OSX_SECURITY
69
70NDN_CXX_KEYCHAIN_REGISTER_TPM(SecTpmFile, "tpm-file", "file");
71
Alexander Afanasyev34a37632015-01-16 17:37:36 -080072template<class T>
73struct Factory
74{
75 Factory(const std::string& canonicalName, const T& create)
76 : canonicalName(canonicalName)
77 , create(create)
78 {
79 }
80
81 std::string canonicalName;
82 T create;
83};
84typedef Factory<KeyChain::PibCreateFunc> PibFactory;
85typedef Factory<KeyChain::TpmCreateFunc> TpmFactory;
86
87static std::map<std::string, PibFactory>&
Alexander Afanasyev07113802015-01-15 19:14:36 -080088getPibFactories()
89{
Alexander Afanasyev34a37632015-01-16 17:37:36 -080090 static std::map<std::string, PibFactory> pibFactories;
Alexander Afanasyev07113802015-01-15 19:14:36 -080091 return pibFactories;
92}
93
Alexander Afanasyev34a37632015-01-16 17:37:36 -080094static std::map<std::string, TpmFactory>&
Alexander Afanasyev07113802015-01-15 19:14:36 -080095getTpmFactories()
96{
Alexander Afanasyev34a37632015-01-16 17:37:36 -080097 static std::map<std::string, TpmFactory> tpmFactories;
Alexander Afanasyev07113802015-01-15 19:14:36 -080098 return tpmFactories;
99}
100
101void
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800102KeyChain::registerPibImpl(const std::string& canonicalName,
103 std::initializer_list<std::string> aliases,
Alexander Afanasyev07113802015-01-15 19:14:36 -0800104 KeyChain::PibCreateFunc createFunc)
105{
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800106 for (const std::string& alias : aliases) {
107 getPibFactories().insert(make_pair(alias, PibFactory(canonicalName, createFunc)));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800108 }
109}
110
111void
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800112KeyChain::registerTpmImpl(const std::string& canonicalName,
113 std::initializer_list<std::string> aliases,
Alexander Afanasyev07113802015-01-15 19:14:36 -0800114 KeyChain::TpmCreateFunc createFunc)
115{
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800116 for (const std::string& alias : aliases) {
117 getTpmFactories().insert(make_pair(alias, TpmFactory(canonicalName, createFunc)));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800118 }
119}
120
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700121KeyChain::KeyChain()
Yingdi Yu41546342014-11-30 23:37:53 -0800122 : m_pib(nullptr)
123 , m_tpm(nullptr)
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700124 , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700125{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800126 ConfigFile config;
127 const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700128
Alexander Afanasyev07113802015-01-15 19:14:36 -0800129 std::string pibLocator = parsed.get<std::string>("pib", "");
130 std::string tpmLocator = parsed.get<std::string>("tpm", "");
131
132 initialize(pibLocator, tpmLocator, false);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700133}
134
135KeyChain::KeyChain(const std::string& pibName,
Yingdi Yu41546342014-11-30 23:37:53 -0800136 const std::string& tpmName,
137 bool allowReset)
138 : m_pib(nullptr)
139 , m_tpm(nullptr)
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700140 , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700141{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800142 initialize(pibName, tpmName, allowReset);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700143}
144
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700145KeyChain::~KeyChain()
146{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800147}
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700148
Alexander Afanasyev07113802015-01-15 19:14:36 -0800149static inline std::tuple<std::string/*type*/, std::string/*location*/>
150parseUri(const std::string& uri)
151{
152 size_t pos = uri.find(':');
153 if (pos != std::string::npos) {
154 return std::make_tuple(uri.substr(0, pos),
155 uri.substr(pos + 1));
156 }
157 else {
158 return std::make_tuple(uri, "");
159 }
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700160}
161
Yingdi Yu281689a2015-06-13 14:32:32 -0700162std::string
163KeyChain::getDefaultPibLocator()
Yingdi Yu41546342014-11-30 23:37:53 -0800164{
Yingdi Yu281689a2015-06-13 14:32:32 -0700165 std::string defaultPibLocator = DEFAULT_PIB_SCHEME + ":";
166 return defaultPibLocator;
167}
Yingdi Yu41546342014-11-30 23:37:53 -0800168
Yingdi Yu281689a2015-06-13 14:32:32 -0700169static inline std::tuple<std::string/*type*/, std::string/*location*/>
170getCanonicalPibLocator(const std::string& pibLocator)
171{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800172 std::string pibScheme, pibLocation;
Yingdi Yu281689a2015-06-13 14:32:32 -0700173 std::tie(pibScheme, pibLocation) = parseUri(pibLocator);
Alexander Afanasyev07113802015-01-15 19:14:36 -0800174
Alexander Afanasyev07113802015-01-15 19:14:36 -0800175 if (pibScheme.empty()) {
176 pibScheme = DEFAULT_PIB_SCHEME;
177 }
Yingdi Yu281689a2015-06-13 14:32:32 -0700178
Alexander Afanasyev07113802015-01-15 19:14:36 -0800179 auto pibFactory = getPibFactories().find(pibScheme);
180 if (pibFactory == getPibFactories().end()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700181 BOOST_THROW_EXCEPTION(KeyChain::Error("PIB scheme '" + pibScheme + "' is not supported"));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800182 }
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800183 pibScheme = pibFactory->second.canonicalName;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800184
Yingdi Yu281689a2015-06-13 14:32:32 -0700185 return std::make_tuple(pibScheme, pibLocation);
186}
187
188unique_ptr<SecPublicInfo>
189KeyChain::createPib(const std::string& pibLocator)
190{
191 BOOST_ASSERT(!getPibFactories().empty());
192
193 std::string pibScheme, pibLocation;
194 std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator);
195 auto pibFactory = getPibFactories().find(pibScheme);
196 BOOST_ASSERT(pibFactory != getPibFactories().end());
197 return pibFactory->second.create(pibLocation);
198}
199
200std::string
201KeyChain::getDefaultTpmLocator()
202{
203 std::string defaultTpmLocator = DEFAULT_TPM_SCHEME + ":";
204 return defaultTpmLocator;
205}
206
207static inline std::tuple<std::string/*type*/, std::string/*location*/>
208getCanonicalTpmLocator(const std::string& tpmLocator)
209{
210 std::string tpmScheme, tpmLocation;
211 std::tie(tpmScheme, tpmLocation) = parseUri(tpmLocator);
212
Alexander Afanasyev07113802015-01-15 19:14:36 -0800213 if (tpmScheme.empty()) {
214 tpmScheme = DEFAULT_TPM_SCHEME;
215 }
216 auto tpmFactory = getTpmFactories().find(tpmScheme);
217 if (tpmFactory == getTpmFactories().end()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700218 BOOST_THROW_EXCEPTION(KeyChain::Error("TPM scheme '" + tpmScheme + "' is not supported"));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800219 }
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800220 tpmScheme = tpmFactory->second.canonicalName;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800221
Yingdi Yu281689a2015-06-13 14:32:32 -0700222 return std::make_tuple(tpmScheme, tpmLocation);
223}
Alexander Afanasyev07113802015-01-15 19:14:36 -0800224
Yingdi Yu281689a2015-06-13 14:32:32 -0700225unique_ptr<SecTpm>
226KeyChain::createTpm(const std::string& tpmLocator)
227{
228 BOOST_ASSERT(!getTpmFactories().empty());
229
230 std::string tpmScheme, tpmLocation;
231 std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator);
232 auto tpmFactory = getTpmFactories().find(tpmScheme);
233 BOOST_ASSERT(tpmFactory != getTpmFactories().end());
234 return tpmFactory->second.create(tpmLocation);
235}
236
237void
238KeyChain::initialize(const std::string& pibLocator,
239 const std::string& tpmLocator,
240 bool allowReset)
241{
242 // PIB Locator
243 std::string pibScheme, pibLocation;
244 std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator);
245 std::string canonicalPibLocator = pibScheme + ":" + pibLocation;
246
247 // Create PIB
248 m_pib = createPib(canonicalPibLocator);
249
250 // TPM Locator
251 std::string tpmScheme, tpmLocation;
252 std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator);
253 std::string canonicalTpmLocator = tpmScheme + ":" + tpmLocation;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800254
255 // Create TPM, checking that it matches to the previously associated one
Yingdi Yu41546342014-11-30 23:37:53 -0800256 try {
Alexander Afanasyev07113802015-01-15 19:14:36 -0800257 if (!allowReset &&
Yingdi Yu281689a2015-06-13 14:32:32 -0700258 !m_pib->getTpmLocator().empty() && m_pib->getTpmLocator() != canonicalTpmLocator)
Alexander Afanasyev07113802015-01-15 19:14:36 -0800259 // Tpm mismatch, but we do not want to reset PIB
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700260 BOOST_THROW_EXCEPTION(MismatchError("TPM locator supplied does not match TPM locator in PIB: "
261 + m_pib->getTpmLocator() + " != " + canonicalTpmLocator));
Yingdi Yu41546342014-11-30 23:37:53 -0800262 }
José Quevedo641de4c2016-01-29 00:11:24 +0000263 catch (const SecPublicInfo::Error&) {
Yingdi Yu41546342014-11-30 23:37:53 -0800264 // TPM locator is not set in PIB yet.
265 }
266
Alexander Afanasyev07113802015-01-15 19:14:36 -0800267 // note that key mismatch may still happen if the TPM locator is initially set to a
268 // wrong one or if the PIB was shared by more than one TPMs before. This is due to the
269 // old PIB does not have TPM info, new pib should not have this problem.
Yingdi Yu281689a2015-06-13 14:32:32 -0700270 m_tpm = createTpm(canonicalTpmLocator);
271 m_pib->setTpmLocator(canonicalTpmLocator);
Yingdi Yu41546342014-11-30 23:37:53 -0800272}
273
Yingdi Yu7036ce22014-06-19 18:53:37 -0700274Name
275KeyChain::createIdentity(const Name& identityName, const KeyParams& params)
276{
277 m_pib->addIdentity(identityName);
278
279 Name keyName;
José Quevedo641de4c2016-01-29 00:11:24 +0000280 try {
281 keyName = m_pib->getDefaultKeyNameForIdentity(identityName);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700282
José Quevedo641de4c2016-01-29 00:11:24 +0000283 shared_ptr<PublicKey> key = m_pib->getPublicKey(keyName);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700284
José Quevedo641de4c2016-01-29 00:11:24 +0000285 if (key->getKeyType() != params.getKeyType()) {
Yingdi Yu7036ce22014-06-19 18:53:37 -0700286 keyName = generateKeyPair(identityName, true, params);
287 m_pib->setDefaultKeyNameForIdentity(keyName);
288 }
José Quevedo641de4c2016-01-29 00:11:24 +0000289 }
290 catch (const SecPublicInfo::Error& e) {
291 keyName = generateKeyPair(identityName, true, params);
292 m_pib->setDefaultKeyNameForIdentity(keyName);
293 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700294
295 Name certName;
José Quevedo641de4c2016-01-29 00:11:24 +0000296 try {
297 certName = m_pib->getDefaultCertificateNameForKey(keyName);
298 }
299 catch (const SecPublicInfo::Error& e) {
300 shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
301 m_pib->addCertificateAsIdentityDefault(*selfCert);
302 certName = selfCert->getName();
303 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700304
305 return certName;
306}
307
308Name
Yingdi Yu41546342014-11-30 23:37:53 -0800309KeyChain::generateRsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
310{
311 RsaKeyParams params(keySize);
312 return generateKeyPair(identityName, isKsk, params);
313}
314
315Name
316KeyChain::generateEcdsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
317{
318 EcdsaKeyParams params(keySize);
319 return generateKeyPair(identityName, isKsk, params);
320}
321
322Name
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700323KeyChain::generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
Yingdi Yu7036ce22014-06-19 18:53:37 -0700324{
325 RsaKeyParams params(keySize);
326
327 Name keyName = generateKeyPair(identityName, isKsk, params);
328
329 m_pib->setDefaultKeyNameForIdentity(keyName);
330
331 return keyName;
332}
333
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700334Name
335KeyChain::generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
336{
337 EcdsaKeyParams params(keySize);
338
339 Name keyName = generateKeyPair(identityName, isKsk, params);
340
341 m_pib->setDefaultKeyNameForIdentity(keyName);
342
343 return keyName;
344}
345
346
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700347shared_ptr<IdentityCertificate>
348KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
349 const Name& signingIdentity,
350 const time::system_clock::TimePoint& notBefore,
351 const time::system_clock::TimePoint& notAfter,
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700352 const std::vector<CertificateSubjectDescription>& subjectDescription,
353 const Name& certPrefix)
354{
355 shared_ptr<PublicKey> publicKey;
José Quevedo641de4c2016-01-29 00:11:24 +0000356 try {
357 publicKey = m_pib->getPublicKey(keyName);
358 }
359 catch (const SecPublicInfo::Error& e) {
360 return nullptr;
361 }
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700362
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)
José Quevedo641de4c2016-01-29 00:11:24 +0000378 return nullptr;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700379
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-")
José Quevedo641de4c2016-01-29 00:11:24 +0000382 return nullptr;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700383
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700384 Name certName;
385
José Quevedo641de4c2016-01-29 00:11:24 +0000386 if (certPrefix == KeyChain::DEFAULT_PREFIX) {
387 // No certificate prefix hint, infer the prefix
388 if (signingIdentity.isPrefixOf(keyName))
389 certName.append(signingIdentity)
390 .append("KEY")
391 .append(keyName.getSubName(signingIdentity.size()))
392 .append("ID-CERT")
393 .appendVersion();
394 else
395 certName.append(keyName.getPrefix(-1))
396 .append("KEY")
397 .append(keyName.get(-1))
398 .append("ID-CERT")
399 .appendVersion();
400 }
401 else {
402 // cert prefix hint is supplied, determine the cert name.
403 if (certPrefix.isPrefixOf(keyName) && certPrefix != keyName)
404 certName.append(certPrefix)
405 .append("KEY")
406 .append(keyName.getSubName(certPrefix.size()))
407 .append("ID-CERT")
408 .appendVersion();
409 else
410 return nullptr;
411 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700412
José Quevedo641de4c2016-01-29 00:11:24 +0000413 auto certificate = make_shared<IdentityCertificate>();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700414 certificate->setName(certName);
415 certificate->setNotBefore(notBefore);
416 certificate->setNotAfter(notAfter);
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700417 certificate->setPublicKeyInfo(publicKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700418
José Quevedo641de4c2016-01-29 00:11:24 +0000419 if (subjectDescription.empty()) {
420 CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri());
421 certificate->addSubjectDescription(subjectName);
422 }
423 else {
424 std::vector<CertificateSubjectDescription>::const_iterator sdIt =
425 subjectDescription.begin();
426 std::vector<CertificateSubjectDescription>::const_iterator sdEnd =
427 subjectDescription.end();
428 for(; sdIt != sdEnd; sdIt++)
429 certificate->addSubjectDescription(*sdIt);
430 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700431
432 certificate->encode();
433
434 return certificate;
435}
436
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700437std::tuple<Name, SignatureInfo>
438KeyChain::prepareSignatureInfo(const SigningInfo& params)
439{
440 SignatureInfo sigInfo = params.getSignatureInfo();
441
442 shared_ptr<IdentityCertificate> signingCert;
443
444 switch (params.getSignerType()) {
José Quevedo641de4c2016-01-29 00:11:24 +0000445 case SigningInfo::SIGNER_TYPE_NULL: {
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700446 if (m_pib->getDefaultCertificate() == nullptr)
447 setDefaultCertificateInternal();
448
449 signingCert = m_pib->getDefaultCertificate();
450 break;
451 }
José Quevedo641de4c2016-01-29 00:11:24 +0000452 case SigningInfo::SIGNER_TYPE_ID: {
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700453 Name signingCertName;
454 try {
455 signingCertName = m_pib->getDefaultCertificateNameForIdentity(params.getSignerName());
456 }
José Quevedo641de4c2016-01-29 00:11:24 +0000457 catch (const SecPublicInfo::Error&) {
458 signingCertName = createIdentity(params.getSignerName(), getDefaultKeyParamsForIdentity(params.getSignerName()));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700459 }
460
461 signingCert = m_pib->getCertificate(signingCertName);
462
463 break;
464 }
José Quevedo641de4c2016-01-29 00:11:24 +0000465 case SigningInfo::SIGNER_TYPE_KEY: {
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700466 Name signingCertName;
467 try {
468 signingCertName = m_pib->getDefaultCertificateNameForKey(params.getSignerName());
469 }
José Quevedo641de4c2016-01-29 00:11:24 +0000470 catch (const SecPublicInfo::Error&) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700471 BOOST_THROW_EXCEPTION(Error("signing certificate does not exist"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700472 }
473
474 signingCert = m_pib->getCertificate(signingCertName);
475
476 break;
477 }
José Quevedo641de4c2016-01-29 00:11:24 +0000478 case SigningInfo::SIGNER_TYPE_CERT: {
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700479 signingCert = m_pib->getCertificate(params.getSignerName());
480 if (signingCert == nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700481 BOOST_THROW_EXCEPTION(Error("signing certificate does not exist"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700482
483 break;
484 }
José Quevedo641de4c2016-01-29 00:11:24 +0000485 case SigningInfo::SIGNER_TYPE_SHA256: {
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700486 sigInfo.setSignatureType(tlv::DigestSha256);
487 return std::make_tuple(DIGEST_SHA256_IDENTITY, sigInfo);
488 }
José Quevedo641de4c2016-01-29 00:11:24 +0000489 default:
490 BOOST_THROW_EXCEPTION(Error("Unrecognized signer type"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700491 }
492
493 sigInfo.setSignatureType(getSignatureType(signingCert->getPublicKeyInfo().getKeyType(),
494 params.getDigestAlgorithm()));
495 sigInfo.setKeyLocator(KeyLocator(signingCert->getName().getPrefix(-1)));
496
497 return std::make_tuple(signingCert->getPublicKeyName(), sigInfo);
498}
499
500void
501KeyChain::sign(Data& data, const SigningInfo& params)
502{
503 signImpl(data, params);
504}
505
506void
507KeyChain::sign(Interest& interest, const SigningInfo& params)
508{
509 signImpl(interest, params);
510}
511
512Block
513KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params)
514{
515 Name keyName;
516 SignatureInfo sigInfo;
517 std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
518 return pureSign(buffer, bufferLength, keyName, DIGEST_ALGORITHM_SHA256);
519}
520
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700521Signature
522KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
523{
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700524 shared_ptr<IdentityCertificate> certificate = m_pib->getCertificate(certificateName);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700525
José Quevedo641de4c2016-01-29 00:11:24 +0000526 if (certificate == nullptr) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700527 BOOST_THROW_EXCEPTION(SecPublicInfo::Error("certificate does not exist"));
José Quevedo641de4c2016-01-29 00:11:24 +0000528 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700529
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700530 Signature sig;
Yingdi Yu4a557052014-07-09 16:40:37 -0700531
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700532 // For temporary usage, we support SHA256 only, but will support more.
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700533 sig.setValue(m_tpm->signInTpm(buffer, bufferLength,
534 certificate->getPublicKeyName(),
535 DIGEST_ALGORITHM_SHA256));
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700536
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700537 return sig;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700538}
539
540shared_ptr<IdentityCertificate>
541KeyChain::selfSign(const Name& keyName)
542{
543 shared_ptr<PublicKey> pubKey;
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700544 try {
545 pubKey = m_pib->getPublicKey(keyName); // may throw an exception.
546 }
José Quevedo641de4c2016-01-29 00:11:24 +0000547 catch (const SecPublicInfo::Error&) {
548 return nullptr;
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700549 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700550
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700551 auto certificate = make_shared<IdentityCertificate>();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700552
553 Name certificateName = keyName.getPrefix(-1);
554 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
555
556 certificate->setName(certificateName);
557 certificate->setNotBefore(time::system_clock::now());
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700558 certificate->setNotAfter(time::system_clock::now() + time::days(7300)); // ~20 years
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700559 certificate->setPublicKeyInfo(*pubKey);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700560 certificate->addSubjectDescription(CertificateSubjectDescription(oid::ATTRIBUTE_NAME,
561 keyName.toUri()));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700562 certificate->encode();
563
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700564 certificate->setSignature(Signature(SignatureInfo()));
565
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700566 selfSign(*certificate);
567 return certificate;
568}
569
570void
571KeyChain::selfSign(IdentityCertificate& cert)
572{
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700573 Name keyName = cert.getPublicKeyName();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700574 if (!m_tpm->doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700575 BOOST_THROW_EXCEPTION(SecTpm::Error("Private key does not exist"));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700576
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700577 SignatureInfo sigInfo(cert.getSignature().getInfo());
578 sigInfo.setKeyLocator(KeyLocator(cert.getName().getPrefix(-1)));
579 sigInfo.setSignatureType(getSignatureType(cert.getPublicKeyInfo().getKeyType(),
580 DIGEST_ALGORITHM_SHA256));
Yingdi Yu4a557052014-07-09 16:40:37 -0700581
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700582 signPacketWrapper(cert, Signature(sigInfo), keyName, DIGEST_ALGORITHM_SHA256);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700583}
584
585shared_ptr<SecuredBag>
586KeyChain::exportIdentity(const Name& identity, const std::string& passwordStr)
587{
588 if (!m_pib->doesIdentityExist(identity))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700589 BOOST_THROW_EXCEPTION(SecPublicInfo::Error("Identity does not exist"));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700590
591 Name keyName = m_pib->getDefaultKeyNameForIdentity(identity);
592
593 ConstBufferPtr pkcs5;
José Quevedo641de4c2016-01-29 00:11:24 +0000594 try {
595 pkcs5 = m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, passwordStr);
596 }
597 catch (const SecTpm::Error& e) {
598 BOOST_THROW_EXCEPTION(SecPublicInfo::Error("Fail to export PKCS5 of private key"));
599 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700600
601 shared_ptr<IdentityCertificate> cert;
José Quevedo641de4c2016-01-29 00:11:24 +0000602 try {
603 cert = m_pib->getCertificate(m_pib->getDefaultCertificateNameForKey(keyName));
604 }
605 catch (const SecPublicInfo::Error& e) {
606 cert = selfSign(keyName);
607 m_pib->addCertificateAsIdentityDefault(*cert);
608 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700609
Alexander Afanasyevb67090a2014-04-29 22:31:01 -0700610 // make_shared on OSX 10.9 has some strange problem here
José Quevedo641de4c2016-01-29 00:11:24 +0000611 return shared_ptr<SecuredBag>(new SecuredBag(*cert, pkcs5));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700612}
613
614void
615KeyChain::importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
616{
617 Name certificateName = securedBag.getCertificate().getName();
618 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
619 Name identity = keyName.getPrefix(-1);
620
621 // Add identity
622 m_pib->addIdentity(identity);
623
624 // Add key
625 m_tpm->importPrivateKeyPkcs5IntoTpm(keyName,
626 securedBag.getKey()->buf(),
627 securedBag.getKey()->size(),
628 passwordStr);
629
630 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
631 // HACK! We should set key type according to the pkcs8 info.
Yingdi Yu41546342014-11-30 23:37:53 -0800632 m_pib->addKey(keyName, *pubKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700633 m_pib->setDefaultKeyNameForIdentity(keyName);
634
635 // Add cert
636 m_pib->addCertificateAsIdentityDefault(securedBag.getCertificate());
637}
638
José Quevedo641de4c2016-01-29 00:11:24 +0000639const KeyParams&
640KeyChain::getDefaultKeyParamsForIdentity(const Name &identityName) const
641{
642 KeyType keyType = KEY_TYPE_NULL;
643 try {
644 keyType = m_pib->getPublicKeyType(m_pib->getDefaultKeyNameForIdentity(identityName));
645 }
646 catch (const SecPublicInfo::Error& e) { // @TODO Switch to Pib::Error
647 return DEFAULT_KEY_PARAMS;
648 }
649
650 switch (keyType) {
651 case KEY_TYPE_RSA: {
652 static RsaKeyParams defaultRsaParams;
653 return defaultRsaParams;
654 }
655 case KEY_TYPE_ECDSA: {
656 static EcdsaKeyParams defaultEcdsaParams;
657 return defaultEcdsaParams;
658 }
659 case KEY_TYPE_NULL: {
660 return DEFAULT_KEY_PARAMS;
661 }
662 default:
663 BOOST_THROW_EXCEPTION(Error("Unsupported key type"));
664 }
665}
666
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700667void
668KeyChain::setDefaultCertificateInternal()
669{
670 m_pib->refreshDefaultCertificate();
671
José Quevedo641de4c2016-01-29 00:11:24 +0000672 if (m_pib->getDefaultCertificate() == nullptr) {
673 Name defaultIdentity;
674 try {
675 defaultIdentity = m_pib->getDefaultIdentity();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700676 }
José Quevedo641de4c2016-01-29 00:11:24 +0000677 catch (const SecPublicInfo::Error& e) {
678 uint32_t random = random::generateWord32();
679 defaultIdentity.append("tmp-identity")
680 .append(reinterpret_cast<uint8_t*>(&random), 4);
681 }
682 createIdentity(defaultIdentity);
683 m_pib->setDefaultIdentity(defaultIdentity);
684 m_pib->refreshDefaultCertificate();
685 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700686}
687
Yingdi Yu7036ce22014-06-19 18:53:37 -0700688Name
689KeyChain::generateKeyPair(const Name& identityName, bool isKsk, const KeyParams& params)
690{
691 Name keyName = m_pib->getNewKeyName(identityName, isKsk);
692
693 m_tpm->generateKeyPairInTpm(keyName.toUri(), params);
694
695 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
696 m_pib->addKey(keyName, *pubKey);
697
698 return keyName;
699}
700
701void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700702KeyChain::signPacketWrapper(Data& data, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700703 const Name& keyName, DigestAlgorithm digestAlgorithm)
704{
705 data.setSignature(signature);
706
707 EncodingBuffer encoder;
708 data.wireEncode(encoder, true);
709
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700710 Block sigValue = pureSign(encoder.buf(), encoder.size(), keyName, digestAlgorithm);
711
712 data.wireEncode(encoder, sigValue);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700713}
714
715void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700716KeyChain::signPacketWrapper(Interest& interest, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700717 const Name& keyName, DigestAlgorithm digestAlgorithm)
718{
719 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
José Quevedo641de4c2016-01-29 00:11:24 +0000720 if (timestamp <= m_lastTimestamp) {
721 timestamp = m_lastTimestamp + time::milliseconds(1);
722 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700723
724 Name signedName = interest.getName();
725 signedName
726 .append(name::Component::fromNumber(timestamp.count())) // timestamp
727 .append(name::Component::fromNumber(random::generateWord64())) // nonce
728 .append(signature.getInfo()); // signatureInfo
729
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700730 Block sigValue = pureSign(signedName.wireEncode().value(),
731 signedName.wireEncode().value_size(),
732 keyName,
733 digestAlgorithm);
734
Yingdi Yu7036ce22014-06-19 18:53:37 -0700735 sigValue.encode();
736 signedName.append(sigValue); // signatureValue
737 interest.setName(signedName);
738}
739
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700740Block
741KeyChain::pureSign(const uint8_t* buf, size_t size,
742 const Name& keyName, DigestAlgorithm digestAlgorithm) const
743{
744 if (keyName == DIGEST_SHA256_IDENTITY)
745 return Block(tlv::SignatureValue, crypto::sha256(buf, size));
746
747 return m_tpm->signInTpm(buf, size, keyName, digestAlgorithm);
748}
749
Yingdi Yu7036ce22014-06-19 18:53:37 -0700750Signature
751KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
752{
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700753 Signature sig;
José Quevedo641de4c2016-01-29 00:11:24 +0000754 sig.setValue(sign(buffer, bufferLength, signingByIdentity(identityName)));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700755 return sig;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700756}
757
758void
759KeyChain::signWithSha256(Data& data)
760{
José Quevedo641de4c2016-01-29 00:11:24 +0000761 return sign(data, signingWithSha256());
Yingdi Yu7036ce22014-06-19 18:53:37 -0700762}
763
764void
Yingdi Yu6ab67812014-11-27 15:00:34 -0800765KeyChain::signWithSha256(Interest& interest)
766{
767 DigestSha256 sig;
768
769 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
770 if (timestamp <= m_lastTimestamp)
771 timestamp = m_lastTimestamp + time::milliseconds(1);
772
773 Name signedName = interest.getName();
774 signedName
775 .append(name::Component::fromNumber(timestamp.count())) // timestamp
776 .append(name::Component::fromNumber(random::generateWord64())) // nonce
777 .append(sig.getInfo()); // signatureInfo
778
779 Block sigValue(tlv::SignatureValue,
780 crypto::sha256(signedName.wireEncode().value(),
781 signedName.wireEncode().value_size()));
782
783 sigValue.encode();
784 signedName.append(sigValue); // signatureValue
785 interest.setName(signedName);
786}
787
788void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700789KeyChain::deleteCertificate(const Name& certificateName)
790{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700791 m_pib->deleteCertificateInfo(certificateName);
792}
793
794void
795KeyChain::deleteKey(const Name& keyName)
796{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700797 m_pib->deletePublicKeyInfo(keyName);
798 m_tpm->deleteKeyPairInTpm(keyName);
799}
800
801void
802KeyChain::deleteIdentity(const Name& identity)
803{
Yingdi Yu6147ef42014-12-08 17:48:32 -0800804 std::vector<Name> keyNames;
805 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, true);
806 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, false);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700807
808 m_pib->deleteIdentityInfo(identity);
809
Yingdi Yu6147ef42014-12-08 17:48:32 -0800810 for (const auto& keyName : keyNames)
811 m_tpm->deleteKeyPairInTpm(keyName);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700812}
813
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700814tlv::SignatureTypeValue
815KeyChain::getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm)
816{
817 switch (keyType) {
818 case KEY_TYPE_RSA:
819 return tlv::SignatureSha256WithRsa;
820 case KEY_TYPE_ECDSA:
821 return tlv::SignatureSha256WithEcdsa;
822 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700823 BOOST_THROW_EXCEPTION(Error("Unsupported key types"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700824 }
825
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700826}
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700827
828} // namespace security
829} // namespace ndn