blob: 796c3edc2d085cfd819d4cb3109d94517b953935 [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 Yue6bfab22014-02-06 16:01:19 -080029 bool isSelfSigned = 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)")
40 ("sign-id,s", po::value<std::string>(&signId), "signing Identity, self-signed 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 Yub61f5402014-02-26 17:46:11 -080066 if (vm.count("sign-id") == 0)
67 {
Yingdi Yue6bfab22014-02-06 16:01:19 -080068 isSelfSigned = true;
69 }
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
145 Name keyName = selfSignedCertificate->getPublicKeyName();
146 Name signIdName;
147 Name certName;
148
Yingdi Yub61f5402014-02-26 17:46:11 -0800149 if (isSelfSigned)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800150 {
151 certName = keyName.getPrefix(keyName.size()-1);
152 certName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
153 }
154 else
155 {
156 signIdName = Name(signId);
Yingdi Yub61f5402014-02-26 17:46:11 -0800157
158 int count = 0;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800159 Name::const_iterator i = keyName.begin();
160 Name::const_iterator j = signIdName.begin();
Yingdi Yub61f5402014-02-26 17:46:11 -0800161 for (; i != keyName.end() && j != signIdName.end(); i++, j++)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800162 {
Yingdi Yub61f5402014-02-26 17:46:11 -0800163 if (*i != *j)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800164 break;
Yingdi Yub61f5402014-02-26 17:46:11 -0800165
166 count++;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800167 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800168
169 if (j != signIdName.end() || i == keyName.end())
Yingdi Yue6bfab22014-02-06 16:01:19 -0800170 {
171 std::cerr << "wrong signing identity!" << std::endl;
172 return 1;
173 }
174
175 certName = keyName.getSubName(0, count);
Yingdi Yub61f5402014-02-26 17:46:11 -0800176 certName.append("KEY")
177 .append(keyName.getSubName(count, keyName.size() - count))
178 .append("ID-CERT")
179 .appendVersion ();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800180 }
181
182 Block wire;
183
Yingdi Yub61f5402014-02-26 17:46:11 -0800184 if (!isNack)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800185 {
Yingdi Yub61f5402014-02-26 17:46:11 -0800186 if (vm.count("subject-name") == 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800187 {
188 std::cerr << "subject_name must be specified" << std::endl;
189 return 1;
190 }
191
Yingdi Yub61f5402014-02-26 17:46:11 -0800192 CertificateSubjectDescription subDescryptName("2.5.4.41", subjectName);
193 IdentityCertificate certificate;
194 certificate.setName(certName);
195 certificate.setNotBefore(notBefore);
196 certificate.setNotAfter(notAfter);
197 certificate.setPublicKeyInfo(selfSignedCertificate->getPublicKeyInfo());
198 certificate.addSubjectDescription(subDescryptName);
199 for (size_t i = 0; i < otherSubDescrypt.size(); i++)
200 certificate.addSubjectDescription(otherSubDescrypt[i]);
201 certificate.encode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800202
Yingdi Yub61f5402014-02-26 17:46:11 -0800203 KeyChain keyChain;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800204
Yingdi Yub61f5402014-02-26 17:46:11 -0800205 if (isSelfSigned)
206 keyChain.selfSign(certificate);
207 else
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800208 {
Yingdi Yub61f5402014-02-26 17:46:11 -0800209 Name signingCertificateName =
210 keyChain.getDefaultCertificateNameForIdentity(Name(signId));
211
212 keyChain.sign(certificate, signingCertificateName);
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800213 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800214 wire = certificate.wireEncode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800215 }
216 else
217 {
218 Data revocationCert;
219 // revocationCert.setContent(void*, 0); // empty content
220 revocationCert.setName(certName);
221
Yingdi Yub61f5402014-02-26 17:46:11 -0800222 KeyChain keyChain;
223
224 Name signingCertificateName =
225 keyChain.getDefaultCertificateNameForIdentity(signId);
226
227 keyChain.sign(revocationCert, signingCertificateName);
228 wire = revocationCert.wireEncode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800229 }
230
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800231 try
232 {
233 using namespace CryptoPP;
234 StringSource ss(wire.wire(), wire.size(), true,
235 new Base64Encoder(new FileSink(std::cout), true, 64));
236 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800237 catch (const CryptoPP::Exception& e)
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800238 {
239 std::cerr << "ERROR: " << e.what() << std::endl;
240 return 1;
241 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800242
243 return 0;
244}
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800245
246#endif //NDNSEC_CERT_GEN_HPP