blob: 8b6e460d1f35378b8b4fd78a0158a395e0811713 [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 Yu8d7468f2014-02-21 14:49:45 -080013int
14ndnsec_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 Yu8d7468f2014-02-21 14:49:45 -080022 typedef boost::posix_time::ptime Time;
23
Yingdi Yue6bfab22014-02-06 16:01:19 -080024 std::string notBeforeStr;
25 std::string notAfterStr;
26 std::string sName;
27 std::string reqFile;
28 std::string signId;
29 std::string subInfo;
30 bool isSelfSigned = false;
31 bool nack = false;
32
Yingdi Yu8d7468f2014-02-21 14:49:45 -080033 po::options_description desc("General Usage\n ndnsec cert-gen [-h] [-S date] [-E date] [-N subject-name] [-I subject-info] [-s sign-id] request\nGeneral options");
Yingdi Yue6bfab22014-02-06 16:01:19 -080034 desc.add_options()
35 ("help,h", "produce help message")
36 ("not-before,S", po::value<std::string>(&notBeforeStr), "certificate starting date, YYYYMMDDhhmmss")
37 ("not-after,E", po::value<std::string>(&notAfterStr), "certificate ending date, YYYYMMDDhhmmss")
38 ("subject-name,N", po::value<std::string>(&sName), "subject name")
39 ("subject-info,I", po::value<std::string>(&subInfo), "subject info, pairs of OID and string description: \"2.5.4.10 'University of California, Los Angeles'\"")
40 ("nack", "Generate revocation certificate (NACK)")
41 ("sign-id,s", po::value<std::string>(&signId), "signing Identity, self-signed if not specified")
42 ("request,r", po::value<std::string>(&reqFile), "request file name, - for stdin")
43 ;
44
45 po::positional_options_description p;
46 p.add("request", 1);
47
48 po::variables_map vm;
49 try
50 {
51 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
52 po::notify(vm);
53 }
54 catch (std::exception &e)
55 {
56 std::cerr << "ERROR: " << e.what() << std::endl;
57 return 1;
58 }
59
60 if (vm.count("help"))
61 {
62 std::cerr << desc << std::endl;
Yingdi Yu8d7468f2014-02-21 14:49:45 -080063 return 0;
Yingdi Yue6bfab22014-02-06 16:01:19 -080064 }
65
66 if (0 == vm.count("sign-id"))
67 {
68 isSelfSigned = true;
69 }
70
71 if (vm.count("nack"))
72 {
73 nack = true;
74 }
75
76 std::vector<CertificateSubjectDescription> otherSubDescrypt;
77 tokenizer<escaped_list_separator<char> > subInfoItems(subInfo, escaped_list_separator<char> ("\\", " \t", "'\""));
78
79 tokenizer<escaped_list_separator<char> >::iterator it = subInfoItems.begin();
80 try
81 {
82 while (it != subInfoItems.end())
83 {
84 std::string oid = *it;
85
86 it++;
87 if (it == subInfoItems.end ())
88 {
89 std::cerr << "ERROR: unmatched info for oid [" << oid << "]" << std::endl;
90 return 1;
91 }
92
93 std::string value = *it;
94
95 otherSubDescrypt.push_back (CertificateSubjectDescription(oid, value));
96
97 it++;
98 }
99 }
100 catch (std::exception &e)
101 {
102 std::cerr << "error in parsing subject info" << std::endl;
103 return 1;
104 }
105
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700106 time::system_clock::TimePoint notBefore;
107 time::system_clock::TimePoint notAfter;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800108 try{
109 if (0 == vm.count("not-before"))
110 {
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700111 notBefore = time::system_clock::now();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800112 }
113 else
114 {
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700115 notBefore = time::fromIsoString(notBeforeStr.substr(0, 8) + "T" + notBeforeStr.substr(8, 6));
Yingdi Yue6bfab22014-02-06 16:01:19 -0800116 }
117
118
119 if (0 == vm.count("not-after"))
120 {
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700121 notAfter = notBefore + time::days(365);
Yingdi Yue6bfab22014-02-06 16:01:19 -0800122 }
123 else
124 {
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700125 notAfter = time::fromIsoString(notAfterStr.substr(0, 8) + "T" + notAfterStr.substr(8, 6));
Yingdi Yue6bfab22014-02-06 16:01:19 -0800126 if(notAfter < notBefore)
127 {
128 std::cerr << "not-before is later than not-after" << std::endl;
129 return 1;
130 }
131 }
132 }catch(std::exception & e){
133 std::cerr << "Error in converting validity timestamp!" << std::endl;
134 return 1;
135 }
136
137 if (0 == vm.count("request"))
138 {
139 std::cerr << "request file must be specified" << std::endl;
140 return 1;
141 }
142
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800143 shared_ptr<IdentityCertificate> selfSignedCertificate = getIdentityCertificate(reqFile);
144 if(!static_cast<bool>(selfSignedCertificate))
Yingdi Yue6bfab22014-02-06 16:01:19 -0800145 {
146 std::cerr << "ERROR: input error" << std::endl;
147 return 1;
148 }
149
150 Name keyName = selfSignedCertificate->getPublicKeyName();
151 Name signIdName;
152 Name certName;
153
154 if(isSelfSigned)
155 {
156 certName = keyName.getPrefix(keyName.size()-1);
157 certName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
158 }
159 else
160 {
161 signIdName = Name(signId);
162
163 Name::const_iterator i = keyName.begin();
164 Name::const_iterator j = signIdName.begin();
165 int count = 0;
166 for(; i != keyName.end() && j != signIdName.end(); i++, j++, count++)
167 {
168 if(*i != *j)
169 break;
170 }
171
172 if(j != signIdName.end() || i == keyName.end())
173 {
174 std::cerr << "wrong signing identity!" << std::endl;
175 return 1;
176 }
177
178 certName = keyName.getSubName(0, count);
179 certName.append("KEY").append(keyName.getSubName(count, keyName.size()-count));
180 certName.append("ID-CERT").appendVersion ();
181 }
182
183 Block wire;
184
185 if (!nack)
186 {
187 if (0 == vm.count("subject-name"))
188 {
189 std::cerr << "subject_name must be specified" << std::endl;
190 return 1;
191 }
192
193 try
194 {
195 CertificateSubjectDescription subDescryptName("2.5.4.41", sName);
196 IdentityCertificate certificate;
197 certificate.setName(certName);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700198 certificate.setNotBefore(notBefore);
199 certificate.setNotAfter(notAfter);
Yingdi Yue6bfab22014-02-06 16:01:19 -0800200 certificate.setPublicKeyInfo(selfSignedCertificate->getPublicKeyInfo());
201 certificate.addSubjectDescription(subDescryptName);
202 for(int i = 0; i < otherSubDescrypt.size(); i++)
203 certificate.addSubjectDescription(otherSubDescrypt[i]);
204 certificate.encode();
205
206 KeyChain keyChain;
207
208 if(isSelfSigned)
209 keyChain.selfSign(certificate);
210 else
211 {
212 Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(Name(signId));
213
214 keyChain.sign(certificate, signingCertificateName);
215 }
216 wire = certificate.wireEncode();
217 }
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800218 catch(SecPublicInfo::Error& e)
219 {
220 std::cerr << "ERROR: " << e.what() << std::endl;
221 return 1;
222 }
223 catch(SecTpm::Error& e)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800224 {
225 std::cerr << "ERROR: " << e.what() << std::endl;
226 return 1;
227 }
228 }
229 else
230 {
231 Data revocationCert;
232 // revocationCert.setContent(void*, 0); // empty content
233 revocationCert.setName(certName);
234
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800235 try
236 {
237 KeyChain keyChain;
238
239 Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(Name(signId));
240
241 keyChain.sign (revocationCert, signingCertificateName);
242 wire = revocationCert.wireEncode();
243 }
244 catch(SecPublicInfo::Error& e)
245 {
246 std::cerr << "ERROR: " << e.what() << std::endl;
247 return 1;
248 }
249 catch(SecTpm::Error& e)
250 {
251 std::cerr << "ERROR: " << e.what() << std::endl;
252 return 1;
253 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800254 }
255
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800256 try
257 {
258 using namespace CryptoPP;
259 StringSource ss(wire.wire(), wire.size(), true,
260 new Base64Encoder(new FileSink(std::cout), true, 64));
261 }
262 catch(CryptoPP::Exception& e)
263 {
264 std::cerr << "ERROR: " << e.what() << std::endl;
265 return 1;
266 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800267
268 return 0;
269}
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800270
271#endif //NDNSEC_CERT_GEN_HPP