blob: b5219dac4c9f601f2d6ee787c0e6a8b5091ce82b [file] [log] [blame]
Yingdi Yufe4733a2015-10-22 14:24:12 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevadc71842017-01-26 22:17:58 -05002/*
Yingdi Yufe4733a2015-10-22 14:24:12 -07003 * Copyright (c) 2013-2017 Regents of the University of California.
4 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * 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.
20 */
21
22#ifndef NDN_SECURITY_V2_KEY_CHAIN_HPP
23#define NDN_SECURITY_V2_KEY_CHAIN_HPP
24
Alexander Afanasyev7e721412017-01-11 13:36:08 -080025#include "../security-common.hpp"
Yingdi Yufe4733a2015-10-22 14:24:12 -070026#include "certificate.hpp"
27#include "../key-params.hpp"
28#include "../pib/pib.hpp"
29#include "../safe-bag.hpp"
30#include "../signing-info.hpp"
31#include "../tpm/tpm.hpp"
32#include "../../interest.hpp"
33
34namespace ndn {
35namespace security {
36namespace v2 {
37
38/**
39 * @brief The interface of signing key management.
40 *
41 * The KeyChain class provides an interface to manage entities related to packet signing,
42 * such as Identity, Key, and Certificates. It consists of two parts: a private key module
43 * (TPM) and a public key information base (PIB). Managing signing key and its related
44 * entities through KeyChain interface guarantees the consistency between TPM and PIB.
45 */
46class KeyChain : noncopyable
47{
48public:
49 class Error : public std::runtime_error
50 {
51 public:
52 explicit
53 Error(const std::string& what)
54 : std::runtime_error(what)
55 {
56 }
57 };
58
59 /**
60 * @brief Error indicating that the supplied TPM locator does not match the locator stored in PIB.
61 */
62 class LocatorMismatchError : public Error
63 {
64 public:
Davide Pesavento3ce6d4e2017-10-05 01:48:24 -040065 using Error::Error;
Yingdi Yufe4733a2015-10-22 14:24:12 -070066 };
67
68 /**
69 * @brief Error indicating that the supplied SigningInfo is invalid.
70 */
71 class InvalidSigningInfoError : public Error
72 {
73 public:
Davide Pesavento3ce6d4e2017-10-05 01:48:24 -040074 using Error::Error;
Yingdi Yufe4733a2015-10-22 14:24:12 -070075 };
76
77 /**
78 * @brief Constructor to create KeyChain with default PIB and TPM.
79 *
80 * Default PIB and TPM are platform-dependent and can be overriden system-wide or
81 * individually for the user.
82 *
83 * @sa manpage ndn-client.conf
84 *
85 * @todo Add detailed description about config file behavior here
86 */
87 KeyChain();
88
89 /**
90 * @brief KeyChain constructor
91 *
92 * @sa manpage ndn-client.conf
93 *
Davide Pesavento3ce6d4e2017-10-05 01:48:24 -040094 * @param pibLocator PIB locator, e.g., `pib-sqlite3:/example/dir`
95 * @param tpmLocator TPM locator, e.g., `tpm-memory:`
96 * @param allowReset if true, the PIB will be reset when the supplied @p tpmLocator
97 * does not match the one in the PIB
Yingdi Yufe4733a2015-10-22 14:24:12 -070098 */
99 KeyChain(const std::string& pibLocator, const std::string& tpmLocator, bool allowReset = false);
100
101 ~KeyChain();
102
103 const Pib&
104 getPib() const
105 {
106 return *m_pib;
107 }
108
109 const Tpm&
110 getTpm() const
111 {
112 return *m_tpm;
113 }
114
115public: // Identity management
116 /**
117 * @brief Create an identity @p identityName.
118 *
119 * This method will check if the identity exists in PIB and whether the identity has a
120 * default key and default certificate. If the identity does not exist, this method will
121 * create the identity in PIB. If the identity's default key does not exist, this method
122 * will create a key pair and set it as the identity's default key. If the key's default
123 * certificate is missing, this method will create a self-signed certificate for the key.
124 *
125 * If @p identityName did not exist and no default identity was selected before, the created
126 * identity will be set as the default identity
127 *
128 * @param identityName The name of the identity.
129 * @param params The key parameters if a key needs to be created for the identity (default:
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700130 * EC key with random key id)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700131 * @return The created Identity instance.
132 */
133 Identity
134 createIdentity(const Name& identityName, const KeyParams& params = getDefaultKeyParams());
135
136 /**
137 * @brief delete @p identity.
138 *
139 * @pre @p identity must be valid.
140 * @post @p identity becomes invalid.
141 */
142 void
143 deleteIdentity(const Identity& identity);
144
145 /**
146 * @brief Set @p identity as the default identity.
147 * @pre @p identity must be valid.
148 */
149 void
150 setDefaultIdentity(const Identity& identity);
151
152public: // Key management
153 /**
154 * @brief Create a key for @p identity according to @p params.
155 *
156 * @param identity reference to a valid Identity object
157 * @param params The key parameters if a key needs to be created for the identity (default:
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700158 * EC key with random key id)
Yingdi Yufe4733a2015-10-22 14:24:12 -0700159 *
160 * If @p identity had no default key selected, the created key will be set as the default for
161 * this identity.
162 *
163 * This method will also create a self-signed certificate for the created key.
164 * @pre @p identity must be valid.
165 */
166 Key
167 createKey(const Identity& identity, const KeyParams& params = getDefaultKeyParams());
168
169 /**
170 * @brief Delete a key @p key of @p identity.
171 *
172 * @pre @p identity must be valid.
173 * @pre @p key must be valid.
174 * @post @p key becomes invalid.
175 * @throw std::invalid_argument @p key does not belong to @p identity
176 */
177 void
178 deleteKey(const Identity& identity, const Key& key);
179
180 /**
181 * @brief Set @p key as the default key of @p identity.
182 *
183 * @pre @p identity must be valid.
184 * @pre @p key must be valid.
185 * @throw std::invalid_argument @p key does not belong to @p identity
186 */
187 void
188 setDefaultKey(const Identity& identity, const Key& key);
189
190public: // Certificate management
191 /**
192 * @brief Add a certificate @p certificate for @p key
193 *
194 * If @p key had no default certificate selected, the added certificate will be set as the
195 * default certificate for this key.
196 *
197 * @note This method overwrites certificate with the same name, without considering the
198 * implicit digest.
199 *
200 * @pre @p key must be valid.
201 * @throw std::invalid_argument @p key does not match @p certificate
Yingdi Yufe4733a2015-10-22 14:24:12 -0700202 */
203 void
204 addCertificate(const Key& key, const Certificate& certificate);
205
206 /**
207 * @brief delete a certificate with name @p certificateName of @p key.
208 *
209 * If the certificate @p certificateName does not exist, this method has no effect.
210 *
211 * @pre @p key must be valid.
212 * @throw std::invalid_argument @p certificateName does not follow certificate naming convention.
213 */
214 void
215 deleteCertificate(const Key& key, const Name& certificateName);
216
217 /**
218 * @brief Set @p cert as the default certificate of @p key.
219 *
220 * The certificate @p cert will be added to the @p key, potentially overriding existing
221 * certificate if it has the same name (without considering implicit digest).
222 *
223 * @pre @p key must be valid.
Davide Pesavento3ce6d4e2017-10-05 01:48:24 -0400224 * @throw std::invalid_argument @p key does not match @p certificate
Yingdi Yufe4733a2015-10-22 14:24:12 -0700225 */
226 void
Davide Pesavento3ce6d4e2017-10-05 01:48:24 -0400227 setDefaultCertificate(const Key& key, const Certificate& certificate);
Yingdi Yufe4733a2015-10-22 14:24:12 -0700228
229public: // signing
230 /**
231 * @brief Sign data according to the supplied signing information.
232 *
233 * This method uses the supplied signing information @p params to create the SignatureInfo block:
234 * - it selects a private key and its certificate to sign the packet
235 * - sets the KeyLocator field with the certificate name, and
236 * - adds other requested information to the SignatureInfo block.
237 *
238 * After that, the method assigns the created SignatureInfo to the data packets, generate a
239 * signature and sets as part of the SignatureValue block.
240 *
241 * @note The exception throwing semantics has changed from v1::KeyChain.
242 * If the requested identity/key/certificate does not exist, it will **not** be created
243 * and exception will be thrown.
244 *
245 * @param data The data to sign
246 * @param params The signing parameters.
247 * @throw Error signing fails
248 * @throw InvalidSigningInfoError invalid @p params is specified or specified identity, key,
249 * or certificate does not exist
250 * @see SigningInfo
251 */
252 void
253 sign(Data& data, const SigningInfo& params = getDefaultSigningInfo());
254
255 /**
256 * @brief Sign interest according to the supplied signing information
257 *
258 * This method uses the supplied signing information @p params to create the SignatureInfo block:
259 * - it selects a private key and its certificate to sign the packet
260 * - sets the KeyLocator field with the certificate name, and
261 * - adds other requested information to the SignatureInfo block.
262 *
263 * After that, the method appends the created SignatureInfo to the interest name, generate a
264 * signature and appends it as part of the SignatureValue block to the interest name.
265 *
266 * @note The exception throwing semantics has changed from v1::KeyChain. If the requested
267 * identity/key/certificate does not exist, it will **not** be created and exception
268 * will be thrown.
269 *
270 * @param interest The interest to sign
271 * @param params The signing parameters.
272 * @throw Error signing fails
273 * @throw InvalidSigningInfoError invalid @p params is specified or specified identity, key,
274 * or certificate does not exist
275 * @see SigningInfo
276 * @see docs/specs/signed-interest.rst
277 */
278 void
279 sign(Interest& interest, const SigningInfo& params = getDefaultSigningInfo());
280
281 /**
282 * @brief Sign buffer according to the supplied signing information @p params
283 *
284 * If @p params refers to an identity, the method selects the default key of the identity.
285 * If @p params refers to a key or certificate, the method select the corresponding key.
286 *
287 * @param buffer The buffer to sign
288 * @param bufferLength The buffer size
289 * @param params The signing parameters.
290 * @return a SignatureValue TLV block
291 * @throw Error signing fails
292 * @see SigningInfo
293 */
294 Block
295 sign(const uint8_t* buffer, size_t bufferLength, const SigningInfo& params = getDefaultSigningInfo());
296
297public: // export & import
298 /**
Davide Pesavento3ce6d4e2017-10-05 01:48:24 -0400299 * @brief Export a certificate and its corresponding private key.
Yingdi Yufe4733a2015-10-22 14:24:12 -0700300 *
301 * @param certificate The certificate to export.
302 * @param pw The password to secure the private key.
303 * @param pwLen The length of password.
304 * @return A SafeBag carrying the certificate and encrypted private key.
305 * @throw Error the certificate or private key does not exist
306 */
307 shared_ptr<SafeBag>
308 exportSafeBag(const Certificate& certificate, const char* pw, size_t pwLen);
309
310 /**
311 * @brief Import a pair of certificate and its corresponding private key encapsulated in a SafeBag.
312 *
313 * If the certificate and key are imported properly, the default setting will be updated as if
314 * a new key and certificate is added into KeyChain.
315 *
316 * @param safeBag The encoded data to import.
317 * @param pw The password to secure the private key.
318 * @param pwLen The length of password.
319 * @throw Error any of following conditions:
320 * - the safebag cannot be decoded or its content does not match;
321 * - private key cannot be imported;
322 * - a private/public key of the same name already exists;
323 * - a certificate of the same name already exists.
324 */
325 void
326 importSafeBag(const SafeBag& safeBag, const char* pw, size_t pwLen);
327
328NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
329 /**
330 * @brief Derive SignatureTypeValue according to key type and digest algorithm.
331 */
332 static tlv::SignatureTypeValue
333 getSignatureType(KeyType keyType, DigestAlgorithm digestAlgorithm);
334
335public: // PIB & TPM backend registry
336 /**
337 * @brief Register a new PIB backend
338 * @param scheme Name for the registered PIB backend scheme
339 *
340 * @note This interface is implementation detail and may change without notice.
341 */
342 template<class PibBackendType>
343 static void
344 registerPibBackend(const std::string& scheme);
345
346 /**
347 * @brief Register a new TPM backend
348 * @param scheme Name for the registered TPM backend scheme
349 *
350 * @note This interface is implementation detail and may change without notice.
351 */
352 template<class TpmBackendType>
353 static void
354 registerTpmBackend(const std::string& scheme);
355
356private:
357 typedef std::map<std::string, function<unique_ptr<pib::PibImpl>(const std::string& location)>> PibFactories;
358 typedef std::map<std::string, function<unique_ptr<tpm::BackEnd>(const std::string& location)>> TpmFactories;
359
360 static PibFactories&
361 getPibFactories();
362
363 static TpmFactories&
364 getTpmFactories();
365
366 static std::tuple<std::string/*type*/, std::string/*location*/>
367 parseAndCheckPibLocator(const std::string& pibLocator);
368
369 static std::tuple<std::string/*type*/, std::string/*location*/>
370 parseAndCheckTpmLocator(const std::string& tpmLocator);
371
372 static const std::string&
373 getDefaultPibScheme();
374
375 static const std::string&
376 getDefaultTpmScheme();
377
378 /**
379 * @brief Create a PIB according to @p pibLocator
380 */
381 static unique_ptr<Pib>
382 createPib(const std::string& pibLocator);
383
384 /**
385 * @brief Create a TPM according to @p tpmLocator
386 */
387 static unique_ptr<Tpm>
388 createTpm(const std::string& tpmLocator);
389
390NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
391 static const std::string&
392 getDefaultPibLocator();
393
394 static const std::string&
395 getDefaultTpmLocator();
396
397private: // signing
398 /**
399 * @brief Generate a self-signed certificate for a public key.
400 *
401 * The self-signed certificate will also be added into PIB
402 *
403 * @param keyName The name of the public key
404 * @return The generated certificate
405 */
406 Certificate
407 selfSign(Key& key);
408
409 /**
410 * @brief Prepare a SignatureInfo TLV according to signing information and return the signing
411 * key name
412 *
413 * @param sigInfo The SignatureInfo to prepare.
414 * @param params The signing parameters.
415 * @return The signing key name and prepared SignatureInfo.
416 * @throw InvalidSigningInfoError when the requested signing method cannot be satisfied.
417 */
418 std::tuple<Name, SignatureInfo>
419 prepareSignatureInfo(const SigningInfo& params);
420
421 /**
422 * @brief Generate a SignatureValue block for a buffer @p buf with size @p size using
423 * a key with name @p keyName and digest algorithm @p digestAlgorithm.
424 */
425 Block
426 sign(const uint8_t* buf, size_t size, const Name& keyName, DigestAlgorithm digestAlgorithm) const;
427
428public:
429 static const SigningInfo&
430 getDefaultSigningInfo();
431
432 static const KeyParams&
433 getDefaultKeyParams();
434
435private:
436 std::unique_ptr<Pib> m_pib;
437 std::unique_ptr<Tpm> m_tpm;
438
439 static std::string s_defaultPibLocator;
440 static std::string s_defaultTpmLocator;
441};
442
443template<class PibType>
444inline void
445KeyChain::registerPibBackend(const std::string& scheme)
446{
447 getPibFactories().emplace(scheme, [] (const std::string& locator) {
448 return unique_ptr<pib::PibImpl>(new PibType(locator));
449 });
450}
451
452template<class TpmType>
453inline void
454KeyChain::registerTpmBackend(const std::string& scheme)
455{
456 getTpmFactories().emplace(scheme, [] (const std::string& locator) {
457 return unique_ptr<tpm::BackEnd>(new TpmType(locator));
458 });
459}
460
461/**
462 * @brief Register Pib backend class in KeyChain
463 *
464 * This macro should be placed once in the implementation file of the
465 * Pib backend class within the namespace where the type is declared.
466 *
467 * @note This interface is implementation detail and may change without notice.
468 */
469#define NDN_CXX_V2_KEYCHAIN_REGISTER_PIB_BACKEND(PibType) \
470static class NdnCxxAuto ## PibType ## PibRegistrationClass \
471{ \
472public: \
473 NdnCxxAuto ## PibType ## PibRegistrationClass() \
474 { \
475 ::ndn::security::v2::KeyChain::registerPibBackend<PibType>(PibType::getScheme()); \
476 } \
477} ndnCxxAuto ## PibType ## PibRegistrationVariable
478
479/**
480 * @brief Register Tpm backend class in KeyChain
481 *
482 * This macro should be placed once in the implementation file of the
483 * Tpm backend class within the namespace where the type is declared.
484 *
485 * @note This interface is implementation detail and may change without notice.
486 */
487#define NDN_CXX_V2_KEYCHAIN_REGISTER_TPM_BACKEND(TpmType) \
488static class NdnCxxAuto ## TpmType ## TpmRegistrationClass \
489{ \
490public: \
491 NdnCxxAuto ## TpmType ## TpmRegistrationClass() \
492 { \
493 ::ndn::security::v2::KeyChain::registerTpmBackend<TpmType>(TpmType::getScheme()); \
494 } \
495} ndnCxxAuto ## TpmType ## TpmRegistrationVariable
496
497} // namespace v2
Alexander Afanasyevadc71842017-01-26 22:17:58 -0500498
499using v2::KeyChain;
500
Yingdi Yufe4733a2015-10-22 14:24:12 -0700501} // namespace security
Alexander Afanasyev80782e02017-01-04 13:16:54 -0800502
503using security::v2::KeyChain;
504
Yingdi Yufe4733a2015-10-22 14:24:12 -0700505} // namespace ndn
506
507#endif // NDN_SECURITY_V2_KEY_CHAIN_HPP