blob: c5df5dbf9c060f5b96ed3a4cf167ddb0b59d8d8a [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
9#ifndef NDN_KEY_CHAIN_HPP
Jeff Thompson2d27e2f2013-08-09 12:55:00 -070010#define NDN_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 Yu31b4af22014-01-14 14:13:00 -080015
Yingdi Yu4f324632014-01-15 18:10:03 -080016#include "sec-public-info-sqlite3.hpp"
17#include "sec-public-info-memory.hpp"
18#include "sec-tpm-osx.hpp"
19#include "sec-tpm-memory.hpp"
Yingdi Yu2abd73f2014-01-08 23:34:11 -080020
Jeff Thompson47c93cf2013-08-09 00:38:48 -070021
22namespace ndn {
23
Jeff Thompson2ce8f492013-09-17 18:01:25 -070024/**
Yingdi Yu2abd73f2014-01-08 23:34:11 -080025 * KeyChain is one of the main classes of the security library.
Jeff Thompsonffa36f92013-09-20 08:42:41 -070026 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -080027 * The KeyChain class provides a set of interfaces of identity management and private key related operations.
Jeff Thompsonffa36f92013-09-20 08:42:41 -070028 */
Yingdi Yu31b4af22014-01-14 14:13:00 -080029template<class Info, class Tpm>
30class KeyChainImpl : public Info, public Tpm
31{
Jeff Thompson47c93cf2013-08-09 00:38:48 -070032public:
Yingdi Yu31b4af22014-01-14 14:13:00 -080033 // struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
Yingdi Yu2abd73f2014-01-08 23:34:11 -080034
35 /**
36 * Create an identity by creating a pair of Key-Signing-Key (KSK) for this identity and a self-signed certificate of the KSK.
37 * @param identityName The name of the identity.
38 * @return The key name of the auto-generated KSK of the identity.
39 */
40 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080041 createIdentity(const Name& identityName)
42 {
43 if (!Info::doesIdentityExist(identityName)) {
44 Info::addIdentity(identityName);
45
46 Name keyName = generateRSAKeyPairAsDefault(identityName, true);
47
48 ptr_lib::shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
49
50 Info::addCertificateAsDefault(*selfCert);
51
52 return keyName;
53 }
54 else
55 return Name();
56 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -080057
58 /**
Yingdi Yu2abd73f2014-01-08 23:34:11 -080059 * Generate a pair of RSA keys for the specified identity.
60 * @param identityName The name of the identity.
61 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
62 * @param keySize The size of the key.
63 * @return The generated key name.
64 */
65 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080066 generateRSAKeyPair(const Name& identityName, bool isKsk = false, int keySize = 2048)
Yingdi Yu2abd73f2014-01-08 23:34:11 -080067 {
Yingdi Yu31b4af22014-01-14 14:13:00 -080068 return generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
Yingdi Yu2abd73f2014-01-08 23:34:11 -080069 }
Alexander Afanasyev64a3d812014-01-05 23:35:05 -080070
Yingdi Yu2abd73f2014-01-08 23:34:11 -080071 /**
72 * Generate a pair of RSA keys for the specified identity and set it as default key for the identity.
73 * @param identityName The name of the identity.
74 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
75 * @param keySize The size of the key.
76 * @return The generated key name.
77 */
78 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080079 generateRSAKeyPairAsDefault(const Name& identityName, bool isKsk = false, int keySize = 2048)
80 {
81 Name keyName = generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
82
83 Info::setDefaultKeyNameForIdentity(keyName);
Yingdi Yu31b4af22014-01-14 14:13:00 -080084
85 return keyName;
86 }
Jeff Thompson79a2d5d2013-09-27 14:32:23 -070087
Yingdi Yu2abd73f2014-01-08 23:34:11 -080088 /**
Yingdi Yu2abd73f2014-01-08 23:34:11 -080089 * Create an identity certificate for a public key managed by this IdentityManager.
90 * @param certificatePrefix The name of public key to be signed.
91 * @param signerCertificateName The name of signing certificate.
92 * @param notBefore The notBefore value in the validity field of the generated certificate.
93 * @param notAfter The notAfter vallue in validity field of the generated certificate.
94 * @return The name of generated identity certificate.
95 */
96 ptr_lib::shared_ptr<IdentityCertificate>
97 createIdentityCertificate
98 (const Name& certificatePrefix,
99 const Name& signerCertificateName,
100 const MillisecondsSince1970& notBefore,
Yingdi Yu31b4af22014-01-14 14:13:00 -0800101 const MillisecondsSince1970& notAfter)
102 {
103 Name keyName = getKeyNameFromCertificatePrefix(certificatePrefix);
104
105 ptr_lib::shared_ptr<PublicKey> pubKey = Info::getPublicKey(keyName);
106 if (!pubKey)
107 throw std::runtime_error("Requested public key [" + keyName.toUri() + "] doesn't exist");
108
109 ptr_lib::shared_ptr<IdentityCertificate> certificate =
110 createIdentityCertificate(certificatePrefix,
111 *pubKey,
112 signerCertificateName,
113 notBefore, notAfter);
114
115 Info::addCertificate(*certificate);
116
117 return certificate;
118 }
119
Jeff Thompson79a2d5d2013-09-27 14:32:23 -0700120
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800121 /**
122 * Create an identity certificate for a public key supplied by the caller.
123 * @param certificatePrefix The name of public key to be signed.
124 * @param publickey The public key to be signed.
125 * @param signerCertificateName The name of signing certificate.
126 * @param notBefore The notBefore value in the validity field of the generated certificate.
127 * @param notAfter The notAfter vallue in validity field of the generated certificate.
128 * @return The generated identity certificate.
129 */
130 ptr_lib::shared_ptr<IdentityCertificate>
131 createIdentityCertificate
132 (const Name& certificatePrefix,
Yingdi Yu31b4af22014-01-14 14:13:00 -0800133 const PublicKey& publicKey,
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800134 const Name& signerCertificateName,
135 const MillisecondsSince1970& notBefore,
Yingdi Yu31b4af22014-01-14 14:13:00 -0800136 const MillisecondsSince1970& notAfter)
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800137 {
Yingdi Yu31b4af22014-01-14 14:13:00 -0800138 ptr_lib::shared_ptr<IdentityCertificate> certificate (new IdentityCertificate());
139 Name keyName = getKeyNameFromCertificatePrefix(certificatePrefix);
140
141 Name certificateName = certificatePrefix;
142 certificateName.append("ID-CERT").appendVersion();
143
144 certificate->setName(certificateName);
145 certificate->setNotBefore(notBefore);
146 certificate->setNotAfter(notAfter);
147 certificate->setPublicKeyInfo(publicKey);
148 certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
149 certificate->encode();
150
151 sign(*certificate, signerCertificateName);
152
153 return certificate;
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -0800154 }
155
Yingdi Yu3c5887c2014-01-21 18:19:49 -0800156 /**
157 * Fetch the private key for keyName and sign the data, and set the signature block of the data packet.
158 * Throw Error if signing fails.
159 * @param data Reference to the input data packet.
160 * @param keyName The name of the signing key.
161 * @param digestAlgorithm the digest algorithm.
162 */
163 void
164 signInTpm(Data &data, const Name& keyName, DigestAlgorithm digestAlgorithm)
165 {
166 data.setSignatureValue
167 (Tpm::signInTpm(data.wireEncode().value(),
168 data.wireEncode().value_size() - data.getSignature().getValue().size(),
169 keyName, digestAlgorithm));
170 }
171
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800172 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800173 sign(Data &data)
174 {
175 if (!Info::defaultCertificate())
176 {
177 Info::refreshDefaultCertificate();
178
179 if(!Info::defaultCertificate())
180 throw std::runtime_error("Default IdentityCertificate cannot be determined");
181 }
182
183 sign(data, *Info::defaultCertificate());
184 }
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800185
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700186 /**
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700187 * Wire encode the Data object, sign it and set its signature.
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700188 * @param data The Data object to be signed. This updates its signature and key locator field and wireEncoding.
Jeff Thompson9296f0c2013-09-23 18:10:27 -0700189 * @param certificateName The certificate name of the key to use for signing. If omitted, infer the signing identity from the data packet name.
Jeff Thompson3c73da42013-08-12 11:19:05 -0700190 */
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800191 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800192 sign(Data& data, const Name& certificateName)
193 {
194 ptr_lib::shared_ptr<IdentityCertificate> cert = Info::getCertificate(certificateName);
195 if (!cert)
196 throw std::runtime_error("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
197
198 SignatureSha256WithRsa signature;
199 signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
200 data.setSignature(signature);
201
202 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu3c5887c2014-01-21 18:19:49 -0800203 signInTpm(data, cert->getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800204 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800205
206 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800207 sign(Data& data, const IdentityCertificate& certificate)
208 {
209 SignatureSha256WithRsa signature;
210 signature.setKeyLocator(certificate.getName().getPrefix(-1));
211 data.setSignature(signature);
212
213 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu3c5887c2014-01-21 18:19:49 -0800214 signInTpm(data, certificate.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800215 }
Jeff Thompson79a2d5d2013-09-27 14:32:23 -0700216
Jeff Thompson29ce3102013-09-27 11:47:48 -0700217 /**
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700218 * Sign the byte array using a certificate name and return a Signature object.
219 * @param buffer The byte array to be signed.
220 * @param bufferLength the length of buffer.
221 * @param certificateName The certificate name used to get the signing key and which will be put into KeyLocator.
222 * @return The Signature.
223 */
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800224 Signature
Yingdi Yu31b4af22014-01-14 14:13:00 -0800225 sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
226 {
227 ptr_lib::shared_ptr<IdentityCertificate> cert = Info::getCertificate(certificateName);
228 if (!cert)
229 throw std::runtime_error("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
230
231 SignatureSha256WithRsa signature;
232 signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
233
234 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yub4bb85a2014-01-16 10:11:04 -0800235 signature.setValue(Tpm::signInTpm(buffer, bufferLength, cert->getPublicKeyName(), DIGEST_ALGORITHM_SHA256));
Yingdi Yu31b4af22014-01-14 14:13:00 -0800236 return signature;
237 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700238
239 /**
Jeff Thompson29ce3102013-09-27 11:47:48 -0700240 * Wire encode the Data object, sign it and set its signature.
Jeff Thompson29ce3102013-09-27 11:47:48 -0700241 * @param data The Data object to be signed. This updates its signature and key locator field and wireEncoding.
242 * @param identityName The identity name for the key to use for signing. If omitted, infer the signing identity from the data packet name.
Jeff Thompson29ce3102013-09-27 11:47:48 -0700243 */
244 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800245 signByIdentity(Data& data, const Name& identityName = Name())
246 {
247 Name signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
248
249 if (signingCertificateName.getComponentCount() == 0)
250 throw std::runtime_error("No qualified certificate name found!");
251
252 sign(data, signingCertificateName);
253 }
Jeff Thompson3c73da42013-08-12 11:19:05 -0700254
255 /**
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700256 * Sign the byte array using an identity name and return a Signature object.
257 * @param buffer The byte array to be signed.
258 * @param bufferLength the length of buffer.
259 * @param identityName The identity name.
260 * @return The Signature.
261 */
Alexander Afanasyev64a3d812014-01-05 23:35:05 -0800262 Signature
Yingdi Yu31b4af22014-01-14 14:13:00 -0800263 signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName = Name())
264 {
265 Name signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
266
267 if (signingCertificateName.size() == 0)
268 throw std::runtime_error("No qualified certificate name found!");
269
270 return sign(buffer, bufferLength, signingCertificateName);
271 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700272
273 /**
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800274 * Generate a self-signed certificate for a public key.
275 * @param keyName The name of the public key.
276 * @return The generated certificate.
277 */
278 ptr_lib::shared_ptr<IdentityCertificate>
Yingdi Yu31b4af22014-01-14 14:13:00 -0800279 selfSign(const Name& keyName)
280 {
Yingdi Yu7ea69502014-01-15 17:21:29 -0800281 if(keyName.empty())
282 throw std::runtime_error("Incorrect key name: " + keyName.toUri());
283
Yingdi Yu31b4af22014-01-14 14:13:00 -0800284 ptr_lib::shared_ptr<IdentityCertificate> certificate = ptr_lib::make_shared<IdentityCertificate>();
285
286 Name certificateName = keyName.getPrefix(-1);
287 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
288
289 ptr_lib::shared_ptr<PublicKey> pubKey = Info::getPublicKey(keyName);
290 if (!pubKey)
291 throw std::runtime_error("Requested public key [" + keyName.toUri() + "] doesn't exist");
292
293 certificate->setName(certificateName);
294 certificate->setNotBefore(getNow());
295 certificate->setNotAfter(getNow() + 630720000 /* 20 years*/);
296 certificate->setPublicKeyInfo(*pubKey);
297 certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
298 certificate->encode();
299
300 selfSign(*certificate);
301 return certificate;
302 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800303
304 /**
305 * @brief Self-sign the supplied identity certificate
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700306 */
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700307 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800308 selfSign (IdentityCertificate& cert)
309 {
310 SignatureSha256WithRsa signature;
311 signature.setKeyLocator(cert.getName().getPrefix(-1)); // implicit conversion should take care
312 cert.setSignature(signature);
313
314 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu3c5887c2014-01-21 18:19:49 -0800315 signInTpm(cert, cert.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800316 }
317
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700318
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800319private:
320 /**
321 * Generate a key pair for the specified identity.
322 * @param identityName The name of the specified identity.
323 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
324 * @param keyType The type of the key pair, e.g. KEY_TYPE_RSA.
325 * @param keySize The size of the key pair.
326 * @return The name of the generated key.
327 */
328 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -0800329 generateKeyPair(const Name& identityName, bool isKsk = false, KeyType keyType = KEY_TYPE_RSA, int keySize = 2048)
330 {
331 Name keyName = Info::getNewKeyName(identityName, isKsk);
332
333 Tpm::generateKeyPairInTpm(keyName.toUri(), keyType, keySize);
334
335 ptr_lib::shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
Yingdi Yuef26ee32014-01-15 16:41:14 -0800336 Info::addPublicKey(keyName, keyType, *pubKey);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800337
338 return keyName;
339 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800340
341 static Name
Yingdi Yu31b4af22014-01-14 14:13:00 -0800342 getKeyNameFromCertificatePrefix(const Name& certificatePrefix)
343 {
344 Name result;
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -0800345
Yingdi Yu31b4af22014-01-14 14:13:00 -0800346 std::string keyString("KEY");
347 int i = 0;
348 for(; i < certificatePrefix.size(); i++) {
349 if (certificatePrefix.get(i).toEscapedString() == keyString)
350 break;
351 }
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -0800352
Yingdi Yu31b4af22014-01-14 14:13:00 -0800353 if (i >= certificatePrefix.size())
354 throw std::runtime_error("Identity Certificate Prefix does not have a KEY component");
Alexander Afanasyevbd5ba402014-01-05 22:41:09 -0800355
Yingdi Yu31b4af22014-01-14 14:13:00 -0800356 result.append(certificatePrefix.getSubName(0, i));
357 result.append(certificatePrefix.getSubName(i + 1, certificatePrefix.size()-i-1));
358
359 return result;
360 }
361
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700362};
363
Yingdi Yu31b4af22014-01-14 14:13:00 -0800364}
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800365
Yingdi Yu31b4af22014-01-14 14:13:00 -0800366#ifdef NDN_CPP_HAVE_OSX_SECURITY
367
368namespace ndn
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800369{
Yingdi Yu31b4af22014-01-14 14:13:00 -0800370typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmOsx> KeyChain;
371};
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800372
Yingdi Yu31b4af22014-01-14 14:13:00 -0800373#else
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800374
Yingdi Yu31b4af22014-01-14 14:13:00 -0800375namespace ndn
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800376{
Yingdi Yu31b4af22014-01-14 14:13:00 -0800377typedef KeyChainImpl<SecPublicInfoMemory, SecTpmMemory> KeyChain;
378};
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800379
Yingdi Yu31b4af22014-01-14 14:13:00 -0800380#endif //NDN_CPP_HAVE_OSX_SECURITY
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700381
382#endif