blob: e6b1ff0ee2faa710286ab445dfa998d34eacbb3e [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 Afanasyev57e00362016-06-23 13:22:54 -0700126 std::string pibLocator;
127 std::string tpmLocator;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700128
Alexander Afanasyev57e00362016-06-23 13:22:54 -0700129 if (getenv("NDN_CLIENT_PIB") != nullptr) {
130 pibLocator = getenv("NDN_CLIENT_PIB");
131 }
132
133 if (getenv("NDN_CLIENT_TPM") != nullptr) {
134 tpmLocator = getenv("NDN_CLIENT_TPM");
135 }
136
137 if (pibLocator.empty() || tpmLocator.empty()) {
138 ConfigFile config;
139 const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
140
141 if (pibLocator.empty()) {
142 pibLocator = parsed.get<std::string>("pib", "");
143 }
144
145 if (tpmLocator.empty()) {
146 tpmLocator = parsed.get<std::string>("tpm", "");
147 }
148 }
Alexander Afanasyev07113802015-01-15 19:14:36 -0800149
150 initialize(pibLocator, tpmLocator, false);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700151}
152
153KeyChain::KeyChain(const std::string& pibName,
Yingdi Yu41546342014-11-30 23:37:53 -0800154 const std::string& tpmName,
155 bool allowReset)
156 : m_pib(nullptr)
157 , m_tpm(nullptr)
Yingdi Yu0f5fb692014-06-10 12:07:28 -0700158 , m_lastTimestamp(time::toUnixTimestamp(time::system_clock::now()))
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700159{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800160 initialize(pibName, tpmName, allowReset);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700161}
162
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700163KeyChain::~KeyChain()
164{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800165}
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700166
Alexander Afanasyev07113802015-01-15 19:14:36 -0800167static inline std::tuple<std::string/*type*/, std::string/*location*/>
168parseUri(const std::string& uri)
169{
170 size_t pos = uri.find(':');
171 if (pos != std::string::npos) {
172 return std::make_tuple(uri.substr(0, pos),
173 uri.substr(pos + 1));
174 }
175 else {
176 return std::make_tuple(uri, "");
177 }
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700178}
179
Yingdi Yu281689a2015-06-13 14:32:32 -0700180std::string
181KeyChain::getDefaultPibLocator()
Yingdi Yu41546342014-11-30 23:37:53 -0800182{
Yingdi Yu281689a2015-06-13 14:32:32 -0700183 std::string defaultPibLocator = DEFAULT_PIB_SCHEME + ":";
184 return defaultPibLocator;
185}
Yingdi Yu41546342014-11-30 23:37:53 -0800186
Yingdi Yu281689a2015-06-13 14:32:32 -0700187static inline std::tuple<std::string/*type*/, std::string/*location*/>
188getCanonicalPibLocator(const std::string& pibLocator)
189{
Alexander Afanasyev07113802015-01-15 19:14:36 -0800190 std::string pibScheme, pibLocation;
Yingdi Yu281689a2015-06-13 14:32:32 -0700191 std::tie(pibScheme, pibLocation) = parseUri(pibLocator);
Alexander Afanasyev07113802015-01-15 19:14:36 -0800192
Alexander Afanasyev07113802015-01-15 19:14:36 -0800193 if (pibScheme.empty()) {
194 pibScheme = DEFAULT_PIB_SCHEME;
195 }
Yingdi Yu281689a2015-06-13 14:32:32 -0700196
Alexander Afanasyev07113802015-01-15 19:14:36 -0800197 auto pibFactory = getPibFactories().find(pibScheme);
198 if (pibFactory == getPibFactories().end()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700199 BOOST_THROW_EXCEPTION(KeyChain::Error("PIB scheme '" + pibScheme + "' is not supported"));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800200 }
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800201 pibScheme = pibFactory->second.canonicalName;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800202
Yingdi Yu281689a2015-06-13 14:32:32 -0700203 return std::make_tuple(pibScheme, pibLocation);
204}
205
206unique_ptr<SecPublicInfo>
207KeyChain::createPib(const std::string& pibLocator)
208{
209 BOOST_ASSERT(!getPibFactories().empty());
210
211 std::string pibScheme, pibLocation;
212 std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator);
213 auto pibFactory = getPibFactories().find(pibScheme);
214 BOOST_ASSERT(pibFactory != getPibFactories().end());
215 return pibFactory->second.create(pibLocation);
216}
217
218std::string
219KeyChain::getDefaultTpmLocator()
220{
221 std::string defaultTpmLocator = DEFAULT_TPM_SCHEME + ":";
222 return defaultTpmLocator;
223}
224
225static inline std::tuple<std::string/*type*/, std::string/*location*/>
226getCanonicalTpmLocator(const std::string& tpmLocator)
227{
228 std::string tpmScheme, tpmLocation;
229 std::tie(tpmScheme, tpmLocation) = parseUri(tpmLocator);
230
Alexander Afanasyev07113802015-01-15 19:14:36 -0800231 if (tpmScheme.empty()) {
232 tpmScheme = DEFAULT_TPM_SCHEME;
233 }
234 auto tpmFactory = getTpmFactories().find(tpmScheme);
235 if (tpmFactory == getTpmFactories().end()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700236 BOOST_THROW_EXCEPTION(KeyChain::Error("TPM scheme '" + tpmScheme + "' is not supported"));
Alexander Afanasyev07113802015-01-15 19:14:36 -0800237 }
Alexander Afanasyev34a37632015-01-16 17:37:36 -0800238 tpmScheme = tpmFactory->second.canonicalName;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800239
Yingdi Yu281689a2015-06-13 14:32:32 -0700240 return std::make_tuple(tpmScheme, tpmLocation);
241}
Alexander Afanasyev07113802015-01-15 19:14:36 -0800242
Yingdi Yu281689a2015-06-13 14:32:32 -0700243unique_ptr<SecTpm>
244KeyChain::createTpm(const std::string& tpmLocator)
245{
246 BOOST_ASSERT(!getTpmFactories().empty());
247
248 std::string tpmScheme, tpmLocation;
249 std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator);
250 auto tpmFactory = getTpmFactories().find(tpmScheme);
251 BOOST_ASSERT(tpmFactory != getTpmFactories().end());
252 return tpmFactory->second.create(tpmLocation);
253}
254
255void
256KeyChain::initialize(const std::string& pibLocator,
257 const std::string& tpmLocator,
258 bool allowReset)
259{
260 // PIB Locator
261 std::string pibScheme, pibLocation;
262 std::tie(pibScheme, pibLocation) = getCanonicalPibLocator(pibLocator);
263 std::string canonicalPibLocator = pibScheme + ":" + pibLocation;
264
265 // Create PIB
266 m_pib = createPib(canonicalPibLocator);
267
268 // TPM Locator
269 std::string tpmScheme, tpmLocation;
270 std::tie(tpmScheme, tpmLocation) = getCanonicalTpmLocator(tpmLocator);
271 std::string canonicalTpmLocator = tpmScheme + ":" + tpmLocation;
Alexander Afanasyev07113802015-01-15 19:14:36 -0800272
273 // Create TPM, checking that it matches to the previously associated one
Yingdi Yu41546342014-11-30 23:37:53 -0800274 try {
Alexander Afanasyev07113802015-01-15 19:14:36 -0800275 if (!allowReset &&
Yingdi Yu281689a2015-06-13 14:32:32 -0700276 !m_pib->getTpmLocator().empty() && m_pib->getTpmLocator() != canonicalTpmLocator)
Alexander Afanasyev07113802015-01-15 19:14:36 -0800277 // Tpm mismatch, but we do not want to reset PIB
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700278 BOOST_THROW_EXCEPTION(MismatchError("TPM locator supplied does not match TPM locator in PIB: "
279 + m_pib->getTpmLocator() + " != " + canonicalTpmLocator));
Yingdi Yu41546342014-11-30 23:37:53 -0800280 }
José Quevedo641de4c2016-01-29 00:11:24 +0000281 catch (const SecPublicInfo::Error&) {
Yingdi Yu41546342014-11-30 23:37:53 -0800282 // TPM locator is not set in PIB yet.
283 }
284
Alexander Afanasyev07113802015-01-15 19:14:36 -0800285 // note that key mismatch may still happen if the TPM locator is initially set to a
286 // wrong one or if the PIB was shared by more than one TPMs before. This is due to the
287 // old PIB does not have TPM info, new pib should not have this problem.
Yingdi Yu281689a2015-06-13 14:32:32 -0700288 m_tpm = createTpm(canonicalTpmLocator);
289 m_pib->setTpmLocator(canonicalTpmLocator);
Yingdi Yu41546342014-11-30 23:37:53 -0800290}
291
Yingdi Yu7036ce22014-06-19 18:53:37 -0700292Name
293KeyChain::createIdentity(const Name& identityName, const KeyParams& params)
294{
295 m_pib->addIdentity(identityName);
296
297 Name keyName;
José Quevedo641de4c2016-01-29 00:11:24 +0000298 try {
299 keyName = m_pib->getDefaultKeyNameForIdentity(identityName);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700300
José Quevedo641de4c2016-01-29 00:11:24 +0000301 shared_ptr<PublicKey> key = m_pib->getPublicKey(keyName);
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700302
José Quevedo641de4c2016-01-29 00:11:24 +0000303 if (key->getKeyType() != params.getKeyType()) {
Yingdi Yu7036ce22014-06-19 18:53:37 -0700304 keyName = generateKeyPair(identityName, true, params);
305 m_pib->setDefaultKeyNameForIdentity(keyName);
306 }
José Quevedo641de4c2016-01-29 00:11:24 +0000307 }
308 catch (const SecPublicInfo::Error& e) {
309 keyName = generateKeyPair(identityName, true, params);
310 m_pib->setDefaultKeyNameForIdentity(keyName);
311 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700312
313 Name certName;
José Quevedo641de4c2016-01-29 00:11:24 +0000314 try {
315 certName = m_pib->getDefaultCertificateNameForKey(keyName);
316 }
317 catch (const SecPublicInfo::Error& e) {
318 shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
319 m_pib->addCertificateAsIdentityDefault(*selfCert);
320 certName = selfCert->getName();
321 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700322
323 return certName;
324}
325
326Name
Yingdi Yu41546342014-11-30 23:37:53 -0800327KeyChain::generateRsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
328{
329 RsaKeyParams params(keySize);
330 return generateKeyPair(identityName, isKsk, params);
331}
332
333Name
334KeyChain::generateEcdsaKeyPair(const Name& identityName, bool isKsk, uint32_t keySize)
335{
336 EcdsaKeyParams params(keySize);
337 return generateKeyPair(identityName, isKsk, params);
338}
339
340Name
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700341KeyChain::generateRsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
Yingdi Yu7036ce22014-06-19 18:53:37 -0700342{
343 RsaKeyParams params(keySize);
344
345 Name keyName = generateKeyPair(identityName, isKsk, params);
346
347 m_pib->setDefaultKeyNameForIdentity(keyName);
348
349 return keyName;
350}
351
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700352Name
353KeyChain::generateEcdsaKeyPairAsDefault(const Name& identityName, bool isKsk, uint32_t keySize)
354{
355 EcdsaKeyParams params(keySize);
356
357 Name keyName = generateKeyPair(identityName, isKsk, params);
358
359 m_pib->setDefaultKeyNameForIdentity(keyName);
360
361 return keyName;
362}
363
364
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700365shared_ptr<IdentityCertificate>
366KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
367 const Name& signingIdentity,
368 const time::system_clock::TimePoint& notBefore,
369 const time::system_clock::TimePoint& notAfter,
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700370 const std::vector<CertificateSubjectDescription>& subjectDescription,
371 const Name& certPrefix)
372{
373 shared_ptr<PublicKey> publicKey;
José Quevedo641de4c2016-01-29 00:11:24 +0000374 try {
375 publicKey = m_pib->getPublicKey(keyName);
376 }
377 catch (const SecPublicInfo::Error& e) {
378 return nullptr;
379 }
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700380
381 return prepareUnsignedIdentityCertificate(keyName, *publicKey, signingIdentity,
382 notBefore, notAfter,
383 subjectDescription, certPrefix);
384}
385
386shared_ptr<IdentityCertificate>
387KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
388 const PublicKey& publicKey,
389 const Name& signingIdentity,
390 const time::system_clock::TimePoint& notBefore,
391 const time::system_clock::TimePoint& notAfter,
392 const std::vector<CertificateSubjectDescription>& subjectDescription,
393 const Name& certPrefix)
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700394{
395 if (keyName.size() < 1)
José Quevedo641de4c2016-01-29 00:11:24 +0000396 return nullptr;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700397
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700398 std::string keyIdPrefix = keyName.get(-1).toUri().substr(0, 4);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700399 if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
José Quevedo641de4c2016-01-29 00:11:24 +0000400 return nullptr;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700401
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700402 Name certName;
403
José Quevedo641de4c2016-01-29 00:11:24 +0000404 if (certPrefix == KeyChain::DEFAULT_PREFIX) {
405 // No certificate prefix hint, infer the prefix
406 if (signingIdentity.isPrefixOf(keyName))
407 certName.append(signingIdentity)
408 .append("KEY")
409 .append(keyName.getSubName(signingIdentity.size()))
410 .append("ID-CERT")
411 .appendVersion();
412 else
413 certName.append(keyName.getPrefix(-1))
414 .append("KEY")
415 .append(keyName.get(-1))
416 .append("ID-CERT")
417 .appendVersion();
418 }
419 else {
420 // cert prefix hint is supplied, determine the cert name.
421 if (certPrefix.isPrefixOf(keyName) && certPrefix != keyName)
422 certName.append(certPrefix)
423 .append("KEY")
424 .append(keyName.getSubName(certPrefix.size()))
425 .append("ID-CERT")
426 .appendVersion();
427 else
428 return nullptr;
429 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700430
José Quevedo641de4c2016-01-29 00:11:24 +0000431 auto certificate = make_shared<IdentityCertificate>();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700432 certificate->setName(certName);
433 certificate->setNotBefore(notBefore);
434 certificate->setNotAfter(notAfter);
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700435 certificate->setPublicKeyInfo(publicKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700436
José Quevedo641de4c2016-01-29 00:11:24 +0000437 if (subjectDescription.empty()) {
438 CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri());
439 certificate->addSubjectDescription(subjectName);
440 }
441 else {
442 std::vector<CertificateSubjectDescription>::const_iterator sdIt =
443 subjectDescription.begin();
444 std::vector<CertificateSubjectDescription>::const_iterator sdEnd =
445 subjectDescription.end();
446 for(; sdIt != sdEnd; sdIt++)
447 certificate->addSubjectDescription(*sdIt);
448 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700449
450 certificate->encode();
451
452 return certificate;
453}
454
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700455std::tuple<Name, SignatureInfo>
456KeyChain::prepareSignatureInfo(const SigningInfo& params)
457{
458 SignatureInfo sigInfo = params.getSignatureInfo();
459
460 shared_ptr<IdentityCertificate> signingCert;
461
462 switch (params.getSignerType()) {
José Quevedo641de4c2016-01-29 00:11:24 +0000463 case SigningInfo::SIGNER_TYPE_NULL: {
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700464 if (m_pib->getDefaultCertificate() == nullptr)
465 setDefaultCertificateInternal();
466
467 signingCert = m_pib->getDefaultCertificate();
468 break;
469 }
José Quevedo641de4c2016-01-29 00:11:24 +0000470 case SigningInfo::SIGNER_TYPE_ID: {
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700471 Name signingCertName;
472 try {
473 signingCertName = m_pib->getDefaultCertificateNameForIdentity(params.getSignerName());
474 }
José Quevedo641de4c2016-01-29 00:11:24 +0000475 catch (const SecPublicInfo::Error&) {
476 signingCertName = createIdentity(params.getSignerName(), getDefaultKeyParamsForIdentity(params.getSignerName()));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700477 }
478
479 signingCert = m_pib->getCertificate(signingCertName);
480
481 break;
482 }
José Quevedo641de4c2016-01-29 00:11:24 +0000483 case SigningInfo::SIGNER_TYPE_KEY: {
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700484 Name signingCertName;
485 try {
486 signingCertName = m_pib->getDefaultCertificateNameForKey(params.getSignerName());
487 }
José Quevedo641de4c2016-01-29 00:11:24 +0000488 catch (const SecPublicInfo::Error&) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700489 BOOST_THROW_EXCEPTION(Error("signing certificate does not exist"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700490 }
491
492 signingCert = m_pib->getCertificate(signingCertName);
493
494 break;
495 }
José Quevedo641de4c2016-01-29 00:11:24 +0000496 case SigningInfo::SIGNER_TYPE_CERT: {
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700497 signingCert = m_pib->getCertificate(params.getSignerName());
498 if (signingCert == nullptr)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700499 BOOST_THROW_EXCEPTION(Error("signing certificate does not exist"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700500
501 break;
502 }
José Quevedo641de4c2016-01-29 00:11:24 +0000503 case SigningInfo::SIGNER_TYPE_SHA256: {
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700504 sigInfo.setSignatureType(tlv::DigestSha256);
505 return std::make_tuple(DIGEST_SHA256_IDENTITY, sigInfo);
506 }
José Quevedo641de4c2016-01-29 00:11:24 +0000507 default:
508 BOOST_THROW_EXCEPTION(Error("Unrecognized signer type"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700509 }
510
511 sigInfo.setSignatureType(getSignatureType(signingCert->getPublicKeyInfo().getKeyType(),
512 params.getDigestAlgorithm()));
513 sigInfo.setKeyLocator(KeyLocator(signingCert->getName().getPrefix(-1)));
514
515 return std::make_tuple(signingCert->getPublicKeyName(), sigInfo);
516}
517
518void
519KeyChain::sign(Data& data, const SigningInfo& params)
520{
521 signImpl(data, params);
522}
523
524void
525KeyChain::sign(Interest& interest, const SigningInfo& params)
526{
527 signImpl(interest, params);
528}
529
530Block
531KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params)
532{
533 Name keyName;
534 SignatureInfo sigInfo;
535 std::tie(keyName, sigInfo) = prepareSignatureInfo(params);
536 return pureSign(buffer, bufferLength, keyName, DIGEST_ALGORITHM_SHA256);
537}
538
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700539Signature
540KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
541{
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700542 shared_ptr<IdentityCertificate> certificate = m_pib->getCertificate(certificateName);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700543
José Quevedo641de4c2016-01-29 00:11:24 +0000544 if (certificate == nullptr) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700545 BOOST_THROW_EXCEPTION(SecPublicInfo::Error("certificate does not exist"));
José Quevedo641de4c2016-01-29 00:11:24 +0000546 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700547
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700548 Signature sig;
Yingdi Yu4a557052014-07-09 16:40:37 -0700549
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700550 // For temporary usage, we support SHA256 only, but will support more.
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700551 sig.setValue(m_tpm->signInTpm(buffer, bufferLength,
552 certificate->getPublicKeyName(),
553 DIGEST_ALGORITHM_SHA256));
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700554
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700555 return sig;
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700556}
557
558shared_ptr<IdentityCertificate>
559KeyChain::selfSign(const Name& keyName)
560{
561 shared_ptr<PublicKey> pubKey;
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700562 try {
563 pubKey = m_pib->getPublicKey(keyName); // may throw an exception.
564 }
José Quevedo641de4c2016-01-29 00:11:24 +0000565 catch (const SecPublicInfo::Error&) {
566 return nullptr;
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700567 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700568
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700569 auto certificate = make_shared<IdentityCertificate>();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700570
571 Name certificateName = keyName.getPrefix(-1);
572 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
573
574 certificate->setName(certificateName);
575 certificate->setNotBefore(time::system_clock::now());
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700576 certificate->setNotAfter(time::system_clock::now() + time::days(7300)); // ~20 years
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700577 certificate->setPublicKeyInfo(*pubKey);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700578 certificate->addSubjectDescription(CertificateSubjectDescription(oid::ATTRIBUTE_NAME,
579 keyName.toUri()));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700580 certificate->encode();
581
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700582 certificate->setSignature(Signature(SignatureInfo()));
583
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700584 selfSign(*certificate);
585 return certificate;
586}
587
588void
589KeyChain::selfSign(IdentityCertificate& cert)
590{
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700591 Name keyName = cert.getPublicKeyName();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700592 if (!m_tpm->doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700593 BOOST_THROW_EXCEPTION(SecTpm::Error("Private key does not exist"));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700594
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700595 SignatureInfo sigInfo(cert.getSignature().getInfo());
596 sigInfo.setKeyLocator(KeyLocator(cert.getName().getPrefix(-1)));
597 sigInfo.setSignatureType(getSignatureType(cert.getPublicKeyInfo().getKeyType(),
598 DIGEST_ALGORITHM_SHA256));
Yingdi Yu4a557052014-07-09 16:40:37 -0700599
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700600 signPacketWrapper(cert, Signature(sigInfo), keyName, DIGEST_ALGORITHM_SHA256);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700601}
602
603shared_ptr<SecuredBag>
604KeyChain::exportIdentity(const Name& identity, const std::string& passwordStr)
605{
606 if (!m_pib->doesIdentityExist(identity))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700607 BOOST_THROW_EXCEPTION(SecPublicInfo::Error("Identity does not exist"));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700608
609 Name keyName = m_pib->getDefaultKeyNameForIdentity(identity);
610
611 ConstBufferPtr pkcs5;
José Quevedo641de4c2016-01-29 00:11:24 +0000612 try {
613 pkcs5 = m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, passwordStr);
614 }
615 catch (const SecTpm::Error& e) {
616 BOOST_THROW_EXCEPTION(SecPublicInfo::Error("Fail to export PKCS5 of private key"));
617 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700618
619 shared_ptr<IdentityCertificate> cert;
José Quevedo641de4c2016-01-29 00:11:24 +0000620 try {
621 cert = m_pib->getCertificate(m_pib->getDefaultCertificateNameForKey(keyName));
622 }
623 catch (const SecPublicInfo::Error& e) {
624 cert = selfSign(keyName);
625 m_pib->addCertificateAsIdentityDefault(*cert);
626 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700627
Alexander Afanasyevb67090a2014-04-29 22:31:01 -0700628 // make_shared on OSX 10.9 has some strange problem here
José Quevedo641de4c2016-01-29 00:11:24 +0000629 return shared_ptr<SecuredBag>(new SecuredBag(*cert, pkcs5));
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700630}
631
632void
633KeyChain::importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
634{
635 Name certificateName = securedBag.getCertificate().getName();
636 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
637 Name identity = keyName.getPrefix(-1);
638
639 // Add identity
640 m_pib->addIdentity(identity);
641
642 // Add key
643 m_tpm->importPrivateKeyPkcs5IntoTpm(keyName,
644 securedBag.getKey()->buf(),
645 securedBag.getKey()->size(),
646 passwordStr);
647
648 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
649 // HACK! We should set key type according to the pkcs8 info.
Yingdi Yu41546342014-11-30 23:37:53 -0800650 m_pib->addKey(keyName, *pubKey);
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700651 m_pib->setDefaultKeyNameForIdentity(keyName);
652
653 // Add cert
654 m_pib->addCertificateAsIdentityDefault(securedBag.getCertificate());
655}
656
José Quevedo641de4c2016-01-29 00:11:24 +0000657const KeyParams&
658KeyChain::getDefaultKeyParamsForIdentity(const Name &identityName) const
659{
660 KeyType keyType = KEY_TYPE_NULL;
661 try {
662 keyType = m_pib->getPublicKeyType(m_pib->getDefaultKeyNameForIdentity(identityName));
663 }
664 catch (const SecPublicInfo::Error& e) { // @TODO Switch to Pib::Error
665 return DEFAULT_KEY_PARAMS;
666 }
667
668 switch (keyType) {
669 case KEY_TYPE_RSA: {
670 static RsaKeyParams defaultRsaParams;
671 return defaultRsaParams;
672 }
673 case KEY_TYPE_ECDSA: {
674 static EcdsaKeyParams defaultEcdsaParams;
675 return defaultEcdsaParams;
676 }
677 case KEY_TYPE_NULL: {
678 return DEFAULT_KEY_PARAMS;
679 }
680 default:
681 BOOST_THROW_EXCEPTION(Error("Unsupported key type"));
682 }
683}
684
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700685void
686KeyChain::setDefaultCertificateInternal()
687{
688 m_pib->refreshDefaultCertificate();
689
José Quevedo641de4c2016-01-29 00:11:24 +0000690 if (m_pib->getDefaultCertificate() == nullptr) {
691 Name defaultIdentity;
692 try {
693 defaultIdentity = m_pib->getDefaultIdentity();
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700694 }
José Quevedo641de4c2016-01-29 00:11:24 +0000695 catch (const SecPublicInfo::Error& e) {
696 uint32_t random = random::generateWord32();
697 defaultIdentity.append("tmp-identity")
698 .append(reinterpret_cast<uint8_t*>(&random), 4);
699 }
700 createIdentity(defaultIdentity);
701 m_pib->setDefaultIdentity(defaultIdentity);
702 m_pib->refreshDefaultCertificate();
703 }
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700704}
705
Yingdi Yu7036ce22014-06-19 18:53:37 -0700706Name
707KeyChain::generateKeyPair(const Name& identityName, bool isKsk, const KeyParams& params)
708{
709 Name keyName = m_pib->getNewKeyName(identityName, isKsk);
710
711 m_tpm->generateKeyPairInTpm(keyName.toUri(), params);
712
713 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
714 m_pib->addKey(keyName, *pubKey);
715
716 return keyName;
717}
718
719void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700720KeyChain::signPacketWrapper(Data& data, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700721 const Name& keyName, DigestAlgorithm digestAlgorithm)
722{
723 data.setSignature(signature);
724
725 EncodingBuffer encoder;
726 data.wireEncode(encoder, true);
727
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700728 Block sigValue = pureSign(encoder.buf(), encoder.size(), keyName, digestAlgorithm);
729
730 data.wireEncode(encoder, sigValue);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700731}
732
733void
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700734KeyChain::signPacketWrapper(Interest& interest, const Signature& signature,
Yingdi Yu7036ce22014-06-19 18:53:37 -0700735 const Name& keyName, DigestAlgorithm digestAlgorithm)
736{
737 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
José Quevedo641de4c2016-01-29 00:11:24 +0000738 if (timestamp <= m_lastTimestamp) {
739 timestamp = m_lastTimestamp + time::milliseconds(1);
740 }
Yingdi Yu7036ce22014-06-19 18:53:37 -0700741
742 Name signedName = interest.getName();
743 signedName
744 .append(name::Component::fromNumber(timestamp.count())) // timestamp
745 .append(name::Component::fromNumber(random::generateWord64())) // nonce
746 .append(signature.getInfo()); // signatureInfo
747
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700748 Block sigValue = pureSign(signedName.wireEncode().value(),
749 signedName.wireEncode().value_size(),
750 keyName,
751 digestAlgorithm);
752
Yingdi Yu7036ce22014-06-19 18:53:37 -0700753 sigValue.encode();
754 signedName.append(sigValue); // signatureValue
755 interest.setName(signedName);
756}
757
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700758Block
759KeyChain::pureSign(const uint8_t* buf, size_t size,
760 const Name& keyName, DigestAlgorithm digestAlgorithm) const
761{
762 if (keyName == DIGEST_SHA256_IDENTITY)
763 return Block(tlv::SignatureValue, crypto::sha256(buf, size));
764
765 return m_tpm->signInTpm(buf, size, keyName, digestAlgorithm);
766}
767
Yingdi Yu7036ce22014-06-19 18:53:37 -0700768Signature
769KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
770{
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700771 Signature sig;
José Quevedo641de4c2016-01-29 00:11:24 +0000772 sig.setValue(sign(buffer, bufferLength, signingByIdentity(identityName)));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700773 return sig;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700774}
775
776void
777KeyChain::signWithSha256(Data& data)
778{
José Quevedo641de4c2016-01-29 00:11:24 +0000779 return sign(data, signingWithSha256());
Yingdi Yu7036ce22014-06-19 18:53:37 -0700780}
781
782void
Yingdi Yu6ab67812014-11-27 15:00:34 -0800783KeyChain::signWithSha256(Interest& interest)
784{
785 DigestSha256 sig;
786
787 time::milliseconds timestamp = time::toUnixTimestamp(time::system_clock::now());
788 if (timestamp <= m_lastTimestamp)
789 timestamp = m_lastTimestamp + time::milliseconds(1);
790
791 Name signedName = interest.getName();
792 signedName
793 .append(name::Component::fromNumber(timestamp.count())) // timestamp
794 .append(name::Component::fromNumber(random::generateWord64())) // nonce
795 .append(sig.getInfo()); // signatureInfo
796
797 Block sigValue(tlv::SignatureValue,
798 crypto::sha256(signedName.wireEncode().value(),
799 signedName.wireEncode().value_size()));
800
801 sigValue.encode();
802 signedName.append(sigValue); // signatureValue
803 interest.setName(signedName);
804}
805
806void
Yingdi Yu7036ce22014-06-19 18:53:37 -0700807KeyChain::deleteCertificate(const Name& certificateName)
808{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700809 m_pib->deleteCertificateInfo(certificateName);
810}
811
812void
813KeyChain::deleteKey(const Name& keyName)
814{
Yingdi Yu7036ce22014-06-19 18:53:37 -0700815 m_pib->deletePublicKeyInfo(keyName);
816 m_tpm->deleteKeyPairInTpm(keyName);
817}
818
819void
820KeyChain::deleteIdentity(const Name& identity)
821{
Yingdi Yu6147ef42014-12-08 17:48:32 -0800822 std::vector<Name> keyNames;
823 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, true);
824 m_pib->getAllKeyNamesOfIdentity(identity, keyNames, false);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700825
826 m_pib->deleteIdentityInfo(identity);
827
Yingdi Yu6147ef42014-12-08 17:48:32 -0800828 for (const auto& keyName : keyNames)
829 m_tpm->deleteKeyPairInTpm(keyName);
Yingdi Yu7036ce22014-06-19 18:53:37 -0700830}
831
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700832tlv::SignatureTypeValue
833KeyChain::getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm)
834{
835 switch (keyType) {
836 case KEY_TYPE_RSA:
837 return tlv::SignatureSha256WithRsa;
838 case KEY_TYPE_ECDSA:
839 return tlv::SignatureSha256WithEcdsa;
840 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700841 BOOST_THROW_EXCEPTION(Error("Unsupported key types"));
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700842 }
843
Yingdi Yuf56c68f2014-04-24 21:50:13 -0700844}
Yingdi Yu1b0311c2015-06-10 14:58:47 -0700845
846} // namespace security
847} // namespace ndn