blob: 012664659a74ca73acfcbc485c8d3e33d19eae9d [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07002/**
Alexander Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Yingdi Yue6bfab22014-02-06 16:01:19 -080022 */
23
Yingdi Yu8d7468f2014-02-21 14:49:45 -080024#ifndef NDNSEC_CERT_GEN_HPP
25#define NDNSEC_CERT_GEN_HPP
Yingdi Yue6bfab22014-02-06 16:01:19 -080026
Yingdi Yu8d7468f2014-02-21 14:49:45 -080027#include "ndnsec-util.hpp"
Yingdi Yue6bfab22014-02-06 16:01:19 -080028
Yingdi Yub61f5402014-02-26 17:46:11 -080029int
Yingdi Yu8d7468f2014-02-21 14:49:45 -080030ndnsec_cert_gen(int argc, char** argv)
Yingdi Yue6bfab22014-02-06 16:01:19 -080031{
Yingdi Yu8d7468f2014-02-21 14:49:45 -080032 using boost::tokenizer;
33 using boost::escaped_list_separator;
Yingdi Yue6bfab22014-02-06 16:01:19 -080034
Yingdi Yu8d7468f2014-02-21 14:49:45 -080035 using namespace ndn;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070036 using namespace ndn::time;
Yingdi Yu8d7468f2014-02-21 14:49:45 -080037 namespace po = boost::program_options;
Yingdi Yue6bfab22014-02-06 16:01:19 -080038
Yingdi Yue6bfab22014-02-06 16:01:19 -080039 std::string notBeforeStr;
40 std::string notAfterStr;
Yingdi Yub61f5402014-02-26 17:46:11 -080041 std::string subjectName;
42 std::string requestFile("-");
Yingdi Yuba8604d2014-10-13 19:03:12 -070043 Name signId;
Yingdi Yub61f5402014-02-26 17:46:11 -080044 std::string subjectInfo;
Yingdi Yuba8604d2014-10-13 19:03:12 -070045 Name certPrefix;
46
47 KeyChain keyChain;
Yingdi Yue6bfab22014-02-06 16:01:19 -080048
Yingdi Yu0eb5d722014-06-10 15:06:25 -070049 po::options_description description(
50 "General Usage\n"
51 " ndnsec cert-gen [-h] [-S date] [-E date] [-N subject-name] [-I subject-info] "
52 "[-s sign-id] [-p cert-prefix] request\n"
53 "General options");
54
Yingdi Yub61f5402014-02-26 17:46:11 -080055 description.add_options()
Yingdi Yue6bfab22014-02-06 16:01:19 -080056 ("help,h", "produce help message")
Yingdi Yuba8604d2014-10-13 19:03:12 -070057 ("not-before,S", po::value<std::string>(&notBeforeStr),
58 "certificate starting date, YYYYMMDDhhmmss (default: now)")
59 ("not-after,E", po::value<std::string>(&notAfterStr),
60 "certificate ending date, YYYYMMDDhhmmss (default: now + 365 days)")
61 ("subject-name,N", po::value<std::string>(&subjectName),
62 "subject name")
63 ("subject-info,I", po::value<std::string>(&subjectInfo),
64 "subject info, pairs of OID and string description: "
65 "\"2.5.4.10 'University of California, Los Angeles'\"")
66 ("sign-id,s", po::value<Name>(&signId)->default_value(keyChain.getDefaultIdentity()),
67 "signing identity")
68 ("cert-prefix,p", po::value<Name>(&certPrefix)->default_value(KeyChain::DEFAULT_PREFIX),
69 "cert prefix, which is the part of certificate name before "
70 "KEY component")
71 ("request,r", po::value<std::string>(&requestFile)->default_value("-"),
72 "request file name, - for stdin")
Yingdi Yue6bfab22014-02-06 16:01:19 -080073 ;
74
75 po::positional_options_description p;
76 p.add("request", 1);
77
78 po::variables_map vm;
79 try
80 {
Yingdi Yub61f5402014-02-26 17:46:11 -080081 po::store(po::command_line_parser(argc, argv).options(description).positional(p).run(),
82 vm);
Yingdi Yue6bfab22014-02-06 16:01:19 -080083 po::notify(vm);
84 }
Yingdi Yub61f5402014-02-26 17:46:11 -080085 catch (const std::exception& e)
Yingdi Yue6bfab22014-02-06 16:01:19 -080086 {
87 std::cerr << "ERROR: " << e.what() << std::endl;
88 return 1;
89 }
90
Yingdi Yub61f5402014-02-26 17:46:11 -080091 if (vm.count("help") != 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -080092 {
Yingdi Yuba8604d2014-10-13 19:03:12 -070093 std::cout << description << std::endl;
Yingdi Yu8d7468f2014-02-21 14:49:45 -080094 return 0;
Yingdi Yue6bfab22014-02-06 16:01:19 -080095 }
96
Yingdi Yu0eb5d722014-06-10 15:06:25 -070097 if (vm.count("subject-name") == 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -080098 {
Yingdi Yuba8604d2014-10-13 19:03:12 -070099 std::cerr << "ERROR: subject name must be specified" << std::endl
100 << std::endl
101 << description << std::endl;
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700102 return 1;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800103 }
104
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700105 std::vector<CertificateSubjectDescription> subjectDescription;
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700106 subjectDescription.push_back(CertificateSubjectDescription(oid::ATTRIBUTE_NAME, subjectName));
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700107
Yingdi Yub61f5402014-02-26 17:46:11 -0800108 tokenizer<escaped_list_separator<char> > subjectInfoItems
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700109 (subjectInfo, escaped_list_separator<char>("\\", " \t", "'\""));
Yingdi Yue6bfab22014-02-06 16:01:19 -0800110
Yingdi Yub61f5402014-02-26 17:46:11 -0800111 tokenizer<escaped_list_separator<char> >::iterator it =
112 subjectInfoItems.begin();
113
114 while (it != subjectInfoItems.end())
Yingdi Yue6bfab22014-02-06 16:01:19 -0800115 {
Yingdi Yub61f5402014-02-26 17:46:11 -0800116 std::string oid = *it;
117
118 it++;
119 if (it == subjectInfoItems.end())
Yingdi Yue6bfab22014-02-06 16:01:19 -0800120 {
Yingdi Yub61f5402014-02-26 17:46:11 -0800121 std::cerr << "ERROR: unmatched info for oid [" << oid << "]" << std::endl;
122 return 1;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800123 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800124
125 std::string value = *it;
126
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700127 subjectDescription.push_back(CertificateSubjectDescription(OID(oid), value));
Yingdi Yub61f5402014-02-26 17:46:11 -0800128
129 it++;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800130 }
131
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700132 system_clock::TimePoint notBefore;
133 system_clock::TimePoint notAfter;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800134
Yingdi Yub61f5402014-02-26 17:46:11 -0800135 if (vm.count("not-before") == 0)
136 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700137 notBefore = system_clock::now();
Yingdi Yub61f5402014-02-26 17:46:11 -0800138 }
139 else
140 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700141 notBefore = fromIsoString(notBeforeStr.substr(0, 8) + "T" +
142 notBeforeStr.substr(8, 6));
Yingdi Yub61f5402014-02-26 17:46:11 -0800143 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800144
Yingdi Yub61f5402014-02-26 17:46:11 -0800145 if (vm.count("not-after") == 0)
146 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700147 notAfter = notBefore + days(365);
Yingdi Yub61f5402014-02-26 17:46:11 -0800148 }
149 else
150 {
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700151 notAfter = fromIsoString(notAfterStr.substr(0, 8) + "T" +
152 notAfterStr.substr(8, 6));
Yingdi Yue6bfab22014-02-06 16:01:19 -0800153
Yingdi Yub61f5402014-02-26 17:46:11 -0800154 if (notAfter < notBefore)
155 {
Yingdi Yuba8604d2014-10-13 19:03:12 -0700156 std::cerr << "ERROR: not-before cannot be later than not-after" << std::endl
157 << std::endl
158 << description << std::endl;
Yingdi Yub61f5402014-02-26 17:46:11 -0800159 return 1;
160 }
161 }
162
163 if (vm.count("request") == 0)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800164 {
Yingdi Yuba8604d2014-10-13 19:03:12 -0700165 std::cerr << "ERROR: request file must be specified" << std::endl
166 << std::endl
167 << description << std::endl;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800168 return 1;
169 }
170
Yingdi Yub61f5402014-02-26 17:46:11 -0800171 shared_ptr<IdentityCertificate> selfSignedCertificate
172 = getIdentityCertificate(requestFile);
173
174 if (!static_cast<bool>(selfSignedCertificate))
Yingdi Yue6bfab22014-02-06 16:01:19 -0800175 {
176 std::cerr << "ERROR: input error" << std::endl;
177 return 1;
178 }
179
180 Name keyName = selfSignedCertificate->getPublicKeyName();
Yingdi Yu05842f22014-04-15 19:21:56 -0700181
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700182 shared_ptr<IdentityCertificate> certificate =
183 keyChain.prepareUnsignedIdentityCertificate(keyName, selfSignedCertificate->getPublicKeyInfo(),
Yingdi Yuba8604d2014-10-13 19:03:12 -0700184 signId, notBefore, notAfter,
185 subjectDescription, certPrefix);
Yingdi Yu05842f22014-04-15 19:21:56 -0700186
Yingdi Yuc4c81202014-07-08 11:07:50 -0700187 if (!static_cast<bool>(certificate))
188 {
Yingdi Yuba8604d2014-10-13 19:03:12 -0700189 std::cerr << "ERROR: key name is not formated correctly or does not match certificate name"
Yingdi Yuc4c81202014-07-08 11:07:50 -0700190 << std::endl;
191 return 1;
192 }
193
Yingdi Yuba8604d2014-10-13 19:03:12 -0700194 keyChain.createIdentity(signId);
195 Name signingCertificateName = keyChain.getDefaultCertificateNameForIdentity(signId);
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700196 keyChain.sign(*certificate, signingCertificateName);
Yingdi Yue6bfab22014-02-06 16:01:19 -0800197
Yingdi Yu0eb5d722014-06-10 15:06:25 -0700198 Block wire = certificate->wireEncode();
Yingdi Yue6bfab22014-02-06 16:01:19 -0800199
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800200 try
201 {
202 using namespace CryptoPP;
203 StringSource ss(wire.wire(), wire.size(), true,
204 new Base64Encoder(new FileSink(std::cout), true, 64));
205 }
Yingdi Yub61f5402014-02-26 17:46:11 -0800206 catch (const CryptoPP::Exception& e)
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800207 {
208 std::cerr << "ERROR: " << e.what() << std::endl;
209 return 1;
210 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800211
212 return 0;
213}
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800214
215#endif //NDNSEC_CERT_GEN_HPP