blob: e58cbf9ae2c080ed2cc723ff3a458c6ec105e6e1 [file] [log] [blame]
Jeff Thompson25b4e612013-10-10 16:03:24 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Jeff Thompson47c93cf2013-08-09 00:38:48 -07002/**
Jeff Thompson7687dc02013-09-13 11:54:07 -07003 * Copyright (C) 2013 Regents of the University of California.
Jeff Thompsonba16b8f2013-12-16 13:11:47 -08004 * @author: Yingdi Yu <yingdi@cs.ucla.edu>
Jeff Thompson7687dc02013-09-13 11:54:07 -07005 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
Jeff Thompson47c93cf2013-08-09 00:38:48 -07006 * See COPYING for copyright and distribution information.
7 */
8
Yingdi Yufc40d872014-02-18 12:56:04 -08009#ifndef NDN_SECURITY_KEY_CHAIN_HPP
10#define NDN_SECURITY_KEY_CHAIN_HPP
Jeff Thompson47c93cf2013-08-09 00:38:48 -070011
Yingdi Yu4f324632014-01-15 18:10:03 -080012#include "identity-certificate.hpp"
13#include "public-key.hpp"
14#include "signature-sha256-with-rsa.hpp"
Yingdi Yu21157162014-02-28 13:02:34 -080015#include "signature-sha256.hpp"
Yingdi Yu64c3fb42014-02-26 17:30:04 -080016#include "secured-bag.hpp"
Yingdi Yu4270f202014-01-28 14:19:16 -080017#include "../interest.hpp"
Yingdi Yu2e57a582014-02-20 23:34:43 -080018#include "../util/random.hpp"
Yingdi Yu21157162014-02-28 13:02:34 -080019#include "../util/crypto.hpp"
Yingdi Yu31b4af22014-01-14 14:13:00 -080020
Yingdi Yu04020922014-01-22 12:46:53 -080021//PublicInfo
Yingdi Yu4f324632014-01-15 18:10:03 -080022#include "sec-public-info-sqlite3.hpp"
23#include "sec-public-info-memory.hpp"
Yingdi Yu04020922014-01-22 12:46:53 -080024//TPM
25#include "sec-tpm-file.hpp"
Yingdi Yu4f324632014-01-15 18:10:03 -080026#include "sec-tpm-memory.hpp"
Yingdi Yu2abd73f2014-01-08 23:34:11 -080027
Yingdi Yu04020922014-01-22 12:46:53 -080028#ifdef NDN_CPP_HAVE_OSX_SECURITY
29#include "sec-tpm-osx.hpp"
30#endif
31
Jeff Thompson47c93cf2013-08-09 00:38:48 -070032
33namespace ndn {
34
Jeff Thompson2ce8f492013-09-17 18:01:25 -070035/**
Yingdi Yu2e57a582014-02-20 23:34:43 -080036 * @brief KeyChain is one of the main classes of the security library.
Jeff Thompsonffa36f92013-09-20 08:42:41 -070037 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -080038 * The KeyChain class provides a set of interfaces of identity management and private key related operations.
Jeff Thompsonffa36f92013-09-20 08:42:41 -070039 */
Yingdi Yu31b4af22014-01-14 14:13:00 -080040template<class Info, class Tpm>
41class KeyChainImpl : public Info, public Tpm
42{
Yingdi Yuf8fc8de2014-02-25 15:45:39 -080043 typedef SecPublicInfo::Error InfoError;
44 typedef SecTpm::Error TpmError;
Jeff Thompson47c93cf2013-08-09 00:38:48 -070045public:
Yingdi Yube4150e2014-02-18 13:02:46 -080046 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -080047 * @brief Create an identity by creating a pair of Key-Signing-Key (KSK) for this identity and a self-signed certificate of the KSK.
Yingdi Yube4150e2014-02-18 13:02:46 -080048 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -080049 * @param identityName The name of the identity.
Yingdi Yu28fd32f2014-01-28 19:03:03 -080050 * @return The name of the default certificate of the identity.
Yingdi Yu2abd73f2014-01-08 23:34:11 -080051 */
52 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080053 createIdentity(const Name& identityName)
54 {
Yingdi Yu2e57a582014-02-20 23:34:43 -080055 Info::addIdentity(identityName);
Yingdi Yu28fd32f2014-01-28 19:03:03 -080056
Yingdi Yu2e57a582014-02-20 23:34:43 -080057 Name keyName;
58 try
59 {
60 keyName = Info::getDefaultKeyNameForIdentity(identityName);
61 }
62 catch(InfoError& e)
63 {
64 keyName = generateRSAKeyPairAsDefault(identityName, true);
65 }
Yingdi Yu31b4af22014-01-14 14:13:00 -080066
Yingdi Yu2e57a582014-02-20 23:34:43 -080067 Name certName;
68 try
69 {
70 certName = Info::getDefaultCertificateNameForKey(keyName);
71 }
72 catch(InfoError& e)
Yingdi Yu28fd32f2014-01-28 19:03:03 -080073 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080074 shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
Yingdi Yu28fd32f2014-01-28 19:03:03 -080075 Info::addCertificateAsIdentityDefault(*selfCert);
76 certName = selfCert->getName();
77 }
78
79 return certName;
Yingdi Yu31b4af22014-01-14 14:13:00 -080080 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -080081
82 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -080083 * @brief Generate a pair of RSA keys for the specified identity.
84 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -080085 * @param identityName The name of the identity.
86 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
87 * @param keySize The size of the key.
88 * @return The generated key name.
89 */
90 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080091 generateRSAKeyPair(const Name& identityName, bool isKsk = false, int keySize = 2048)
Yingdi Yu2abd73f2014-01-08 23:34:11 -080092 {
Yingdi Yu31b4af22014-01-14 14:13:00 -080093 return generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
Yingdi Yu2abd73f2014-01-08 23:34:11 -080094 }
Alexander Afanasyev64a3d812014-01-05 23:35:05 -080095
Yingdi Yu2abd73f2014-01-08 23:34:11 -080096 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -080097 * @brief Generate a pair of RSA keys for the specified identity and set it as default key for the identity.
98 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -080099 * @param identityName The name of the identity.
100 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
101 * @param keySize The size of the key.
102 * @return The generated key name.
103 */
104 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -0800105 generateRSAKeyPairAsDefault(const Name& identityName, bool isKsk = false, int keySize = 2048)
106 {
107 Name keyName = generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
108
109 Info::setDefaultKeyNameForIdentity(keyName);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800110
111 return keyName;
112 }
Jeff Thompson79a2d5d2013-09-27 14:32:23 -0700113
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800114 /**
Yingdi Yuc55680b2014-02-26 12:31:35 -0800115 * @brief prepare an unsigned identity certificate
116 *
117 * @param keyName Key name, e.g., /<identity_name>/ksk-123456.
118 * @param signingIdentity The signing identity.
119 * @param notBefore Refer to IdentityCertificate.
120 * @param notAfter Refer to IdentityCertificate.
121 * @param subjectDescription Refer to IdentityCertificate.
122 * @return IdentityCertificate.
123 */
124 shared_ptr<IdentityCertificate>
125 prepareUnsignedIdentityCertificate(const Name& keyName,
126 const Name& signingIdentity,
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700127 const time::system_clock::TimePoint& notBefore,
128 const time::system_clock::TimePoint& notAfter,
Yingdi Yuc55680b2014-02-26 12:31:35 -0800129 const std::vector<CertificateSubjectDescription>& subjectDescription)
130
131 {
132 if(keyName.size() < 1)
133 return shared_ptr<IdentityCertificate>();
134
135 std::string keyIdPrefix = keyName.get(-1).toEscapedString().substr(0, 4);
136 if(keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
137 return shared_ptr<IdentityCertificate>();
138
139 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
140 Name certName;
141
142 if(signingIdentity.isPrefixOf(keyName))
143 {
144 certName.append(signingIdentity).append("KEY").append(keyName.getSubName(signingIdentity.size())).append("ID-CERT").appendVersion();
145 }
146 else
147 {
148 certName.append(keyName.getPrefix(-1)).append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
149 }
150
151 certificate->setName(certName);
152 certificate->setNotBefore(notBefore);
153 certificate->setNotAfter(notAfter);
154
155 shared_ptr<PublicKey> publicKey;
156 try
157 {
158 publicKey = Info::getPublicKey(keyName);
159 }
160 catch(InfoError& e)
161 {
162 return shared_ptr<IdentityCertificate>();
163 }
164 certificate->setPublicKeyInfo(*publicKey);
165
166 if(subjectDescription.empty())
167 {
168 CertificateSubjectDescription subDescryptName("2.5.4.41", keyName.getPrefix(-1).toUri());
169 certificate->addSubjectDescription(subDescryptName);
170 }
171 else
172 {
173 std::vector<CertificateSubjectDescription>::const_iterator sdIt = subjectDescription.begin();
174 std::vector<CertificateSubjectDescription>::const_iterator sdEnd = subjectDescription.end();
175 for(; sdIt != sdEnd; sdIt++)
176 certificate->addSubjectDescription(*sdIt);
177 }
178
179 certificate->encode();
180
181 return certificate;
182 }
183
184 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800185 * @brief Sign packet with default identity
186 *
187 * on return signatureInfo and signatureValue in the packet are set.
188 *
189 * @param packet The packet to be signed
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800190 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800191 template<typename T>
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800192 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800193 sign(T& packet)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800194 {
195 if (!Info::defaultCertificate())
196 {
197 Info::refreshDefaultCertificate();
198
199 if(!Info::defaultCertificate())
Yingdi Yu2e57a582014-02-20 23:34:43 -0800200 {
201 Name defaultIdentity;
202 try
203 {
204 defaultIdentity = Info::getDefaultIdentity();
205 }
206 catch(InfoError& e)
207 {
208 uint32_t random = random::generateWord32();
209 defaultIdentity.append("tmp-identity").append(reinterpret_cast<uint8_t*>(&random), 4);
210 }
211 createIdentity(defaultIdentity);
212 Info::refreshDefaultCertificate();
213 }
Yingdi Yu31b4af22014-01-14 14:13:00 -0800214 }
215
Yingdi Yu2e57a582014-02-20 23:34:43 -0800216 sign(packet, *Info::defaultCertificate());
Yingdi Yu4270f202014-01-28 14:19:16 -0800217 }
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800218
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700219 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800220 * @brief Sign packet with a particular certificate.
221 *
222 * @param packet The packet to be signed.
223 * @param certificateName The certificate name of the key to use for signing.
224 * @throws SecPublicInfo::Error if certificate does not exist.
Jeff Thompson3c73da42013-08-12 11:19:05 -0700225 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800226 template<typename T>
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800227 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800228 sign(T& packet, const Name& certificateName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800229 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800230 if (!Info::doesCertificateExist(certificateName))
Yingdi Yu4270f202014-01-28 14:19:16 -0800231 throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
Yingdi Yu31b4af22014-01-14 14:13:00 -0800232
233 SignatureSha256WithRsa signature;
234 signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
Yingdi Yu31b4af22014-01-14 14:13:00 -0800235
236 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800237 signPacketWrapper(packet, signature,
238 IdentityCertificate::certificateNameToPublicKeyName(certificateName),
239 DIGEST_ALGORITHM_SHA256);
Yingdi Yu4270f202014-01-28 14:19:16 -0800240 }
Jeff Thompson79a2d5d2013-09-27 14:32:23 -0700241
Jeff Thompson29ce3102013-09-27 11:47:48 -0700242 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800243 * @brief Sign the byte array using a particular certificate.
244 *
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700245 * @param buffer The byte array to be signed.
246 * @param bufferLength the length of buffer.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800247 * @param certificateName The certificate name of the signing key.
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700248 * @return The Signature.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800249 * @throws SecPublicInfo::Error if certificate does not exist.
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700250 */
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800251 Signature
Yingdi Yu31b4af22014-01-14 14:13:00 -0800252 sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
253 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800254 if (!Info::doesCertificateExist(certificateName))
Yingdi Yu4270f202014-01-28 14:19:16 -0800255 throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
Yingdi Yu31b4af22014-01-14 14:13:00 -0800256
257 SignatureSha256WithRsa signature;
258 signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
259
260 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800261 signature.setValue(Tpm::signInTpm(buffer, bufferLength,
262 IdentityCertificate::certificateNameToPublicKeyName(certificateName),
263 DIGEST_ALGORITHM_SHA256));
Yingdi Yu31b4af22014-01-14 14:13:00 -0800264 return signature;
265 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700266
267 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800268 * @brief Sign packet using the default certificate of a particular identity.
269 *
270 * If there is no default certificate of that identity, this method will create a self-signed certificate.
271 *
272 * @param packet The packet to be signed.
273 * @param identityName The signing identity name.
Jeff Thompson29ce3102013-09-27 11:47:48 -0700274 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800275 template<typename T>
Jeff Thompson29ce3102013-09-27 11:47:48 -0700276 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800277 signByIdentity(T& packet, const Name& identityName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800278 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800279 Name signingCertificateName;
280 try
281 {
282 signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
283 }
284 catch(InfoError& e)
285 {
286 signingCertificateName = createIdentity(identityName);
287 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which is a fatal error.
288 }
Yingdi Yu31b4af22014-01-14 14:13:00 -0800289
Yingdi Yu2e57a582014-02-20 23:34:43 -0800290 // We either get or create the signing certificate, sign packet! (no exception unless fatal error in TPM)
291 sign(packet, signingCertificateName);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800292 }
Yingdi Yu21157162014-02-28 13:02:34 -0800293
Jeff Thompson3c73da42013-08-12 11:19:05 -0700294 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800295 * @brief Sign the byte array using the default certificate of a particular identity.
296 *
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700297 * @param buffer The byte array to be signed.
298 * @param bufferLength the length of buffer.
299 * @param identityName The identity name.
300 * @return The Signature.
301 */
Alexander Afanasyev64a3d812014-01-05 23:35:05 -0800302 Signature
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800303 signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800304 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800305 Name signingCertificateName;
306 try
307 {
308 signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
309 }
310 catch(InfoError& e)
311 {
312 signingCertificateName = createIdentity(identityName);
313 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which is a fatal error.
314 }
Yingdi Yu31b4af22014-01-14 14:13:00 -0800315
Yingdi Yu2e57a582014-02-20 23:34:43 -0800316 // We either get or create the signing certificate, sign data! (no exception unless fatal error in TPM)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800317 return sign(buffer, bufferLength, signingCertificateName);
318 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700319
320 /**
Yingdi Yu21157162014-02-28 13:02:34 -0800321 * @brief Set Sha256 weak signature.
322 *
323 * @param data.
324 */
325 void
326 signWithSha256(Data& data)
327 {
328 SignatureSha256 sig;
329 data.setSignature(sig);
330
331 Block sigValue(Tlv::SignatureValue,
332 crypto::sha256(data.wireEncode().value(),
333 data.wireEncode().value_size() - data.getSignature().getValue().size()));
334 data.setSignatureValue(sigValue);
335
336 }
337
338 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800339 * @brief Generate a self-signed certificate for a public key.
340 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800341 * @param keyName The name of the public key.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800342 * @return The generated certificate, NULL if selfSign fails.
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800343 */
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800344 shared_ptr<IdentityCertificate>
Yingdi Yu31b4af22014-01-14 14:13:00 -0800345 selfSign(const Name& keyName)
346 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800347 shared_ptr<PublicKey> pubKey;
348 try
349 {
350 pubKey = Info::getPublicKey(keyName); // may throw an exception.
351 }
352 catch(InfoError& e)
353 {
354 return shared_ptr<IdentityCertificate>();
355 }
Yingdi Yu7ea69502014-01-15 17:21:29 -0800356
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800357 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
Yingdi Yu31b4af22014-01-14 14:13:00 -0800358
359 Name certificateName = keyName.getPrefix(-1);
360 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
Yingdi Yu2e57a582014-02-20 23:34:43 -0800361
Yingdi Yu31b4af22014-01-14 14:13:00 -0800362 certificate->setName(certificateName);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700363 certificate->setNotBefore(time::system_clock::now());
364 certificate->setNotAfter(time::system_clock::now() + time::days(7300)/* ~20 years*/);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800365 certificate->setPublicKeyInfo(*pubKey);
366 certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
367 certificate->encode();
368
369 selfSign(*certificate);
370 return certificate;
371 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800372
373 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800374 * @brief Self-sign the supplied identity certificate.
375 *
376 * @param cert The supplied cert.
377 * @throws SecTpm::Error if the private key does not exist.
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700378 */
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700379 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800380 selfSign (IdentityCertificate& cert)
381 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800382 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(cert.getName());
383 if(!Tpm::doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
384 throw TpmError("private key does not exist!");
385
Yingdi Yu31b4af22014-01-14 14:13:00 -0800386 SignatureSha256WithRsa signature;
387 signature.setKeyLocator(cert.getName().getPrefix(-1)); // implicit conversion should take care
Yingdi Yu31b4af22014-01-14 14:13:00 -0800388
389 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800390 signPacketWrapper(cert, signature, keyName, DIGEST_ALGORITHM_SHA256);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800391 }
392
Yingdi Yu2e57a582014-02-20 23:34:43 -0800393 /**
394 * @brief delete a certificate.
395 *
396 * If the certificate to be deleted is current default system default,
397 * the method will not delete the certificate and return immediately.
398 *
399 * @param certificateName The certificate to be deleted.
400 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800401 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800402 deleteCertificate (const Name& certificateName)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800403 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800404 try
405 {
406 if(Info::getDefaultCertificateName() == certificateName)
407 return;
408 }
409 catch(InfoError& e)
410 {
411 // Not a real error, just try to delete the certificate
412 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800413
414 Info::deleteCertificateInfo(certificateName);
415 }
416
Yingdi Yu2e57a582014-02-20 23:34:43 -0800417 /**
418 * @brief delete a key.
419 *
420 * If the key to be deleted is current default system default,
421 * the method will not delete the key and return immediately.
422 *
423 * @param keyName The key to be deleted.
424 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800425 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800426 deleteKey (const Name& keyName)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800427 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800428 try
429 {
430 if(Info::getDefaultKeyNameForIdentity(Info::getDefaultIdentity()) == keyName)
431 return;
432 }
433 catch(InfoError& e)
434 {
435 // Not a real error, just try to delete the key
436 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800437
438 Info::deletePublicKeyInfo(keyName);
439 Tpm::deleteKeyPairInTpm(keyName);
440 }
441
Yingdi Yu2e57a582014-02-20 23:34:43 -0800442 /**
443 * @brief delete an identity.
444 *
445 * If the identity to be deleted is current default system default,
446 * the method will not delete the identity and return immediately.
447 *
448 * @param identity The identity to be deleted.
449 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800450 void
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800451 deleteIdentity (const Name& identity)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800452 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800453 try
454 {
455 if(Info::getDefaultIdentity() == identity)
456 return;
457 }
458 catch(InfoError& e)
459 {
460 // Not a real error, just try to delete the identity
461 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800462
463 std::vector<Name> nameList;
464 Info::getAllKeyNamesOfIdentity(identity, nameList, true);
465 Info::getAllKeyNamesOfIdentity(identity, nameList, false);
466
467 Info::deleteIdentityInfo(identity);
468
469 std::vector<Name>::const_iterator it = nameList.begin();
470 for(; it != nameList.end(); it++)
471 Tpm::deleteKeyPairInTpm(*it);
472 }
473
Yingdi Yu2e57a582014-02-20 23:34:43 -0800474 /**
475 * @brief export an identity.
476 *
477 * @param identity The identity to export.
478 * @param passwordStr The password to secure the private key.
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800479 * @return The encoded export data.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800480 * @throws InfoError if anything goes wrong in exporting.
481 */
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800482 shared_ptr<SecuredBag>
Yingdi Yube4150e2014-02-18 13:02:46 -0800483 exportIdentity(const Name& identity, const std::string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800484 {
485 if (!Info::doesIdentityExist(identity))
486 throw InfoError("Identity does not exist!");
487
488 Name keyName = Info::getDefaultKeyNameForIdentity(identity);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800489
Yingdi Yu2e57a582014-02-20 23:34:43 -0800490 ConstBufferPtr pkcs8;
491 try
492 {
493 pkcs8 = Tpm::exportPrivateKeyPkcs8FromTpm(keyName, passwordStr);
494 }
495 catch(TpmError& e)
496 {
497 throw InfoError("Fail to export PKCS8 of private key");
498 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800499
Yingdi Yu2e57a582014-02-20 23:34:43 -0800500 shared_ptr<IdentityCertificate> cert;
501 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800502 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800503 cert = Info::getCertificate(Info::getDefaultCertificateNameForKey(keyName));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800504 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800505 catch(InfoError& e)
506 {
507 cert = selfSign(keyName);
508 Info::addCertificateAsIdentityDefault(*cert);
509 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800510
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800511 shared_ptr<SecuredBag> secureBag = make_shared<SecuredBag>(boost::cref(*cert), boost::cref(pkcs8));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800512
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800513 return secureBag;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800514 }
515
Yingdi Yu2e57a582014-02-20 23:34:43 -0800516 /**
517 * @brief import an identity.
518 *
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800519 * @param securedBag The encoded import data.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800520 * @param passwordStr The password to secure the private key.
521 */
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800522 void
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800523 importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800524 {
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800525 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(securedBag.getCertificate().getName());
526 Name identity = keyName.getPrefix(-1);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800527
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800528 // Add identity
529 Info::addIdentity(identity);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800530
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800531 // Add key
532 Tpm::importPrivateKeyPkcs8IntoTpm(keyName, securedBag.getKey()->buf(), securedBag.getKey()->size(), passwordStr);
533 shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
534 Info::addPublicKey(keyName, KEY_TYPE_RSA, *pubKey); // HACK! We should set key type according to the pkcs8 info.
535 Info::setDefaultKeyNameForIdentity(keyName);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800536
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800537 // Add cert
538 Info::addCertificateAsIdentityDefault(securedBag.getCertificate());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800539 }
540
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700541
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800542private:
Yingdi Yu2e57a582014-02-20 23:34:43 -0800543 /**
544 * @brief sign a packet using a pariticular certificate.
545 *
546 * @param packet The packet to be signed.
547 * @param certificate The signing certificate.
548 */
549 template<typename T>
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800550 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800551 sign(T& packet, const IdentityCertificate& certificate)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800552 {
553 SignatureSha256WithRsa signature;
554 signature.setKeyLocator(certificate.getName().getPrefix(-1));
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800555
556 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800557 signPacketWrapper(packet, signature, certificate.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800558 }
559
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800560 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800561 * @brief Generate a key pair for the specified identity.
562 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800563 * @param identityName The name of the specified identity.
564 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
565 * @param keyType The type of the key pair, e.g. KEY_TYPE_RSA.
566 * @param keySize The size of the key pair.
567 * @return The name of the generated key.
568 */
569 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -0800570 generateKeyPair(const Name& identityName, bool isKsk = false, KeyType keyType = KEY_TYPE_RSA, int keySize = 2048)
571 {
572 Name keyName = Info::getNewKeyName(identityName, isKsk);
573
574 Tpm::generateKeyPairInTpm(keyName.toUri(), keyType, keySize);
575
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800576 shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
Yingdi Yuef26ee32014-01-15 16:41:14 -0800577 Info::addPublicKey(keyName, keyType, *pubKey);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800578
579 return keyName;
580 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800581
Yingdi Yu8726f652014-01-23 10:35:12 -0800582 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800583 * @brief Sign the data using a particular key.
584 *
585 * @param data Reference to the data packet.
586 * @param signature Signature to be added.
Yingdi Yu8726f652014-01-23 10:35:12 -0800587 * @param keyName The name of the signing key.
588 * @param digestAlgorithm the digest algorithm.
589 * @throws Tpm::Error
590 */
591 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800592 signPacketWrapper(Data& data, const SignatureSha256WithRsa& signature, const Name& keyName, DigestAlgorithm digestAlgorithm)
Yingdi Yu8726f652014-01-23 10:35:12 -0800593 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800594 data.setSignature(signature);
Yingdi Yu8726f652014-01-23 10:35:12 -0800595 data.setSignatureValue
596 (Tpm::signInTpm(data.wireEncode().value(),
597 data.wireEncode().value_size() - data.getSignature().getValue().size(),
598 keyName, digestAlgorithm));
599 }
600
Yingdi Yu2e57a582014-02-20 23:34:43 -0800601 /**
602 * @brief Sign the interest using a particular key.
603 *
604 * @param interest Reference to the interest packet.
605 * @param signature Signature to be added.
606 * @param keyName The name of the signing key.
607 * @param digestAlgorithm the digest algorithm.
608 * @throws Tpm::Error
609 */
610 void
611 signPacketWrapper(Interest& interest, const SignatureSha256WithRsa& signature, const Name& keyName, DigestAlgorithm digestAlgorithm)
612 {
613 Name signedName = Name(interest.getName()).append(signature.getInfo());
614
615 Block sigValue = Tpm::signInTpm(signedName.wireEncode().value(),
616 signedName.wireEncode().value_size(),
617 keyName,
618 DIGEST_ALGORITHM_SHA256);
619 sigValue.encode();
620 signedName.append(sigValue);
621 interest.setName(signedName);
622 }
623
624
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700625};
626
Yingdi Yufc40d872014-02-18 12:56:04 -0800627} // namespace ndn
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800628
Yingdi Yu04020922014-01-22 12:46:53 -0800629
630
Alexander Afanasyev3e08d5d2014-02-12 19:24:28 -0800631#if defined(NDN_CPP_HAVE_OSX_SECURITY) and defined(NDN_CPP_WITH_OSX_KEYCHAIN)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800632
633namespace ndn
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800634{
Yingdi Yu31b4af22014-01-14 14:13:00 -0800635typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmOsx> KeyChain;
636};
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800637
Yingdi Yu31b4af22014-01-14 14:13:00 -0800638#else
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800639
Yingdi Yu31b4af22014-01-14 14:13:00 -0800640namespace ndn
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800641{
Yingdi Yu04020922014-01-22 12:46:53 -0800642typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmFile> KeyChain;
Yingdi Yu31b4af22014-01-14 14:13:00 -0800643};
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800644
Yingdi Yu31b4af22014-01-14 14:13:00 -0800645#endif //NDN_CPP_HAVE_OSX_SECURITY
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700646
Yingdi Yufc40d872014-02-18 12:56:04 -0800647#endif //NDN_SECURITY_KEY_CHAIN_HPP