blob: 3bfca037cc93187cbb382c73bf23d9bcf37af8cf [file] [log] [blame]
Yumin Xiaf853ad72016-11-03 21:14:07 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yumin Xia2c509c22017-02-09 14:37:36 -08002/*
Yumin Xia55a7cc42017-05-14 18:43:34 -07003 * Copyright (c) 2014-2018, Regents of the University of California.
Yumin Xiaf853ad72016-11-03 21:14:07 -07004 *
5 * This file is part of NDNS (Named Data Networking Domain Name Service).
6 * See AUTHORS.md for complete list of NDNS authors and contributors.
7 *
8 * NDNS 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.
11 *
12 * NDNS 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.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * NDNS, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "rrset-factory.hpp"
21#include "mgmt/management-tool.hpp"
Yumin Xia2c509c22017-02-09 14:37:36 -080022#include "util/cert-helper.hpp"
23
24#include <ndn-cxx/security/signing-helpers.hpp>
Yumin Xiaf853ad72016-11-03 21:14:07 -070025
26#include <boost/algorithm/string/join.hpp>
27
28namespace ndn {
29namespace ndns {
30
31NDNS_LOG_INIT("RrsetFactory")
32
Yumin Xiab87b9d92016-11-14 23:41:25 -080033RrsetFactory::RrsetFactory(const boost::filesystem::path& dbFile,
Yumin Xiaf853ad72016-11-03 21:14:07 -070034 const Name& zoneName,
35 KeyChain& keyChain,
36 const Name& inputDskCertName)
37 : m_keyChain(keyChain)
Yumin Xiab87b9d92016-11-14 23:41:25 -080038 , m_dbFile(dbFile.string())
Yumin Xiaf853ad72016-11-03 21:14:07 -070039 , m_zone(zoneName)
40 , m_dskCertName(inputDskCertName)
41 , m_checked(false)
42{
Yumin Xia918343d2017-03-17 19:04:55 -070043 Name identityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
Yumin Xiaf853ad72016-11-03 21:14:07 -070044 if (m_dskCertName == DEFAULT_CERT) {
Yumin Xia2c509c22017-02-09 14:37:36 -080045 m_dskName = CertHelper::getDefaultKeyNameOfIdentity(m_keyChain, identityName);
46 m_dskCertName = CertHelper::getDefaultCertificateNameOfIdentity(m_keyChain, identityName);
Yumin Xiaf853ad72016-11-03 21:14:07 -070047 }
48}
49
50void
51RrsetFactory::checkZoneKey()
52{
53 onlyCheckZone();
Yumin Xia918343d2017-03-17 19:04:55 -070054 Name zoneIdentityName = Name(m_zone.getName()).append(label::NDNS_ITERATIVE_QUERY);
Yumin Xiaf853ad72016-11-03 21:14:07 -070055 if (m_dskCertName != DEFAULT_CERT &&
Yumin Xia2c509c22017-02-09 14:37:36 -080056 !matchCertificate(m_dskCertName, zoneIdentityName)) {
Yumin Xiaf853ad72016-11-03 21:14:07 -070057 BOOST_THROW_EXCEPTION(Error("Cannot verify certificate"));
58 }
59}
60
61void
62RrsetFactory::onlyCheckZone()
63{
64 if (m_checked) {
65 return ;
66 }
67 m_checked = true;
68
69 DbMgr dbMgr(m_dbFile);
70 const Name& zoneName = m_zone.getName();
71 if (!dbMgr.find(m_zone)) {
72 BOOST_THROW_EXCEPTION(Error(zoneName.toUri() + " is not presented in the NDNS db"));
73 }
74}
75
76
77std::pair<Rrset, Name>
78RrsetFactory::generateBaseRrset(const Name& label,
79 const name::Component& type,
Yumin Xia55a7cc42017-05-14 18:43:34 -070080 uint64_t version,
Yumin Xiaf853ad72016-11-03 21:14:07 -070081 const time::seconds& ttl)
82{
83 Rrset rrset(&m_zone);
84
85 rrset.setLabel(label);
86 rrset.setType(type);
87 rrset.setTtl(ttl);
88
Yumin Xiaf853ad72016-11-03 21:14:07 -070089 Name name;
90 name.append(m_zone.getName())
Yumin Xia918343d2017-03-17 19:04:55 -070091 .append(label::NDNS_ITERATIVE_QUERY)
Yumin Xiaf853ad72016-11-03 21:14:07 -070092 .append(label)
93 .append(type);
94
95 if (version != VERSION_USE_UNIX_TIMESTAMP) {
96 name.append(name::Component::fromVersion(version));
Yumin Xia2c509c22017-02-09 14:37:36 -080097 }
98 else {
Yumin Xiaf853ad72016-11-03 21:14:07 -070099 name.appendVersion();
100 }
101
102 rrset.setVersion(name.get(-1));
103
104 return std::make_pair(rrset, name);
105}
106
107bool
108RrsetFactory::matchCertificate(const Name& certName, const Name& identity)
109{
Yumin Xia2c509c22017-02-09 14:37:36 -0800110 try {
111 CertHelper::getCertificate(m_keyChain, identity, certName);
112 return true;
113 } catch (ndn::security::Pib::Error) {
Yumin Xiaf853ad72016-11-03 21:14:07 -0700114 return false;
115 }
Yumin Xiaf853ad72016-11-03 21:14:07 -0700116}
117
118Rrset
119RrsetFactory::generateNsRrset(const Name& label,
Yumin Xia55a7cc42017-05-14 18:43:34 -0700120 uint64_t version,
Yumin Xiaf853ad72016-11-03 21:14:07 -0700121 time::seconds ttl,
Yumin Xia2c509c22017-02-09 14:37:36 -0800122 const ndn::DelegationList& delegations)
Yumin Xiaf853ad72016-11-03 21:14:07 -0700123{
124 if (!m_checked) {
125 BOOST_THROW_EXCEPTION(Error("You have to call checkZoneKey before call generate functions"));
126 }
127
128 if (ttl == DEFAULT_RR_TTL)
129 ttl = m_zone.getTtl();
130
Yumin Xiad4e8ce52017-03-17 19:56:52 -0700131 std::pair<Rrset, Name> rrsetAndName = generateBaseRrset(label, label::NS_RR_TYPE, version, ttl);
Yumin Xiaf853ad72016-11-03 21:14:07 -0700132 const Name& name = rrsetAndName.second;
133 Rrset& rrset = rrsetAndName.first;
134
135 Link link(name);
Yumin Xia2c509c22017-02-09 14:37:36 -0800136 link.setDelegationList(delegations);
Yumin Xiaf853ad72016-11-03 21:14:07 -0700137
Yumin Xiaa484ba72016-11-10 20:40:12 -0800138 setContentType(link, NDNS_LINK, ttl);
Yumin Xiaf853ad72016-11-03 21:14:07 -0700139 sign(link);
140 rrset.setData(link.wireEncode());
141
142 return rrset;
143}
144
145Rrset
146RrsetFactory::generateTxtRrset(const Name& label,
Yumin Xia55a7cc42017-05-14 18:43:34 -0700147 uint64_t version,
Yumin Xiaf853ad72016-11-03 21:14:07 -0700148 time::seconds ttl,
149 const std::vector<std::string>& strings)
150{
151 if (!m_checked) {
152 BOOST_THROW_EXCEPTION(Error("You have to call checkZoneKey before call generate functions"));
153 }
154
155 if (ttl == DEFAULT_RR_TTL)
156 ttl = m_zone.getTtl();
157
158 Name name;
159 Rrset rrset;
Yumin Xiad4e8ce52017-03-17 19:56:52 -0700160 std::tie(rrset, name) = generateBaseRrset(label, label::TXT_RR_TYPE, version, ttl);
Yumin Xiaf853ad72016-11-03 21:14:07 -0700161
162 std::vector<Block> rrs;
163 for (const auto& item : strings) {
164 rrs.push_back(makeBinaryBlock(ndns::tlv::RrData,
165 item.c_str(),
166 item.size()));
167 }
168
169 Data data(name);
170 data.setContent(wireEncode(rrs));
171
Yumin Xiaa484ba72016-11-10 20:40:12 -0800172 setContentType(data, NDNS_RESP, ttl);
Yumin Xiaf853ad72016-11-03 21:14:07 -0700173 sign(data);
174 rrset.setData(data.wireEncode());
175
176 return rrset;
177}
178
179Rrset
180RrsetFactory::generateCertRrset(const Name& label,
Yumin Xia55a7cc42017-05-14 18:43:34 -0700181 uint64_t version,
Yumin Xiaf853ad72016-11-03 21:14:07 -0700182 time::seconds ttl,
Yumin Xia2c509c22017-02-09 14:37:36 -0800183 const ndn::security::v2::Certificate& cert)
Yumin Xiaf853ad72016-11-03 21:14:07 -0700184{
185 if (!m_checked) {
186 BOOST_THROW_EXCEPTION(Error("You have to call checkZoneKey before call generate functions"));
187 }
188
189 if (ttl == DEFAULT_RR_TTL)
190 ttl = m_zone.getTtl();
191
192 Name name;
193 Rrset rrset;
Yumin Xiad4e8ce52017-03-17 19:56:52 -0700194 std::tie(rrset, name) = generateBaseRrset(label, label::APPCERT_RR_TYPE, version, ttl);
Yumin Xiaf853ad72016-11-03 21:14:07 -0700195
196 Data data(name);
197 data.setContent(cert.wireEncode());
198
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800199 setContentType(data, NDNS_KEY, ttl);
Yumin Xiaf853ad72016-11-03 21:14:07 -0700200 sign(data);
201 rrset.setData(data.wireEncode());
202
203 return rrset;
204}
205
Yumin Xiaacd21332016-11-28 22:54:48 -0800206Rrset
207RrsetFactory::generateAuthRrset(const Name& label,
Yumin Xia55a7cc42017-05-14 18:43:34 -0700208 uint64_t version,
Yumin Xiaacd21332016-11-28 22:54:48 -0800209 time::seconds ttl)
210{
211 if (!m_checked) {
212 BOOST_THROW_EXCEPTION(Error("You have to call checkZoneKey before call generate functions"));
213 }
214
215 if (ttl == DEFAULT_RR_TTL)
216 ttl = m_zone.getTtl();
217
218 Name name;
219 Rrset rrset;
Yumin Xiad4e8ce52017-03-17 19:56:52 -0700220 std::tie(rrset, name) = generateBaseRrset(label, label::NS_RR_TYPE, version, ttl);
Yumin Xiaacd21332016-11-28 22:54:48 -0800221
222 Data data(name);
223
224 setContentType(data, NDNS_AUTH, ttl);
225 sign(data);
226 rrset.setData(data.wireEncode());
227
228 return rrset;
229}
Yumin Xiaf853ad72016-11-03 21:14:07 -0700230
Yumin Xia55a7cc42017-05-14 18:43:34 -0700231Rrset
232RrsetFactory::generateDoeRrset(const Name& label,
233 uint64_t version,
234 time::seconds ttl,
235 const Name& lowerLabel,
236 const Name& upperLabel)
237{
238 if (!m_checked) {
239 BOOST_THROW_EXCEPTION(Error("You have to call checkZoneKey before call generate functions"));
240 }
241
242 if (ttl == DEFAULT_RR_TTL)
243 ttl = m_zone.getTtl();
244
245 Name name;
246 Rrset rrset;
247 std::tie(rrset, name) = generateBaseRrset(label, label::DOE_RR_TYPE, version, ttl);
248
249 std::vector<Block> range;
250 range.push_back(lowerLabel.wireEncode());
251 range.push_back(upperLabel.wireEncode());
252
253 Data data(name);
254 data.setContent(wireEncode(range));
255
256 setContentType(data, NDNS_DOE, ttl);
257 sign(data);
258 rrset.setData(data.wireEncode());
259
260 return rrset;
261}
262
263
Yumin Xiaf853ad72016-11-03 21:14:07 -0700264void
265RrsetFactory::sign(Data& data)
266{
Yumin Xia2c509c22017-02-09 14:37:36 -0800267 m_keyChain.sign(data, signingByCertificate(m_dskCertName));
Yumin Xiaf853ad72016-11-03 21:14:07 -0700268}
269
270void
Yumin Xiaa484ba72016-11-10 20:40:12 -0800271RrsetFactory::setContentType(Data& data, NdnsContentType contentType,
272 const time::seconds& ttl)
Yumin Xiaf853ad72016-11-03 21:14:07 -0700273{
Yumin Xiaa484ba72016-11-10 20:40:12 -0800274 data.setContentType(contentType);
275 data.setFreshnessPeriod(ttl);
Yumin Xiaf853ad72016-11-03 21:14:07 -0700276}
277
278template<encoding::Tag TAG>
279inline size_t
280RrsetFactory::wireEncode(EncodingImpl<TAG>& block, const std::vector<Block>& rrs) const
281{
282 // Content :: = CONTENT-TYPE TLV-LENGTH
283 // Block*
284
285 size_t totalLength = 0;
286 for (auto iter = rrs.rbegin(); iter != rrs.rend(); ++iter) {
287 totalLength += block.prependBlock(*iter);
288 }
289
290 totalLength += block.prependVarNumber(totalLength);
291 totalLength += block.prependVarNumber(::ndn::tlv::Content);
292
293 return totalLength;
294}
295
296const Block
297RrsetFactory::wireEncode(const std::vector<Block>& rrs) const
298{
299 EncodingEstimator estimator;
300 size_t estimatedSize = wireEncode(estimator, rrs);
301 EncodingBuffer buffer(estimatedSize, 0);
302 wireEncode(buffer, rrs);
303 return buffer.block();
304}
305
306std::vector<std::string>
307RrsetFactory::wireDecodeTxt(const Block& wire)
308{
309 std::vector<std::string> txts;
310 wire.parse();
311
Yumin Xiaa484ba72016-11-10 20:40:12 -0800312 for (const auto& e : wire.elements()) {
Yumin Xiaf853ad72016-11-03 21:14:07 -0700313 txts.push_back(std::string(reinterpret_cast<const char*>(e.value()),
314 e.value_size()));
315 }
316
317 return txts;
318}
319
320
321} // namespace ndns
322} // namespace ndn