blob: 67c440b78903bf206a3b607dc589822f9053aa79 [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/**
Alexander Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 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 Afanasyev09c613f2014-01-29 00:23:58 -080026#include "common.hpp"
Alexander Afanasyev8e96e582013-11-19 12:07:04 -080027
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080028#include "certificate.hpp"
Yingdi Yu4f324632014-01-15 18:10:03 -080029#include "../util/time.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070030#include "cryptopp.hpp"
Yingdi Yu4f324632014-01-15 18:10:03 -080031#include "../encoding/cryptopp/asn_ext.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070032#include "../encoding/buffer-stream.hpp"
Yingdi Yu80979ba2014-11-25 14:38:36 -080033#include "../util/concepts.hpp"
Jeff Thompsona5dc3512013-10-17 10:26:19 -070034
Jeff Thompsona5dc3512013-10-17 10:26:19 -070035namespace ndn {
36
Yingdi Yu80979ba2014-11-25 14:38:36 -080037BOOST_CONCEPT_ASSERT((WireEncodable<Certificate>));
38BOOST_CONCEPT_ASSERT((WireDecodable<Certificate>));
39static_assert(std::is_base_of<tlv::Error, Certificate::Error>::value,
40 "Certificate::Error must inherit from tlv::Error");
41
Jeff Thompsona5dc3512013-10-17 10:26:19 -070042Certificate::Certificate()
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070043 : m_notBefore(time::system_clock::TimePoint::max())
44 , m_notAfter(time::system_clock::TimePoint::min())
45{
46}
Jeff Thompsona5dc3512013-10-17 10:26:19 -070047
48Certificate::Certificate(const Data& data)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070049 // Use the copy constructor. It clones the signature object.
50 : Data(data)
Jeff Thompsona5dc3512013-10-17 10:26:19 -070051{
Jeff Thompsona5dc3512013-10-17 10:26:19 -070052 decode();
53}
54
Yingdi Yu80979ba2014-11-25 14:38:36 -080055Certificate::Certificate(const Block& block)
56 : Data(block)
57{
58 decode();
59}
60
Jeff Thompsona5dc3512013-10-17 10:26:19 -070061Certificate::~Certificate()
62{
Yingdi Yu80979ba2014-11-25 14:38:36 -080063}
64
65void
66Certificate::wireDecode(const Block& wire)
67{
68 Data::wireDecode(wire);
69 decode();
Jeff Thompsona5dc3512013-10-17 10:26:19 -070070}
71
72bool
73Certificate::isTooEarly()
74{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070075 if (time::system_clock::now() < m_notBefore)
Jeff Thompsona5dc3512013-10-17 10:26:19 -070076 return true;
77 else
78 return false;
79}
80
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070081bool
Jeff Thompsona5dc3512013-10-17 10:26:19 -070082Certificate::isTooLate()
83{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070084 if (time::system_clock::now() > m_notAfter)
Jeff Thompsona5dc3512013-10-17 10:26:19 -070085 return true;
86 else
87 return false;
88}
89
Jeff Thompsona5dc3512013-10-17 10:26:19 -070090void
91Certificate::encode()
92{
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080093 // Name
94 // <key_name>/ID-CERT/<id#>
95 // Content
96 // DER encoded idCert:
97 //
Yingdi Yu5ec0ee32014-06-24 16:26:09 -070098 // idCert ::= SEQUENCE {
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080099 // validity Validity,
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700100 // subject Name,
101 // subjectPubKeyInfo SubjectPublicKeyInfo,
102 // extension Extensions OPTIONAL }
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800103 //
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700104 // Validity ::= SEQUENCE {
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800105 // notBefore Time,
106 // notAfter Time }
107 //
108 // Name ::= CHOICE {
109 // RDNSequence }
110 //
111 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
112 //
113 // RelativeDistinguishedName ::=
114 // SET OF AttributeTypeAndValue
115 //
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700116 // SubjectPublicKeyInfo ::= SEQUENCE {
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800117 // algorithm AlgorithmIdentifier
118 // keybits BIT STRING }
119 //
120 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
121 //
122 // (see http://www.ietf.org/rfc/rfc3280.txt for more detail)
123 //
124 // KeyLocator
125 // issuer’s certificate name
126 // Signature
127
128 using namespace CryptoPP;
129
130 OBufferStream os;
131 CryptoPP::FileSink sink(os);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700132
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800133 // idCert ::= SEQUENCE {
134 // validity Validity,
135 // subject Name,
136 // subjectPubKeyInfo SubjectPublicKeyInfo,
137 // extension Extensions OPTIONAL }
138 DERSequenceEncoder idCert(sink);
139 {
140 // Validity ::= SEQUENCE {
141 // notBefore Time,
142 // notAfter Time }
143 DERSequenceEncoder validity(idCert);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700144 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700145 DEREncodeGeneralTime(validity, m_notBefore);
146 DEREncodeGeneralTime(validity, m_notAfter);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700147 }
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800148 validity.MessageEnd();
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700149
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800150 // Name ::= CHOICE {
151 // RDNSequence }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700152 //
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800153 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
154 DERSequenceEncoder name(idCert);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700155 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700156 for (SubjectDescriptionList::iterator it = m_subjectDescriptionList.begin();
157 it != m_subjectDescriptionList.end(); ++it)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800158 {
159 it->encode(name);
160 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700161 }
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800162 name.MessageEnd();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700163
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800164 // SubjectPublicKeyInfo
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700165 m_key.encode(idCert);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700166
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800167 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
168 //
169 // Extension ::= SEQUENCE {
170 // extnID OBJECT IDENTIFIER,
171 // critical BOOLEAN DEFAULT FALSE,
172 // extnValue OCTET STRING }
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700173 if (!m_extensionList.empty())
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800174 {
175 DERSequenceEncoder extensions(idCert);
176 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700177 for (ExtensionList::iterator it = m_extensionList.begin();
178 it != m_extensionList.end(); ++it)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800179 {
180 it->encode(extensions);
181 }
182 }
183 extensions.MessageEnd();
184 }
185 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700186
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800187 idCert.MessageEnd();
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700188
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800189 setContent(os.buf());
Junxiao Shia464b922014-11-12 21:13:06 -0700190 setContentType(tlv::ContentType_Key);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700191}
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700192
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700193void
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700194Certificate::decode()
195{
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800196 using namespace CryptoPP;
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700197
Yingdi Yu80979ba2014-11-25 14:38:36 -0800198 try {
199 OBufferStream os;
200 StringSource source(getContent().value(), getContent().value_size(), true);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700201
Yingdi Yu80979ba2014-11-25 14:38:36 -0800202 // idCert ::= SEQUENCE {
203 // validity Validity,
204 // subject Name,
205 // subjectPubKeyInfo SubjectPublicKeyInfo,
206 // extension Extensions OPTIONAL }
207 BERSequenceDecoder idCert(source);
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800208 {
Yingdi Yu80979ba2014-11-25 14:38:36 -0800209 // Validity ::= SEQUENCE {
210 // notBefore Time,
211 // notAfter Time }
212 BERSequenceDecoder validity(idCert);
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800213 {
Yingdi Yu80979ba2014-11-25 14:38:36 -0800214 BERDecodeTime(validity, m_notBefore);
215 BERDecodeTime(validity, m_notAfter);
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800216 }
Yingdi Yu80979ba2014-11-25 14:38:36 -0800217 validity.MessageEnd();
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700218
Yingdi Yu80979ba2014-11-25 14:38:36 -0800219 // Name ::= CHOICE {
220 // RDNSequence }
221 //
222 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
223 m_subjectDescriptionList.clear();
224 BERSequenceDecoder name(idCert);
225 {
226 while (!name.EndReached())
227 {
228 m_subjectDescriptionList.push_back(CertificateSubjectDescription(name));
229 }
230 }
231 name.MessageEnd();
232
233 // SubjectPublicKeyInfo ::= SEQUENCE {
234 // algorithm AlgorithmIdentifier
235 // keybits BIT STRING }
236 m_key.decode(idCert);
237
238 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
239 //
240 // Extension ::= SEQUENCE {
241 // extnID OBJECT IDENTIFIER,
242 // critical BOOLEAN DEFAULT FALSE,
243 // extnValue OCTET STRING }
244 m_extensionList.clear();
245 if (!idCert.EndReached())
246 {
247 BERSequenceDecoder extensions(idCert);
248 {
249 while (!extensions.EndReached())
250 {
251 m_extensionList.push_back(CertificateExtension(extensions));
252 }
253 }
254 extensions.MessageEnd();
255 }
256 }
257
258 idCert.MessageEnd();
259 }
260 catch (CryptoPP::BERDecodeErr&) {
261 throw Error("Certificate Decoding Error");
262 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700263}
264
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700265void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700266Certificate::printCertificate(std::ostream& os) const
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700267{
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700268 os << "Certificate name:" << std::endl;
269 os << " " << getName() << std::endl;
270 os << "Validity:" << std::endl;
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800271 {
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700272 os << " NotBefore: " << time::toIsoString(m_notBefore) << std::endl;
273 os << " NotAfter: " << time::toIsoString(m_notAfter) << std::endl;
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700274 }
275
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700276 os << "Subject Description:" << std::endl;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700277 for (SubjectDescriptionList::const_iterator it = m_subjectDescriptionList.begin();
278 it != m_subjectDescriptionList.end(); ++it)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800279 {
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700280 os << " " << it->getOidString() << ": " << it->getValue() << std::endl;
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800281 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700282
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800283 os << "Public key bits: ";
284 switch (m_key.getKeyType()) {
285 case KEY_TYPE_RSA:
286 os << "(RSA)";
287 break;
288 case KEY_TYPE_ECDSA:
289 os << "(ECDSA)";
290 break;
291 default:
292 os << "(Unknown key type)";
293 break;
294 }
295 os << std::endl;
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800296 CryptoPP::Base64Encoder encoder(new CryptoPP::FileSink(os), true, 64);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700297 m_key.encode(encoder);
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800298
299 os << std::endl;
300 os << "Signature Information:" << std::endl;
301 {
302 os << " Signature Type: ";
303 switch (getSignature().getType()) {
304 case tlv::SignatureTypeValue::DigestSha256:
305 os << "DigestSha256";
306 break;
307 case tlv::SignatureTypeValue::SignatureSha256WithRsa:
308 os << "SignatureSha256WithRsa";
309 break;
310 case tlv::SignatureTypeValue::SignatureSha256WithEcdsa:
311 os << "SignatureSha256WithEcdsa";
312 break;
313 default:
314 os << "Unknown Signature Type";
315 }
316 os << std::endl;
317
318 if (getSignature().hasKeyLocator()) {
319 const KeyLocator& keyLocator = getSignature().getKeyLocator();
320 os << " Key Locator: ";
321 switch (keyLocator.getType()) {
322 case KeyLocator::KeyLocator_Name:
323 {
324 const Name& signerName = keyLocator.getName();
325 if (signerName.isPrefixOf(getName()))
326 os << "(Self-Signed) " << keyLocator.getName();
327 else
328 os << "(Name) " << keyLocator.getName();
329 break;
330 }
331 case KeyLocator::KeyLocator_KeyDigest:
332 os << "(KeyDigest)";
333 break;
334 case KeyLocator::KeyLocator_None:
335 os << "None";
336 break;
337 default:
338 os << "Unknown";
339 }
340 os << std::endl;
341 }
342 }
343
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700344}
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700345
Yingdi Yu80979ba2014-11-25 14:38:36 -0800346std::ostream&
347operator<<(std::ostream& os, const Certificate& cert)
348{
349 cert.printCertificate(os);
350 return os;
351}
352
353
Yingdi Yufc40d872014-02-18 12:56:04 -0800354} // namespace ndn