blob: 629d244f4bbdc502ebc6ec27dd64708bcc63c1c7 [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 Yu04020922014-01-22 12:46:53 -080016//PublicInfo
Yingdi Yu4f324632014-01-15 18:10:03 -080017#include "sec-public-info-sqlite3.hpp"
18#include "sec-public-info-memory.hpp"
Yingdi Yu04020922014-01-22 12:46:53 -080019//TPM
20#include "sec-tpm-file.hpp"
Yingdi Yu4f324632014-01-15 18:10:03 -080021#include "sec-tpm-memory.hpp"
Yingdi Yu2abd73f2014-01-08 23:34:11 -080022
Yingdi Yu04020922014-01-22 12:46:53 -080023#ifdef NDN_CPP_HAVE_OSX_SECURITY
24#include "sec-tpm-osx.hpp"
25#endif
26
Jeff Thompson47c93cf2013-08-09 00:38:48 -070027
28namespace ndn {
29
Jeff Thompson2ce8f492013-09-17 18:01:25 -070030/**
Yingdi Yu2abd73f2014-01-08 23:34:11 -080031 * KeyChain is one of the main classes of the security library.
Jeff Thompsonffa36f92013-09-20 08:42:41 -070032 *
Yingdi Yu2abd73f2014-01-08 23:34:11 -080033 * The KeyChain class provides a set of interfaces of identity management and private key related operations.
Jeff Thompsonffa36f92013-09-20 08:42:41 -070034 */
Yingdi Yu31b4af22014-01-14 14:13:00 -080035template<class Info, class Tpm>
36class KeyChainImpl : public Info, public Tpm
37{
Jeff Thompson47c93cf2013-08-09 00:38:48 -070038public:
Yingdi Yu31b4af22014-01-14 14:13:00 -080039 // struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
Yingdi Yu2abd73f2014-01-08 23:34:11 -080040
41 /**
42 * Create an identity by creating a pair of Key-Signing-Key (KSK) for this identity and a self-signed certificate of the KSK.
43 * @param identityName The name of the identity.
44 * @return The key name of the auto-generated KSK of the identity.
45 */
46 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080047 createIdentity(const Name& identityName)
48 {
49 if (!Info::doesIdentityExist(identityName)) {
50 Info::addIdentity(identityName);
51
52 Name keyName = generateRSAKeyPairAsDefault(identityName, true);
53
54 ptr_lib::shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
55
56 Info::addCertificateAsDefault(*selfCert);
57
58 return keyName;
59 }
60 else
61 return Name();
62 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -080063
64 /**
Yingdi Yu2abd73f2014-01-08 23:34:11 -080065 * Generate a pair of RSA keys for the specified identity.
66 * @param identityName The name of the identity.
67 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
68 * @param keySize The size of the key.
69 * @return The generated key name.
70 */
71 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080072 generateRSAKeyPair(const Name& identityName, bool isKsk = false, int keySize = 2048)
Yingdi Yu2abd73f2014-01-08 23:34:11 -080073 {
Yingdi Yu31b4af22014-01-14 14:13:00 -080074 return generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
Yingdi Yu2abd73f2014-01-08 23:34:11 -080075 }
Alexander Afanasyev64a3d812014-01-05 23:35:05 -080076
Yingdi Yu2abd73f2014-01-08 23:34:11 -080077 /**
78 * Generate a pair of RSA keys for the specified identity and set it as default key for the identity.
79 * @param identityName The name of the identity.
80 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
81 * @param keySize The size of the key.
82 * @return The generated key name.
83 */
84 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -080085 generateRSAKeyPairAsDefault(const Name& identityName, bool isKsk = false, int keySize = 2048)
86 {
87 Name keyName = generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
88
89 Info::setDefaultKeyNameForIdentity(keyName);
Yingdi Yu31b4af22014-01-14 14:13:00 -080090
91 return keyName;
92 }
Jeff Thompson79a2d5d2013-09-27 14:32:23 -070093
Yingdi Yu2abd73f2014-01-08 23:34:11 -080094 /**
Yingdi Yu2abd73f2014-01-08 23:34:11 -080095 * Create an identity certificate for a public key managed by this IdentityManager.
96 * @param certificatePrefix The name of public key to be signed.
97 * @param signerCertificateName The name of signing certificate.
98 * @param notBefore The notBefore value in the validity field of the generated certificate.
99 * @param notAfter The notAfter vallue in validity field of the generated certificate.
100 * @return The name of generated identity certificate.
101 */
102 ptr_lib::shared_ptr<IdentityCertificate>
103 createIdentityCertificate
104 (const Name& certificatePrefix,
105 const Name& signerCertificateName,
106 const MillisecondsSince1970& notBefore,
Yingdi Yu31b4af22014-01-14 14:13:00 -0800107 const MillisecondsSince1970& notAfter)
108 {
109 Name keyName = getKeyNameFromCertificatePrefix(certificatePrefix);
110
111 ptr_lib::shared_ptr<PublicKey> pubKey = Info::getPublicKey(keyName);
112 if (!pubKey)
113 throw std::runtime_error("Requested public key [" + keyName.toUri() + "] doesn't exist");
114
115 ptr_lib::shared_ptr<IdentityCertificate> certificate =
116 createIdentityCertificate(certificatePrefix,
117 *pubKey,
118 signerCertificateName,
119 notBefore, notAfter);
120
121 Info::addCertificate(*certificate);
122
123 return certificate;
124 }
125
Jeff Thompson79a2d5d2013-09-27 14:32:23 -0700126
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800127 /**
128 * Create an identity certificate for a public key supplied by the caller.
129 * @param certificatePrefix The name of public key to be signed.
130 * @param publickey The public key to be signed.
131 * @param signerCertificateName The name of signing certificate.
132 * @param notBefore The notBefore value in the validity field of the generated certificate.
133 * @param notAfter The notAfter vallue in validity field of the generated certificate.
134 * @return The generated identity certificate.
135 */
136 ptr_lib::shared_ptr<IdentityCertificate>
137 createIdentityCertificate
138 (const Name& certificatePrefix,
Yingdi Yu31b4af22014-01-14 14:13:00 -0800139 const PublicKey& publicKey,
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800140 const Name& signerCertificateName,
141 const MillisecondsSince1970& notBefore,
Yingdi Yu31b4af22014-01-14 14:13:00 -0800142 const MillisecondsSince1970& notAfter)
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800143 {
Yingdi Yu31b4af22014-01-14 14:13:00 -0800144 ptr_lib::shared_ptr<IdentityCertificate> certificate (new IdentityCertificate());
145 Name keyName = getKeyNameFromCertificatePrefix(certificatePrefix);
146
147 Name certificateName = certificatePrefix;
148 certificateName.append("ID-CERT").appendVersion();
149
150 certificate->setName(certificateName);
151 certificate->setNotBefore(notBefore);
152 certificate->setNotAfter(notAfter);
153 certificate->setPublicKeyInfo(publicKey);
154 certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
155 certificate->encode();
156
157 sign(*certificate, signerCertificateName);
158
159 return certificate;
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -0800160 }
161
Yingdi Yu3c5887c2014-01-21 18:19:49 -0800162 /**
163 * Fetch the private key for keyName and sign the data, and set the signature block of the data packet.
164 * Throw Error if signing fails.
165 * @param data Reference to the input data packet.
166 * @param keyName The name of the signing key.
167 * @param digestAlgorithm the digest algorithm.
168 */
169 void
170 signInTpm(Data &data, const Name& keyName, DigestAlgorithm digestAlgorithm)
171 {
172 data.setSignatureValue
173 (Tpm::signInTpm(data.wireEncode().value(),
174 data.wireEncode().value_size() - data.getSignature().getValue().size(),
175 keyName, digestAlgorithm));
176 }
177
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800178 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800179 sign(Data &data)
180 {
181 if (!Info::defaultCertificate())
182 {
183 Info::refreshDefaultCertificate();
184
185 if(!Info::defaultCertificate())
186 throw std::runtime_error("Default IdentityCertificate cannot be determined");
187 }
188
189 sign(data, *Info::defaultCertificate());
190 }
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800191
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700192 /**
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700193 * Wire encode the Data object, sign it and set its signature.
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700194 * @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 -0700195 * @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 -0700196 */
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800197 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800198 sign(Data& data, const Name& certificateName)
199 {
200 ptr_lib::shared_ptr<IdentityCertificate> cert = Info::getCertificate(certificateName);
201 if (!cert)
202 throw std::runtime_error("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
203
204 SignatureSha256WithRsa signature;
205 signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
206 data.setSignature(signature);
207
208 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu3c5887c2014-01-21 18:19:49 -0800209 signInTpm(data, cert->getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800210 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800211
212 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800213 sign(Data& data, const IdentityCertificate& certificate)
214 {
215 SignatureSha256WithRsa signature;
216 signature.setKeyLocator(certificate.getName().getPrefix(-1));
217 data.setSignature(signature);
218
219 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu3c5887c2014-01-21 18:19:49 -0800220 signInTpm(data, certificate.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800221 }
Jeff Thompson79a2d5d2013-09-27 14:32:23 -0700222
Jeff Thompson29ce3102013-09-27 11:47:48 -0700223 /**
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700224 * Sign the byte array using a certificate name and return a Signature object.
225 * @param buffer The byte array to be signed.
226 * @param bufferLength the length of buffer.
227 * @param certificateName The certificate name used to get the signing key and which will be put into KeyLocator.
228 * @return The Signature.
229 */
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800230 Signature
Yingdi Yu31b4af22014-01-14 14:13:00 -0800231 sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
232 {
233 ptr_lib::shared_ptr<IdentityCertificate> cert = Info::getCertificate(certificateName);
234 if (!cert)
235 throw std::runtime_error("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
236
237 SignatureSha256WithRsa signature;
238 signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
239
240 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yub4bb85a2014-01-16 10:11:04 -0800241 signature.setValue(Tpm::signInTpm(buffer, bufferLength, cert->getPublicKeyName(), DIGEST_ALGORITHM_SHA256));
Yingdi Yu31b4af22014-01-14 14:13:00 -0800242 return signature;
243 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700244
245 /**
Jeff Thompson29ce3102013-09-27 11:47:48 -0700246 * Wire encode the Data object, sign it and set its signature.
Jeff Thompson29ce3102013-09-27 11:47:48 -0700247 * @param data The Data object to be signed. This updates its signature and key locator field and wireEncoding.
248 * @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 -0700249 */
250 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800251 signByIdentity(Data& data, const Name& identityName = Name())
252 {
253 Name signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
254
255 if (signingCertificateName.getComponentCount() == 0)
256 throw std::runtime_error("No qualified certificate name found!");
257
258 sign(data, signingCertificateName);
259 }
Jeff Thompson3c73da42013-08-12 11:19:05 -0700260
261 /**
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700262 * Sign the byte array using an identity name and return a Signature object.
263 * @param buffer The byte array to be signed.
264 * @param bufferLength the length of buffer.
265 * @param identityName The identity name.
266 * @return The Signature.
267 */
Alexander Afanasyev64a3d812014-01-05 23:35:05 -0800268 Signature
Yingdi Yu31b4af22014-01-14 14:13:00 -0800269 signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName = Name())
270 {
271 Name signingCertificateName = Info::getDefaultCertificateNameForIdentity(identityName);
272
273 if (signingCertificateName.size() == 0)
274 throw std::runtime_error("No qualified certificate name found!");
275
276 return sign(buffer, bufferLength, signingCertificateName);
277 }
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700278
279 /**
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800280 * Generate a self-signed certificate for a public key.
281 * @param keyName The name of the public key.
282 * @return The generated certificate.
283 */
284 ptr_lib::shared_ptr<IdentityCertificate>
Yingdi Yu31b4af22014-01-14 14:13:00 -0800285 selfSign(const Name& keyName)
286 {
Yingdi Yu7ea69502014-01-15 17:21:29 -0800287 if(keyName.empty())
288 throw std::runtime_error("Incorrect key name: " + keyName.toUri());
289
Yingdi Yu31b4af22014-01-14 14:13:00 -0800290 ptr_lib::shared_ptr<IdentityCertificate> certificate = ptr_lib::make_shared<IdentityCertificate>();
291
292 Name certificateName = keyName.getPrefix(-1);
293 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
294
295 ptr_lib::shared_ptr<PublicKey> pubKey = Info::getPublicKey(keyName);
296 if (!pubKey)
297 throw std::runtime_error("Requested public key [" + keyName.toUri() + "] doesn't exist");
298
299 certificate->setName(certificateName);
300 certificate->setNotBefore(getNow());
301 certificate->setNotAfter(getNow() + 630720000 /* 20 years*/);
302 certificate->setPublicKeyInfo(*pubKey);
303 certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
304 certificate->encode();
305
306 selfSign(*certificate);
307 return certificate;
308 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800309
310 /**
311 * @brief Self-sign the supplied identity certificate
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700312 */
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700313 void
Yingdi Yu31b4af22014-01-14 14:13:00 -0800314 selfSign (IdentityCertificate& cert)
315 {
316 SignatureSha256WithRsa signature;
317 signature.setKeyLocator(cert.getName().getPrefix(-1)); // implicit conversion should take care
318 cert.setSignature(signature);
319
320 // For temporary usage, we support RSA + SHA256 only, but will support more.
Yingdi Yu3c5887c2014-01-21 18:19:49 -0800321 signInTpm(cert, cert.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800322 }
323
Jeff Thompson8efe5ad2013-08-20 17:36:38 -0700324
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800325private:
326 /**
327 * Generate a key pair for the specified identity.
328 * @param identityName The name of the specified identity.
329 * @param isKsk true for generating a Key-Signing-Key (KSK), false for a Data-Signing-Key (KSK).
330 * @param keyType The type of the key pair, e.g. KEY_TYPE_RSA.
331 * @param keySize The size of the key pair.
332 * @return The name of the generated key.
333 */
334 Name
Yingdi Yu31b4af22014-01-14 14:13:00 -0800335 generateKeyPair(const Name& identityName, bool isKsk = false, KeyType keyType = KEY_TYPE_RSA, int keySize = 2048)
336 {
337 Name keyName = Info::getNewKeyName(identityName, isKsk);
338
339 Tpm::generateKeyPairInTpm(keyName.toUri(), keyType, keySize);
340
341 ptr_lib::shared_ptr<PublicKey> pubKey = Tpm::getPublicKeyFromTpm(keyName.toUri());
Yingdi Yuef26ee32014-01-15 16:41:14 -0800342 Info::addPublicKey(keyName, keyType, *pubKey);
Yingdi Yu31b4af22014-01-14 14:13:00 -0800343
344 return keyName;
345 }
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800346
347 static Name
Yingdi Yu31b4af22014-01-14 14:13:00 -0800348 getKeyNameFromCertificatePrefix(const Name& certificatePrefix)
349 {
350 Name result;
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -0800351
Yingdi Yu31b4af22014-01-14 14:13:00 -0800352 std::string keyString("KEY");
353 int i = 0;
354 for(; i < certificatePrefix.size(); i++) {
355 if (certificatePrefix.get(i).toEscapedString() == keyString)
356 break;
357 }
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -0800358
Yingdi Yu31b4af22014-01-14 14:13:00 -0800359 if (i >= certificatePrefix.size())
360 throw std::runtime_error("Identity Certificate Prefix does not have a KEY component");
Alexander Afanasyevbd5ba402014-01-05 22:41:09 -0800361
Yingdi Yu31b4af22014-01-14 14:13:00 -0800362 result.append(certificatePrefix.getSubName(0, i));
363 result.append(certificatePrefix.getSubName(i + 1, certificatePrefix.size()-i-1));
364
365 return result;
366 }
367
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700368};
369
Yingdi Yu31b4af22014-01-14 14:13:00 -0800370}
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800371
Yingdi Yu04020922014-01-22 12:46:53 -0800372
373
Yingdi Yu31b4af22014-01-14 14:13:00 -0800374#ifdef NDN_CPP_HAVE_OSX_SECURITY
375
376namespace ndn
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800377{
Yingdi Yu31b4af22014-01-14 14:13:00 -0800378typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmOsx> KeyChain;
379};
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800380
Yingdi Yu31b4af22014-01-14 14:13:00 -0800381#else
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800382
Yingdi Yu31b4af22014-01-14 14:13:00 -0800383namespace ndn
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800384{
Yingdi Yu04020922014-01-22 12:46:53 -0800385typedef KeyChainImpl<SecPublicInfoSqlite3, SecTpmFile> KeyChain;
Yingdi Yu31b4af22014-01-14 14:13:00 -0800386};
Alexander Afanasyeve64788e2014-01-05 22:38:21 -0800387
Yingdi Yu31b4af22014-01-14 14:13:00 -0800388#endif //NDN_CPP_HAVE_OSX_SECURITY
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700389
390#endif