blob: 69d5ffbe903965568688c792d2439236d72d041f [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/**
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07003 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
11 *
12 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Jeff Thompson47c93cf2013-08-09 00:38:48 -070013 */
14
Yingdi Yufc40d872014-02-18 12:56:04 -080015#ifndef NDN_SECURITY_KEY_CHAIN_HPP
16#define NDN_SECURITY_KEY_CHAIN_HPP
Jeff Thompson47c93cf2013-08-09 00:38:48 -070017
Yingdi Yu4f324632014-01-15 18:10:03 -080018#include "identity-certificate.hpp"
19#include "public-key.hpp"
20#include "signature-sha256-with-rsa.hpp"
Yingdi Yu21157162014-02-28 13:02:34 -080021#include "signature-sha256.hpp"
Yingdi Yu64c3fb42014-02-26 17:30:04 -080022#include "secured-bag.hpp"
Yingdi Yu4270f202014-01-28 14:19:16 -080023#include "../interest.hpp"
Yingdi Yu2e57a582014-02-20 23:34:43 -080024#include "../util/random.hpp"
Yingdi Yu21157162014-02-28 13:02:34 -080025#include "../util/crypto.hpp"
Yingdi Yu31b4af22014-01-14 14:13:00 -080026
Yingdi Yu04020922014-01-22 12:46:53 -080027//PublicInfo
Yingdi Yu4f324632014-01-15 18:10:03 -080028#include "sec-public-info-sqlite3.hpp"
29#include "sec-public-info-memory.hpp"
Yingdi Yu04020922014-01-22 12:46:53 -080030//TPM
31#include "sec-tpm-file.hpp"
Yingdi Yu4f324632014-01-15 18:10:03 -080032#include "sec-tpm-memory.hpp"
Yingdi Yu2abd73f2014-01-08 23:34:11 -080033
Alexander Afanasyev766cea72014-04-24 19:16:42 -070034#ifdef NDN_CXX_HAVE_OSX_SECURITY
Yingdi Yu04020922014-01-22 12:46:53 -080035#include "sec-tpm-osx.hpp"
36#endif
37
Jeff Thompson47c93cf2013-08-09 00:38:48 -070038
39namespace ndn {
40
Jeff Thompson2ce8f492013-09-17 18:01:25 -070041/**
Yingdi Yu2e57a582014-02-20 23:34:43 -080042 * @brief KeyChain is one of the main classes of the security library.
Jeff Thompsonffa36f92013-09-20 08:42:41 -070043 *
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070044 * The KeyChain class provides a set of interfaces of identity management and private key related
45 * operations.
Jeff Thompsonffa36f92013-09-20 08:42:41 -070046 */
Yingdi Yu31b4af22014-01-14 14:13:00 -080047template<class Info, class Tpm>
48class KeyChainImpl : public Info, public Tpm
49{
Yingdi Yuf8fc8de2014-02-25 15:45:39 -080050 typedef SecPublicInfo::Error InfoError;
51 typedef SecTpm::Error TpmError;
Jeff Thompson47c93cf2013-08-09 00:38:48 -070052public:
Yingdi Yube4150e2014-02-18 13:02:46 -080053 /**
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070054 * @brief Create an identity by creating a pair of Key-Signing-Key (KSK) for this identity and a
55 * self-signed certificate of the KSK.
Yingdi Yube4150e2014-02-18 13:02:46 -080056 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -080057 * @param identityName The name of the identity.
Yingdi Yu28fd32f2014-01-28 19:03:03 -080058 * @return The name of the default certificate of the identity.
Yingdi Yu2abd73f2014-01-08 23:34:11 -080059 */
60 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080061 createIdentity(const Name& identityName)
62 {
Yingdi Yu2e57a582014-02-20 23:34:43 -080063 Info::addIdentity(identityName);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070064
Yingdi Yu2e57a582014-02-20 23:34:43 -080065 Name keyName;
66 try
67 {
68 keyName = Info::getDefaultKeyNameForIdentity(identityName);
69 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070070 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080071 {
72 keyName = generateRSAKeyPairAsDefault(identityName, true);
73 }
Yingdi Yu31b4af22014-01-14 14:13:00 -080074
Yingdi Yu2e57a582014-02-20 23:34:43 -080075 Name certName;
76 try
77 {
78 certName = Info::getDefaultCertificateNameForKey(keyName);
79 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070080 catch (InfoError& e)
Yingdi Yu28fd32f2014-01-28 19:03:03 -080081 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070082 shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
Yingdi Yu28fd32f2014-01-28 19:03:03 -080083 Info::addCertificateAsIdentityDefault(*selfCert);
84 certName = selfCert->getName();
85 }
86
87 return certName;
Yingdi Yu31b4af22014-01-14 14:13:00 -080088 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070089
Yingdi Yu2abd73f2014-01-08 23:34:11 -080090 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -080091 * @brief Generate a pair of RSA keys for the specified identity.
92 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -080093 * @param identityName The name of the identity.
94 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
95 * @param keySize The size of the key.
96 * @return The generated key name.
97 */
98 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080099 generateRSAKeyPair(const Name& identityName, bool isKsk = false, int keySize = 2048)
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800100 {
Yingdi Yu31b4af22014-01-14 14:13:00 -0800101 return generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800102 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700103
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800104 /**
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700105 * @brief Generate a pair of RSA keys for the specified identity and set it as default key for
106 * the identity.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800107 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800108 * @param identityName The name of the identity.
109 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
110 * @param keySize The size of the key.
111 * @return The generated key name.
112 */
113 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -0800114 generateRSAKeyPairAsDefault(const Name& identityName, bool isKsk = false, int keySize = 2048)
115 {
116 Name keyName = generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
117
118 Info::setDefaultKeyNameForIdentity(keyName);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700119
Yingdi Yu31b4af22014-01-14 14:13:00 -0800120 return keyName;
121 }
Jeff Thompson79a2d5d2013-09-27 14:32:23 -0700122
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800123 /**
Yingdi Yuc55680b2014-02-26 12:31:35 -0800124 * @brief prepare an unsigned identity certificate
125 *
126 * @param keyName Key name, e.g., /<identity_name>/ksk-123456.
127 * @param signingIdentity The signing identity.
128 * @param notBefore Refer to IdentityCertificate.
129 * @param notAfter Refer to IdentityCertificate.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700130 * @param subjectDescription Refer to IdentityCertificate.
Yingdi Yuc55680b2014-02-26 12:31:35 -0800131 * @return IdentityCertificate.
132 */
133 shared_ptr<IdentityCertificate>
134 prepareUnsignedIdentityCertificate(const Name& keyName,
135 const Name& signingIdentity,
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700136 const time::system_clock::TimePoint& notBefore,
137 const time::system_clock::TimePoint& notAfter,
Yingdi Yuc55680b2014-02-26 12:31:35 -0800138 const std::vector<CertificateSubjectDescription>& subjectDescription)
139
140 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700141 if (keyName.size() < 1)
Yingdi Yuc55680b2014-02-26 12:31:35 -0800142 return shared_ptr<IdentityCertificate>();
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700143
Yingdi Yuc55680b2014-02-26 12:31:35 -0800144 std::string keyIdPrefix = keyName.get(-1).toEscapedString().substr(0, 4);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700145 if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
Yingdi Yuc55680b2014-02-26 12:31:35 -0800146 return shared_ptr<IdentityCertificate>();
147
148 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
149 Name certName;
150
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700151 if (signingIdentity.isPrefixOf(keyName))
Yingdi Yuc55680b2014-02-26 12:31:35 -0800152 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700153 certName.append(signingIdentity)
154 .append("KEY")
155 .append(keyName.getSubName(signingIdentity.size()))
156 .append("ID-CERT")
157 .appendVersion();
Yingdi Yuc55680b2014-02-26 12:31:35 -0800158 }
159 else
160 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700161 certName.append(keyName.getPrefix(-1))
162 .append("KEY")
163 .append(keyName.get(-1))
164 .append("ID-CERT")
165 .appendVersion();
Yingdi Yuc55680b2014-02-26 12:31:35 -0800166 }
167
168 certificate->setName(certName);
169 certificate->setNotBefore(notBefore);
170 certificate->setNotAfter(notAfter);
171
172 shared_ptr<PublicKey> publicKey;
173 try
174 {
175 publicKey = Info::getPublicKey(keyName);
176 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700177 catch (InfoError& e)
Yingdi Yuc55680b2014-02-26 12:31:35 -0800178 {
179 return shared_ptr<IdentityCertificate>();
180 }
181 certificate->setPublicKeyInfo(*publicKey);
182
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700183 if (subjectDescription.empty())
Yingdi Yuc55680b2014-02-26 12:31:35 -0800184 {
185 CertificateSubjectDescription subDescryptName("2.5.4.41", keyName.getPrefix(-1).toUri());
186 certificate->addSubjectDescription(subDescryptName);
187 }
188 else
189 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700190 std::vector<CertificateSubjectDescription>::const_iterator sdIt =
191 subjectDescription.begin();
192 std::vector<CertificateSubjectDescription>::const_iterator sdEnd =
193 subjectDescription.end();
Yingdi Yuc55680b2014-02-26 12:31:35 -0800194 for(; sdIt != sdEnd; sdIt++)
195 certificate->addSubjectDescription(*sdIt);
196 }
197
198 certificate->encode();
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700199
Yingdi Yuc55680b2014-02-26 12:31:35 -0800200 return certificate;
201 }
202
203 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800204 * @brief Sign packet with default identity
205 *
Yingdi Yu60bd7082014-03-25 18:18:54 -0700206 * On return, signatureInfo and signatureValue in the packet are set.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700207 * If default identity does not exist,
Yingdi Yu60bd7082014-03-25 18:18:54 -0700208 * a temporary identity will be created and set as default.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800209 *
210 * @param packet The packet to be signed
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800211 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800212 template<typename T>
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800213 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800214 sign(T& packet)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800215 {
Yingdi Yu60bd7082014-03-25 18:18:54 -0700216 if (!static_cast<bool>(Info::defaultCertificate()))
Yingdi Yu31b4af22014-01-14 14:13:00 -0800217 {
218 Info::refreshDefaultCertificate();
219
Yingdi Yu60bd7082014-03-25 18:18:54 -0700220 if (!static_cast<bool>(Info::defaultCertificate()))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800221 {
222 Name defaultIdentity;
223 try
224 {
225 defaultIdentity = Info::getDefaultIdentity();
226 }
Yingdi Yu60bd7082014-03-25 18:18:54 -0700227 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800228 {
229 uint32_t random = random::generateWord32();
Yingdi Yu60bd7082014-03-25 18:18:54 -0700230 defaultIdentity.append("tmp-identity")
231 .append(reinterpret_cast<uint8_t*>(&random), 4);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800232 }
233 createIdentity(defaultIdentity);
Yingdi Yu60bd7082014-03-25 18:18:54 -0700234 Info::setDefaultIdentity(defaultIdentity);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800235 Info::refreshDefaultCertificate();
236 }
Yingdi Yu31b4af22014-01-14 14:13:00 -0800237 }
238
Yingdi Yu2e57a582014-02-20 23:34:43 -0800239 sign(packet, *Info::defaultCertificate());
Yingdi Yu4270f202014-01-28 14:19:16 -0800240 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700241
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700242 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800243 * @brief Sign packet with a particular certificate.
244 *
245 * @param packet The packet to be signed.
246 * @param certificateName The certificate name of the key to use for signing.
247 * @throws SecPublicInfo::Error if certificate does not exist.
Jeff Thompson3c73da42013-08-12 11:19:05 -0700248 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800249 template<typename T>
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700250 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800251 sign(T& packet, const Name& certificateName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800252 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800253 if (!Info::doesCertificateExist(certificateName))
Yingdi Yu4270f202014-01-28 14:19:16 -0800254 throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
Yingdi Yu31b4af22014-01-14 14:13:00 -0800255
256 SignatureSha256WithRsa signature;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700257 // implicit conversion should take care
258 signature.setKeyLocator(certificateName.getPrefix(-1));
Yingdi Yu31b4af22014-01-14 14:13:00 -0800259
260 // For temporary usage, we support RSA + SHA256 only, but will support more.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700261 signPacketWrapper(packet, signature,
262 IdentityCertificate::certificateNameToPublicKeyName(certificateName),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800263 DIGEST_ALGORITHM_SHA256);
Yingdi Yu4270f202014-01-28 14:19:16 -0800264 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700265
Jeff Thompson29ce3102013-09-27 11:47:48 -0700266 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800267 * @brief Sign the byte array using a particular certificate.
268 *
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700269 * @param buffer The byte array to be signed.
270 * @param bufferLength the length of buffer.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800271 * @param certificateName The certificate name of the signing key.
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700272 * @return The Signature.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800273 * @throws SecPublicInfo::Error if certificate does not exist.
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700274 */
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800275 Signature
Yingdi Yu31b4af22014-01-14 14:13:00 -0800276 sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
277 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800278 if (!Info::doesCertificateExist(certificateName))
Yingdi Yu4270f202014-01-28 14:19:16 -0800279 throw InfoError("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
Yingdi Yu31b4af22014-01-14 14:13:00 -0800280
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700281 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
282
Yingdi Yu31b4af22014-01-14 14:13:00 -0800283 SignatureSha256WithRsa signature;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700284 // implicit conversion should take care
285 signature.setKeyLocator(certificateName.getPrefix(-1));
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700286
Yingdi Yu31b4af22014-01-14 14:13:00 -0800287 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700288 signature.setValue(Tpm::signInTpm(buffer, bufferLength, keyName, DIGEST_ALGORITHM_SHA256));
Yingdi Yu31b4af22014-01-14 14:13:00 -0800289 return signature;
290 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700291
292 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800293 * @brief Sign packet using the default certificate of a particular identity.
294 *
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700295 * If there is no default certificate of that identity, this method will create a self-signed
296 * certificate.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800297 *
298 * @param packet The packet to be signed.
299 * @param identityName The signing identity name.
Jeff Thompson29ce3102013-09-27 11:47:48 -0700300 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800301 template<typename T>
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700302 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800303 signByIdentity(T& packet, 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 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700310 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800311 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700312 signingCertificateName = createIdentity(identityName);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700313 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which
314 // is a fatal error.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800315 }
Yingdi Yu31b4af22014-01-14 14:13:00 -0800316
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700317 // We either get or create the signing certificate, sign packet! (no exception unless fatal
318 // error in TPM)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800319 sign(packet, signingCertificateName);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800320 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700321
Jeff Thompson3c73da42013-08-12 11:19:05 -0700322 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800323 * @brief Sign the byte array using the default certificate of a particular identity.
324 *
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700325 * @param buffer The byte array to be signed.
326 * @param bufferLength the length of buffer.
327 * @param identityName The identity name.
328 * @return The Signature.
329 */
Alexander Afanasyev64a3d812014-01-05 23:35:05 -0800330 Signature
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800331 signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800332 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800333 Name signingCertificateName;
334 try
335 {
336 signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
337 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700338 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800339 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700340 signingCertificateName = createIdentity(identityName);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700341 // Ideally, no exception will be thrown out, unless something goes wrong in the TPM, which
342 // is a fatal error.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800343 }
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700344
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700345 // We either get or create the signing certificate, sign data! (no exception unless fatal error
346 // in TPM)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800347 return sign(buffer, bufferLength, signingCertificateName);
348 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700349
350 /**
Yingdi Yu21157162014-02-28 13:02:34 -0800351 * @brief Set Sha256 weak signature.
352 *
353 * @param data.
354 */
355 void
356 signWithSha256(Data& data)
357 {
358 SignatureSha256 sig;
359 data.setSignature(sig);
360
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700361 Block sigValue(Tlv::SignatureValue,
362 crypto::sha256(data.wireEncode().value(),
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700363 data.wireEncode().value_size() -
364 data.getSignature().getValue().size()));
Yingdi Yu21157162014-02-28 13:02:34 -0800365 data.setSignatureValue(sigValue);
Yingdi Yu21157162014-02-28 13:02:34 -0800366 }
367
368 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800369 * @brief Generate a self-signed certificate for a public key.
370 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800371 * @param keyName The name of the public key.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800372 * @return The generated certificate, NULL if selfSign fails.
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800373 */
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800374 shared_ptr<IdentityCertificate>
Yingdi Yu31b4af22014-01-14 14:13:00 -0800375 selfSign(const Name& keyName)
376 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800377 shared_ptr<PublicKey> pubKey;
378 try
379 {
380 pubKey = Info::getPublicKey(keyName); // may throw an exception.
381 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700382 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800383 {
384 return shared_ptr<IdentityCertificate>();
385 }
Yingdi Yu7ea69502014-01-15 17:21:29 -0800386
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800387 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700388
Yingdi Yu31b4af22014-01-14 14:13:00 -0800389 Name certificateName = keyName.getPrefix(-1);
390 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
Yingdi Yu2e57a582014-02-20 23:34:43 -0800391
Yingdi Yu31b4af22014-01-14 14:13:00 -0800392 certificate->setName(certificateName);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700393 certificate->setNotBefore(time::system_clock::now());
394 certificate->setNotAfter(time::system_clock::now() + time::days(7300)/* ~20 years*/);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800395 certificate->setPublicKeyInfo(*pubKey);
396 certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
397 certificate->encode();
398
399 selfSign(*certificate);
400 return certificate;
401 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800402
403 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800404 * @brief Self-sign the supplied identity certificate.
405 *
406 * @param cert The supplied cert.
407 * @throws SecTpm::Error if the private key does not exist.
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700408 */
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700409 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800410 selfSign (IdentityCertificate& cert)
411 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800412 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(cert.getName());
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700413 if (!Tpm::doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800414 throw TpmError("private key does not exist!");
415
Yingdi Yu31b4af22014-01-14 14:13:00 -0800416 SignatureSha256WithRsa signature;
417 signature.setKeyLocator(cert.getName().getPrefix(-1)); // implicit conversion should take care
Yingdi Yu31b4af22014-01-14 14:13:00 -0800418
419 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800420 signPacketWrapper(cert, signature, keyName, DIGEST_ALGORITHM_SHA256);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800421 }
422
Yingdi Yu2e57a582014-02-20 23:34:43 -0800423 /**
424 * @brief delete a certificate.
425 *
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700426 * If the certificate to be deleted is current default system default,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800427 * the method will not delete the certificate and return immediately.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700428 *
Yingdi Yu2e57a582014-02-20 23:34:43 -0800429 * @param certificateName The certificate to be deleted.
430 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800431 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800432 deleteCertificate (const Name& certificateName)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800433 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800434 try
435 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700436 if (Info::getDefaultCertificateName() == certificateName)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800437 return;
438 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700439 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800440 {
441 // Not a real error, just try to delete the certificate
442 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800443
444 Info::deleteCertificateInfo(certificateName);
445 }
446
Yingdi Yu2e57a582014-02-20 23:34:43 -0800447 /**
448 * @brief delete a key.
449 *
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700450 * If the key to be deleted is current default system default,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800451 * the method will not delete the key and return immediately.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700452 *
Yingdi Yu2e57a582014-02-20 23:34:43 -0800453 * @param keyName The key to be deleted.
454 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800455 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800456 deleteKey (const Name& keyName)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800457 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800458 try
459 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700460 if (Info::getDefaultKeyNameForIdentity(Info::getDefaultIdentity()) == keyName)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800461 return;
462 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700463 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800464 {
465 // Not a real error, just try to delete the key
466 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800467
468 Info::deletePublicKeyInfo(keyName);
469 Tpm::deleteKeyPairInTpm(keyName);
470 }
471
Yingdi Yu2e57a582014-02-20 23:34:43 -0800472 /**
473 * @brief delete an identity.
474 *
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700475 * If the identity to be deleted is current default system default,
Yingdi Yu2e57a582014-02-20 23:34:43 -0800476 * the method will not delete the identity and return immediately.
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700477 *
Yingdi Yu2e57a582014-02-20 23:34:43 -0800478 * @param identity The identity to be deleted.
479 */
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800480 void
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800481 deleteIdentity (const Name& identity)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800482 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800483 try
484 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700485 if (Info::getDefaultIdentity() == identity)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800486 return;
487 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700488 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800489 {
490 // Not a real error, just try to delete the identity
491 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800492
493 std::vector<Name> nameList;
494 Info::getAllKeyNamesOfIdentity(identity, nameList, true);
495 Info::getAllKeyNamesOfIdentity(identity, nameList, false);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700496
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800497 Info::deleteIdentityInfo(identity);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700498
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800499 std::vector<Name>::const_iterator it = nameList.begin();
500 for(; it != nameList.end(); it++)
501 Tpm::deleteKeyPairInTpm(*it);
502 }
503
Yingdi Yu2e57a582014-02-20 23:34:43 -0800504 /**
505 * @brief export an identity.
506 *
507 * @param identity The identity to export.
508 * @param passwordStr The password to secure the private key.
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800509 * @return The encoded export data.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800510 * @throws InfoError if anything goes wrong in exporting.
511 */
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800512 shared_ptr<SecuredBag>
Yingdi Yube4150e2014-02-18 13:02:46 -0800513 exportIdentity(const Name& identity, const std::string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800514 {
515 if (!Info::doesIdentityExist(identity))
516 throw InfoError("Identity does not exist!");
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700517
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800518 Name keyName = Info::getDefaultKeyNameForIdentity(identity);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800519
Yingdi Yu5e96e002014-04-23 18:32:15 -0700520 ConstBufferPtr pkcs5;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800521 try
522 {
Yingdi Yu5e96e002014-04-23 18:32:15 -0700523 pkcs5 = Tpm::exportPrivateKeyPkcs5FromTpm(keyName, passwordStr);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800524 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700525 catch (TpmError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800526 {
Yingdi Yu5e96e002014-04-23 18:32:15 -0700527 throw InfoError("Fail to export PKCS5 of private key");
Yingdi Yu2e57a582014-02-20 23:34:43 -0800528 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800529
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700530 shared_ptr<IdentityCertificate> cert;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800531 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800532 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800533 cert = Info::getCertificate(Info::getDefaultCertificateNameForKey(keyName));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800534 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700535 catch (InfoError& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800536 {
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700537 cert = selfSign(keyName);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800538 Info::addCertificateAsIdentityDefault(*cert);
539 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800540
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700541 shared_ptr<SecuredBag> secureBag = make_shared<SecuredBag>(boost::cref(*cert),
Yingdi Yu5e96e002014-04-23 18:32:15 -0700542 boost::cref(pkcs5));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800543
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800544 return secureBag;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800545 }
546
Yingdi Yu2e57a582014-02-20 23:34:43 -0800547 /**
548 * @brief import an identity.
549 *
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800550 * @param securedBag The encoded import data.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800551 * @param passwordStr The password to secure the private key.
552 */
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800553 void
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800554 importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800555 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700556 Name certificateName = securedBag.getCertificate().getName();
557 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800558 Name identity = keyName.getPrefix(-1);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700559
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800560 // Add identity
561 Info::addIdentity(identity);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700562
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800563 // Add key
Yingdi Yu5e96e002014-04-23 18:32:15 -0700564 Tpm::importPrivateKeyPkcs5IntoTpm(keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700565 securedBag.getKey()->buf(),
566 securedBag.getKey()->size(),
567 passwordStr);
568
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800569 shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700570 // HACK! We should set key type according to the pkcs8 info.
571 Info::addPublicKey(keyName, KEY_TYPE_RSA, *pubKey);
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800572 Info::setDefaultKeyNameForIdentity(keyName);
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700573
Yingdi Yu64c3fb42014-02-26 17:30:04 -0800574 // Add cert
575 Info::addCertificateAsIdentityDefault(securedBag.getCertificate());
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800576 }
577
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700578
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800579private:
Yingdi Yu2e57a582014-02-20 23:34:43 -0800580 /**
581 * @brief sign a packet using a pariticular certificate.
582 *
583 * @param packet The packet to be signed.
584 * @param certificate The signing certificate.
585 */
586 template<typename T>
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800587 void
Yingdi Yu2e57a582014-02-20 23:34:43 -0800588 sign(T& packet, const IdentityCertificate& certificate)
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800589 {
590 SignatureSha256WithRsa signature;
591 signature.setKeyLocator(certificate.getName().getPrefix(-1));
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800592
593 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800594 signPacketWrapper(packet, signature, certificate.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800595 }
596
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800597 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800598 * @brief Generate a key pair for the specified identity.
599 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800600 * @param identityName The name of the specified identity.
601 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
602 * @param keyType The type of the key pair, e.g. KEY_TYPE_RSA.
603 * @param keySize The size of the key pair.
604 * @return The name of the generated key.
605 */
606 Name
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700607 generateKeyPair(const Name& identityName, bool isKsk = false,
608 KeyType keyType = KEY_TYPE_RSA, int keySize = 2048)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800609 {
610 Name keyName = Info::getNewKeyName(identityName, isKsk);
611
612 Tpm::generateKeyPairInTpm(keyName.toUri(), keyType, keySize);
613
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800614 shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
Yingdi Yuef26ee32014-01-15 16:41:14 -0800615 Info::addPublicKey(keyName, keyType, *pubKey);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800616
617 return keyName;
618 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800619
Yingdi Yu8726f652014-01-23 10:35:12 -0800620 /**
Yingdi Yu2e57a582014-02-20 23:34:43 -0800621 * @brief Sign the data using a particular key.
622 *
623 * @param data Reference to the data packet.
624 * @param signature Signature to be added.
Yingdi Yu8726f652014-01-23 10:35:12 -0800625 * @param keyName The name of the signing key.
626 * @param digestAlgorithm the digest algorithm.
627 * @throws Tpm::Error
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700628 */
Yingdi Yu8726f652014-01-23 10:35:12 -0800629 void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700630 signPacketWrapper(Data& data, const SignatureSha256WithRsa& signature,
631 const Name& keyName, DigestAlgorithm digestAlgorithm)
Yingdi Yu8726f652014-01-23 10:35:12 -0800632 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800633 data.setSignature(signature);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700634 data.setSignatureValue(Tpm::signInTpm(data.wireEncode().value(),
635 data.wireEncode().value_size() -
636 data.getSignature().getValue().size(),
637 keyName, digestAlgorithm));
Yingdi Yu8726f652014-01-23 10:35:12 -0800638 }
639
Yingdi Yu2e57a582014-02-20 23:34:43 -0800640 /**
641 * @brief Sign the interest using a particular key.
642 *
643 * @param interest Reference to the interest packet.
644 * @param signature Signature to be added.
645 * @param keyName The name of the signing key.
646 * @param digestAlgorithm the digest algorithm.
647 * @throws Tpm::Error
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700648 */
Yingdi Yu2e57a582014-02-20 23:34:43 -0800649 void
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700650 signPacketWrapper(Interest& interest, const SignatureSha256WithRsa& signature,
651 const Name& keyName, DigestAlgorithm digestAlgorithm)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800652 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700653 Name signedName = interest.getName();
654 signedName.append(signature.getInfo());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800655
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700656 Block sigValue = Tpm::signInTpm(signedName.wireEncode().value(),
657 signedName.wireEncode().value_size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800658 keyName,
659 DIGEST_ALGORITHM_SHA256);
660 sigValue.encode();
661 signedName.append(sigValue);
662 interest.setName(signedName);
663 }
664
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700665};
666
Yingdi Yufc40d872014-02-18 12:56:04 -0800667} // namespace ndn
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800668
Yingdi Yu04020922014-01-22 12:46:53 -0800669
670
Alexander Afanasyev766cea72014-04-24 19:16:42 -0700671#if defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
Yingdi Yu31b4af22014-01-14 14:13:00 -0800672
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700673namespace ndn {
674
Yingdi Yu31b4af22014-01-14 14:13:00 -0800675typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmOsx> KeyChain;
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700676
677} // namespace ndn
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800678
Yingdi Yu31b4af22014-01-14 14:13:00 -0800679#else
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800680
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700681namespace ndn {
682
Yingdi Yu04020922014-01-22 12:46:53 -0800683typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmFile> KeyChain;
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700684
685} // namespace ndn
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800686
Alexander Afanasyev766cea72014-04-24 19:16:42 -0700687#endif // NDN_CXX_HAVE_OSX_SECURITY
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700688
Alexander Afanasyev766cea72014-04-24 19:16:42 -0700689#endif // NDN_SECURITY_KEY_CHAIN_HPP