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