blob: 3af9bf9dfdfdb1b79da8052a6eb907231abd06c1 [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"
Jeff Thompsona5dc3512013-10-17 10:26:19 -070033
Jeff Thompsona5dc3512013-10-17 10:26:19 -070034namespace ndn {
35
36Certificate::Certificate()
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070037 : m_notBefore(time::system_clock::TimePoint::max())
38 , m_notAfter(time::system_clock::TimePoint::min())
39{
40}
Jeff Thompsona5dc3512013-10-17 10:26:19 -070041
42Certificate::Certificate(const Data& data)
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070043 // Use the copy constructor. It clones the signature object.
44 : Data(data)
Jeff Thompsona5dc3512013-10-17 10:26:19 -070045{
Jeff Thompsona5dc3512013-10-17 10:26:19 -070046 decode();
47}
48
49Certificate::~Certificate()
50{
51 //TODO:
52}
53
54bool
55Certificate::isTooEarly()
56{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070057 if (time::system_clock::now() < m_notBefore)
Jeff Thompsona5dc3512013-10-17 10:26:19 -070058 return true;
59 else
60 return false;
61}
62
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -070063bool
Jeff Thompsona5dc3512013-10-17 10:26:19 -070064Certificate::isTooLate()
65{
Yingdi Yu4b8c6a22014-04-15 23:00:54 -070066 if (time::system_clock::now() > m_notAfter)
Jeff Thompsona5dc3512013-10-17 10:26:19 -070067 return true;
68 else
69 return false;
70}
71
Jeff Thompsona5dc3512013-10-17 10:26:19 -070072void
73Certificate::encode()
74{
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080075 // Name
76 // <key_name>/ID-CERT/<id#>
77 // Content
78 // DER encoded idCert:
79 //
Yingdi Yu5ec0ee32014-06-24 16:26:09 -070080 // idCert ::= SEQUENCE {
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080081 // validity Validity,
Yingdi Yu5ec0ee32014-06-24 16:26:09 -070082 // subject Name,
83 // subjectPubKeyInfo SubjectPublicKeyInfo,
84 // extension Extensions OPTIONAL }
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080085 //
Yingdi Yu5ec0ee32014-06-24 16:26:09 -070086 // Validity ::= SEQUENCE {
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080087 // notBefore Time,
88 // notAfter Time }
89 //
90 // Name ::= CHOICE {
91 // RDNSequence }
92 //
93 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
94 //
95 // RelativeDistinguishedName ::=
96 // SET OF AttributeTypeAndValue
97 //
Yingdi Yu5ec0ee32014-06-24 16:26:09 -070098 // SubjectPublicKeyInfo ::= SEQUENCE {
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -080099 // algorithm AlgorithmIdentifier
100 // keybits BIT STRING }
101 //
102 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
103 //
104 // (see http://www.ietf.org/rfc/rfc3280.txt for more detail)
105 //
106 // KeyLocator
107 // issuer’s certificate name
108 // Signature
109
110 using namespace CryptoPP;
111
112 OBufferStream os;
113 CryptoPP::FileSink sink(os);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700114
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800115 // idCert ::= SEQUENCE {
116 // validity Validity,
117 // subject Name,
118 // subjectPubKeyInfo SubjectPublicKeyInfo,
119 // extension Extensions OPTIONAL }
120 DERSequenceEncoder idCert(sink);
121 {
122 // Validity ::= SEQUENCE {
123 // notBefore Time,
124 // notAfter Time }
125 DERSequenceEncoder validity(idCert);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700126 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700127 DEREncodeGeneralTime(validity, m_notBefore);
128 DEREncodeGeneralTime(validity, m_notAfter);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700129 }
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800130 validity.MessageEnd();
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700131
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800132 // Name ::= CHOICE {
133 // RDNSequence }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700134 //
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800135 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
136 DERSequenceEncoder name(idCert);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700137 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700138 for (SubjectDescriptionList::iterator it = m_subjectDescriptionList.begin();
139 it != m_subjectDescriptionList.end(); ++it)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800140 {
141 it->encode(name);
142 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700143 }
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800144 name.MessageEnd();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700145
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800146 // SubjectPublicKeyInfo
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700147 m_key.encode(idCert);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700148
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800149 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
150 //
151 // Extension ::= SEQUENCE {
152 // extnID OBJECT IDENTIFIER,
153 // critical BOOLEAN DEFAULT FALSE,
154 // extnValue OCTET STRING }
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700155 if (!m_extensionList.empty())
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800156 {
157 DERSequenceEncoder extensions(idCert);
158 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700159 for (ExtensionList::iterator it = m_extensionList.begin();
160 it != m_extensionList.end(); ++it)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800161 {
162 it->encode(extensions);
163 }
164 }
165 extensions.MessageEnd();
166 }
167 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700168
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800169 idCert.MessageEnd();
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700170
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800171 setContent(os.buf());
Junxiao Shia464b922014-11-12 21:13:06 -0700172 setContentType(tlv::ContentType_Key);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700173}
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700174
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700175void
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700176Certificate::decode()
177{
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800178 using namespace CryptoPP;
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700179
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800180 OBufferStream os;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700181 StringSource source(getContent().value(), getContent().value_size(), true);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700182
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800183 // idCert ::= SEQUENCE {
184 // validity Validity,
185 // subject Name,
186 // subjectPubKeyInfo SubjectPublicKeyInfo,
187 // extension Extensions OPTIONAL }
188 BERSequenceDecoder idCert(source);
189 {
190 // Validity ::= SEQUENCE {
191 // notBefore Time,
192 // notAfter Time }
193 BERSequenceDecoder validity(idCert);
194 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700195 BERDecodeTime(validity, m_notBefore);
196 BERDecodeTime(validity, m_notAfter);
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800197 }
198 validity.MessageEnd();
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700199
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800200 // Name ::= CHOICE {
201 // RDNSequence }
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700202 //
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800203 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700204 m_subjectDescriptionList.clear();
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800205 BERSequenceDecoder name(idCert);
206 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700207 while (!name.EndReached())
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800208 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700209 m_subjectDescriptionList.push_back(CertificateSubjectDescription(name));
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800210 }
211 }
212 name.MessageEnd();
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700213
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800214 // SubjectPublicKeyInfo ::= SEQUENCE {
215 // algorithm AlgorithmIdentifier
216 // keybits BIT STRING }
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700217 m_key.decode(idCert);
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700218
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800219 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
220 //
221 // Extension ::= SEQUENCE {
222 // extnID OBJECT IDENTIFIER,
223 // critical BOOLEAN DEFAULT FALSE,
224 // extnValue OCTET STRING }
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700225 m_extensionList.clear();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700226 if (!idCert.EndReached())
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800227 {
228 BERSequenceDecoder extensions(idCert);
229 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700230 while (!extensions.EndReached())
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800231 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700232 m_extensionList.push_back(CertificateExtension(extensions));
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800233 }
234 }
235 extensions.MessageEnd();
236 }
237 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700238
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800239 idCert.MessageEnd();
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700240}
241
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700242void
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700243Certificate::printCertificate(std::ostream& os) const
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700244{
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700245 os << "Certificate name:" << std::endl;
246 os << " " << getName() << std::endl;
247 os << "Validity:" << std::endl;
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800248 {
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700249 os << " NotBefore: " << time::toIsoString(m_notBefore) << std::endl;
250 os << " NotAfter: " << time::toIsoString(m_notAfter) << std::endl;
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700251 }
252
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700253 os << "Subject Description:" << std::endl;
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700254 for (SubjectDescriptionList::const_iterator it = m_subjectDescriptionList.begin();
255 it != m_subjectDescriptionList.end(); ++it)
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800256 {
Yingdi Yu5ec0ee32014-06-24 16:26:09 -0700257 os << " " << it->getOidString() << ": " << it->getValue() << std::endl;
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800258 }
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700259
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800260 os << "Public key bits: ";
261 switch (m_key.getKeyType()) {
262 case KEY_TYPE_RSA:
263 os << "(RSA)";
264 break;
265 case KEY_TYPE_ECDSA:
266 os << "(ECDSA)";
267 break;
268 default:
269 os << "(Unknown key type)";
270 break;
271 }
272 os << std::endl;
Alexander Afanasyev0ea6e082013-12-26 15:16:37 -0800273 CryptoPP::Base64Encoder encoder(new CryptoPP::FileSink(os), true, 64);
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700274 m_key.encode(encoder);
Yingdi Yu3b4c3142014-11-18 10:30:45 -0800275
276 os << std::endl;
277 os << "Signature Information:" << std::endl;
278 {
279 os << " Signature Type: ";
280 switch (getSignature().getType()) {
281 case tlv::SignatureTypeValue::DigestSha256:
282 os << "DigestSha256";
283 break;
284 case tlv::SignatureTypeValue::SignatureSha256WithRsa:
285 os << "SignatureSha256WithRsa";
286 break;
287 case tlv::SignatureTypeValue::SignatureSha256WithEcdsa:
288 os << "SignatureSha256WithEcdsa";
289 break;
290 default:
291 os << "Unknown Signature Type";
292 }
293 os << std::endl;
294
295 if (getSignature().hasKeyLocator()) {
296 const KeyLocator& keyLocator = getSignature().getKeyLocator();
297 os << " Key Locator: ";
298 switch (keyLocator.getType()) {
299 case KeyLocator::KeyLocator_Name:
300 {
301 const Name& signerName = keyLocator.getName();
302 if (signerName.isPrefixOf(getName()))
303 os << "(Self-Signed) " << keyLocator.getName();
304 else
305 os << "(Name) " << keyLocator.getName();
306 break;
307 }
308 case KeyLocator::KeyLocator_KeyDigest:
309 os << "(KeyDigest)";
310 break;
311 case KeyLocator::KeyLocator_None:
312 os << "None";
313 break;
314 default:
315 os << "Unknown";
316 }
317 os << std::endl;
318 }
319 }
320
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700321}
Jeff Thompsona5dc3512013-10-17 10:26:19 -0700322
Yingdi Yufc40d872014-02-18 12:56:04 -0800323} // namespace ndn