blob: 8d3f4120b40594662919d67c01666822f5ba127d [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
Jeff Thompson25b4e612013-10-10 16:03:24 -07009#include <ndn-cpp/security/key-chain.hpp>
Alexander Afanasyev6be1a6a2014-01-06 00:08:14 -080010#include <ndn-cpp/security/identity/basic-identity-storage.hpp>
Yingdi Yu2abd73f2014-01-08 23:34:11 -080011#include <ndn-cpp/security/signature/signature-sha256-with-rsa.hpp>
12#include "../util/logging.hpp"
13#include "../c/util/time.h"
Alexander Afanasyevbd5ba402014-01-05 22:41:09 -080014
15
Jeff Thompson47c93cf2013-08-09 00:38:48 -070016using namespace std;
Jeff Thompson2381da82013-11-06 14:34:09 -080017using namespace ndn::func_lib;
Alexander Afanasyev6be1a6a2014-01-06 00:08:14 -080018#if NDN_CPP_HAVE_CXX11
Jeff Thompson09324ed2013-11-06 14:40:35 -080019// In the std library, the placeholders are in a different namespace than boost.
20using namespace ndn::func_lib::placeholders;
Jeff Thompson9bdeb6d2013-11-06 14:30:07 -080021#endif
Jeff Thompson47c93cf2013-08-09 00:38:48 -070022
Yingdi Yu2abd73f2014-01-08 23:34:11 -080023INIT_LOGGER("ndn.KeyChain");
24
Jeff Thompson47c93cf2013-08-09 00:38:48 -070025namespace ndn {
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -080026
Alexander Afanasyevbd5ba402014-01-05 22:41:09 -080027const ptr_lib::shared_ptr<IdentityStorage> KeyChain::DefaultIdentityStorage = ptr_lib::shared_ptr<IdentityStorage>();
28const ptr_lib::shared_ptr<PrivateKeyStorage> KeyChain::DefaultPrivateKeyStorage = ptr_lib::shared_ptr<PrivateKeyStorage>();
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -080029
Alexander Afanasyevbd5ba402014-01-05 22:41:09 -080030KeyChain::KeyChain(const ptr_lib::shared_ptr<IdentityStorage> &publicInfoStorage /* = DefaultIdentityStorage */,
Yingdi Yu2abd73f2014-01-08 23:34:11 -080031 const ptr_lib::shared_ptr<PrivateKeyStorage> &privateKeyStorage /* = DefaultPrivateKeyStorage */)
Alexander Afanasyevbd5ba402014-01-05 22:41:09 -080032 : publicInfoStorage_(publicInfoStorage)
33 , privateKeyStorage_(privateKeyStorage)
Alexander Afanasyevbd5ba402014-01-05 22:41:09 -080034{
35 if (publicInfoStorage_ == DefaultIdentityStorage)
36 {
37 publicInfoStorage_ = ptr_lib::make_shared<BasicIdentityStorage>();
38 }
39
40 if (privateKeyStorage_ == DefaultPrivateKeyStorage)
41 {
42#ifdef USE_OSX_PRIVATEKEY_STORAGE
43 privateStorage_ = ptr_lib::make_shared<OSXPrivatekeyStorage>();
44 // #else
45 // m_privateStorage = Ptr<SimpleKeyStore>::Create();
46#endif
47 }
Jeff Thompson9296f0c2013-09-23 18:10:27 -070048}
49
Yingdi Yu2abd73f2014-01-08 23:34:11 -080050Name
51KeyChain::createIdentity(const Name& identityName)
52{
53 if (!info().doesIdentityExist(identityName)) {
54 _LOG_DEBUG("Create Identity");
55 info().addIdentity(identityName);
56
57 _LOG_DEBUG("Create Default RSA key pair");
58 Name keyName = generateRSAKeyPairAsDefault(identityName, true);
59
60 _LOG_DEBUG("Create self-signed certificate");
61 ptr_lib::shared_ptr<IdentityCertificate> selfCert = selfSign(keyName);
62
63 _LOG_DEBUG("Add self-signed certificate as default");
64 addCertificateAsDefault(*selfCert);
65
66 return keyName;
67 }
68 else
69 throw Error("Identity has already been created!");
70}
71
72Name
73KeyChain::generateKeyPair(const Name& identityName, bool isKsk, KeyType keyType, int keySize)
74{
75 _LOG_DEBUG("Get new key ID");
76 Name keyName = info().getNewKeyName(identityName, isKsk);
77
78 _LOG_DEBUG("Generate key pair in private storage");
79 tpm().generateKeyPair(keyName.toUri(), keyType, keySize);
80
81 _LOG_DEBUG("Create a key record in public storage");
82 ptr_lib::shared_ptr<PublicKey> pubKey = tpm().getPublicKey(keyName.toUri());
83 info().addKey(keyName, keyType, *pubKey);
84
85 return keyName;
86}
87
88Name
89KeyChain::generateRSAKeyPair(const Name& identityName, bool isKsk, int keySize)
90{
91 Name keyName = generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
92
93 return keyName;
94}
95
96Name
97KeyChain::generateRSAKeyPairAsDefault(const Name& identityName, bool isKsk, int keySize)
98{
99 defaultCertificate_.reset();
100
101 Name keyName = generateKeyPair(identityName, isKsk, KEY_TYPE_RSA, keySize);
102
103 info().setDefaultKeyNameForIdentity(keyName, identityName);
104
105 return keyName;
106}
107
108ptr_lib::shared_ptr<IdentityCertificate>
109KeyChain::createIdentityCertificate(const Name& certificatePrefix,
110 const Name& signerCertificateName,
111 const MillisecondsSince1970& notBefore,
112 const MillisecondsSince1970& notAfter)
113{
114 Name keyName = getKeyNameFromCertificatePrefix(certificatePrefix);
115
116 ptr_lib::shared_ptr<PublicKey> pubKey = info().getKey(keyName);
117 if (!pubKey)
118 throw Error("Requested public key [" + keyName.toUri() + "] doesn't exist");
119
120 ptr_lib::shared_ptr<IdentityCertificate> certificate =
121 createIdentityCertificate(certificatePrefix,
122 *pubKey,
123 signerCertificateName,
124 notBefore, notAfter);
125
126 info().addCertificate(*certificate);
127
128 return certificate;
129}
130
131ptr_lib::shared_ptr<IdentityCertificate>
132KeyChain::createIdentityCertificate(const Name& certificatePrefix,
133 const PublicKey& publicKey,
134 const Name& signerCertificateName,
135 const MillisecondsSince1970& notBefore,
136 const MillisecondsSince1970& notAfter)
137{
138 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;
154}
155
156Name
157KeyChain::getKeyNameFromCertificatePrefix(const Name & certificatePrefix)
158{
159 Name result;
160
161 string keyString("KEY");
162 int i = 0;
163 for(; i < certificatePrefix.size(); i++) {
164 if (certificatePrefix.get(i).toEscapedString() == keyString)
165 break;
166 }
167
168 if (i >= certificatePrefix.size())
169 throw Error("Identity Certificate Prefix does not have a KEY component");
170
171 result.append(certificatePrefix.getSubName(0, i));
172 result.append(certificatePrefix.getSubName(i + 1, certificatePrefix.size()-i-1));
173
174 return result;
175}
176
177void
178KeyChain::setDefaultCertificateForKey(const IdentityCertificate& certificate)
179{
180 defaultCertificate_.reset();
181
182 Name keyName = certificate.getPublicKeyName();
183
184 if(!info().doesKeyExist(keyName))
185 throw Error("No corresponding Key record for certificate!");
186
187 info().setDefaultCertificateNameForKey(keyName, certificate.getName());
188}
189
190void
191KeyChain::addCertificateAsIdentityDefault(const IdentityCertificate& certificate)
192{
193 info().addCertificate(certificate);
194
195 Name keyName = certificate.getPublicKeyName();
196
197 setDefaultKeyForIdentity(keyName);
198
199 setDefaultCertificateForKey(certificate);
200}
201
202void
203KeyChain::addCertificateAsDefault(const IdentityCertificate& certificate)
204{
205 info().addCertificate(certificate);
206
207 setDefaultCertificateForKey(certificate);
208}
209
210void
211KeyChain::sign(Data &data)
212{
213 if (!defaultCertificate_)
214 {
215 defaultCertificate_ = info().getCertificate(
216 info().getDefaultCertificateNameForIdentity(
217 info().getDefaultIdentity()));
218
219 if(!defaultCertificate_)
220 throw Error("Default IdentityCertificate cannot be determined");
221 }
222
223 sign(data, *defaultCertificate_);
224}
225
226void
227KeyChain::sign(Data &data, const Name &certificateName)
228{
229 ptr_lib::shared_ptr<IdentityCertificate> cert = info().getCertificate(certificateName);
230 if (!cert)
231 throw Error("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
232
233 SignatureSha256WithRsa signature;
234 signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
235 data.setSignature(signature);
236
237 // For temporary usage, we support RSA + SHA256 only, but will support more.
238 tpm().sign(data, cert->getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
239}
240
241void
242KeyChain::sign(Data& data, const IdentityCertificate& certificate)
243{
244 SignatureSha256WithRsa signature;
245 signature.setKeyLocator(certificate.getName().getPrefix(-1));
246 data.setSignature(signature);
247
248 // For temporary usage, we support RSA + SHA256 only, but will support more.
249 tpm().sign(data, certificate.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
250}
251
252Signature
253KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
254{
255 ptr_lib::shared_ptr<IdentityCertificate> cert = info().getCertificate(certificateName);
256 if (!cert)
257 throw Error("Requested certificate [" + certificateName.toUri() + "] doesn't exist");
258
259 SignatureSha256WithRsa signature;
260 signature.setKeyLocator(certificateName.getPrefix(-1)); // implicit conversion should take care
261
262 // For temporary usage, we support RSA + SHA256 only, but will support more.
263 signature.setValue
264 (tpm().sign(buffer, bufferLength, cert->getPublicKeyName(), DIGEST_ALGORITHM_SHA256));
265 return signature;
266}
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700267
Jeff Thompson29ce3102013-09-27 11:47:48 -0700268void
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -0800269KeyChain::signByIdentity(Data& data, const Name& identityName)
Jeff Thompson29ce3102013-09-27 11:47:48 -0700270{
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800271 Name signingCertificateName = info().getDefaultCertificateNameForIdentity(identityName);
Jeff Thompson29ce3102013-09-27 11:47:48 -0700272
273 if (signingCertificateName.getComponentCount() == 0)
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -0800274 throw Error("No qualified certificate name found!");
Jeff Thompson29ce3102013-09-27 11:47:48 -0700275
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800276 sign(data, signingCertificateName);
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700277}
278
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -0800279Signature
Jeff Thompsone9ffe792013-10-22 10:58:48 -0700280KeyChain::signByIdentity(const uint8_t* buffer, size_t bufferLength, const Name& identityName)
281{
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800282 Name signingCertificateName = info().getDefaultCertificateNameForIdentity(identityName);
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700283
Jeff Thompsone9ffe792013-10-22 10:58:48 -0700284 if (signingCertificateName.size() == 0)
Alexander Afanasyevbf1a67a2014-01-05 23:36:13 -0800285 throw Error("No qualified certificate name found!");
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700286
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800287 return sign(buffer, bufferLength, signingCertificateName);
288}
289
290ptr_lib::shared_ptr<IdentityCertificate>
291KeyChain::selfSign(const Name& keyName)
292{
293 ptr_lib::shared_ptr<IdentityCertificate> certificate = ptr_lib::make_shared<IdentityCertificate>();
294
295 Name certificateName = keyName.getPrefix(-1);
296 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
297
298 ptr_lib::shared_ptr<PublicKey> pubKey = info().getKey(keyName);
299 if (!pubKey)
300 throw Error("Requested public key [" + keyName.toUri() + "] doesn't exist");
301
302 certificate->setName(certificateName);
303 certificate->setNotBefore(ndn_getNowMilliseconds());
304 certificate->setNotAfter(ndn_getNowMilliseconds() + 630720000 /* 20 years*/);
305 certificate->setPublicKeyInfo(*pubKey);
306 certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
307 certificate->encode();
308
309 selfSign(*certificate);
310 return certificate;
Jeff Thompsone9ffe792013-10-22 10:58:48 -0700311}
Jeff Thompsonc01e1782013-10-21 14:08:42 -0700312
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700313void
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800314KeyChain::selfSign (IdentityCertificate& cert)
Jeff Thompson2ce8f492013-09-17 18:01:25 -0700315{
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800316 SignatureSha256WithRsa signature;
317 signature.setKeyLocator(cert.getName().getPrefix(-1)); // implicit conversion should take care
318 cert.setSignature(signature);
Jeff Thompson1e90d8c2013-08-12 16:09:25 -0700319
Yingdi Yu2abd73f2014-01-08 23:34:11 -0800320 // For temporary usage, we support RSA + SHA256 only, but will support more.
321 tpm().sign(cert, cert.getPublicKeyName(), DIGEST_ALGORITHM_SHA256);
Jeff Thompsoncda349e2013-11-05 17:37:39 -0800322}
323
Jeff Thompson47c93cf2013-08-09 00:38:48 -0700324}