blob: d686a50a813d6b1f5cf008e1a7a855fd6194b468 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Jeff Thompsona5dc3512013-10-17 10:26:19 -07002/**
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -07003 * Copyright (c) 2013-2017 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * 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.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
22 * @author Jeff Thompson <jefft0@remap.ucla.edu>
23 * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
Jeff Thompsona5dc3512013-10-17 10:26:19 -070024 */
25
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080026#include "certificate.hpp"
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070027#include "../../util/time.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070028#include "cryptopp.hpp"
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070029#include "../../encoding/cryptopp/asn_ext.hpp"
30#include "../../encoding/buffer-stream.hpp"
31#include "../../util/concepts.hpp"
32#include "../../util/indented-stream.hpp"
Jeff Thompsona5dc3512013-10-17 10:26:19 -070033
Yingdi Yu3e8b52e2014-11-26 22:05:00 -080034#include <boost/algorithm/string/split.hpp>
35
Jeff Thompsona5dc3512013-10-17 10:26:19 -070036namespace ndn {
Alexander Afanasyev2fa59392016-07-29 17:24:23 -070037namespace security {
38namespace v1 {
Jeff Thompsona5dc3512013-10-17 10:26:19 -070039
Yingdi Yu80979ba2014-11-25 14:38:36 -080040BOOST_CONCEPT_ASSERT((WireEncodable<Certificate>));
41BOOST_CONCEPT_ASSERT((WireDecodable<Certificate>));
42static_assert(std::is_base_of<tlv::Error, Certificate::Error>::value,
43 "Certificate::Error must inherit from tlv::Error");
44
Jeff Thompsona5dc3512013-10-17 10:26:19 -070045Certificate::Certificate()
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070046 : m_notBefore(time::system_clock::TimePoint::max())
47 , m_notAfter(time::system_clock::TimePoint::min())
48{
49}
Jeff Thompsona5dc3512013-10-17 10:26:19 -070050
51Certificate::Certificate(const Data& data)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070052 // Use the copy constructor. It clones the signature object.
53 : Data(data)
Jeff Thompsona5dc3512013-10-17 10:26:19 -070054{
Jeff Thompsona5dc3512013-10-17 10:26:19 -070055 decode();
56}
57
Yingdi Yu80979ba2014-11-25 14:38:36 -080058Certificate::Certificate(const Block& block)
59 : Data(block)
60{
61 decode();
62}
63
Jeff Thompsona5dc3512013-10-17 10:26:19 -070064Certificate::~Certificate()
65{
Yingdi Yu80979ba2014-11-25 14:38:36 -080066}
67
68void
69Certificate::wireDecode(const Block& wire)
70{
71 Data::wireDecode(wire);
72 decode();
Jeff Thompsona5dc3512013-10-17 10:26:19 -070073}
74
75bool
76Certificate::isTooEarly()
77{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070078 if (time::system_clock::now() < m_notBefore)
Jeff Thompsona5dc3512013-10-17 10:26:19 -070079 return true;
80 else
81 return false;
82}
83
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070084bool
Jeff Thompsona5dc3512013-10-17 10:26:19 -070085Certificate::isTooLate()
86{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070087 if (time::system_clock::now() > m_notAfter)
Jeff Thompsona5dc3512013-10-17 10:26:19 -070088 return true;
89 else
90 return false;
91}
92
Jeff Thompsona5dc3512013-10-17 10:26:19 -070093void
94Certificate::encode()
95{
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080096 // Name
97 // <key_name>/ID-CERT/<id#>
98 // Content
99 // DER encoded idCert:
100 //
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700101 // idCert ::= SEQUENCE {
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800102 // validity Validity,
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700103 // subject Name,
104 // subjectPubKeyInfo SubjectPublicKeyInfo,
105 // extension Extensions OPTIONAL }
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800106 //
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700107 // Validity ::= SEQUENCE {
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800108 // notBefore Time,
109 // notAfter Time }
110 //
111 // Name ::= CHOICE {
112 // RDNSequence }
113 //
114 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
115 //
116 // RelativeDistinguishedName ::=
117 // SET OF AttributeTypeAndValue
118 //
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700119 // SubjectPublicKeyInfo ::= SEQUENCE {
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800120 // algorithm AlgorithmIdentifier
121 // keybits BIT STRING }
122 //
123 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
124 //
125 // (see http://www.ietf.org/rfc/rfc3280.txt for more detail)
126 //
127 // KeyLocator
128 // issuer’s certificate name
129 // Signature
130
131 using namespace CryptoPP;
132
133 OBufferStream os;
134 CryptoPP::FileSink sink(os);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700135
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800136 // idCert ::= SEQUENCE {
137 // validity Validity,
138 // subject Name,
139 // subjectPubKeyInfo SubjectPublicKeyInfo,
140 // extension Extensions OPTIONAL }
141 DERSequenceEncoder idCert(sink);
142 {
143 // Validity ::= SEQUENCE {
144 // notBefore Time,
145 // notAfter Time }
146 DERSequenceEncoder validity(idCert);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700147 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700148 DEREncodeGeneralTime(validity, m_notBefore);
149 DEREncodeGeneralTime(validity, m_notAfter);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700150 }
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800151 validity.MessageEnd();
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700152
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800153 // Name ::= CHOICE {
154 // RDNSequence }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700155 //
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800156 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
157 DERSequenceEncoder name(idCert);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700158 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700159 for (SubjectDescriptionList::iterator it = m_subjectDescriptionList.begin();
160 it != m_subjectDescriptionList.end(); ++it)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800161 {
162 it->encode(name);
163 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700164 }
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800165 name.MessageEnd();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700166
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800167 // SubjectPublicKeyInfo
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700168 m_key.encode(idCert);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700169
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800170 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
171 //
172 // Extension ::= SEQUENCE {
173 // extnID OBJECT IDENTIFIER,
174 // critical BOOLEAN DEFAULT FALSE,
175 // extnValue OCTET STRING }
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700176 if (!m_extensionList.empty())
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800177 {
178 DERSequenceEncoder extensions(idCert);
179 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700180 for (ExtensionList::iterator it = m_extensionList.begin();
181 it != m_extensionList.end(); ++it)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800182 {
183 it->encode(extensions);
184 }
185 }
186 extensions.MessageEnd();
187 }
188 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700189
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800190 idCert.MessageEnd();
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700191
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800192 setContent(os.buf());
Junxiao Shia464b922014-11-12 21:13:06 -0700193 setContentType(tlv::ContentType_Key);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700194}
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700195
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700196void
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700197Certificate::decode()
198{
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800199 using namespace CryptoPP;
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700200
Yingdi Yu80979ba2014-11-25 14:38:36 -0800201 try {
202 OBufferStream os;
203 StringSource source(getContent().value(), getContent().value_size(), true);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700204
Yingdi Yu80979ba2014-11-25 14:38:36 -0800205 // idCert ::= SEQUENCE {
206 // validity Validity,
207 // subject Name,
208 // subjectPubKeyInfo SubjectPublicKeyInfo,
209 // extension Extensions OPTIONAL }
210 BERSequenceDecoder idCert(source);
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800211 {
Yingdi Yu80979ba2014-11-25 14:38:36 -0800212 // Validity ::= SEQUENCE {
213 // notBefore Time,
214 // notAfter Time }
215 BERSequenceDecoder validity(idCert);
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800216 {
Yingdi Yu80979ba2014-11-25 14:38:36 -0800217 BERDecodeTime(validity, m_notBefore);
218 BERDecodeTime(validity, m_notAfter);
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800219 }
Yingdi Yu80979ba2014-11-25 14:38:36 -0800220 validity.MessageEnd();
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700221
Yingdi Yu80979ba2014-11-25 14:38:36 -0800222 // Name ::= CHOICE {
223 // RDNSequence }
224 //
225 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
226 m_subjectDescriptionList.clear();
227 BERSequenceDecoder name(idCert);
228 {
229 while (!name.EndReached())
230 {
231 m_subjectDescriptionList.push_back(CertificateSubjectDescription(name));
232 }
233 }
234 name.MessageEnd();
235
236 // SubjectPublicKeyInfo ::= SEQUENCE {
237 // algorithm AlgorithmIdentifier
238 // keybits BIT STRING }
239 m_key.decode(idCert);
240
241 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
242 //
243 // Extension ::= SEQUENCE {
244 // extnID OBJECT IDENTIFIER,
245 // critical BOOLEAN DEFAULT FALSE,
246 // extnValue OCTET STRING }
247 m_extensionList.clear();
248 if (!idCert.EndReached())
249 {
250 BERSequenceDecoder extensions(idCert);
251 {
252 while (!extensions.EndReached())
253 {
254 m_extensionList.push_back(CertificateExtension(extensions));
255 }
256 }
257 extensions.MessageEnd();
258 }
259 }
260
261 idCert.MessageEnd();
262 }
263 catch (CryptoPP::BERDecodeErr&) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700264 BOOST_THROW_EXCEPTION(Error("Certificate Decoding Error"));
Yingdi Yu80979ba2014-11-25 14:38:36 -0800265 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700266}
267
Yingdi Yu3e8b52e2014-11-26 22:05:00 -0800268void
269Certificate::printCertificate(std::ostream& oss, const std::string& indent) const
270{
Alexander Afanasyevbbb31f92014-12-01 13:15:59 -0800271 util::IndentedStream os(oss, indent);
Yingdi Yu3e8b52e2014-11-26 22:05:00 -0800272
273 os << "Certificate name:\n";
274 os << " " << getName() << "\n";
275 os << "Validity:\n";
276 {
277 os << " NotBefore: " << time::toIsoString(m_notBefore) << "\n";
278 os << " NotAfter: " << time::toIsoString(m_notAfter) << "\n";
279 }
280
281 os << "Subject Description:\n";
282 for (const auto& description : m_subjectDescriptionList)
283 os << " " << description.getOidString() << ": " << description.getValue() << "\n";
284
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800285 os << "Public key bits: ";
286 switch (m_key.getKeyType()) {
Yingdi Yu99b2a002015-08-12 12:47:44 -0700287 case KeyType::RSA:
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800288 os << "(RSA)";
289 break;
Yingdi Yu99b2a002015-08-12 12:47:44 -0700290 case KeyType::EC:
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700291 os << "(EC)";
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800292 break;
293 default:
294 os << "(Unknown key type)";
295 break;
296 }
Yingdi Yu3e8b52e2014-11-26 22:05:00 -0800297 os << "\n";
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800298
Yingdi Yu3e8b52e2014-11-26 22:05:00 -0800299 {
Alexander Afanasyevbbb31f92014-12-01 13:15:59 -0800300 util::IndentedStream os2(os, " ");
Yingdi Yu3e8b52e2014-11-26 22:05:00 -0800301 CryptoPP::Base64Encoder encoder(new CryptoPP::FileSink(os2), true, 64);
302 m_key.encode(encoder);
303 }
304
305 os << "Signature Information:\n";
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800306 {
307 os << " Signature Type: ";
308 switch (getSignature().getType()) {
309 case tlv::SignatureTypeValue::DigestSha256:
310 os << "DigestSha256";
311 break;
312 case tlv::SignatureTypeValue::SignatureSha256WithRsa:
313 os << "SignatureSha256WithRsa";
314 break;
315 case tlv::SignatureTypeValue::SignatureSha256WithEcdsa:
316 os << "SignatureSha256WithEcdsa";
317 break;
318 default:
319 os << "Unknown Signature Type";
320 }
Yingdi Yu3e8b52e2014-11-26 22:05:00 -0800321 os << "\n";
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800322
323 if (getSignature().hasKeyLocator()) {
324 const KeyLocator& keyLocator = getSignature().getKeyLocator();
325 os << " Key Locator: ";
326 switch (keyLocator.getType()) {
327 case KeyLocator::KeyLocator_Name:
328 {
329 const Name& signerName = keyLocator.getName();
330 if (signerName.isPrefixOf(getName()))
331 os << "(Self-Signed) " << keyLocator.getName();
332 else
333 os << "(Name) " << keyLocator.getName();
334 break;
335 }
336 case KeyLocator::KeyLocator_KeyDigest:
337 os << "(KeyDigest)";
338 break;
339 case KeyLocator::KeyLocator_None:
340 os << "None";
341 break;
342 default:
343 os << "Unknown";
344 }
Yingdi Yu3e8b52e2014-11-26 22:05:00 -0800345 os << "\n";
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800346 }
347 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700348}
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700349
Yingdi Yu80979ba2014-11-25 14:38:36 -0800350std::ostream&
351operator<<(std::ostream& os, const Certificate& cert)
352{
353 cert.printCertificate(os);
354 return os;
355}
356
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700357} // namespace v1
358} // namespace security
Yingdi Yufc40d872014-02-18 12:56:04 -0800359} // namespace ndn