blob: 6a1a8646f79fac92d34bcd811e5150556d19ceba [file] [log] [blame]
Yingdi Yue6bfab22014-02-06 16:01:19 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07002/**
3 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
5 *
6 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
8 *
9 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
11 *
12 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Yingdi Yue6bfab22014-02-06 16:01:19 -080013 */
14
Yingdi Yu8d7468f2014-02-21 14:49:45 -080015#ifndef NDNSEC_CERT_GEN_HPP
16#define NDNSEC_CERT_GEN_HPP
Yingdi Yue6bfab22014-02-06 16:01:19 -080017
Yingdi Yu8d7468f2014-02-21 14:49:45 -080018#include "ndnsec-util.hpp"
Yingdi Yue6bfab22014-02-06 16:01:19 -080019
Yingdi Yub61f5402014-02-26 17:46:11 -080020int
Yingdi Yu8d7468f2014-02-21 14:49:45 -080021ndnsec_cert_gen(int argc, char** argv)
Yingdi Yue6bfab22014-02-06 16:01:19 -080022{
Yingdi Yu8d7468f2014-02-21 14:49:45 -080023 using boost::tokenizer;
24 using boost::escaped_list_separator;
Yingdi Yue6bfab22014-02-06 16:01:19 -080025
Yingdi Yu8d7468f2014-02-21 14:49:45 -080026 using namespace ndn;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070027 using namespace ndn::time;
Yingdi Yu8d7468f2014-02-21 14:49:45 -080028 namespace po = boost::program_options;
Yingdi Yue6bfab22014-02-06 16:01:19 -080029
Yingdi Yue6bfab22014-02-06 16:01:19 -080030 std::string notBeforeStr;
31 std::string notAfterStr;
Yingdi Yub61f5402014-02-26 17:46:11 -080032 std::string subjectName;
33 std::string requestFile("-");
Yingdi Yue6bfab22014-02-06 16:01:19 -080034 std::string signId;
Yingdi Yub61f5402014-02-26 17:46:11 -080035 std::string subjectInfo;
Yingdi Yu05842f22014-04-15 19:21:56 -070036 bool hasSignId = false;
Yingdi Yub61f5402014-02-26 17:46:11 -080037 bool isNack = false;
Yingdi Yue6bfab22014-02-06 16:01:19 -080038
Yingdi Yub61f5402014-02-26 17:46:11 -080039 po::options_description description("General Usage\n ndnsec cert-gen [-h] [-S date] [-E date] [-N subject-name] [-I subject-info] [-s sign-id] request\nGeneral options");
40 description.add_options()
Yingdi Yue6bfab22014-02-06 16:01:19 -080041 ("help,h", "produce help message")
42 ("not-before,S", po::value<std::string>(&notBeforeStr), "certificate starting date, YYYYMMDDhhmmss")
43 ("not-after,E", po::value<std::string>(&notAfterStr), "certificate ending date, YYYYMMDDhhmmss")
Yingdi Yub61f5402014-02-26 17:46:11 -080044 ("subject-name,N", po::value<std::string>(&subjectName), "subject name")
45 ("subject-info,I", po::value<std::string>(&subjectInfo), "subject info, pairs of OID and string description: \"2.5.4.10 'University of California, Los Angeles'\"")
Yingdi Yue6bfab22014-02-06 16:01:19 -080046 ("nack", "Generate revocation certificate (NACK)")
Yingdi Yu05842f22014-04-15 19:21:56 -070047 ("sign-id,s", po::value<std::string>(&signId), "signing Identity, system default identity if not specified")
Yingdi Yub61f5402014-02-26 17:46:11 -080048 ("request,r", po::value<std::string>(&requestFile), "request file name, - for stdin")
Yingdi Yue6bfab22014-02-06 16:01:19 -080049 ;
50
51 po::positional_options_description p;
52 p.add("request", 1);
53
54 po::variables_map vm;
55 try
56 {
Yingdi Yub61f5402014-02-26 17:46:11 -080057 po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(),
58 vm);
Yingdi Yue6bfab22014-02-06 16:01:19 -080059 po::notify(vm);
60 }
Yingdi Yub61f5402014-02-26 17:46:11 -080061 catch (const std::exception& e)
Yingdi Yue6bfab22014-02-06 16:01:19 -080062 {
63 std::cerr << "ERROR: " << e.what() << std::endl;
64 return 1;
65 }
66
Yingdi Yub61f5402014-02-26 17:46:11 -080067 if (vm.count("help") != 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -080068 {
Yingdi Yub61f5402014-02-26 17:46:11 -080069 std::cerr << description << std::endl;
Yingdi Yu8d7468f2014-02-21 14:49:45 -080070 return 0;
Yingdi Yue6bfab22014-02-06 16:01:19 -080071 }
72
Yingdi Yu05842f22014-04-15 19:21:56 -070073 if (vm.count("sign-id") != 0)
Yingdi Yub61f5402014-02-26 17:46:11 -080074 {
Yingdi Yu05842f22014-04-15 19:21:56 -070075 hasSignId = true;
Yingdi Yue6bfab22014-02-06 16:01:19 -080076 }
77
Yingdi Yub61f5402014-02-26 17:46:11 -080078 if (vm.count("nack") != 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -080079 {
Yingdi Yub61f5402014-02-26 17:46:11 -080080 isNack = true;
Yingdi Yue6bfab22014-02-06 16:01:19 -080081 }
82
83 std::vector<CertificateSubjectDescription> otherSubDescrypt;
Yingdi Yub61f5402014-02-26 17:46:11 -080084 tokenizer<escaped_list_separator<char> > subjectInfoItems
85 (subjectInfo, escaped_list_separator<char> ("\\", " \t", "'\""));
Yingdi Yue6bfab22014-02-06 16:01:19 -080086
Yingdi Yub61f5402014-02-26 17:46:11 -080087 tokenizer<escaped_list_separator<char> >::iterator it =
88 subjectInfoItems.begin();
89
90 while (it != subjectInfoItems.end())
Yingdi Yue6bfab22014-02-06 16:01:19 -080091 {
Yingdi Yub61f5402014-02-26 17:46:11 -080092 std::string oid = *it;
93
94 it++;
95 if (it == subjectInfoItems.end())
Yingdi Yue6bfab22014-02-06 16:01:19 -080096 {
Yingdi Yub61f5402014-02-26 17:46:11 -080097 std::cerr << "ERROR: unmatched info for oid [" << oid << "]" << std::endl;
98 return 1;
Yingdi Yue6bfab22014-02-06 16:01:19 -080099 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800100
101 std::string value = *it;
102
103 otherSubDescrypt.push_back(CertificateSubjectDescription(oid, value));
104
105 it++;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800106 }
107
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700108 system_clock::TimePoint notBefore;
109 system_clock::TimePoint notAfter;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800110
Yingdi Yub61f5402014-02-26 17:46:11 -0800111 if (vm.count("not-before") == 0)
112 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700113 notBefore = system_clock::now();
Yingdi Yub61f5402014-02-26 17:46:11 -0800114 }
115 else
116 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700117 notBefore = fromIsoString(notBeforeStr.substr(0, 8) + "T" +
118 notBeforeStr.substr(8, 6));
Yingdi Yub61f5402014-02-26 17:46:11 -0800119 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800120
Yingdi Yub61f5402014-02-26 17:46:11 -0800121 if (vm.count("not-after") == 0)
122 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700123 notAfter = notBefore + days(365);
Yingdi Yub61f5402014-02-26 17:46:11 -0800124 }
125 else
126 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700127 notAfter = fromIsoString(notAfterStr.substr(0, 8) + "T" +
128 notAfterStr.substr(8, 6));
Yingdi Yue6bfab22014-02-06 16:01:19 -0800129
Yingdi Yub61f5402014-02-26 17:46:11 -0800130 if (notAfter < notBefore)
131 {
132 std::cerr << "not-before is later than not-after" << std::endl;
133 return 1;
134 }
135 }
136
137 if (vm.count("request") == 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800138 {
139 std::cerr << "request file must be specified" << std::endl;
140 return 1;
141 }
142
Yingdi Yub61f5402014-02-26 17:46:11 -0800143 shared_ptr<IdentityCertificate> selfSignedCertificate
144 = getIdentityCertificate(requestFile);
145
146 if (!static_cast<bool>(selfSignedCertificate))
Yingdi Yue6bfab22014-02-06 16:01:19 -0800147 {
148 std::cerr << "ERROR: input error" << std::endl;
149 return 1;
150 }
151
Yingdi Yu05842f22014-04-15 19:21:56 -0700152 KeyChain keyChain;
153
Yingdi Yue6bfab22014-02-06 16:01:19 -0800154 Name keyName = selfSignedCertificate->getPublicKeyName();
155 Name signIdName;
156 Name certName;
157
Yingdi Yu05842f22014-04-15 19:21:56 -0700158 if (!hasSignId)
159 signIdName = keyChain.getDefaultIdentity();
160 else
161 signIdName = Name(signId);
162
163
164 if (signIdName.isPrefixOf(keyName))
Yingdi Yue6bfab22014-02-06 16:01:19 -0800165 {
Yingdi Yu05842f22014-04-15 19:21:56 -0700166 // if signee's namespace is a sub-namespace of signer, for example, signer's namespace is
167 // /ndn/test, signee's namespace is /ndn/test/alice, the generated certificate name is
168 // /ndn/test/KEY/alice/ksk-1234/ID-CERT/%01%02
169 certName.append(signIdName)
170 .append("KEY")
171 .append(keyName.getSubName(signIdName.size()))
172 .append("ID-CERT")
173 .appendVersion();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800174 }
175 else
176 {
Yingdi Yu05842f22014-04-15 19:21:56 -0700177 // if signee's namespace is not a sub-namespace of signer, for example, signer's namespace is
178 // /ndn/test, signee's namespace is /ndn/ucla/bob, the generated certificate name is
179 // /ndn/ucla/bob/KEY/ksk-1234/ID-CERT/%01%02
180 certName.append(keyName.getPrefix(-1))
181 .append("KEY")
182 .append(keyName.get(-1))
Yingdi Yub61f5402014-02-26 17:46:11 -0800183 .append("ID-CERT")
Yingdi Yu05842f22014-04-15 19:21:56 -0700184 .appendVersion();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800185 }
186
187 Block wire;
188
Yingdi Yub61f5402014-02-26 17:46:11 -0800189 if (!isNack)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800190 {
Yingdi Yub61f5402014-02-26 17:46:11 -0800191 if (vm.count("subject-name") == 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800192 {
193 std::cerr << "subject_name must be specified" << std::endl;
194 return 1;
195 }
196
Yingdi Yub61f5402014-02-26 17:46:11 -0800197 CertificateSubjectDescription subDescryptName("2.5.4.41", subjectName);
198 IdentityCertificate certificate;
199 certificate.setName(certName);
200 certificate.setNotBefore(notBefore);
201 certificate.setNotAfter(notAfter);
202 certificate.setPublicKeyInfo(selfSignedCertificate->getPublicKeyInfo());
203 certificate.addSubjectDescription(subDescryptName);
204 for (size_t i = 0; i < otherSubDescrypt.size(); i++)
205 certificate.addSubjectDescription(otherSubDescrypt[i]);
206 certificate.encode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800207
Yingdi Yu05842f22014-04-15 19:21:56 -0700208 keyChain.createIdentity(signIdName);
209 Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(signIdName);
210 keyChain.sign(certificate, signingCertificateName);
Yingdi Yue6bfab22014-02-06 16:01:19 -0800211
Yingdi Yub61f5402014-02-26 17:46:11 -0800212 wire = certificate.wireEncode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800213 }
214 else
215 {
216 Data revocationCert;
217 // revocationCert.setContent(void*, 0); // empty content
218 revocationCert.setName(certName);
219
Yingdi Yu05842f22014-04-15 19:21:56 -0700220 keyChain.createIdentity(signIdName);
221 Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(signIdName);
Yingdi Yub61f5402014-02-26 17:46:11 -0800222 keyChain.sign(revocationCert, signingCertificateName);
Yingdi Yu05842f22014-04-15 19:21:56 -0700223
Yingdi Yub61f5402014-02-26 17:46:11 -0800224 wire = revocationCert.wireEncode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800225 }
226
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800227 try
228 {
229 using namespace CryptoPP;
230 StringSource ss(wire.wire(), wire.size(), true,
231 new Base64Encoder(new FileSink(std::cout), true, 64));
232 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800233 catch (const CryptoPP::Exception& e)
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800234 {
235 std::cerr << "ERROR: " << e.what() << std::endl;
236 return 1;
237 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800238
239 return 0;
240}
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800241
242#endif //NDNSEC_CERT_GEN_HPP