blob: 58c35706cef86f2be1a5dcbd5c26551a5249dfb0 [file] [log] [blame]
Yingdi Yuf56c68f2014-04-24 21:50:13 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * 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/>
13 */
14
15#include "key-chain.hpp"
16
17#include "sec-public-info-sqlite3.hpp"
18#include "sec-tpm-file.hpp"
19
20#ifdef NDN_CXX_HAVE_OSX_SECURITY
21#include "sec-tpm-osx.hpp"
22#endif
23
24#include "../util/random.hpp"
25#include "../util/config-file.hpp"
26
27namespace ndn {
28
29KeyChain::KeyChain()
30 : m_pib(0)
31 , m_tpm(0)
32{
33
34 ConfigFile config;
35 const ConfigFile::Parsed& parsed = config.getParsedConfiguration();
36
37 std::string pibName;
38 try
39 {
40 pibName = parsed.get<std::string>("pib");
41 }
42 catch (boost::property_tree::ptree_bad_path& error)
43 {
44 // pib is not specified, take the default
45 }
46 catch (boost::property_tree::ptree_bad_data& error)
47 {
48 throw ConfigFile::Error(error.what());
49 }
50
51 std::string tpmName;
52 try
53 {
54 tpmName = parsed.get<std::string>("tpm");
55 }
56 catch (boost::property_tree::ptree_bad_path& error)
57 {
58 // tpm is not specified, take the default
59 }
60 catch (boost::property_tree::ptree_bad_data& error)
61 {
62 throw ConfigFile::Error(error.what());
63 }
64
65
66 if (pibName.empty() || pibName == "sqlite3")
67 m_pib = new SecPublicInfoSqlite3;
68 else
69 throw Error("PIB type '" + pibName + "' is not supported");
70
71 if (tpmName.empty())
72#if defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
73 m_tpm = new SecTpmOsx();
74#else
75 m_tpm = new SecTpmFile();
76#endif // defined(NDN_CXX_HAVE_OSX_SECURITY) and defined(NDN_CXX_WITH_OSX_KEYCHAIN)
77 else if (tpmName == "osx-keychain")
78#if defined(NDN_CXX_HAVE_OSX_SECURITY)
79 m_tpm = new SecTpmOsx();
80#else
81 throw Error("TPM type '" + tpmName + "' is not supported on this platform");
82#endif // NDN_CXX_HAVE_OSX_SECURITY
83 else if (tpmName == "file")
84 m_tpm = new SecTpmFile();
85 else
86 throw Error("TPM type '" + tpmName + "' is not supported");
87}
88
89KeyChain::KeyChain(const std::string& pibName,
90 const std::string& tpmName)
91 : m_pib(0)
92 , m_tpm(0)
93{
94 if (pibName == "sqlite3")
95 m_pib = new SecPublicInfoSqlite3;
96 else
97 throw Error("PIB type '" + pibName + "' is not supported");
98
99 if (tpmName == "file")
100 m_tpm = new SecTpmFile;
101#if defined(NDN_CXX_HAVE_OSX_SECURITY)
102 else if (tpmName == "osx-keychain")
103 m_tpm = new SecTpmOsx();
104#endif //NDN_CXX_HAVE_OSX_SECURITY
105 else
106 throw Error("TPM type '" + tpmName + "' is not supported");
107}
108
109shared_ptr<IdentityCertificate>
110KeyChain::prepareUnsignedIdentityCertificate(const Name& keyName,
111 const Name& signingIdentity,
112 const time::system_clock::TimePoint& notBefore,
113 const time::system_clock::TimePoint& notAfter,
114 const std::vector<CertificateSubjectDescription>& subjectDescription)
115{
116 if (keyName.size() < 1)
117 return shared_ptr<IdentityCertificate>();
118
119 std::string keyIdPrefix = keyName.get(-1).toEscapedString().substr(0, 4);
120 if (keyIdPrefix != "ksk-" && keyIdPrefix != "dsk-")
121 return shared_ptr<IdentityCertificate>();
122
123 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
124 Name certName;
125
126 if (signingIdentity.isPrefixOf(keyName))
127 {
128 certName.append(signingIdentity)
129 .append("KEY")
130 .append(keyName.getSubName(signingIdentity.size()))
131 .append("ID-CERT")
132 .appendVersion();
133 }
134 else
135 {
136 certName.append(keyName.getPrefix(-1))
137 .append("KEY")
138 .append(keyName.get(-1))
139 .append("ID-CERT")
140 .appendVersion();
141 }
142
143 certificate->setName(certName);
144 certificate->setNotBefore(notBefore);
145 certificate->setNotAfter(notAfter);
146
147 shared_ptr<PublicKey> publicKey;
148 try
149 {
150 publicKey = m_pib->getPublicKey(keyName);
151 }
152 catch (SecPublicInfo::Error& e)
153 {
154 return shared_ptr<IdentityCertificate>();
155 }
156 certificate->setPublicKeyInfo(*publicKey);
157
158 if (subjectDescription.empty())
159 {
160 CertificateSubjectDescription subjectName("2.5.4.41", keyName.getPrefix(-1).toUri());
161 certificate->addSubjectDescription(subjectName);
162 }
163 else
164 {
165 std::vector<CertificateSubjectDescription>::const_iterator sdIt =
166 subjectDescription.begin();
167 std::vector<CertificateSubjectDescription>::const_iterator sdEnd =
168 subjectDescription.end();
169 for(; sdIt != sdEnd; sdIt++)
170 certificate->addSubjectDescription(*sdIt);
171 }
172
173 certificate->encode();
174
175 return certificate;
176}
177
178Signature
179KeyChain::sign(const uint8_t* buffer, size_t bufferLength, const Name& certificateName)
180{
181 if (!m_pib->doesCertificateExist(certificateName))
182 throw SecPublicInfo::Error("Requested certificate ["
183 + certificateName.toUri() + "] doesn't exist");
184
185 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
186
187 SignatureSha256WithRsa signature;
188 // implicit conversion should take care
189 signature.setKeyLocator(certificateName.getPrefix(-1));
190
191 // For temporary usage, we support RSA + SHA256 only, but will support more.
192 signature.setValue(m_tpm->signInTpm(buffer, bufferLength, keyName, DIGEST_ALGORITHM_SHA256));
193 return signature;
194}
195
196shared_ptr<IdentityCertificate>
197KeyChain::selfSign(const Name& keyName)
198{
199 shared_ptr<PublicKey> pubKey;
200 try
201 {
202 pubKey = m_pib->getPublicKey(keyName); // may throw an exception.
203 }
204 catch (SecPublicInfo::Error& e)
205 {
206 return shared_ptr<IdentityCertificate>();
207 }
208
209 shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>();
210
211 Name certificateName = keyName.getPrefix(-1);
212 certificateName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
213
214 certificate->setName(certificateName);
215 certificate->setNotBefore(time::system_clock::now());
216 certificate->setNotAfter(time::system_clock::now() + time::days(7300)/* ~20 years*/);
217 certificate->setPublicKeyInfo(*pubKey);
218 certificate->addSubjectDescription(CertificateSubjectDescription("2.5.4.41", keyName.toUri()));
219 certificate->encode();
220
221 selfSign(*certificate);
222 return certificate;
223}
224
225void
226KeyChain::selfSign(IdentityCertificate& cert)
227{
228 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(cert.getName());
229 if (!m_tpm->doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE))
230 throw SecTpm::Error("private key does not exist!");
231
232 SignatureSha256WithRsa signature;
233 signature.setKeyLocator(cert.getName().getPrefix(-1)); // implicit conversion should take care
234
235 // For temporary usage, we support RSA + SHA256 only, but will support more.
236 signPacketWrapper(cert, signature, keyName, DIGEST_ALGORITHM_SHA256);
237}
238
239shared_ptr<SecuredBag>
240KeyChain::exportIdentity(const Name& identity, const std::string& passwordStr)
241{
242 if (!m_pib->doesIdentityExist(identity))
243 throw SecPublicInfo::Error("Identity does not exist!");
244
245 Name keyName = m_pib->getDefaultKeyNameForIdentity(identity);
246
247 ConstBufferPtr pkcs5;
248 try
249 {
250 pkcs5 = m_tpm->exportPrivateKeyPkcs5FromTpm(keyName, passwordStr);
251 }
252 catch (SecTpm::Error& e)
253 {
254 throw SecPublicInfo::Error("Fail to export PKCS5 of private key");
255 }
256
257 shared_ptr<IdentityCertificate> cert;
258 try
259 {
260 cert = m_pib->getCertificate(m_pib->getDefaultCertificateNameForKey(keyName));
261 }
262 catch (SecPublicInfo::Error& e)
263 {
264 cert = selfSign(keyName);
265 m_pib->addCertificateAsIdentityDefault(*cert);
266 }
267
268 shared_ptr<SecuredBag> secureBag = make_shared<SecuredBag>(boost::cref(*cert),
269 boost::cref(pkcs5));
270
271 return secureBag;
272}
273
274void
275KeyChain::importIdentity(const SecuredBag& securedBag, const std::string& passwordStr)
276{
277 Name certificateName = securedBag.getCertificate().getName();
278 Name keyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
279 Name identity = keyName.getPrefix(-1);
280
281 // Add identity
282 m_pib->addIdentity(identity);
283
284 // Add key
285 m_tpm->importPrivateKeyPkcs5IntoTpm(keyName,
286 securedBag.getKey()->buf(),
287 securedBag.getKey()->size(),
288 passwordStr);
289
290 shared_ptr<PublicKey> pubKey = m_tpm->getPublicKeyFromTpm(keyName.toUri());
291 // HACK! We should set key type according to the pkcs8 info.
292 m_pib->addPublicKey(keyName, KEY_TYPE_RSA, *pubKey);
293 m_pib->setDefaultKeyNameForIdentity(keyName);
294
295 // Add cert
296 m_pib->addCertificateAsIdentityDefault(securedBag.getCertificate());
297}
298
299void
300KeyChain::setDefaultCertificateInternal()
301{
302 m_pib->refreshDefaultCertificate();
303
304 if (!static_cast<bool>(m_pib->defaultCertificate()))
305 {
306 Name defaultIdentity;
307 try
308 {
309 defaultIdentity = m_pib->getDefaultIdentity();
310 }
311 catch (SecPublicInfo::Error& e)
312 {
313 uint32_t random = random::generateWord32();
314 defaultIdentity.append("tmp-identity")
315 .append(reinterpret_cast<uint8_t*>(&random), 4);
316 }
317 createIdentity(defaultIdentity);
318 m_pib->setDefaultIdentity(defaultIdentity);
319 m_pib->refreshDefaultCertificate();
320 }
321}
322
323}