blob: dc48c3e4a4ec318080b593cc4e1552ac62b67e77 [file] [log] [blame]
Zhiyi Zhangf4bb5c72015-08-19 19:02:51 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento5d0b0102017-10-07 13:43:16 -04002/*
Yingdi Yu6ee2d362015-07-16 21:48:05 -07003 * Copyright (c) 2013-2017 Regents of the University of California.
Zhiyi Zhangf4bb5c72015-08-19 19:02:51 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 *
21 * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
22 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
23 */
24
25#include "certificate.hpp"
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -080026#include "additional-description.hpp"
Zhiyi Zhangf4bb5c72015-08-19 19:02:51 -070027#include "../../encoding/block-helpers.hpp"
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -080028#include "../../util/indented-stream.hpp"
29#include "../transform.hpp"
Zhiyi Zhangf4bb5c72015-08-19 19:02:51 -070030
31namespace ndn {
32namespace security {
33namespace v2 {
34
35BOOST_CONCEPT_ASSERT((WireEncodable<Certificate>));
36BOOST_CONCEPT_ASSERT((WireDecodable<Certificate>));
37
38// /<NameSpace>/KEY/[KeyId]/[IssuerId]/[Version]
39
40const ssize_t Certificate::VERSION_OFFSET = -1;
41const ssize_t Certificate::ISSUER_ID_OFFSET = -2;
42const ssize_t Certificate::KEY_ID_OFFSET = -3;
43const ssize_t Certificate::KEY_COMPONENT_OFFSET = -4;
44const size_t Certificate::MIN_CERT_NAME_LENGTH = 4;
45const size_t Certificate::MIN_KEY_NAME_LENGTH = 2;
46const name::Component Certificate::KEY_COMPONENT("KEY");
47
48Certificate::Certificate()
49{
50 setContentType(tlv::ContentTypeValue::ContentType_Key);
51}
52
53Certificate::Certificate(Data&& data)
54 : Data(data)
55{
56 if (!isValidName(getName())) {
57 BOOST_THROW_EXCEPTION(Data::Error("Name does not follow the naming convention for certificate"));
58 }
59 if (getContentType() != tlv::ContentTypeValue::ContentType_Key) {
60 BOOST_THROW_EXCEPTION(Data::Error("ContentType is not KEY"));
61 }
62 if (getFreshnessPeriod() < time::seconds::zero()) {
63 BOOST_THROW_EXCEPTION(Data::Error("FreshnessPeriod is not set"));
64 }
65 if (getContent().value_size() == 0) {
66 BOOST_THROW_EXCEPTION(Data::Error("Content is empty"));
67 }
68}
69
70Certificate::Certificate(const Data& data)
71 : Certificate(Data(data))
72{
73}
74
75Certificate::Certificate(const Block& block)
76 : Certificate(Data(block))
77{
78}
79
80Name
81Certificate::getKeyName() const
82{
83 return getName().getPrefix(KEY_ID_OFFSET + 1);
84}
85
86Name
87Certificate::getIdentity() const
88{
89 return getName().getPrefix(KEY_COMPONENT_OFFSET);
90}
91
92name::Component
93Certificate::getKeyId() const
94{
95 return getName().at(KEY_ID_OFFSET);
96}
97
98name::Component
99Certificate::getIssuerId() const
100{
101 return getName().at(ISSUER_ID_OFFSET);
102}
103
Yingdi Yu03997682015-11-23 16:41:38 -0800104Buffer
Zhiyi Zhangf4bb5c72015-08-19 19:02:51 -0700105Certificate::getPublicKey() const
106{
107 if (getContent().value_size() == 0)
108 BOOST_THROW_EXCEPTION(Data::Error("Content is empty"));
109 return Buffer(getContent().value(), getContent().value_size());
110}
111
112ValidityPeriod
113Certificate::getValidityPeriod() const
114{
115 return getSignature().getSignatureInfo().getValidityPeriod();
116}
117
118bool
119Certificate::isValid(const time::system_clock::TimePoint& ts) const
120{
121 return getSignature().getSignatureInfo().getValidityPeriod().isValid(ts);
122}
123
124const Block&
125Certificate::getExtension(uint32_t type) const
126{
127 return getSignature().getSignatureInfo().getTypeSpecificTlv(type);
128}
129
130bool
131Certificate::isValidName(const Name& certName)
132{
133 // /<NameSpace>/KEY/[KeyId]/[IssuerId]/[Version]
134 return (certName.size() >= Certificate::MIN_CERT_NAME_LENGTH &&
135 certName.get(Certificate::KEY_COMPONENT_OFFSET) == Certificate::KEY_COMPONENT);
136}
137
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800138std::ostream&
139operator<<(std::ostream& os, const Certificate& cert)
140{
141 os << "Certificate name:\n";
142 os << " " << cert.getName() << "\n";
143 os << "Validity:\n";
144 {
145 os << " NotBefore: " << time::toIsoString(cert.getValidityPeriod().getPeriod().first) << "\n";
146 os << " NotAfter: " << time::toIsoString(cert.getValidityPeriod().getPeriod().second) << "\n";
147 }
148
149 try {
150 const Block& info = cert.getSignature().getSignatureInfo().getTypeSpecificTlv(tlv::AdditionalDescription);
151 os << "Additional Description:\n";
152 for (const auto& item : v2::AdditionalDescription(info)) {
153 os << " " << item.first << ": " << item.second << "\n";
154 }
155 }
156 catch (const SignatureInfo::Error&) {
157 // ignore
158 }
159
160 os << "Public key bits:\n";
161 {
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400162 using namespace transform;
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800163 util::IndentedStream os2(os, " ");
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400164 bufferSource(cert.getPublicKey().data(), cert.getPublicKey().size()) >> base64Encode() >> streamSink(os2);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800165 }
166
167 os << "Signature Information:\n";
168 {
169 os << " Signature Type: " << static_cast<tlv::SignatureTypeValue>(cert.getSignature().getType()) << "\n";
170
171 if (cert.getSignature().hasKeyLocator()) {
172 os << " Key Locator: ";
173 const KeyLocator& keyLocator = cert.getSignature().getKeyLocator();
174 if (keyLocator.getType() == KeyLocator::KeyLocator_Name && keyLocator.getName() == cert.getKeyName()) {
175 os << "Self-Signed ";
176 }
177 os << keyLocator << "\n";
178 }
179 }
180
181 return os;
182}
183
Yingdi Yu6ee2d362015-07-16 21:48:05 -0700184Name
185extractIdentityFromCertName(const Name& certName)
186{
187 if (!Certificate::isValidName(certName)) {
188 BOOST_THROW_EXCEPTION(std::invalid_argument("Certificate name `" + certName.toUri() + "` "
189 "does not follow the naming conventions"));
190 }
191
192 return certName.getPrefix(Certificate::KEY_COMPONENT_OFFSET); // trim everything after and including "KEY"
193}
194
195Name
196extractKeyNameFromCertName(const Name& certName)
197{
198 if (!Certificate::isValidName(certName)) {
199 BOOST_THROW_EXCEPTION(std::invalid_argument("Certificate name `" + certName.toUri() + "` "
200 "does not follow the naming conventions"));
201 }
202
203 return certName.getPrefix(Certificate::KEY_ID_OFFSET + 1); // trim everything after key id
204}
205
Zhiyi Zhangf4bb5c72015-08-19 19:02:51 -0700206} // namespace v2
207} // namespace security
208} // namespace ndn