blob: 4bcd4a266401c284f2e4d6510852e0c636794248 [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
4 * Yingdi Yu
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Yingdi Yu <yingdi@cs.ucla.edu>
9 */
10
11#include <iostream>
12#include <fstream>
13
14#include <boost/program_options/options_description.hpp>
15#include <boost/program_options/variables_map.hpp>
16#include <boost/program_options/parsers.hpp>
17#include <boost/date_time/posix_time/posix_time.hpp>
18#include <boost/asio.hpp>
19
20#include <cryptopp/base64.h>
21#include <cryptopp/files.h>
22
23#include "security/key-chain.hpp"
24
25using namespace std;
26using namespace ndn;
27namespace po = boost::program_options;
28
29ptr_lib::shared_ptr<IdentityCertificate>
30getCertificate(const string& fileName)
31{
32 istream* ifs;
33 if(fileName == string("-"))
34 ifs = &cin;
35 else
36 ifs = new ifstream(fileName.c_str());
37
38 string decoded;
39 CryptoPP::FileSource ss2(*ifs, true,
40 new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded)));
41
42 ptr_lib::shared_ptr<IdentityCertificate> identityCertificate = ptr_lib::make_shared<IdentityCertificate>();
43 identityCertificate->wireDecode(Block(decoded.c_str(), decoded.size()));
44
45 return identityCertificate;
46}
47
48struct HttpException : public std::exception
49{
50 HttpException(const std::string &reason)
51 : m_reason(reason)
52 {
53 }
54 ~HttpException() throw()
55 {
56 }
57
58 const char* what() const throw()
59 {
60 return m_reason.c_str();
61 }
62
63private:
64 std::string m_reason;
65};
66
67ptr_lib::shared_ptr<IdentityCertificate>
68getCertificateHttp(const std::string &host, const std::string &port, const std::string &path)
69{
70 using namespace boost::asio::ip;
71 tcp::iostream request_stream;
72#if (BOOST_VERSION >= 104700)
73 request_stream.expires_from_now(boost::posix_time::milliseconds(3000));
74#endif
75 request_stream.connect(host,port);
76 if(!request_stream)
77 {
78 throw HttpException("HTTP connection error");
79 }
80 request_stream << "GET " << path << " HTTP/1.0\r\n";
81 request_stream << "Host: " << host << "\r\n";
82 request_stream << "Accept: */*\r\n";
83 request_stream << "Cache-Control: no-cache\r\n";
84 request_stream << "Connection: close\r\n\r\n";
85 request_stream.flush();
86
87 std::string line1;
88 std::getline(request_stream,line1);
89 if (!request_stream)
90 {
91 throw HttpException("HTTP communication error");
92 }
93
94 std::stringstream response_stream(line1);
95 std::string http_version;
96 response_stream >> http_version;
97 unsigned int status_code;
98 response_stream >> status_code;
99 std::string status_message;
100
101 std::getline(response_stream,status_message);
102 if (!response_stream || http_version.substr(0,5)!="HTTP/")
103 {
104 throw HttpException("HTTP communication error");
105 }
106 if (status_code!=200)
107 {
108 throw HttpException("HTTP server error");
109 }
110 std::string header;
111 while (std::getline(request_stream, header) && header != "\r") ;
112
113
114 string decoded;
115 CryptoPP::FileSource ss2(request_stream, true,
116 new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded)));
117
118 ptr_lib::shared_ptr<IdentityCertificate> identityCertificate = ptr_lib::make_shared<IdentityCertificate>();
119 identityCertificate->wireDecode(Block(decoded.c_str(), decoded.size()));
120
121 return identityCertificate;
122}
123
124int main(int argc, char** argv)
125{
126 string certFileName;
127 bool systemDefault = true;
128 bool identityDefault = false;
129 bool keyDefault = false;
130 bool noDefault = false;
131 bool any = false;
132
133 po::options_description desc("General Usage\n ndn-install-cert [-h] [-I|K|N] cert-file\nGeneral options");
134 desc.add_options()
135 ("help,h", "produce help message")
136 ("cert-file,f", po::value<string>(&certFileName), "file name of the ceritificate, - for stdin. "
137 "If starts with http://, will try to fetch "
138 "the certificate using HTTP GET request")
139 ("identity-default,I", "optional, if specified, the certificate will be set as the default certificate of the identity")
140 ("key-default,K", "optional, if specified, the certificate will be set as the default certificate of the key")
141 ("no-default,N", "optional, if specified, the certificate will be simply installed")
142 ;
143 po::positional_options_description p;
144 p.add("cert-file", 1);
145
146 po::variables_map vm;
147 try
148 {
149 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
150 po::notify(vm);
151 }
152 catch (exception &e)
153 {
154 cerr << "ERROR: " << e.what() << endl;
155 return 1;
156 }
157
158 if (vm.count("help"))
159 {
160 cerr << desc << endl;
161 return 1;
162 }
163
164 if (0 == vm.count("cert-file"))
165 {
166 cerr << "cert_file must be specified" << endl;
167 cerr << desc << endl;
168 return 1;
169 }
170
171 if (vm.count("identity-default"))
172 {
173 identityDefault = true;
174 systemDefault = false;
175 }
176 else if (vm.count("key-default"))
177 {
178 keyDefault = true;
179 systemDefault = false;
180 }
181 else if (vm.count("no-default"))
182 {
183 noDefault = true;
184 systemDefault = false;
185 }
186
187 try
188 {
189 ptr_lib::shared_ptr<IdentityCertificate> cert;
190
191 if(certFileName.find("http://") == 0)
192 {
193 string host;
194 string port;
195 string path;
196
197 size_t pos = 7;
198 size_t posSlash = certFileName.find ("/", pos);
199
200 if (posSlash == string::npos)
201 throw HttpException("Request line is not correctly formatted");
202
203 size_t posPort = certFileName.find (":", pos);
204
205 if (posPort != string::npos && posPort < posSlash) // port is specified
206 {
207 port = certFileName.substr (posPort + 1, posSlash - posPort - 1);
208 host = certFileName.substr (pos, posPort-pos);
209 }
210 else
211 {
212 port = "80";
213 host = certFileName.substr (pos, posSlash-pos);
214 }
215
216 path = certFileName.substr (posSlash, certFileName.size () - posSlash);
217
218 cert = getCertificateHttp(host, port, path);
219 }
220 else
221 {
222 cert = getCertificate(certFileName);
223 }
224
225 KeyChain keyChain;
226
227 if(systemDefault)
228 {
229 keyChain.addCertificateAsIdentityDefault(*cert);
230 Name keyName = cert->getPublicKeyName();
231 Name identity = keyName.getSubName(0, keyName.size()-1);
232 keyChain.setDefaultIdentity(identity);
233 }
234 else if(identityDefault)
235 {
236 keyChain.addCertificateAsIdentityDefault(*cert);
237 }
238 else if(keyDefault)
239 {
240 keyChain.addCertificateAsKeyDefault(*cert);
241 }
242 else
243 {
244 keyChain.addCertificate(*cert);
245 }
246
247 cout << "OK: certificate with name [" << cert->getName().toUri() << "] has been successfully installed" << endl;
248
249 return 0;
250 }
251 catch(std::exception &e)
252 {
253 cerr << "ERROR: " << e.what() << endl;
254 return 1;
255 }
256 catch(...)
257 {
258 cerr << "ERROR: unknown error" << endl;
259 return 1;
260 }
261}