blob: 042bf2e8f3295587c6493eb518ac31e7e068a3ac [file] [log] [blame]
Yingdi Yu77627ab2015-07-21 16:13:49 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev244feac2016-08-01 14:30:01 -07003 * Copyright (c) 2014-2016, Regents of the University of California.
Yingdi Yu77627ab2015-07-21 16:13:49 -07004 *
Yingdi Yu0a312e52015-07-22 13:14:53 -07005 * This file is part of ndn-tools (Named Data Networking Essential Tools).
6 * See AUTHORS.md for complete list of ndn-tools authors and contributors.
Yingdi Yu77627ab2015-07-21 16:13:49 -07007 *
Yingdi Yu0a312e52015-07-22 13:14:53 -07008 * ndn-tools is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
Yingdi Yu77627ab2015-07-21 16:13:49 -070011 *
Yingdi Yu0a312e52015-07-22 13:14:53 -070012 * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
Yingdi Yu77627ab2015-07-21 16:13:49 -070015 *
Yingdi Yu0a312e52015-07-22 13:14:53 -070016 * You should have received a copy of the GNU General Public License along with
17 * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Yingdi Yu77627ab2015-07-21 16:13:49 -070018 *
Yingdi Yu0a312e52015-07-22 13:14:53 -070019 * @author Yingdi Yu <yingdi@cs.ucla.edu>
Yingdi Yu77627ab2015-07-21 16:13:49 -070020 */
21
22#include "pib.hpp"
23
24#include "encoding/pib-encoding.hpp"
25#include <ndn-cxx/security/key-chain.hpp>
26#include <ndn-cxx/util/io.hpp>
27#include <ndn-cxx/util/crypto.hpp>
28#include <ndn-cxx/util/concepts.hpp>
29
30#include <boost/lexical_cast.hpp>
31
32namespace ndn {
33namespace pib {
34
35using std::string;
36using std::vector;
37using std::set;
38
39const Name Pib::PIB_PREFIX("/localhost/pib");
40const Name Pib::EMPTY_SIGNER_NAME;
41const name::Component Pib::MGMT_LABEL("mgmt");
42
43// \todo make this a static method in KeyChain
44static inline void
45signWithDigestSha256(Data& data)
46{
47 DigestSha256 sig;
48 data.setSignature(sig);
49 Block sigValue(tlv::SignatureValue,
50 crypto::sha256(data.wireEncode().value(),
51 data.wireEncode().value_size() -
52 data.getSignature().getValue().size()));
53 data.setSignatureValue(sigValue);
54 data.wireEncode();
55}
56
57Pib::Pib(Face& face,
58 const std::string& dbDir,
59 const std::string& tpmLocator,
60 const std::string& owner)
61 : m_db(dbDir)
62 , m_tpm(nullptr)
63 , m_owner(owner)
64 , m_validator(m_db)
65 , m_face(face)
66 , m_certPublisher(m_face, m_db)
67 , m_getProcessor(m_db)
68 , m_defaultProcessor(m_db)
69 , m_listProcessor(m_db)
70 , m_updateProcessor(m_db, *this)
71 , m_deleteProcessor(m_db)
72{
73 if (!m_db.getOwnerName().empty() && m_db.getOwnerName() != owner)
74 throw Error("owner argument differs from OwnerName in database");
75
76 if (!m_db.getTpmLocator().empty() && m_db.getTpmLocator() != tpmLocator)
77 throw Error("tpmLocator argument differs from TpmLocator in database");
78
79 initializeTpm(tpmLocator);
80 initializeMgmtCert();
81 m_db.setTpmLocator(tpmLocator);
82
83 registerPrefix();
84}
85
86Pib::~Pib()
87{
88 m_face.unsetInterestFilter(m_pibMgmtFilterId);
89 m_face.unsetInterestFilter(m_pibGetFilterId);
90 m_face.unsetInterestFilter(m_pibDefaultFilterId);
91 m_face.unsetInterestFilter(m_pibListFilterId);
92 m_face.unsetInterestFilter(m_pibUpdateFilterId);
93 m_face.unsetInterestFilter(m_pibDeleteFilterId);
94
95 m_face.unsetInterestFilter(m_pibPrefixId);
96}
97
98void
99Pib::setMgmtCert(std::shared_ptr<IdentityCertificate> mgmtCert)
100{
101 if (mgmtCert != nullptr)
102 m_mgmtCert = mgmtCert;
103}
104
105void
106Pib::initializeTpm(const string& tpmLocator)
107{
108 m_tpm = KeyChain::createTpm(tpmLocator);
109}
110
111void
112Pib::initializeMgmtCert()
113{
114 shared_ptr<IdentityCertificate> mgmtCert = m_db.getMgmtCertificate();
115
116 if (mgmtCert == nullptr ||
Alexander Afanasyev244feac2016-08-01 14:30:01 -0700117 !m_tpm->doesKeyExistInTpm(mgmtCert->getPublicKeyName(), KeyClass::PRIVATE)) {
Yingdi Yu77627ab2015-07-21 16:13:49 -0700118 // If mgmt cert is set, or corresponding private key of the current mgmt cert is missing,
119 // generate new mgmt cert
120
121 // key name: /localhost/pib/[UserName]/mgmt/dsk-...
122 Name mgmtKeyName = PIB_PREFIX;
123 mgmtKeyName.append(m_owner).append(MGMT_LABEL);
124 std::ostringstream oss;
125 oss << "dsk-" << time::toUnixTimestamp(time::system_clock::now()).count();
126 mgmtKeyName.append(oss.str());
127
128 // self-sign pib root key
129 m_mgmtCert = prepareCertificate(mgmtKeyName, RsaKeyParams(),
130 time::system_clock::now(),
131 time::system_clock::now() + time::days(7300));
132
133 // update management certificate in database
134 m_db.updateMgmtCertificate(*m_mgmtCert);
135 }
136 else
137 m_mgmtCert = mgmtCert;
138}
139
140shared_ptr<IdentityCertificate>
141Pib::prepareCertificate(const Name& keyName, const KeyParams& keyParams,
142 const time::system_clock::TimePoint& notBefore,
143 const time::system_clock::TimePoint& notAfter,
144 const Name& signerName)
145{
146 // Generate mgmt key
147 m_tpm->generateKeyPairInTpm(keyName, keyParams);
148 shared_ptr<PublicKey> publicKey = m_tpm->getPublicKeyFromTpm(keyName);
149
150 // Set mgmt cert
151 auto certificate = make_shared<IdentityCertificate>();
152 Name certName = keyName.getPrefix(-1);
153 certName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
154 certificate->setName(certName);
155 certificate->setNotBefore(notBefore);
156 certificate->setNotAfter(notAfter);
157 certificate->setPublicKeyInfo(*publicKey);
158 CertificateSubjectDescription subjectName(oid::ATTRIBUTE_NAME, keyName.getPrefix(-1).toUri());
159 certificate->addSubjectDescription(subjectName);
160 certificate->encode();
161
162
163 Name signingKeyName;
164 KeyLocator keyLocator;
165 if (signerName == EMPTY_SIGNER_NAME) {
166 // Self-sign mgmt cert
167 keyLocator = KeyLocator(certificate->getName().getPrefix(-1));
168 signingKeyName = keyName;
169 }
170 else {
171 keyLocator = KeyLocator(signerName.getPrefix(-1));
172 signingKeyName = IdentityCertificate::certificateNameToPublicKeyName(signerName);
173 }
174
175 SignatureSha256WithRsa signature(keyLocator);
176 certificate->setSignature(signature);
177 EncodingBuffer encoder;
178 certificate->wireEncode(encoder, true);
179 Block signatureValue = m_tpm->signInTpm(encoder.buf(), encoder.size(),
Alexander Afanasyev244feac2016-08-01 14:30:01 -0700180 signingKeyName, DigestAlgorithm::SHA256);
Yingdi Yu77627ab2015-07-21 16:13:49 -0700181 certificate->wireEncode(encoder, signatureValue);
182
183 return certificate;
184}
185
186void
187Pib::registerPrefix()
188{
189 // register pib prefix
190 Name pibPrefix = PIB_PREFIX;
191 pibPrefix.append(m_owner);
192 m_pibPrefixId =
193 m_face.registerPrefix(pibPrefix,
194 [] (const Name& name) {},
195 [] (const Name& name, const string& msg) {
196 throw Error("cannot register pib prefix");
197 });
198
199 // set interest filter for management certificate
200 m_pibMgmtFilterId =
201 m_face.setInterestFilter(Name(pibPrefix).append(MGMT_LABEL),
202 [this] (const InterestFilter&, const Interest& interest) {
203 if (m_mgmtCert != nullptr) {
204 m_face.put(*m_mgmtCert);
205 }
206 });
207
208 // set interest filter for get command
209 m_pibGetFilterId = registerProcessor(Name(pibPrefix).append(GetParam::VERB), m_getProcessor);
210
211 // set interest filter for default command
212 m_pibDefaultFilterId = registerProcessor(Name(pibPrefix).append(DefaultParam::VERB),
213 m_defaultProcessor);
214
215 // set interest filter for list command
216 m_pibListFilterId = registerProcessor(Name(pibPrefix).append(ListParam::VERB),
217 m_listProcessor);
218
219 // set interest filter for update command
220 m_pibUpdateFilterId = registerSignedCommandProcessor(Name(pibPrefix).append(UpdateParam::VERB),
221 m_updateProcessor);
222
223 // set interest filter for delete command
224 m_pibDeleteFilterId = registerSignedCommandProcessor(Name(pibPrefix).append(DeleteParam::VERB),
225 m_deleteProcessor);
226}
227
228template<class Processor>
229const InterestFilterId*
230Pib::registerProcessor(const Name& prefix, Processor& process)
231{
232 return m_face.setInterestFilter(prefix,
233 [&] (const InterestFilter&, const Interest& interest) {
234 processCommand(process, interest);
235 });
236}
237
238template<class Processor>
239const InterestFilterId*
240Pib::registerSignedCommandProcessor(const Name& prefix, Processor& process)
241{
242 const InterestFilterId* filterId =
243 m_face.setInterestFilter(prefix,
244 [&] (const InterestFilter&, const Interest& interest) {
245 m_validator.validate(interest,
246 [&] (const shared_ptr<const Interest>& interest) {
247 processCommand(process, *interest);
248 },
249 [] (const shared_ptr<const Interest>&, const string&) {});
250 });
251
252 return filterId;
253}
254
255template<class Processor>
256void
257Pib::processCommand(Processor& process, const Interest& interest)
258{
259 std::pair<bool, Block> result = process(interest);
260 if (result.first)
261 returnResult(Name(interest.getName()).appendVersion(),
262 result.second);
263}
264
265void
266Pib::returnResult(const Name& dataName, const Block& content)
267{
268 shared_ptr<Data> data = make_shared<Data>(dataName);
269
270 data->setFreshnessPeriod(time::milliseconds::zero());
271 data->setContent(content);
272 signWithDigestSha256(*data);
273
274 // Put data into response cache
275 m_responseCache.insert(*data);
276
277 // Put data to face.
278 m_face.put(*data);
279}
280
281} // namespace pib
282} // namespace ndn