blob: 363dd57ba051deaacde2a9145b8f13fb19f91920 [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 Yue6bfab22014-02-06 16:01:19 -080022 std::string notBeforeStr;
23 std::string notAfterStr;
24 std::string sName;
25 std::string reqFile;
26 std::string signId;
27 std::string subInfo;
28 bool isSelfSigned = false;
29 bool nack = false;
30
Yingdi Yu8d7468f2014-02-21 14:49:45 -080031 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 -080032 desc.add_options()
33 ("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")
36 ("subject-name,N", po::value<std::string>(&sName), "subject name")
37 ("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'\"")
38 ("nack", "Generate revocation certificate (NACK)")
39 ("sign-id,s", po::value<std::string>(&signId), "signing Identity, self-signed if not specified")
40 ("request,r", po::value<std::string>(&reqFile), "request file name, - for stdin")
41 ;
42
43 po::positional_options_description p;
44 p.add("request", 1);
45
46 po::variables_map vm;
47 try
48 {
49 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
50 po::notify(vm);
51 }
52 catch (std::exception &e)
53 {
54 std::cerr << "ERROR: " << e.what() << std::endl;
55 return 1;
56 }
57
58 if (vm.count("help"))
59 {
60 std::cerr << desc << std::endl;
Yingdi Yu8d7468f2014-02-21 14:49:45 -080061 return 0;
Yingdi Yue6bfab22014-02-06 16:01:19 -080062 }
63
64 if (0 == vm.count("sign-id"))
65 {
66 isSelfSigned = true;
67 }
68
69 if (vm.count("nack"))
70 {
71 nack = true;
72 }
73
74 std::vector<CertificateSubjectDescription> otherSubDescrypt;
75 tokenizer<escaped_list_separator<char> > subInfoItems(subInfo, escaped_list_separator<char> ("\\", " \t", "'\""));
76
77 tokenizer<escaped_list_separator<char> >::iterator it = subInfoItems.begin();
78 try
79 {
80 while (it != subInfoItems.end())
81 {
82 std::string oid = *it;
83
84 it++;
85 if (it == subInfoItems.end ())
86 {
87 std::cerr << "ERROR: unmatched info for oid [" << oid << "]" << std::endl;
88 return 1;
89 }
90
91 std::string value = *it;
92
93 otherSubDescrypt.push_back (CertificateSubjectDescription(oid, value));
94
95 it++;
96 }
97 }
98 catch (std::exception &e)
99 {
100 std::cerr << "error in parsing subject info" << std::endl;
101 return 1;
102 }
103
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700104 time::system_clock::TimePoint notBefore;
105 time::system_clock::TimePoint notAfter;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800106 try{
107 if (0 == vm.count("not-before"))
108 {
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700109 notBefore = time::system_clock::now();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800110 }
111 else
112 {
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700113 notBefore = time::fromIsoString(notBeforeStr.substr(0, 8) + "T" + notBeforeStr.substr(8, 6));
Yingdi Yue6bfab22014-02-06 16:01:19 -0800114 }
115
116
117 if (0 == vm.count("not-after"))
118 {
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700119 notAfter = notBefore + time::days(365);
Yingdi Yue6bfab22014-02-06 16:01:19 -0800120 }
121 else
122 {
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700123 notAfter = time::fromIsoString(notAfterStr.substr(0, 8) + "T" + notAfterStr.substr(8, 6));
Yingdi Yue6bfab22014-02-06 16:01:19 -0800124 if(notAfter < notBefore)
125 {
126 std::cerr << "not-before is later than not-after" << std::endl;
127 return 1;
128 }
129 }
130 }catch(std::exception & e){
131 std::cerr << "Error in converting validity timestamp!" << std::endl;
132 return 1;
133 }
134
135 if (0 == vm.count("request"))
136 {
137 std::cerr << "request file must be specified" << std::endl;
138 return 1;
139 }
140
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800141 shared_ptr<IdentityCertificate> selfSignedCertificate = getIdentityCertificate(reqFile);
142 if(!static_cast<bool>(selfSignedCertificate))
Yingdi Yue6bfab22014-02-06 16:01:19 -0800143 {
144 std::cerr << "ERROR: input error" << std::endl;
145 return 1;
146 }
147
148 Name keyName = selfSignedCertificate->getPublicKeyName();
149 Name signIdName;
150 Name certName;
151
152 if(isSelfSigned)
153 {
154 certName = keyName.getPrefix(keyName.size()-1);
155 certName.append("KEY").append(keyName.get(-1)).append("ID-CERT").appendVersion();
156 }
157 else
158 {
159 signIdName = Name(signId);
160
161 Name::const_iterator i = keyName.begin();
162 Name::const_iterator j = signIdName.begin();
163 int count = 0;
164 for(; i != keyName.end() && j != signIdName.end(); i++, j++, count++)
165 {
166 if(*i != *j)
167 break;
168 }
169
170 if(j != signIdName.end() || i == keyName.end())
171 {
172 std::cerr << "wrong signing identity!" << std::endl;
173 return 1;
174 }
175
176 certName = keyName.getSubName(0, count);
177 certName.append("KEY").append(keyName.getSubName(count, keyName.size()-count));
178 certName.append("ID-CERT").appendVersion ();
179 }
180
181 Block wire;
182
183 if (!nack)
184 {
185 if (0 == vm.count("subject-name"))
186 {
187 std::cerr << "subject_name must be specified" << std::endl;
188 return 1;
189 }
190
191 try
192 {
193 CertificateSubjectDescription subDescryptName("2.5.4.41", sName);
194 IdentityCertificate certificate;
195 certificate.setName(certName);
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700196 certificate.setNotBefore(notBefore);
197 certificate.setNotAfter(notAfter);
Yingdi Yue6bfab22014-02-06 16:01:19 -0800198 certificate.setPublicKeyInfo(selfSignedCertificate->getPublicKeyInfo());
199 certificate.addSubjectDescription(subDescryptName);
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700200 for (size_t i = 0; i < otherSubDescrypt.size(); i++)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800201 certificate.addSubjectDescription(otherSubDescrypt[i]);
202 certificate.encode();
203
204 KeyChain keyChain;
205
206 if(isSelfSigned)
207 keyChain.selfSign(certificate);
208 else
209 {
210 Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(Name(signId));
211
212 keyChain.sign(certificate, signingCertificateName);
213 }
214 wire = certificate.wireEncode();
215 }
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800216 catch(SecPublicInfo::Error& e)
217 {
218 std::cerr << "ERROR: " << e.what() << std::endl;
219 return 1;
220 }
221 catch(SecTpm::Error& e)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800222 {
223 std::cerr << "ERROR: " << e.what() << std::endl;
224 return 1;
225 }
226 }
227 else
228 {
229 Data revocationCert;
230 // revocationCert.setContent(void*, 0); // empty content
231 revocationCert.setName(certName);
232
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800233 try
234 {
235 KeyChain keyChain;
236
237 Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(Name(signId));
238
239 keyChain.sign (revocationCert, signingCertificateName);
240 wire = revocationCert.wireEncode();
241 }
242 catch(SecPublicInfo::Error& e)
243 {
244 std::cerr << "ERROR: " << e.what() << std::endl;
245 return 1;
246 }
247 catch(SecTpm::Error& e)
248 {
249 std::cerr << "ERROR: " << e.what() << std::endl;
250 return 1;
251 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800252 }
253
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800254 try
255 {
256 using namespace CryptoPP;
257 StringSource ss(wire.wire(), wire.size(), true,
258 new Base64Encoder(new FileSink(std::cout), true, 64));
259 }
260 catch(CryptoPP::Exception& e)
261 {
262 std::cerr << "ERROR: " << e.what() << std::endl;
263 return 1;
264 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800265
266 return 0;
267}
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800268
269#endif //NDNSEC_CERT_GEN_HPP