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