security_file_certgen.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 #include "squid.h"
12 #include "ssl/crtd_message.h"
13 
14 #include <cstring>
15 #include <iostream>
16 #include <sstream>
17 #include <stdexcept>
18 #include <string>
19 #if HAVE_GETOPT_H
20 #include <getopt.h>
21 #endif
22 
74 static const char *const B_KBYTES_STR = "KB";
75 static const char *const B_MBYTES_STR = "MB";
76 static const char *const B_GBYTES_STR = "GB";
77 static const char *const B_BYTES_STR = "B";
78 
80 time_t getCurrentTime(void)
81 {
82  struct timeval current_time;
83 #if GETTIMEOFDAY_NO_TZP
84  gettimeofday(&current_time);
85 #else
86  gettimeofday(&current_time, NULL);
87 #endif
88  return current_time.tv_sec;
89 }
90 
95 static size_t parseBytesUnits(const char * unit)
96 {
97  if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)) ||
98  !strncasecmp(unit, "", strlen(unit)))
99  return 1;
100 
101  if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
102  return 1 << 10;
103 
104  if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
105  return 1 << 20;
106 
107  if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
108  return 1 << 30;
109 
110  std::cerr << "WARNING: Unknown bytes unit '" << unit << "'" << std::endl;
111 
112  return 0;
113 }
114 
116 static bool parseBytesOptionValue(size_t * bptr, char const * value)
117 {
118  // Find number from string beginning.
119  char const * number_begin = value;
120  char const * number_end = value;
121 
122  while ((*number_end >= '0' && *number_end <= '9')) {
123  ++number_end;
124  }
125 
126  std::string number(number_begin, number_end - number_begin);
127  std::istringstream in(number);
128  int d = 0;
129  if (!(in >> d))
130  return false;
131 
132  int m;
133  if ((m = parseBytesUnits(number_end)) == 0) {
134  return false;
135  }
136 
137  *bptr = static_cast<size_t>(m * d);
138  if (static_cast<long>(*bptr * 2) != m * d * 2)
139  return false;
140 
141  return true;
142 }
143 
145 static void usage()
146 {
147  std::string example_host_name = "host.dom";
148  std::string request_string = Ssl::CrtdMessage::param_host + "=" + example_host_name;
149  std::stringstream request_string_size_stream;
150  request_string_size_stream << request_string.length();
151  std::string help_string =
152  "usage: security_file_certgen -hv -s ssl_storage_path -M storage_max_size\n"
153  "\t-h Help\n"
154  "\t-v Version\n"
155  "\t-s ssl_storage_path Path to specific disk storage of ssl server\n"
156  "\t certificates.\n"
157  "\t-M storage_max_size max size of ssl certificates storage.\n"
158  "\t-b fs_block_size File system block size in bytes. Need for processing\n"
159  "\t natural size of certificate on disk. Default value is\n"
160  "\t 2048 bytes.\n"
161  "\n"
162  "After running write requests in the next format:\n"
163  "<request code><whitespace><body_len><whitespace><body>\n"
164  "There are two kind of request now:\n"
165  + Ssl::CrtdMessage::code_new_certificate + " " + request_string_size_stream.str() + " " + request_string + "\n" +
166  "\tCreate new private key and selfsigned certificate for \"host.dom\".\n"
167  + Ssl::CrtdMessage::code_new_certificate + " xxx " + request_string + "\n" +
168  "-----BEGIN CERTIFICATE-----\n"
169  "...\n"
170  "-----END CERTIFICATE-----\n"
171  "-----BEGIN RSA PRIVATE KEY-----\n"
172  "...\n"
173  "-----END RSA PRIVATE KEY-----\n"
174  "\tCreate new private key and certificate request for \"host.dom\"\n"
175  "\tSign new request by received certificate and private key.\n"
176  "usage: security_file_certgen -c -s ssl_store_path\n"
177  "\t-c Init ssl db directories and exit.\n";
178  std::cerr << help_string << std::endl;
179 }
180 
182 static bool processNewRequest(Ssl::CrtdMessage & request_message, std::string const & db_path, size_t max_db_size, size_t fs_block_size)
183 {
184  Ssl::CertificateProperties certProperties;
185  std::string error;
186  if (!request_message.parseRequest(certProperties, error))
187  throw std::runtime_error("Error while parsing the crtd request: " + error);
188 
189  Ssl::CertificateDb db(db_path, max_db_size, fs_block_size);
190 
191  Security::CertPointer cert;
192  Security::PrivateKeyPointer pkey;
193  Security::CertPointer orig;
194  std::string &certKey = Ssl::OnDiskCertificateDbKey(certProperties);
195 
196  bool dbFailed = false;
197  try {
198  db.find(certKey, certProperties.mimicCert, cert, pkey);
199  } catch (std::runtime_error &err) {
200  dbFailed = true;
201  error = err.what();
202  }
203 
204  if (!cert || !pkey) {
205  if (!Ssl::generateSslCertificate(cert, pkey, certProperties))
206  throw std::runtime_error("Cannot create ssl certificate or private key.");
207 
208  if (!dbFailed && db.IsEnabledDiskStore()) {
209  try {
210  if (!db.addCertAndPrivateKey(certKey, cert, pkey, certProperties.mimicCert)) {
211  dbFailed = true;
212  error = "Cannot add certificate to db.";
213  }
214  } catch (const std::runtime_error &err) {
215  dbFailed = true;
216  error = err.what();
217  }
218  }
219  }
220 
221  if (dbFailed)
222  std::cerr << "security_file_certgen helper database '" << db_path << "' failed: " << error << std::endl;
223 
224  std::string bufferToWrite;
225  if (!Ssl::writeCertAndPrivateKeyToMemory(cert, pkey, bufferToWrite))
226  throw std::runtime_error("Cannot write ssl certificate or/and private key to memory.");
227 
228  Ssl::CrtdMessage response_message(Ssl::CrtdMessage::REPLY);
229  response_message.setCode("OK");
230  response_message.setBody(bufferToWrite);
231 
232  // Use the '\1' char as end-of-message character
233  std::cout << response_message.compose() << '\1' << std::flush;
234 
235  return true;
236 }
237 
239 int main(int argc, char *argv[])
240 {
241  try {
242  size_t max_db_size = 0;
243  size_t fs_block_size = 0;
244  int8_t c;
245  bool create_new_db = false;
246  std::string db_path;
247  // process options.
248  while ((c = getopt(argc, argv, "dcghvs:M:b:n:")) != -1) {
249  switch (c) {
250  case 'd':
251  debug_enabled = 1;
252  break;
253  case 'b':
254  if (!parseBytesOptionValue(&fs_block_size, optarg)) {
255  throw std::runtime_error("Error when parsing -b options value");
256  }
257  break;
258  case 's':
259  db_path = optarg;
260  break;
261  case 'M':
262  if (!parseBytesOptionValue(&max_db_size, optarg)) {
263  throw std::runtime_error("Error when parsing -M options value");
264  }
265  break;
266  case 'v':
267  std::cout << "security_file_certgen version " << VERSION << std::endl;
268  exit(EXIT_SUCCESS);
269  break;
270  case 'c':
271  create_new_db = true;
272  break;
273  case 'h':
274  usage();
275  exit(EXIT_SUCCESS);
276  default:
277  exit(EXIT_FAILURE);
278  }
279  }
280 
281  if (create_new_db) {
282  std::cout << "Initialization SSL db..." << std::endl;
284  std::cout << "Done" << std::endl;
285  exit(EXIT_SUCCESS);
286  }
287 
288  if (fs_block_size == 0) {
289  struct statvfs sfs;
290 
291  if (xstatvfs(db_path.c_str(), &sfs)) {
292  fs_block_size = 2048;
293  } else {
294  fs_block_size = sfs.f_frsize;
295  // Sanity check; make sure we have a meaningful value.
296  if (fs_block_size < 512)
297  fs_block_size = 2048;
298  }
299  }
300 
301  {
302  Ssl::CertificateDb::Check(db_path, max_db_size, fs_block_size);
303  }
304  // Initialize SSL subsystem
305  SSL_load_error_strings();
306  SSLeay_add_ssl_algorithms();
307  // process request.
308  for (;;) {
312 
313  while (parse_result == Ssl::CrtdMessage::INCOMPLETE) {
314  if (fgets(request, HELPER_INPUT_BUFFER, stdin) == NULL)
315  exit(EXIT_FAILURE);
316  size_t gcount = strlen(request);
317  parse_result = request_message.parse(request, gcount);
318  }
319 
320  if (parse_result == Ssl::CrtdMessage::ERROR) {
321  throw std::runtime_error("Cannot parse request message.");
322  } else if (request_message.getCode() == Ssl::CrtdMessage::code_new_certificate) {
323  processNewRequest(request_message, db_path, max_db_size, fs_block_size);
324  } else {
325  throw std::runtime_error("Unknown request code: \"" + request_message.getCode() + "\".");
326  }
327  std::cout.flush();
328  }
329  } catch (std::runtime_error & error) {
330  std::cerr << argv[0] << ": " << error.what() << std::endl;
331  return EXIT_FAILURE;
332  }
333  return EXIT_SUCCESS;
334 }
335 
static const char *const B_BYTES_STR
void setBody(std::string const &aBody)
Set new body to encode.
static bool processNewRequest(Ssl::CrtdMessage &request_message, std::string const &db_path, size_t max_db_size, size_t fs_block_size)
Process new request message.
static void Create(std::string const &db_path)
Create and initialize a database under the db_path.
DB * db
int debug_enabled
Definition: debug.cc:13
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
void error(char *format,...)
bool IsEnabledDiskStore() const
Check enabled of dist store.
unsigned long f_frsize
Definition: statvfs.h:45
std::string const & getCode() const
Current response/request code. If parsing is not finished the method may return incompleted code...
bool generateSslCertificate(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, CertificateProperties const &properties)
Definition: gadgets.cc:685
static const std::string code_new_certificate
String code for "new_certificate" messages.
Definition: crtd_message.h:76
#define HELPER_INPUT_BUFFER
Definition: UserRequest.cc:26
static const char *const B_GBYTES_STR
static bool parseBytesOptionValue(size_t *bptr, char const *value)
Parse uninterrapted string of bytes value. It looks like "4MB".
static void usage()
Print help using response code.
int xstatvfs(const char *path, struct statvfs *sfs)
Definition: statvfs.cc:22
Security::CertPointer mimicCert
Certificate to mimic.
Definition: gadgets.h:216
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:62
static void Check(std::string const &db_path, size_t max_db_size, size_t fs_block_size)
Check the database stored under the db_path.
std::string & OnDiskCertificateDbKey(const CertificateProperties &)
Definition: gadgets.cc:237
bool find(std::string const &key, const Security::CertPointer &expectedOrig, Security::CertPointer &cert, Security::PrivateKeyPointer &pkey)
finds matching generated certificate and its private key
ParseResult
Parse result codes.
Definition: crtd_message.h:29
void setCode(std::string const &aCode)
Set new request/reply code to compose.
std::string compose() const
time_t getCurrentTime(void)
Get current time.
number
Definition: testStatHist.cc:16
bool parseRequest(Ssl::CertificateProperties &, std::string &error)
orchestrates entire request parsing
#define VERSION
bool writeCertAndPrivateKeyToMemory(Security::CertPointer const &cert, Security::PrivateKeyPointer const &pkey, std::string &bufferToWrite)
Definition: gadgets.cc:73
char * db_path
ParseResult parse(const char *buffer, size_t len)
Definition: crtd_message.cc:21
static const char *const B_MBYTES_STR
static size_t parseBytesUnits(const char *unit)
static const char *const B_KBYTES_STR
int main(int argc, char *argv[])
This is the external security_file_certgen process.
char * optarg
Definition: getopt.c:51
#define NULL
Definition: types.h:166
bool addCertAndPrivateKey(std::string const &useKey, const Security::CertPointer &cert, const Security::PrivateKeyPointer &pkey, const Security::CertPointer &orig)
Save certificate to disk.
static const std::string param_host
Parameter name for passing hostname.
Definition: crtd_message.h:78

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors