blob: e564326659ca60e535f8ffdc6690907bd3208f18 [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
Yingdi Yufe4733a2015-10-22 14:24:12 -0700210 */
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
Alexander Afanasyev80782e02017-01-04 13:16:54 -0800506
507using security::v2::KeyChain;
508
Yingdi Yufe4733a2015-10-22 14:24:12 -0700509} // namespace ndn
510
511#endif // NDN_SECURITY_V2_KEY_CHAIN_HPP