blob: 197cc6b4446d29f503a052510054ffc1c6892c49 [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;
20 namespace po = boost::program_options;
Yingdi Yue6bfab22014-02-06 16:01:19 -080021
Yingdi Yue6bfab22014-02-06 16:01:19 -080022 std::string notBeforeStr;
23 std::string notAfterStr;
Yingdi Yub61f5402014-02-26 17:46:11 -080024 std::string subjectName;
25 std::string requestFile("-");
Yingdi Yue6bfab22014-02-06 16:01:19 -080026 std::string signId;
Yingdi Yub61f5402014-02-26 17:46:11 -080027 std::string subjectInfo;
Yingdi Yue6bfab22014-02-06 16:01:19 -080028 bool isSelfSigned = false;
Yingdi Yub61f5402014-02-26 17:46:11 -080029 bool isNack = false;
Yingdi Yue6bfab22014-02-06 16:01:19 -080030
Yingdi Yub61f5402014-02-26 17:46:11 -080031 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");
32 description.add_options()
Yingdi Yue6bfab22014-02-06 16:01:19 -080033 ("help,h", "produce help message")
34 ("not-before,S", po::value<std::string>(&notBeforeStr), "certificate starting date, YYYYMMDDhhmmss")
35 ("not-after,E", po::value<std::string>(&notAfterStr), "certificate ending date, YYYYMMDDhhmmss")
Yingdi Yub61f5402014-02-26 17:46:11 -080036 ("subject-name,N", po::value<std::string>(&subjectName), "subject name")
37 ("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 -080038 ("nack", "Generate revocation certificate (NACK)")
39 ("sign-id,s", po::value<std::string>(&signId), "signing Identity, self-signed if not specified")
Yingdi Yub61f5402014-02-26 17:46:11 -080040 ("request,r", po::value<std::string>(&requestFile), "request file name, - for stdin")
Yingdi Yue6bfab22014-02-06 16:01:19 -080041 ;
42
43 po::positional_options_description p;
44 p.add("request", 1);
45
46 po::variables_map vm;
47 try
48 {
Yingdi Yub61f5402014-02-26 17:46:11 -080049 po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(),
50 vm);
Yingdi Yue6bfab22014-02-06 16:01:19 -080051 po::notify(vm);
52 }
Yingdi Yub61f5402014-02-26 17:46:11 -080053 catch (const std::exception& e)
Yingdi Yue6bfab22014-02-06 16:01:19 -080054 {
55 std::cerr << "ERROR: " << e.what() << std::endl;
56 return 1;
57 }
58
Yingdi Yub61f5402014-02-26 17:46:11 -080059 if (vm.count("help") != 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -080060 {
Yingdi Yub61f5402014-02-26 17:46:11 -080061 std::cerr << description << std::endl;
Yingdi Yu8d7468f2014-02-21 14:49:45 -080062 return 0;
Yingdi Yue6bfab22014-02-06 16:01:19 -080063 }
64
Yingdi Yub61f5402014-02-26 17:46:11 -080065 if (vm.count("sign-id") == 0)
66 {
Yingdi Yue6bfab22014-02-06 16:01:19 -080067 isSelfSigned = true;
68 }
69
Yingdi Yub61f5402014-02-26 17:46:11 -080070 if (vm.count("nack") != 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -080071 {
Yingdi Yub61f5402014-02-26 17:46:11 -080072 isNack = true;
Yingdi Yue6bfab22014-02-06 16:01:19 -080073 }
74
75 std::vector<CertificateSubjectDescription> otherSubDescrypt;
Yingdi Yub61f5402014-02-26 17:46:11 -080076 tokenizer<escaped_list_separator<char> > subjectInfoItems
77 (subjectInfo, escaped_list_separator<char> ("\\", " \t", "'\""));
Yingdi Yue6bfab22014-02-06 16:01:19 -080078
Yingdi Yub61f5402014-02-26 17:46:11 -080079 tokenizer<escaped_list_separator<char> >::iterator it =
80 subjectInfoItems.begin();
81
82 while (it != subjectInfoItems.end())
Yingdi Yue6bfab22014-02-06 16:01:19 -080083 {
Yingdi Yub61f5402014-02-26 17:46:11 -080084 std::string oid = *it;
85
86 it++;
87 if (it == subjectInfoItems.end())
Yingdi Yue6bfab22014-02-06 16:01:19 -080088 {
Yingdi Yub61f5402014-02-26 17:46:11 -080089 std::cerr << "ERROR: unmatched info for oid [" << oid << "]" << std::endl;
90 return 1;
Yingdi Yue6bfab22014-02-06 16:01:19 -080091 }
Yingdi Yub61f5402014-02-26 17:46:11 -080092
93 std::string value = *it;
94
95 otherSubDescrypt.push_back(CertificateSubjectDescription(oid, value));
96
97 it++;
Yingdi Yue6bfab22014-02-06 16:01:19 -080098 }
99
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700100 time::system_clock::TimePoint notBefore;
101 time::system_clock::TimePoint notAfter;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800102
Yingdi Yub61f5402014-02-26 17:46:11 -0800103 if (vm.count("not-before") == 0)
104 {
105 notBefore = time::system_clock::now();
106 }
107 else
108 {
109 notBefore = time::fromIsoString(notBeforeStr.substr(0, 8) + "T" +
110 notBeforeStr.substr(8, 6));
111 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800112
Yingdi Yub61f5402014-02-26 17:46:11 -0800113 if (vm.count("not-after") == 0)
114 {
115 notAfter = notBefore + time::days(365);
116 }
117 else
118 {
119 notAfter = time::fromIsoString(notAfterStr.substr(0, 8) + "T" +
120 notAfterStr.substr(8, 6));
Yingdi Yue6bfab22014-02-06 16:01:19 -0800121
Yingdi Yub61f5402014-02-26 17:46:11 -0800122 if (notAfter < notBefore)
123 {
124 std::cerr << "not-before is later than not-after" << std::endl;
125 return 1;
126 }
127 }
128
129 if (vm.count("request") == 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800130 {
131 std::cerr << "request file must be specified" << std::endl;
132 return 1;
133 }
134
Yingdi Yub61f5402014-02-26 17:46:11 -0800135 shared_ptr<IdentityCertificate> selfSignedCertificate
136 = getIdentityCertificate(requestFile);
137
138 if (!static_cast<bool>(selfSignedCertificate))
Yingdi Yue6bfab22014-02-06 16:01:19 -0800139 {
140 std::cerr << "ERROR: input error" << std::endl;
141 return 1;
142 }
143
144 Name keyName = selfSignedCertificate->getPublicKeyName();
145 Name signIdName;
146 Name certName;
147
Yingdi Yub61f5402014-02-26 17:46:11 -0800148 if (isSelfSigned)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800149 {
150 certName = keyName.getPrefix(keyName.size()-1);
151 certName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
152 }
153 else
154 {
155 signIdName = Name(signId);
Yingdi Yub61f5402014-02-26 17:46:11 -0800156
157 int count = 0;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800158 Name::const_iterator i = keyName.begin();
159 Name::const_iterator j = signIdName.begin();
Yingdi Yub61f5402014-02-26 17:46:11 -0800160 for (; i != keyName.end() && j != signIdName.end(); i++, j++)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800161 {
Yingdi Yub61f5402014-02-26 17:46:11 -0800162 if (*i != *j)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800163 break;
Yingdi Yub61f5402014-02-26 17:46:11 -0800164
165 count++;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800166 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800167
168 if (j != signIdName.end() || i == keyName.end())
Yingdi Yue6bfab22014-02-06 16:01:19 -0800169 {
170 std::cerr << "wrong signing identity!" << std::endl;
171 return 1;
172 }
173
174 certName = keyName.getSubName(0, count);
Yingdi Yub61f5402014-02-26 17:46:11 -0800175 certName.append("KEY")
176 .append(keyName.getSubName(count, keyName.size() - count))
177 .append("ID-CERT")
178 .appendVersion ();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800179 }
180
181 Block wire;
182
Yingdi Yub61f5402014-02-26 17:46:11 -0800183 if (!isNack)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800184 {
Yingdi Yub61f5402014-02-26 17:46:11 -0800185 if (vm.count("subject-name") == 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800186 {
187 std::cerr << "subject_name must be specified" << std::endl;
188 return 1;
189 }
190
Yingdi Yub61f5402014-02-26 17:46:11 -0800191 CertificateSubjectDescription subDescryptName("2.5.4.41", subjectName);
192 IdentityCertificate certificate;
193 certificate.setName(certName);
194 certificate.setNotBefore(notBefore);
195 certificate.setNotAfter(notAfter);
196 certificate.setPublicKeyInfo(selfSignedCertificate->getPublicKeyInfo());
197 certificate.addSubjectDescription(subDescryptName);
198 for (size_t i = 0; i < otherSubDescrypt.size(); i++)
199 certificate.addSubjectDescription(otherSubDescrypt[i]);
200 certificate.encode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800201
Yingdi Yub61f5402014-02-26 17:46:11 -0800202 KeyChain keyChain;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800203
Yingdi Yub61f5402014-02-26 17:46:11 -0800204 if (isSelfSigned)
205 keyChain.selfSign(certificate);
206 else
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800207 {
Yingdi Yub61f5402014-02-26 17:46:11 -0800208 Name signingCertificateName =
209 keyChain.getDefaultCertificateNameForIdentity(Name(signId));
210
211 keyChain.sign(certificate, signingCertificateName);
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800212 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800213 wire = certificate.wireEncode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800214 }
215 else
216 {
217 Data revocationCert;
218 // revocationCert.setContent(void*, 0); // empty content
219 revocationCert.setName(certName);
220
Yingdi Yub61f5402014-02-26 17:46:11 -0800221 KeyChain keyChain;
222
223 Name signingCertificateName =
224 keyChain.getDefaultCertificateNameForIdentity(signId);
225
226 keyChain.sign(revocationCert, signingCertificateName);
227 wire = revocationCert.wireEncode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800228 }
229
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800230 try
231 {
232 using namespace CryptoPP;
233 StringSource ss(wire.wire(), wire.size(), true,
234 new Base64Encoder(new FileSink(std::cout), true, 64));
235 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800236 catch (const CryptoPP::Exception& e)
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800237 {
238 std::cerr << "ERROR: " << e.what() << std::endl;
239 return 1;
240 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800241
242 return 0;
243}
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800244
245#endif //NDNSEC_CERT_GEN_HPP