blob: 70593a93771d1985b35737e83bc2f20eae88c1fc [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);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070056
Yingdi Yu2e57a582014-02-20 23:34:43 -080057 Name keyName;
58 try
59 {
60 keyName = Info::getDefaultKeyNameForIdentity(identityName);
61 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070062 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080063 {
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 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070072 catch (InfoError& e)
Yingdi Yu28fd32f2014-01-28 19:03:03 -080073 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070074 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 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070081
Yingdi Yu2abd73f2014-01-08 23:34:11 -080082 /**
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 Afanasyevb78bc4d2014-04-09 21:20:52 -070095
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);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700110
Yingdi Yu31b4af22014-01-14 14:13:00 -0800111 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.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700121 * @param subjectDescription Refer to IdentityCertificate.
Yingdi Yuc55680b2014-02-26 12:31:35 -0800122 * @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 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700132 if (keyName.size() < 1)
Yingdi Yuc55680b2014-02-26 12:31:35 -0800133 return shared_ptr<IdentityCertificate>();
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700134
Yingdi Yuc55680b2014-02-26 12:31:35 -0800135 std::string keyIdPrefix = keyName.get(-1).toEscapedString().substr(0, 4);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700136 if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
Yingdi Yuc55680b2014-02-26 12:31:35 -0800137 return shared_ptr<IdentityCertificate>();
138
139 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
140 Name certName;
141
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700142 if (signingIdentity.isPrefixOf(keyName))
Yingdi Yuc55680b2014-02-26 12:31:35 -0800143 {
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 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700160 catch (InfoError& e)
Yingdi Yuc55680b2014-02-26 12:31:35 -0800161 {
162 return shared_ptr<IdentityCertificate>();
163 }
164 certificate->setPublicKeyInfo(*publicKey);
165
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700166 if (subjectDescription.empty())
Yingdi Yuc55680b2014-02-26 12:31:35 -0800167 {
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();
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700180
Yingdi Yuc55680b2014-02-26 12:31:35 -0800181 return certificate;
182 }
183
184 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800185 * @brief Sign packet with default identity
186 *
Yingdi Yu60bd7082014-03-25 18:18:54 -0700187 * On return, signatureInfo and signatureValue in the packet are set.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700188 * If default identity does not exist,
Yingdi Yu60bd7082014-03-25 18:18:54 -0700189 * a temporary identity will be created and set as default.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800190 *
191 * @param packet The packet to be signed
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800192 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800193 template<typename T>
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800194 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800195 sign(T& packet)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800196 {
Yingdi Yu60bd7082014-03-25 18:18:54 -0700197 if (!static_cast<bool>(Info::defaultCertificate()))
Yingdi Yu31b4af22014-01-14 14:13:00 -0800198 {
199 Info::refreshDefaultCertificate();
200
Yingdi Yu60bd7082014-03-25 18:18:54 -0700201 if (!static_cast<bool>(Info::defaultCertificate()))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800202 {
203 Name defaultIdentity;
204 try
205 {
206 defaultIdentity = Info::getDefaultIdentity();
207 }
Yingdi Yu60bd7082014-03-25 18:18:54 -0700208 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800209 {
210 uint32_t random = random::generateWord32();
Yingdi Yu60bd7082014-03-25 18:18:54 -0700211 defaultIdentity.append("tmp-identity")
212 .append(reinterpret_cast<uint8_t*>(&random), 4);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800213 }
214 createIdentity(defaultIdentity);
Yingdi Yu60bd7082014-03-25 18:18:54 -0700215 Info::setDefaultIdentity(defaultIdentity);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800216 Info::refreshDefaultCertificate();
217 }
Yingdi Yu31b4af22014-01-14 14:13:00 -0800218 }
219
Yingdi Yu2e57a582014-02-20 23:34:43 -0800220 sign(packet, *Info::defaultCertificate());
Yingdi Yu4270f202014-01-28 14:19:16 -0800221 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700222
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700223 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800224 * @brief Sign packet with a particular certificate.
225 *
226 * @param packet The packet to be signed.
227 * @param certificateName The certificate name of the key to use for signing.
228 * @throws SecPublicInfo::Error if certificate does not exist.
Jeff Thompson3c73da42013-08-12 11:19:05 -0700229 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800230 template<typename T>
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700231 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800232 sign(T& packet, const Name& certificateName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800233 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800234 if (!Info::doesCertificateExist(certificateName))
Yingdi Yu4270f202014-01-28 14:19:16 -0800235 throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
Yingdi Yu31b4af22014-01-14 14:13:00 -0800236
237 SignatureSha256WithRsa signature;
238 signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
Yingdi Yu31b4af22014-01-14 14:13:00 -0800239
240 // For temporary usage, we support RSA + SHA256 only, but will support more.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700241 signPacketWrapper(packet, signature,
242 IdentityCertificate::certificateNameToPublicKeyName(certificateName),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800243 DIGEST_ALGORITHM_SHA256);
Yingdi Yu4270f202014-01-28 14:19:16 -0800244 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700245
Jeff Thompson29ce3102013-09-27 11:47:48 -0700246 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800247 * @brief Sign the byte array using a particular certificate.
248 *
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700249 * @param buffer The byte array to be signed.
250 * @param bufferLength the length of buffer.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800251 * @param certificateName The certificate name of the signing key.
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700252 * @return The Signature.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800253 * @throws SecPublicInfo::Error if certificate does not exist.
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700254 */
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800255 Signature
Yingdi Yu31b4af22014-01-14 14:13:00 -0800256 sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
257 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800258 if (!Info::doesCertificateExist(certificateName))
Yingdi Yu4270f202014-01-28 14:19:16 -0800259 throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
Yingdi Yu31b4af22014-01-14 14:13:00 -0800260
261 SignatureSha256WithRsa signature;
262 signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700263
Yingdi Yu31b4af22014-01-14 14:13:00 -0800264 // For temporary usage, we support RSA + SHA256 only, but will support more.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700265 signature.setValue(Tpm::signInTpm(buffer, bufferLength,
266 IdentityCertificate::certificateNameToPublicKeyName(certificateName),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800267 DIGEST_ALGORITHM_SHA256));
Yingdi Yu31b4af22014-01-14 14:13:00 -0800268 return signature;
269 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700270
271 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800272 * @brief Sign packet using the default certificate of a particular identity.
273 *
274 * If there is no default certificate of that identity, this method will create a self-signed certificate.
275 *
276 * @param packet The packet to be signed.
277 * @param identityName The signing identity name.
Jeff Thompson29ce3102013-09-27 11:47:48 -0700278 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800279 template<typename T>
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700280 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800281 signByIdentity(T& packet, const Name& identityName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800282 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800283 Name signingCertificateName;
284 try
285 {
286 signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
287 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700288 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800289 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700290 signingCertificateName = createIdentity(identityName);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800291 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which is a fatal error.
292 }
Yingdi Yu31b4af22014-01-14 14:13:00 -0800293
Yingdi Yu2e57a582014-02-20 23:34:43 -0800294 // We either get or create the signing certificate, sign packet! (no exception unless fatal error in TPM)
295 sign(packet, signingCertificateName);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800296 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700297
Jeff Thompson3c73da42013-08-12 11:19:05 -0700298 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800299 * @brief Sign the byte array using the default certificate of a particular identity.
300 *
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700301 * @param buffer The byte array to be signed.
302 * @param bufferLength the length of buffer.
303 * @param identityName The identity name.
304 * @return The Signature.
305 */
Alexander Afanasyev64a3d812014-01-05 23:35:05 -0800306 Signature
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800307 signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800308 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800309 Name signingCertificateName;
310 try
311 {
312 signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
313 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700314 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800315 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700316 signingCertificateName = createIdentity(identityName);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800317 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which is a fatal error.
318 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700319
Yingdi Yu2e57a582014-02-20 23:34:43 -0800320 // We either get or create the signing certificate, sign data! (no exception unless fatal error in TPM)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800321 return sign(buffer, bufferLength, signingCertificateName);
322 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700323
324 /**
Yingdi Yu21157162014-02-28 13:02:34 -0800325 * @brief Set Sha256 weak signature.
326 *
327 * @param data.
328 */
329 void
330 signWithSha256(Data& data)
331 {
332 SignatureSha256 sig;
333 data.setSignature(sig);
334
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700335 Block sigValue(Tlv::SignatureValue,
336 crypto::sha256(data.wireEncode().value(),
Yingdi Yu21157162014-02-28 13:02:34 -0800337 data.wireEncode().value_size() - data.getSignature().getValue().size()));
338 data.setSignatureValue(sigValue);
339
340 }
341
342 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800343 * @brief Generate a self-signed certificate for a public key.
344 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800345 * @param keyName The name of the public key.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800346 * @return The generated certificate, NULL if selfSign fails.
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800347 */
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800348 shared_ptr<IdentityCertificate>
Yingdi Yu31b4af22014-01-14 14:13:00 -0800349 selfSign(const Name& keyName)
350 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800351 shared_ptr<PublicKey> pubKey;
352 try
353 {
354 pubKey = Info::getPublicKey(keyName); // may throw an exception.
355 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700356 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800357 {
358 return shared_ptr<IdentityCertificate>();
359 }
Yingdi Yu7ea69502014-01-15 17:21:29 -0800360
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800361 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700362
Yingdi Yu31b4af22014-01-14 14:13:00 -0800363 Name certificateName = keyName.getPrefix(-1);
364 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
Yingdi Yu2e57a582014-02-20 23:34:43 -0800365
Yingdi Yu31b4af22014-01-14 14:13:00 -0800366 certificate->setName(certificateName);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700367 certificate->setNotBefore(time::system_clock::now());
368 certificate->setNotAfter(time::system_clock::now() + time::days(7300)/* ~20 years*/);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800369 certificate->setPublicKeyInfo(*pubKey);
370 certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
371 certificate->encode();
372
373 selfSign(*certificate);
374 return certificate;
375 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800376
377 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800378 * @brief Self-sign the supplied identity certificate.
379 *
380 * @param cert The supplied cert.
381 * @throws SecTpm::Error if the private key does not exist.
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700382 */
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700383 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800384 selfSign (IdentityCertificate& cert)
385 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800386 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(cert.getName());
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700387 if (!Tpm::doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800388 throw TpmError("private key does not exist!");
389
Yingdi Yu31b4af22014-01-14 14:13:00 -0800390 SignatureSha256WithRsa signature;
391 signature.setKeyLocator(cert.getName().getPrefix(-1)); // implicit conversion should take care
Yingdi Yu31b4af22014-01-14 14:13:00 -0800392
393 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800394 signPacketWrapper(cert, signature, keyName, DIGEST_ALGORITHM_SHA256);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800395 }
396
Yingdi Yu2e57a582014-02-20 23:34:43 -0800397 /**
398 * @brief delete a certificate.
399 *
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700400 * If the certificate to be deleted is current default system default,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800401 * the method will not delete the certificate and return immediately.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700402 *
Yingdi Yu2e57a582014-02-20 23:34:43 -0800403 * @param certificateName The certificate to be deleted.
404 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800405 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800406 deleteCertificate (const Name& certificateName)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800407 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800408 try
409 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700410 if (Info::getDefaultCertificateName() == certificateName)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800411 return;
412 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700413 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800414 {
415 // Not a real error, just try to delete the certificate
416 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800417
418 Info::deleteCertificateInfo(certificateName);
419 }
420
Yingdi Yu2e57a582014-02-20 23:34:43 -0800421 /**
422 * @brief delete a key.
423 *
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700424 * If the key to be deleted is current default system default,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800425 * the method will not delete the key and return immediately.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700426 *
Yingdi Yu2e57a582014-02-20 23:34:43 -0800427 * @param keyName The key to be deleted.
428 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800429 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800430 deleteKey (const Name& keyName)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800431 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800432 try
433 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700434 if (Info::getDefaultKeyNameForIdentity(Info::getDefaultIdentity()) == keyName)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800435 return;
436 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700437 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800438 {
439 // Not a real error, just try to delete the key
440 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800441
442 Info::deletePublicKeyInfo(keyName);
443 Tpm::deleteKeyPairInTpm(keyName);
444 }
445
Yingdi Yu2e57a582014-02-20 23:34:43 -0800446 /**
447 * @brief delete an identity.
448 *
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700449 * If the identity to be deleted is current default system default,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800450 * the method will not delete the identity and return immediately.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700451 *
Yingdi Yu2e57a582014-02-20 23:34:43 -0800452 * @param identity The identity to be deleted.
453 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800454 void
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800455 deleteIdentity (const Name& identity)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800456 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800457 try
458 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700459 if (Info::getDefaultIdentity() == identity)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800460 return;
461 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700462 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800463 {
464 // Not a real error, just try to delete the identity
465 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800466
467 std::vector<Name> nameList;
468 Info::getAllKeyNamesOfIdentity(identity, nameList, true);
469 Info::getAllKeyNamesOfIdentity(identity, nameList, false);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700470
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800471 Info::deleteIdentityInfo(identity);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700472
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800473 std::vector<Name>::const_iterator it = nameList.begin();
474 for(; it != nameList.end(); it++)
475 Tpm::deleteKeyPairInTpm(*it);
476 }
477
Yingdi Yu2e57a582014-02-20 23:34:43 -0800478 /**
479 * @brief export an identity.
480 *
481 * @param identity The identity to export.
482 * @param passwordStr The password to secure the private key.
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800483 * @return The encoded export data.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800484 * @throws InfoError if anything goes wrong in exporting.
485 */
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800486 shared_ptr<SecuredBag>
Yingdi Yube4150e2014-02-18 13:02:46 -0800487 exportIdentity(const Name& identity, const std::string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800488 {
489 if (!Info::doesIdentityExist(identity))
490 throw InfoError("Identity does not exist!");
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700491
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800492 Name keyName = Info::getDefaultKeyNameForIdentity(identity);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800493
Yingdi Yu2e57a582014-02-20 23:34:43 -0800494 ConstBufferPtr pkcs8;
495 try
496 {
497 pkcs8 = Tpm::exportPrivateKeyPkcs8FromTpm(keyName, passwordStr);
498 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700499 catch (TpmError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800500 {
501 throw InfoError("Fail to export PKCS8 of private key");
502 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800503
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700504 shared_ptr<IdentityCertificate> cert;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800505 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800506 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800507 cert = Info::getCertificate(Info::getDefaultCertificateNameForKey(keyName));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800508 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700509 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800510 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700511 cert = selfSign(keyName);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800512 Info::addCertificateAsIdentityDefault(*cert);
513 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800514
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800515 shared_ptr<SecuredBag> secureBag = make_shared<SecuredBag>(boost::cref(*cert), boost::cref(pkcs8));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800516
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800517 return secureBag;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800518 }
519
Yingdi Yu2e57a582014-02-20 23:34:43 -0800520 /**
521 * @brief import an identity.
522 *
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800523 * @param securedBag The encoded import data.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800524 * @param passwordStr The password to secure the private key.
525 */
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800526 void
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800527 importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800528 {
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800529 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(securedBag.getCertificate().getName());
530 Name identity = keyName.getPrefix(-1);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700531
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800532 // Add identity
533 Info::addIdentity(identity);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700534
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800535 // Add key
536 Tpm::importPrivateKeyPkcs8IntoTpm(keyName, securedBag.getKey()->buf(), securedBag.getKey()->size(), passwordStr);
537 shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
538 Info::addPublicKey(keyName, KEY_TYPE_RSA, *pubKey); // HACK! We should set key type according to the pkcs8 info.
539 Info::setDefaultKeyNameForIdentity(keyName);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700540
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800541 // Add cert
542 Info::addCertificateAsIdentityDefault(securedBag.getCertificate());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800543 }
544
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700545
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800546private:
Yingdi Yu2e57a582014-02-20 23:34:43 -0800547 /**
548 * @brief sign a packet using a pariticular certificate.
549 *
550 * @param packet The packet to be signed.
551 * @param certificate The signing certificate.
552 */
553 template<typename T>
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800554 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800555 sign(T& packet, const IdentityCertificate& certificate)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800556 {
557 SignatureSha256WithRsa signature;
558 signature.setKeyLocator(certificate.getName().getPrefix(-1));
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800559
560 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800561 signPacketWrapper(packet, signature, certificate.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800562 }
563
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800564 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800565 * @brief Generate a key pair for the specified identity.
566 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800567 * @param identityName The name of the specified identity.
568 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
569 * @param keyType The type of the key pair, e.g. KEY_TYPE_RSA.
570 * @param keySize The size of the key pair.
571 * @return The name of the generated key.
572 */
573 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -0800574 generateKeyPair(const Name& identityName, bool isKsk = false, KeyType keyType = KEY_TYPE_RSA, int keySize = 2048)
575 {
576 Name keyName = Info::getNewKeyName(identityName, isKsk);
577
578 Tpm::generateKeyPairInTpm(keyName.toUri(), keyType, keySize);
579
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800580 shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
Yingdi Yuef26ee32014-01-15 16:41:14 -0800581 Info::addPublicKey(keyName, keyType, *pubKey);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800582
583 return keyName;
584 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800585
Yingdi Yu8726f652014-01-23 10:35:12 -0800586 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800587 * @brief Sign the data using a particular key.
588 *
589 * @param data Reference to the data packet.
590 * @param signature Signature to be added.
Yingdi Yu8726f652014-01-23 10:35:12 -0800591 * @param keyName The name of the signing key.
592 * @param digestAlgorithm the digest algorithm.
593 * @throws Tpm::Error
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700594 */
Yingdi Yu8726f652014-01-23 10:35:12 -0800595 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800596 signPacketWrapper(Data& data, const SignatureSha256WithRsa& signature, const Name& keyName, DigestAlgorithm digestAlgorithm)
Yingdi Yu8726f652014-01-23 10:35:12 -0800597 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800598 data.setSignature(signature);
Yingdi Yu8726f652014-01-23 10:35:12 -0800599 data.setSignatureValue
600 (Tpm::signInTpm(data.wireEncode().value(),
601 data.wireEncode().value_size() - data.getSignature().getValue().size(),
602 keyName, digestAlgorithm));
603 }
604
Yingdi Yu2e57a582014-02-20 23:34:43 -0800605 /**
606 * @brief Sign the interest using a particular key.
607 *
608 * @param interest Reference to the interest packet.
609 * @param signature Signature to be added.
610 * @param keyName The name of the signing key.
611 * @param digestAlgorithm the digest algorithm.
612 * @throws Tpm::Error
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700613 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800614 void
615 signPacketWrapper(Interest& interest, const SignatureSha256WithRsa& signature, const Name& keyName, DigestAlgorithm digestAlgorithm)
616 {
617 Name signedName = Name(interest.getName()).append(signature.getInfo());
618
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700619 Block sigValue = Tpm::signInTpm(signedName.wireEncode().value(),
620 signedName.wireEncode().value_size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800621 keyName,
622 DIGEST_ALGORITHM_SHA256);
623 sigValue.encode();
624 signedName.append(sigValue);
625 interest.setName(signedName);
626 }
627
628
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700629};
630
Yingdi Yufc40d872014-02-18 12:56:04 -0800631} // namespace ndn
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800632
Yingdi Yu04020922014-01-22 12:46:53 -0800633
634
Alexander Afanasyev3e08d5d2014-02-12 19:24:28 -0800635#if defined(NDN_CPP_HAVE_OSX_SECURITY) and defined(NDN_CPP_WITH_OSX_KEYCHAIN)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800636
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700637namespace ndn {
638
Yingdi Yu31b4af22014-01-14 14:13:00 -0800639typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmOsx> KeyChain;
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700640
641} // namespace ndn
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800642
Yingdi Yu31b4af22014-01-14 14:13:00 -0800643#else
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800644
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700645namespace ndn {
646
Yingdi Yu04020922014-01-22 12:46:53 -0800647typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmFile> KeyChain;
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700648
649} // namespace ndn
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800650
Yingdi Yu31b4af22014-01-14 14:13:00 -0800651#endif //NDN_CPP_HAVE_OSX_SECURITY
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700652
Yingdi Yufc40d872014-02-18 12:56:04 -0800653#endif //NDN_SECURITY_KEY_CHAIN_HPP