blob: 1a76d1ae9abda039c5aa7863568e10711755c35b [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 Yu4b8c6a22014-04-15 23:00:54 -070038 * The KeyChain class provides a set of interfaces of identity management and private key related
39 * operations.
Jeff Thompsonffa36f92013-09-20 08:42:41 -070040 */
Yingdi Yu31b4af22014-01-14 14:13:00 -080041template<class Info, class Tpm>
42class KeyChainImpl : public Info, public Tpm
43{
Yingdi Yuf8fc8de2014-02-25 15:45:39 -080044 typedef SecPublicInfo::Error InfoError;
45 typedef SecTpm::Error TpmError;
Jeff Thompson47c93cf2013-08-09 00:38:48 -070046public:
Yingdi Yube4150e2014-02-18 13:02:46 -080047 /**
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070048 * @brief Create an identity by creating a pair of Key-Signing-Key (KSK) for this identity and a
49 * self-signed certificate of the KSK.
Yingdi Yube4150e2014-02-18 13:02:46 -080050 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -080051 * @param identityName The name of the identity.
Yingdi Yu28fd32f2014-01-28 19:03:03 -080052 * @return The name of the default certificate of the identity.
Yingdi Yu2abd73f2014-01-08 23:34:11 -080053 */
54 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080055 createIdentity(const Name& identityName)
56 {
Yingdi Yu2e57a582014-02-20 23:34:43 -080057 Info::addIdentity(identityName);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070058
Yingdi Yu2e57a582014-02-20 23:34:43 -080059 Name keyName;
60 try
61 {
62 keyName = Info::getDefaultKeyNameForIdentity(identityName);
63 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070064 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080065 {
66 keyName = generateRSAKeyPairAsDefault(identityName, true);
67 }
Yingdi Yu31b4af22014-01-14 14:13:00 -080068
Yingdi Yu2e57a582014-02-20 23:34:43 -080069 Name certName;
70 try
71 {
72 certName = Info::getDefaultCertificateNameForKey(keyName);
73 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070074 catch (InfoError& e)
Yingdi Yu28fd32f2014-01-28 19:03:03 -080075 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070076 shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
Yingdi Yu28fd32f2014-01-28 19:03:03 -080077 Info::addCertificateAsIdentityDefault(*selfCert);
78 certName = selfCert->getName();
79 }
80
81 return certName;
Yingdi Yu31b4af22014-01-14 14:13:00 -080082 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070083
Yingdi Yu2abd73f2014-01-08 23:34:11 -080084 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -080085 * @brief Generate a pair of RSA keys for the specified identity.
86 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -080087 * @param identityName The name of the identity.
88 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
89 * @param keySize The size of the key.
90 * @return The generated key name.
91 */
92 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080093 generateRSAKeyPair(const Name& identityName, bool isKsk = false, int keySize = 2048)
Yingdi Yu2abd73f2014-01-08 23:34:11 -080094 {
Yingdi Yu31b4af22014-01-14 14:13:00 -080095 return generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
Yingdi Yu2abd73f2014-01-08 23:34:11 -080096 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070097
Yingdi Yu2abd73f2014-01-08 23:34:11 -080098 /**
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070099 * @brief Generate a pair of RSA keys for the specified identity and set it as default key for
100 * the identity.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800101 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800102 * @param identityName The name of the identity.
103 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
104 * @param keySize The size of the key.
105 * @return The generated key name.
106 */
107 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -0800108 generateRSAKeyPairAsDefault(const Name& identityName, bool isKsk = false, int keySize = 2048)
109 {
110 Name keyName = generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
111
112 Info::setDefaultKeyNameForIdentity(keyName);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700113
Yingdi Yu31b4af22014-01-14 14:13:00 -0800114 return keyName;
115 }
Jeff Thompson79a2d5d2013-09-27 14:32:23 -0700116
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800117 /**
Yingdi Yuc55680b2014-02-26 12:31:35 -0800118 * @brief prepare an unsigned identity certificate
119 *
120 * @param keyName Key name, e.g., /<identity_name>/ksk-123456.
121 * @param signingIdentity The signing identity.
122 * @param notBefore Refer to IdentityCertificate.
123 * @param notAfter Refer to IdentityCertificate.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700124 * @param subjectDescription Refer to IdentityCertificate.
Yingdi Yuc55680b2014-02-26 12:31:35 -0800125 * @return IdentityCertificate.
126 */
127 shared_ptr<IdentityCertificate>
128 prepareUnsignedIdentityCertificate(const Name& keyName,
129 const Name& signingIdentity,
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700130 const time::system_clock::TimePoint& notBefore,
131 const time::system_clock::TimePoint& notAfter,
Yingdi Yuc55680b2014-02-26 12:31:35 -0800132 const std::vector<CertificateSubjectDescription>& subjectDescription)
133
134 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700135 if (keyName.size() < 1)
Yingdi Yuc55680b2014-02-26 12:31:35 -0800136 return shared_ptr<IdentityCertificate>();
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700137
Yingdi Yuc55680b2014-02-26 12:31:35 -0800138 std::string keyIdPrefix = keyName.get(-1).toEscapedString().substr(0, 4);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700139 if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
Yingdi Yuc55680b2014-02-26 12:31:35 -0800140 return shared_ptr<IdentityCertificate>();
141
142 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
143 Name certName;
144
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700145 if (signingIdentity.isPrefixOf(keyName))
Yingdi Yuc55680b2014-02-26 12:31:35 -0800146 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700147 certName.append(signingIdentity)
148 .append("KEY")
149 .append(keyName.getSubName(signingIdentity.size()))
150 .append("ID-CERT")
151 .appendVersion();
Yingdi Yuc55680b2014-02-26 12:31:35 -0800152 }
153 else
154 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700155 certName.append(keyName.getPrefix(-1))
156 .append("KEY")
157 .append(keyName.get(-1))
158 .append("ID-CERT")
159 .appendVersion();
Yingdi Yuc55680b2014-02-26 12:31:35 -0800160 }
161
162 certificate->setName(certName);
163 certificate->setNotBefore(notBefore);
164 certificate->setNotAfter(notAfter);
165
166 shared_ptr<PublicKey> publicKey;
167 try
168 {
169 publicKey = Info::getPublicKey(keyName);
170 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700171 catch (InfoError& e)
Yingdi Yuc55680b2014-02-26 12:31:35 -0800172 {
173 return shared_ptr<IdentityCertificate>();
174 }
175 certificate->setPublicKeyInfo(*publicKey);
176
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700177 if (subjectDescription.empty())
Yingdi Yuc55680b2014-02-26 12:31:35 -0800178 {
179 CertificateSubjectDescription subDescryptName("2.5.4.41", keyName.getPrefix(-1).toUri());
180 certificate->addSubjectDescription(subDescryptName);
181 }
182 else
183 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700184 std::vector<CertificateSubjectDescription>::const_iterator sdIt =
185 subjectDescription.begin();
186 std::vector<CertificateSubjectDescription>::const_iterator sdEnd =
187 subjectDescription.end();
Yingdi Yuc55680b2014-02-26 12:31:35 -0800188 for(; sdIt != sdEnd; sdIt++)
189 certificate->addSubjectDescription(*sdIt);
190 }
191
192 certificate->encode();
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700193
Yingdi Yuc55680b2014-02-26 12:31:35 -0800194 return certificate;
195 }
196
197 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800198 * @brief Sign packet with default identity
199 *
Yingdi Yu60bd7082014-03-25 18:18:54 -0700200 * On return, signatureInfo and signatureValue in the packet are set.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700201 * If default identity does not exist,
Yingdi Yu60bd7082014-03-25 18:18:54 -0700202 * a temporary identity will be created and set as default.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800203 *
204 * @param packet The packet to be signed
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800205 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800206 template<typename T>
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800207 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800208 sign(T& packet)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800209 {
Yingdi Yu60bd7082014-03-25 18:18:54 -0700210 if (!static_cast<bool>(Info::defaultCertificate()))
Yingdi Yu31b4af22014-01-14 14:13:00 -0800211 {
212 Info::refreshDefaultCertificate();
213
Yingdi Yu60bd7082014-03-25 18:18:54 -0700214 if (!static_cast<bool>(Info::defaultCertificate()))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800215 {
216 Name defaultIdentity;
217 try
218 {
219 defaultIdentity = Info::getDefaultIdentity();
220 }
Yingdi Yu60bd7082014-03-25 18:18:54 -0700221 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800222 {
223 uint32_t random = random::generateWord32();
Yingdi Yu60bd7082014-03-25 18:18:54 -0700224 defaultIdentity.append("tmp-identity")
225 .append(reinterpret_cast<uint8_t*>(&random), 4);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800226 }
227 createIdentity(defaultIdentity);
Yingdi Yu60bd7082014-03-25 18:18:54 -0700228 Info::setDefaultIdentity(defaultIdentity);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800229 Info::refreshDefaultCertificate();
230 }
Yingdi Yu31b4af22014-01-14 14:13:00 -0800231 }
232
Yingdi Yu2e57a582014-02-20 23:34:43 -0800233 sign(packet, *Info::defaultCertificate());
Yingdi Yu4270f202014-01-28 14:19:16 -0800234 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700235
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700236 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800237 * @brief Sign packet with a particular certificate.
238 *
239 * @param packet The packet to be signed.
240 * @param certificateName The certificate name of the key to use for signing.
241 * @throws SecPublicInfo::Error if certificate does not exist.
Jeff Thompson3c73da42013-08-12 11:19:05 -0700242 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800243 template<typename T>
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700244 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800245 sign(T& packet, const Name& certificateName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800246 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800247 if (!Info::doesCertificateExist(certificateName))
Yingdi Yu4270f202014-01-28 14:19:16 -0800248 throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
Yingdi Yu31b4af22014-01-14 14:13:00 -0800249
250 SignatureSha256WithRsa signature;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700251 // implicit conversion should take care
252 signature.setKeyLocator(certificateName.getPrefix(-1));
Yingdi Yu31b4af22014-01-14 14:13:00 -0800253
254 // For temporary usage, we support RSA + SHA256 only, but will support more.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700255 signPacketWrapper(packet, signature,
256 IdentityCertificate::certificateNameToPublicKeyName(certificateName),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800257 DIGEST_ALGORITHM_SHA256);
Yingdi Yu4270f202014-01-28 14:19:16 -0800258 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700259
Jeff Thompson29ce3102013-09-27 11:47:48 -0700260 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800261 * @brief Sign the byte array using a particular certificate.
262 *
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700263 * @param buffer The byte array to be signed.
264 * @param bufferLength the length of buffer.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800265 * @param certificateName The certificate name of the signing key.
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700266 * @return The Signature.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800267 * @throws SecPublicInfo::Error if certificate does not exist.
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700268 */
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800269 Signature
Yingdi Yu31b4af22014-01-14 14:13:00 -0800270 sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
271 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800272 if (!Info::doesCertificateExist(certificateName))
Yingdi Yu4270f202014-01-28 14:19:16 -0800273 throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
Yingdi Yu31b4af22014-01-14 14:13:00 -0800274
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700275 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
276
Yingdi Yu31b4af22014-01-14 14:13:00 -0800277 SignatureSha256WithRsa signature;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700278 // implicit conversion should take care
279 signature.setKeyLocator(certificateName.getPrefix(-1));
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700280
Yingdi Yu31b4af22014-01-14 14:13:00 -0800281 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700282 signature.setValue(Tpm::signInTpm(buffer, bufferLength, keyName, DIGEST_ALGORITHM_SHA256));
Yingdi Yu31b4af22014-01-14 14:13:00 -0800283 return signature;
284 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700285
286 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800287 * @brief Sign packet using the default certificate of a particular identity.
288 *
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700289 * If there is no default certificate of that identity, this method will create a self-signed
290 * certificate.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800291 *
292 * @param packet The packet to be signed.
293 * @param identityName The signing identity name.
Jeff Thompson29ce3102013-09-27 11:47:48 -0700294 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800295 template<typename T>
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700296 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800297 signByIdentity(T& packet, const Name& identityName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800298 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800299 Name signingCertificateName;
300 try
301 {
302 signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
303 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700304 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800305 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700306 signingCertificateName = createIdentity(identityName);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700307 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which
308 // is a fatal error.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800309 }
Yingdi Yu31b4af22014-01-14 14:13:00 -0800310
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700311 // We either get or create the signing certificate, sign packet! (no exception unless fatal
312 // error in TPM)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800313 sign(packet, signingCertificateName);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800314 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700315
Jeff Thompson3c73da42013-08-12 11:19:05 -0700316 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800317 * @brief Sign the byte array using the default certificate of a particular identity.
318 *
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700319 * @param buffer The byte array to be signed.
320 * @param bufferLength the length of buffer.
321 * @param identityName The identity name.
322 * @return The Signature.
323 */
Alexander Afanasyev64a3d812014-01-05 23:35:05 -0800324 Signature
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800325 signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800326 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800327 Name signingCertificateName;
328 try
329 {
330 signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
331 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700332 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800333 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700334 signingCertificateName = createIdentity(identityName);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700335 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which
336 // is a fatal error.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800337 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700338
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700339 // We either get or create the signing certificate, sign data! (no exception unless fatal error
340 // in TPM)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800341 return sign(buffer, bufferLength, signingCertificateName);
342 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700343
344 /**
Yingdi Yu21157162014-02-28 13:02:34 -0800345 * @brief Set Sha256 weak signature.
346 *
347 * @param data.
348 */
349 void
350 signWithSha256(Data& data)
351 {
352 SignatureSha256 sig;
353 data.setSignature(sig);
354
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700355 Block sigValue(Tlv::SignatureValue,
356 crypto::sha256(data.wireEncode().value(),
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700357 data.wireEncode().value_size() -
358 data.getSignature().getValue().size()));
Yingdi Yu21157162014-02-28 13:02:34 -0800359 data.setSignatureValue(sigValue);
Yingdi Yu21157162014-02-28 13:02:34 -0800360 }
361
362 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800363 * @brief Generate a self-signed certificate for a public key.
364 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800365 * @param keyName The name of the public key.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800366 * @return The generated certificate, NULL if selfSign fails.
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800367 */
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800368 shared_ptr<IdentityCertificate>
Yingdi Yu31b4af22014-01-14 14:13:00 -0800369 selfSign(const Name& keyName)
370 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800371 shared_ptr<PublicKey> pubKey;
372 try
373 {
374 pubKey = Info::getPublicKey(keyName); // may throw an exception.
375 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700376 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800377 {
378 return shared_ptr<IdentityCertificate>();
379 }
Yingdi Yu7ea69502014-01-15 17:21:29 -0800380
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800381 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700382
Yingdi Yu31b4af22014-01-14 14:13:00 -0800383 Name certificateName = keyName.getPrefix(-1);
384 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
Yingdi Yu2e57a582014-02-20 23:34:43 -0800385
Yingdi Yu31b4af22014-01-14 14:13:00 -0800386 certificate->setName(certificateName);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700387 certificate->setNotBefore(time::system_clock::now());
388 certificate->setNotAfter(time::system_clock::now() + time::days(7300)/* ~20 years*/);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800389 certificate->setPublicKeyInfo(*pubKey);
390 certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
391 certificate->encode();
392
393 selfSign(*certificate);
394 return certificate;
395 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800396
397 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800398 * @brief Self-sign the supplied identity certificate.
399 *
400 * @param cert The supplied cert.
401 * @throws SecTpm::Error if the private key does not exist.
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700402 */
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700403 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800404 selfSign (IdentityCertificate& cert)
405 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800406 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(cert.getName());
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700407 if (!Tpm::doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800408 throw TpmError("private key does not exist!");
409
Yingdi Yu31b4af22014-01-14 14:13:00 -0800410 SignatureSha256WithRsa signature;
411 signature.setKeyLocator(cert.getName().getPrefix(-1)); // implicit conversion should take care
Yingdi Yu31b4af22014-01-14 14:13:00 -0800412
413 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800414 signPacketWrapper(cert, signature, keyName, DIGEST_ALGORITHM_SHA256);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800415 }
416
Yingdi Yu2e57a582014-02-20 23:34:43 -0800417 /**
418 * @brief delete a certificate.
419 *
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700420 * If the certificate to be deleted is current default system default,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800421 * the method will not delete the certificate and return immediately.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700422 *
Yingdi Yu2e57a582014-02-20 23:34:43 -0800423 * @param certificateName The certificate to be deleted.
424 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800425 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800426 deleteCertificate (const Name& certificateName)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800427 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800428 try
429 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700430 if (Info::getDefaultCertificateName() == certificateName)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800431 return;
432 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700433 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800434 {
435 // Not a real error, just try to delete the certificate
436 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800437
438 Info::deleteCertificateInfo(certificateName);
439 }
440
Yingdi Yu2e57a582014-02-20 23:34:43 -0800441 /**
442 * @brief delete a key.
443 *
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700444 * If the key to be deleted is current default system default,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800445 * the method will not delete the key and return immediately.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700446 *
Yingdi Yu2e57a582014-02-20 23:34:43 -0800447 * @param keyName The key to be deleted.
448 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800449 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800450 deleteKey (const Name& keyName)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800451 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800452 try
453 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700454 if (Info::getDefaultKeyNameForIdentity(Info::getDefaultIdentity()) == keyName)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800455 return;
456 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700457 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800458 {
459 // Not a real error, just try to delete the key
460 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800461
462 Info::deletePublicKeyInfo(keyName);
463 Tpm::deleteKeyPairInTpm(keyName);
464 }
465
Yingdi Yu2e57a582014-02-20 23:34:43 -0800466 /**
467 * @brief delete an identity.
468 *
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700469 * If the identity to be deleted is current default system default,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800470 * the method will not delete the identity and return immediately.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700471 *
Yingdi Yu2e57a582014-02-20 23:34:43 -0800472 * @param identity The identity to be deleted.
473 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800474 void
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800475 deleteIdentity (const Name& identity)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800476 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800477 try
478 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700479 if (Info::getDefaultIdentity() == identity)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800480 return;
481 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700482 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800483 {
484 // Not a real error, just try to delete the identity
485 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800486
487 std::vector<Name> nameList;
488 Info::getAllKeyNamesOfIdentity(identity, nameList, true);
489 Info::getAllKeyNamesOfIdentity(identity, nameList, false);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700490
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800491 Info::deleteIdentityInfo(identity);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700492
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800493 std::vector<Name>::const_iterator it = nameList.begin();
494 for(; it != nameList.end(); it++)
495 Tpm::deleteKeyPairInTpm(*it);
496 }
497
Yingdi Yu2e57a582014-02-20 23:34:43 -0800498 /**
499 * @brief export an identity.
500 *
501 * @param identity The identity to export.
502 * @param passwordStr The password to secure the private key.
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800503 * @return The encoded export data.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800504 * @throws InfoError if anything goes wrong in exporting.
505 */
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800506 shared_ptr<SecuredBag>
Yingdi Yube4150e2014-02-18 13:02:46 -0800507 exportIdentity(const Name& identity, const std::string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800508 {
509 if (!Info::doesIdentityExist(identity))
510 throw InfoError("Identity does not exist!");
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700511
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800512 Name keyName = Info::getDefaultKeyNameForIdentity(identity);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800513
Yingdi Yu2e57a582014-02-20 23:34:43 -0800514 ConstBufferPtr pkcs8;
515 try
516 {
517 pkcs8 = Tpm::exportPrivateKeyPkcs8FromTpm(keyName, passwordStr);
518 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700519 catch (TpmError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800520 {
521 throw InfoError("Fail to export PKCS8 of private key");
522 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800523
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700524 shared_ptr<IdentityCertificate> cert;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800525 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800526 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800527 cert = Info::getCertificate(Info::getDefaultCertificateNameForKey(keyName));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800528 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700529 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800530 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700531 cert = selfSign(keyName);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800532 Info::addCertificateAsIdentityDefault(*cert);
533 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800534
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700535 shared_ptr<SecuredBag> secureBag = make_shared<SecuredBag>(boost::cref(*cert),
536 boost::cref(pkcs8));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800537
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800538 return secureBag;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800539 }
540
Yingdi Yu2e57a582014-02-20 23:34:43 -0800541 /**
542 * @brief import an identity.
543 *
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800544 * @param securedBag The encoded import data.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800545 * @param passwordStr The password to secure the private key.
546 */
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800547 void
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800548 importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800549 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700550 Name certificateName = securedBag.getCertificate().getName();
551 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800552 Name identity = keyName.getPrefix(-1);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700553
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800554 // Add identity
555 Info::addIdentity(identity);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700556
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800557 // Add key
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700558 Tpm::importPrivateKeyPkcs8IntoTpm(keyName,
559 securedBag.getKey()->buf(),
560 securedBag.getKey()->size(),
561 passwordStr);
562
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800563 shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700564 // HACK! We should set key type according to the pkcs8 info.
565 Info::addPublicKey(keyName, KEY_TYPE_RSA, *pubKey);
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800566 Info::setDefaultKeyNameForIdentity(keyName);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700567
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800568 // Add cert
569 Info::addCertificateAsIdentityDefault(securedBag.getCertificate());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800570 }
571
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700572
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800573private:
Yingdi Yu2e57a582014-02-20 23:34:43 -0800574 /**
575 * @brief sign a packet using a pariticular certificate.
576 *
577 * @param packet The packet to be signed.
578 * @param certificate The signing certificate.
579 */
580 template<typename T>
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800581 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800582 sign(T& packet, const IdentityCertificate& certificate)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800583 {
584 SignatureSha256WithRsa signature;
585 signature.setKeyLocator(certificate.getName().getPrefix(-1));
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800586
587 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800588 signPacketWrapper(packet, signature, certificate.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800589 }
590
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800591 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800592 * @brief Generate a key pair for the specified identity.
593 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800594 * @param identityName The name of the specified identity.
595 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
596 * @param keyType The type of the key pair, e.g. KEY_TYPE_RSA.
597 * @param keySize The size of the key pair.
598 * @return The name of the generated key.
599 */
600 Name
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700601 generateKeyPair(const Name& identityName, bool isKsk = false,
602 KeyType keyType = KEY_TYPE_RSA, int keySize = 2048)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800603 {
604 Name keyName = Info::getNewKeyName(identityName, isKsk);
605
606 Tpm::generateKeyPairInTpm(keyName.toUri(), keyType, keySize);
607
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800608 shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
Yingdi Yuef26ee32014-01-15 16:41:14 -0800609 Info::addPublicKey(keyName, keyType, *pubKey);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800610
611 return keyName;
612 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800613
Yingdi Yu8726f652014-01-23 10:35:12 -0800614 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800615 * @brief Sign the data using a particular key.
616 *
617 * @param data Reference to the data packet.
618 * @param signature Signature to be added.
Yingdi Yu8726f652014-01-23 10:35:12 -0800619 * @param keyName The name of the signing key.
620 * @param digestAlgorithm the digest algorithm.
621 * @throws Tpm::Error
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700622 */
Yingdi Yu8726f652014-01-23 10:35:12 -0800623 void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700624 signPacketWrapper(Data& data, const SignatureSha256WithRsa& signature,
625 const Name& keyName, DigestAlgorithm digestAlgorithm)
Yingdi Yu8726f652014-01-23 10:35:12 -0800626 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800627 data.setSignature(signature);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700628 data.setSignatureValue(Tpm::signInTpm(data.wireEncode().value(),
629 data.wireEncode().value_size() -
630 data.getSignature().getValue().size(),
631 keyName, digestAlgorithm));
Yingdi Yu8726f652014-01-23 10:35:12 -0800632 }
633
Yingdi Yu2e57a582014-02-20 23:34:43 -0800634 /**
635 * @brief Sign the interest using a particular key.
636 *
637 * @param interest Reference to the interest packet.
638 * @param signature Signature to be added.
639 * @param keyName The name of the signing key.
640 * @param digestAlgorithm the digest algorithm.
641 * @throws Tpm::Error
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700642 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800643 void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700644 signPacketWrapper(Interest& interest, const SignatureSha256WithRsa& signature,
645 const Name& keyName, DigestAlgorithm digestAlgorithm)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800646 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700647 Name signedName = interest.getName();
648 signedName.append(signature.getInfo());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800649
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700650 Block sigValue = Tpm::signInTpm(signedName.wireEncode().value(),
651 signedName.wireEncode().value_size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800652 keyName,
653 DIGEST_ALGORITHM_SHA256);
654 sigValue.encode();
655 signedName.append(sigValue);
656 interest.setName(signedName);
657 }
658
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700659};
660
Yingdi Yufc40d872014-02-18 12:56:04 -0800661} // namespace ndn
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800662
Yingdi Yu04020922014-01-22 12:46:53 -0800663
664
Alexander Afanasyev3e08d5d2014-02-12 19:24:28 -0800665#if defined(NDN_CPP_HAVE_OSX_SECURITY) and defined(NDN_CPP_WITH_OSX_KEYCHAIN)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800666
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700667namespace ndn {
668
Yingdi Yu31b4af22014-01-14 14:13:00 -0800669typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmOsx> KeyChain;
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700670
671} // namespace ndn
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800672
Yingdi Yu31b4af22014-01-14 14:13:00 -0800673#else
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800674
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700675namespace ndn {
676
Yingdi Yu04020922014-01-22 12:46:53 -0800677typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmFile> KeyChain;
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700678
679} // namespace ndn
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800680
Yingdi Yu31b4af22014-01-14 14:13:00 -0800681#endif //NDN_CPP_HAVE_OSX_SECURITY
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700682
Yingdi Yufc40d872014-02-18 12:56:04 -0800683#endif //NDN_SECURITY_KEY_CHAIN_HPP