blob: 24386b7bf3bbfa72212e9a30bb38d66940cacc81 [file] [log] [blame]
Yingdi Yue6bfab22014-02-06 16:01:19 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
Yingdi Yue6bfab22014-02-06 16:01:19 -08004 * BSD license, See the LICENSE file for more information
Yingdi Yue6bfab22014-02-06 16:01:19 -08005 * Author: Yingdi Yu <yingdi@cs.ucla.edu>
6 */
7
Yingdi Yu8d7468f2014-02-21 14:49:45 -08008#ifndef NDNSEC_CERT_GEN_HPP
9#define NDNSEC_CERT_GEN_HPP
Yingdi Yue6bfab22014-02-06 16:01:19 -080010
Yingdi Yu8d7468f2014-02-21 14:49:45 -080011#include "ndnsec-util.hpp"
Yingdi Yue6bfab22014-02-06 16:01:19 -080012
Yingdi Yub61f5402014-02-26 17:46:11 -080013int
Yingdi Yu8d7468f2014-02-21 14:49:45 -080014ndnsec_cert_gen(int argc, char** argv)
Yingdi Yue6bfab22014-02-06 16:01:19 -080015{
Yingdi Yu8d7468f2014-02-21 14:49:45 -080016 using boost::tokenizer;
17 using boost::escaped_list_separator;
Yingdi Yue6bfab22014-02-06 16:01:19 -080018
Yingdi Yu8d7468f2014-02-21 14:49:45 -080019 using namespace ndn;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070020 using namespace ndn::time;
Yingdi Yu8d7468f2014-02-21 14:49:45 -080021 namespace po = boost::program_options;
Yingdi Yue6bfab22014-02-06 16:01:19 -080022
Yingdi Yue6bfab22014-02-06 16:01:19 -080023 std::string notBeforeStr;
24 std::string notAfterStr;
Yingdi Yub61f5402014-02-26 17:46:11 -080025 std::string subjectName;
26 std::string requestFile("-");
Yingdi Yue6bfab22014-02-06 16:01:19 -080027 std::string signId;
Yingdi Yub61f5402014-02-26 17:46:11 -080028 std::string subjectInfo;
Yingdi Yu05842f22014-04-15 19:21:56 -070029 bool hasSignId = false;
Yingdi Yub61f5402014-02-26 17:46:11 -080030 bool isNack = false;
Yingdi Yue6bfab22014-02-06 16:01:19 -080031
Yingdi Yub61f5402014-02-26 17:46:11 -080032 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");
33 description.add_options()
Yingdi Yue6bfab22014-02-06 16:01:19 -080034 ("help,h", "produce help message")
35 ("not-before,S", po::value<std::string>(&notBeforeStr), "certificate starting date, YYYYMMDDhhmmss")
36 ("not-after,E", po::value<std::string>(&notAfterStr), "certificate ending date, YYYYMMDDhhmmss")
Yingdi Yub61f5402014-02-26 17:46:11 -080037 ("subject-name,N", po::value<std::string>(&subjectName), "subject name")
38 ("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 -080039 ("nack", "Generate revocation certificate (NACK)")
Yingdi Yu05842f22014-04-15 19:21:56 -070040 ("sign-id,s", po::value<std::string>(&signId), "signing Identity, system default identity if not specified")
Yingdi Yub61f5402014-02-26 17:46:11 -080041 ("request,r", po::value<std::string>(&requestFile), "request file name, - for stdin")
Yingdi Yue6bfab22014-02-06 16:01:19 -080042 ;
43
44 po::positional_options_description p;
45 p.add("request", 1);
46
47 po::variables_map vm;
48 try
49 {
Yingdi Yub61f5402014-02-26 17:46:11 -080050 po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(),
51 vm);
Yingdi Yue6bfab22014-02-06 16:01:19 -080052 po::notify(vm);
53 }
Yingdi Yub61f5402014-02-26 17:46:11 -080054 catch (const std::exception& e)
Yingdi Yue6bfab22014-02-06 16:01:19 -080055 {
56 std::cerr << "ERROR: " << e.what() << std::endl;
57 return 1;
58 }
59
Yingdi Yub61f5402014-02-26 17:46:11 -080060 if (vm.count("help") != 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -080061 {
Yingdi Yub61f5402014-02-26 17:46:11 -080062 std::cerr << description << std::endl;
Yingdi Yu8d7468f2014-02-21 14:49:45 -080063 return 0;
Yingdi Yue6bfab22014-02-06 16:01:19 -080064 }
65
Yingdi Yu05842f22014-04-15 19:21:56 -070066 if (vm.count("sign-id") != 0)
Yingdi Yub61f5402014-02-26 17:46:11 -080067 {
Yingdi Yu05842f22014-04-15 19:21:56 -070068 hasSignId = true;
Yingdi Yue6bfab22014-02-06 16:01:19 -080069 }
70
Yingdi Yub61f5402014-02-26 17:46:11 -080071 if (vm.count("nack") != 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -080072 {
Yingdi Yub61f5402014-02-26 17:46:11 -080073 isNack = true;
Yingdi Yue6bfab22014-02-06 16:01:19 -080074 }
75
76 std::vector<CertificateSubjectDescription> otherSubDescrypt;
Yingdi Yub61f5402014-02-26 17:46:11 -080077 tokenizer<escaped_list_separator<char> > subjectInfoItems
78 (subjectInfo, escaped_list_separator<char> ("\\", " \t", "'\""));
Yingdi Yue6bfab22014-02-06 16:01:19 -080079
Yingdi Yub61f5402014-02-26 17:46:11 -080080 tokenizer<escaped_list_separator<char> >::iterator it =
81 subjectInfoItems.begin();
82
83 while (it != subjectInfoItems.end())
Yingdi Yue6bfab22014-02-06 16:01:19 -080084 {
Yingdi Yub61f5402014-02-26 17:46:11 -080085 std::string oid = *it;
86
87 it++;
88 if (it == subjectInfoItems.end())
Yingdi Yue6bfab22014-02-06 16:01:19 -080089 {
Yingdi Yub61f5402014-02-26 17:46:11 -080090 std::cerr << "ERROR: unmatched info for oid [" << oid << "]" << std::endl;
91 return 1;
Yingdi Yue6bfab22014-02-06 16:01:19 -080092 }
Yingdi Yub61f5402014-02-26 17:46:11 -080093
94 std::string value = *it;
95
96 otherSubDescrypt.push_back(CertificateSubjectDescription(oid, value));
97
98 it++;
Yingdi Yue6bfab22014-02-06 16:01:19 -080099 }
100
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700101 system_clock::TimePoint notBefore;
102 system_clock::TimePoint notAfter;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800103
Yingdi Yub61f5402014-02-26 17:46:11 -0800104 if (vm.count("not-before") == 0)
105 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700106 notBefore = system_clock::now();
Yingdi Yub61f5402014-02-26 17:46:11 -0800107 }
108 else
109 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700110 notBefore = fromIsoString(notBeforeStr.substr(0, 8) + "T" +
111 notBeforeStr.substr(8, 6));
Yingdi Yub61f5402014-02-26 17:46:11 -0800112 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800113
Yingdi Yub61f5402014-02-26 17:46:11 -0800114 if (vm.count("not-after") == 0)
115 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700116 notAfter = notBefore + days(365);
Yingdi Yub61f5402014-02-26 17:46:11 -0800117 }
118 else
119 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700120 notAfter = fromIsoString(notAfterStr.substr(0, 8) + "T" +
121 notAfterStr.substr(8, 6));
Yingdi Yue6bfab22014-02-06 16:01:19 -0800122
Yingdi Yub61f5402014-02-26 17:46:11 -0800123 if (notAfter < notBefore)
124 {
125 std::cerr << "not-before is later than not-after" << std::endl;
126 return 1;
127 }
128 }
129
130 if (vm.count("request") == 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800131 {
132 std::cerr << "request file must be specified" << std::endl;
133 return 1;
134 }
135
Yingdi Yub61f5402014-02-26 17:46:11 -0800136 shared_ptr<IdentityCertificate> selfSignedCertificate
137 = getIdentityCertificate(requestFile);
138
139 if (!static_cast<bool>(selfSignedCertificate))
Yingdi Yue6bfab22014-02-06 16:01:19 -0800140 {
141 std::cerr << "ERROR: input error" << std::endl;
142 return 1;
143 }
144
Yingdi Yu05842f22014-04-15 19:21:56 -0700145 KeyChain keyChain;
146
Yingdi Yue6bfab22014-02-06 16:01:19 -0800147 Name keyName = selfSignedCertificate->getPublicKeyName();
148 Name signIdName;
149 Name certName;
150
Yingdi Yu05842f22014-04-15 19:21:56 -0700151 if (!hasSignId)
152 signIdName = keyChain.getDefaultIdentity();
153 else
154 signIdName = Name(signId);
155
156
157 if (signIdName.isPrefixOf(keyName))
Yingdi Yue6bfab22014-02-06 16:01:19 -0800158 {
Yingdi Yu05842f22014-04-15 19:21:56 -0700159 // if signee's namespace is a sub-namespace of signer, for example, signer's namespace is
160 // /ndn/test, signee's namespace is /ndn/test/alice, the generated certificate name is
161 // /ndn/test/KEY/alice/ksk-1234/ID-CERT/%01%02
162 certName.append(signIdName)
163 .append("KEY")
164 .append(keyName.getSubName(signIdName.size()))
165 .append("ID-CERT")
166 .appendVersion();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800167 }
168 else
169 {
Yingdi Yu05842f22014-04-15 19:21:56 -0700170 // if signee's namespace is not a sub-namespace of signer, for example, signer's namespace is
171 // /ndn/test, signee's namespace is /ndn/ucla/bob, the generated certificate name is
172 // /ndn/ucla/bob/KEY/ksk-1234/ID-CERT/%01%02
173 certName.append(keyName.getPrefix(-1))
174 .append("KEY")
175 .append(keyName.get(-1))
Yingdi Yub61f5402014-02-26 17:46:11 -0800176 .append("ID-CERT")
Yingdi Yu05842f22014-04-15 19:21:56 -0700177 .appendVersion();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800178 }
179
180 Block wire;
181
Yingdi Yub61f5402014-02-26 17:46:11 -0800182 if (!isNack)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800183 {
Yingdi Yub61f5402014-02-26 17:46:11 -0800184 if (vm.count("subject-name") == 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800185 {
186 std::cerr << "subject_name must be specified" << std::endl;
187 return 1;
188 }
189
Yingdi Yub61f5402014-02-26 17:46:11 -0800190 CertificateSubjectDescription subDescryptName("2.5.4.41", subjectName);
191 IdentityCertificate certificate;
192 certificate.setName(certName);
193 certificate.setNotBefore(notBefore);
194 certificate.setNotAfter(notAfter);
195 certificate.setPublicKeyInfo(selfSignedCertificate->getPublicKeyInfo());
196 certificate.addSubjectDescription(subDescryptName);
197 for (size_t i = 0; i < otherSubDescrypt.size(); i++)
198 certificate.addSubjectDescription(otherSubDescrypt[i]);
199 certificate.encode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800200
Yingdi Yu05842f22014-04-15 19:21:56 -0700201 keyChain.createIdentity(signIdName);
202 Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(signIdName);
203 keyChain.sign(certificate, signingCertificateName);
Yingdi Yue6bfab22014-02-06 16:01:19 -0800204
Yingdi Yub61f5402014-02-26 17:46:11 -0800205 wire = certificate.wireEncode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800206 }
207 else
208 {
209 Data revocationCert;
210 // revocationCert.setContent(void*, 0); // empty content
211 revocationCert.setName(certName);
212
Yingdi Yu05842f22014-04-15 19:21:56 -0700213 keyChain.createIdentity(signIdName);
214 Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(signIdName);
Yingdi Yub61f5402014-02-26 17:46:11 -0800215 keyChain.sign(revocationCert, signingCertificateName);
Yingdi Yu05842f22014-04-15 19:21:56 -0700216
Yingdi Yub61f5402014-02-26 17:46:11 -0800217 wire = revocationCert.wireEncode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800218 }
219
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800220 try
221 {
222 using namespace CryptoPP;
223 StringSource ss(wire.wire(), wire.size(), true,
224 new Base64Encoder(new FileSink(std::cout), true, 64));
225 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800226 catch (const CryptoPP::Exception& e)
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800227 {
228 std::cerr << "ERROR: " << e.what() << std::endl;
229 return 1;
230 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800231
232 return 0;
233}
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800234
235#endif //NDNSEC_CERT_GEN_HPP