blob: 1d3347f08693fc9520aab16017134ef8c2129645 [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_INSTALL_HPP
9#define NDNSEC_CERT_INSTALL_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 Yue6bfab22014-02-06 16:01:19 -080013
14struct HttpException : public std::exception
15{
16 HttpException(const std::string &reason)
17 : m_reason(reason)
18 {
19 }
20 ~HttpException() throw()
21 {
22 }
23
24 const char* what() const throw()
25 {
26 return m_reason.c_str();
27 }
28
29private:
30 std::string m_reason;
31};
32
Yingdi Yu8d7468f2014-02-21 14:49:45 -080033ndn::shared_ptr<ndn::IdentityCertificate>
Yingdi Yue6bfab22014-02-06 16:01:19 -080034getCertificateHttp(const std::string &host, const std::string &port, const std::string &path)
35{
36 using namespace boost::asio::ip;
37 tcp::iostream request_stream;
38#if (BOOST_VERSION >= 104700)
39 request_stream.expires_from_now(boost::posix_time::milliseconds(3000));
40#endif
41 request_stream.connect(host,port);
42 if(!request_stream)
43 {
44 throw HttpException("HTTP connection error");
45 }
46 request_stream << "GET " << path << " HTTP/1.0\r\n";
47 request_stream << "Host: " << host << "\r\n";
48 request_stream << "Accept: */*\r\n";
49 request_stream << "Cache-Control: no-cache\r\n";
50 request_stream << "Connection: close\r\n\r\n";
51 request_stream.flush();
52
53 std::string line1;
54 std::getline(request_stream,line1);
55 if (!request_stream)
56 {
57 throw HttpException("HTTP communication error");
58 }
59
60 std::stringstream response_stream(line1);
61 std::string http_version;
62 response_stream >> http_version;
63 unsigned int status_code;
64 response_stream >> status_code;
65 std::string status_message;
66
67 std::getline(response_stream,status_message);
68 if (!response_stream || http_version.substr(0,5)!="HTTP/")
69 {
70 throw HttpException("HTTP communication error");
71 }
72 if (status_code!=200)
73 {
74 throw HttpException("HTTP server error");
75 }
76 std::string header;
77 while (std::getline(request_stream, header) && header != "\r") ;
78
Yingdi Yu8d7468f2014-02-21 14:49:45 -080079 ndn::OBufferStream os;
80 CryptoPP::FileSource ss2(request_stream, true, new CryptoPP::Base64Decoder(new CryptoPP::FileSink(os)));
Yingdi Yue6bfab22014-02-06 16:01:19 -080081
Yingdi Yu8d7468f2014-02-21 14:49:45 -080082 ndn::shared_ptr<ndn::IdentityCertificate> identityCertificate = ndn::make_shared<ndn::IdentityCertificate>();
83 identityCertificate->wireDecode(ndn::Block(os.buf()));
Yingdi Yue6bfab22014-02-06 16:01:19 -080084
85 return identityCertificate;
86}
87
Yingdi Yu8d7468f2014-02-21 14:49:45 -080088int
89ndnsec_cert_install(int argc, char** argv)
Yingdi Yue6bfab22014-02-06 16:01:19 -080090{
Yingdi Yu8d7468f2014-02-21 14:49:45 -080091 using namespace ndn;
92 namespace po = boost::program_options;
93
94 std::string certFileName;
Yingdi Yue6bfab22014-02-06 16:01:19 -080095 bool systemDefault = true;
96 bool identityDefault = false;
97 bool keyDefault = false;
98 bool noDefault = false;
99 bool any = false;
100
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800101 po::options_description desc("General Usage\n ndnsec cert-install [-h] [-I|K|N] cert-file\nGeneral options");
Yingdi Yue6bfab22014-02-06 16:01:19 -0800102 desc.add_options()
103 ("help,h", "produce help message")
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800104 ("cert-file,f", po::value<std::string>(&certFileName), "file name of the ceritificate, - for stdin. "
Yingdi Yue6bfab22014-02-06 16:01:19 -0800105 "If starts with http://, will try to fetch "
106 "the certificate using HTTP GET request")
107 ("identity-default,I", "optional, if specified, the certificate will be set as the default certificate of the identity")
108 ("key-default,K", "optional, if specified, the certificate will be set as the default certificate of the key")
109 ("no-default,N", "optional, if specified, the certificate will be simply installed")
110 ;
111 po::positional_options_description p;
112 p.add("cert-file", 1);
113
114 po::variables_map vm;
115 try
116 {
117 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
118 po::notify(vm);
119 }
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800120 catch (std::exception &e)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800121 {
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800122 std::cerr << "ERROR: " << e.what() << std::endl;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800123 return 1;
124 }
125
126 if (vm.count("help"))
127 {
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800128 std::cerr << desc << std::endl;
129 return 0;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800130 }
131
132 if (0 == vm.count("cert-file"))
133 {
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800134 std::cerr << "cert_file must be specified" << std::endl;
135 std::cerr << desc << std::endl;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800136 return 1;
137 }
138
139 if (vm.count("identity-default"))
140 {
141 identityDefault = true;
142 systemDefault = false;
143 }
144 else if (vm.count("key-default"))
145 {
146 keyDefault = true;
147 systemDefault = false;
148 }
149 else if (vm.count("no-default"))
150 {
151 noDefault = true;
152 systemDefault = false;
153 }
154
155 try
156 {
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800157 shared_ptr<IdentityCertificate> cert;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800158
159 if(certFileName.find("http://") == 0)
160 {
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800161 std::string host;
162 std::string port;
163 std::string path;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800164
165 size_t pos = 7;
166 size_t posSlash = certFileName.find ("/", pos);
167
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800168 if (posSlash == std::string::npos)
Yingdi Yue6bfab22014-02-06 16:01:19 -0800169 throw HttpException("Request line is not correctly formatted");
170
171 size_t posPort = certFileName.find (":", pos);
172
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800173 if (posPort != std::string::npos && posPort < posSlash) // port is specified
Yingdi Yue6bfab22014-02-06 16:01:19 -0800174 {
175 port = certFileName.substr (posPort + 1, posSlash - posPort - 1);
176 host = certFileName.substr (pos, posPort-pos);
177 }
178 else
179 {
180 port = "80";
181 host = certFileName.substr (pos, posSlash-pos);
182 }
183
184 path = certFileName.substr (posSlash, certFileName.size () - posSlash);
185
186 cert = getCertificateHttp(host, port, path);
187 }
188 else
189 {
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800190 cert = getIdentityCertificate(certFileName);
Yingdi Yue6bfab22014-02-06 16:01:19 -0800191 }
192
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800193 if(!static_cast<bool>(cert))
194 return 1;
195
Yingdi Yue6bfab22014-02-06 16:01:19 -0800196 KeyChain keyChain;
197
198 if(systemDefault)
199 {
200 keyChain.addCertificateAsIdentityDefault(*cert);
201 Name keyName = cert->getPublicKeyName();
202 Name identity = keyName.getSubName(0, keyName.size()-1);
203 keyChain.setDefaultIdentity(identity);
204 }
205 else if(identityDefault)
206 {
207 keyChain.addCertificateAsIdentityDefault(*cert);
208 }
209 else if(keyDefault)
210 {
211 keyChain.addCertificateAsKeyDefault(*cert);
212 }
213 else
214 {
215 keyChain.addCertificate(*cert);
216 }
217
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800218 std::cerr << "OK: certificate with name [" << cert->getName().toUri() << "] has been successfully installed" << std::endl;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800219
220 return 0;
221 }
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800222 catch(SecPublicInfo::Error& e)
223 {
224 std::cerr << "ERROR: " << e.what() << std::endl;
225 return 1;
226 }
227 catch(SecTpm::Error& e)
228 {
229 std::cerr << "ERROR: " << e.what() << std::endl;
230 return 1;
231 }
Yingdi Yue6bfab22014-02-06 16:01:19 -0800232 catch(std::exception &e)
233 {
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800234 std::cerr << "ERROR: " << e.what() << std::endl;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800235 return 1;
236 }
237 catch(...)
238 {
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800239 std::cerr << "ERROR: unknown error" << std::endl;
Yingdi Yue6bfab22014-02-06 16:01:19 -0800240 return 1;
241 }
242}
Yingdi Yu8d7468f2014-02-21 14:49:45 -0800243
244#endif //NDNSEC_CERT_INSTALL_HPP