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