6 #include "helpers/defines.h"
7 #include "ssl/gadgets.h"
8 #include "ssl/crtd_message.h"
9 #include "ssl/certificate_db.h"
31 \defgroup ssl_crtd ssl_crtd
32 \ingroup ExternalPrograms
34 Because the standart generation of ssl certificate for
35 sslBump feature, Squid must use external proccess to
36 actually make these calls. This process generate new ssl
37 certificates and worked with ssl certificates disk cache.
38 Typically there will be five ssl_crtd processes spawned
39 from Squid. Communication occurs via TCP sockets bound
40 to the loopback interface. The class in helper.h are
41 primally concerned with starting and stopping the ssl_crtd.
42 Reading and writing to and from the ssl_crtd occurs in the
43 \link IPCacheAPI IP\endlink and the dnsservers occurs in
44 the \link IPCacheAPI IP\endlink and \link FQDNCacheAPI
45 FQDN\endlink cache modules.
47 \section ssl_crtdInterface Command Line Interface
49 usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size
52 -s ssl_storage_path Path to specific disk storage of ssl server
54 -M storage_max_size max size of ssl certificates storage.
55 -b fs_block_size File system block size in bytes. Need for processing
56 natural size of certificate on disk. Default value is
59 After running write requests in the next format:
60 <request code><whitespace><body_len><whitespace><body>
61 There are two kind of request now:
62 new_certificate 14 host=host.dom
63 Create new private key and selfsigned certificate for "host.dom".
65 new_certificate xxx host=host.dom
66 -----BEGIN CERTIFICATE-----
68 -----END CERTIFICATE-----
69 -----BEGIN RSA PRIVATE KEY-----
71 -----END RSA PRIVATE KEY-----
72 Create new private key and certificate request for "host.dom".
73 Sign new request by received certificate and private key.
75 usage: ssl_crtd -c -s ssl_store_path\n -n new_serial_number
76 -c Init ssl db directories and exit.
77 -n new_serial_number HEX serial number to use when initializing db.
78 The default value of serial number is
79 the number of seconds since Epoch minus 1200000000
81 usage: ssl_crtd -g -s ssl_store_path
82 -g Show current serial number and exit.
86 static const char *const B_KBYTES_STR
= "KB";
87 static const char *const B_MBYTES_STR
= "MB";
88 static const char *const B_GBYTES_STR
= "GB";
89 static const char *const B_BYTES_STR
= "B";
95 time_t getCurrentTime(void)
97 struct timeval current_time
;
98 #if GETTIMEOFDAY_NO_TZP
99 gettimeofday(¤t_time
);
101 gettimeofday(¤t_time
, NULL
);
103 return current_time
.tv_sec
;
108 * Parse bytes unit. It would be one of the next value: MB, GB, KB or B.
109 * This function is caseinsensitive.
111 static size_t parseBytesUnits(const char * unit
)
113 if (!strncasecmp(unit
, B_BYTES_STR
, strlen(B_BYTES_STR
)) ||
114 !strncasecmp(unit
, "", strlen(unit
)))
117 if (!strncasecmp(unit
, B_KBYTES_STR
, strlen(B_KBYTES_STR
)))
120 if (!strncasecmp(unit
, B_MBYTES_STR
, strlen(B_MBYTES_STR
)))
123 if (!strncasecmp(unit
, B_GBYTES_STR
, strlen(B_GBYTES_STR
)))
131 * Parse uninterrapted string of bytes value. It looks like "4MB".
133 static bool parseBytesOptionValue(size_t * bptr
, char const * value
)
135 // Find number from string beginning.
136 char const * number_begin
= value
;
137 char const * number_end
= value
;
139 while ((*number_end
>= '0' && *number_end
<= '9')) {
143 std::string
number(number_begin
, number_end
- number_begin
);
144 std::istringstream
in(number
);
150 if ((m
= parseBytesUnits(number_end
)) == 0) {
154 *bptr
= static_cast<size_t>(m
* d
);
155 if (static_cast<long>(*bptr
* 2) != m
* d
* 2)
163 * Print help using response code.
167 std::string example_host_name
= "host.dom";
168 std::string request_string
= Ssl::CrtdMessage::param_host
+ "=" + example_host_name
;
169 std::stringstream request_string_size_stream
;
170 request_string_size_stream
<< request_string
.length();
171 std::string help_string
=
172 "usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size\n"
175 "\t-s ssl_storage_path Path to specific disk storage of ssl server\n"
177 "\t-M storage_max_size max size of ssl certificates storage.\n"
178 "\t-b fs_block_size File system block size in bytes. Need for processing\n"
179 "\t natural size of certificate on disk. Default value is\n"
182 "After running write requests in the next format:\n"
183 "<request code><whitespace><body_len><whitespace><body>\n"
184 "There are two kind of request now:\n"
185 + Ssl::CrtdMessage::code_new_certificate
+ " " + request_string_size_stream
.str() + " " + request_string
+ "\n" +
186 "\tCreate new private key and selfsigned certificate for \"host.dom\".\n"
187 + Ssl::CrtdMessage::code_new_certificate
+ " xxx " + request_string
+ "\n" +
188 "-----BEGIN CERTIFICATE-----\n"
190 "-----END CERTIFICATE-----\n"
191 "-----BEGIN RSA PRIVATE KEY-----\n"
193 "-----END RSA PRIVATE KEY-----\n"
194 "\tCreate new private key and certificate request for \"host.dom\"\n"
195 "\tSign new request by received certificate and private key.\n"
196 "usage: ssl_crtd -c -s ssl_store_path -n new_serial_number\n"
197 "\t-c Init ssl db directories and exit.\n"
198 "\t-n new_serial_number HEX serial number to use when initializing db.\n"
199 "\t The default value of serial number is\n"
200 "\t the number of seconds since Epoch minus 1200000000\n"
201 "usage: ssl_crtd -g -s ssl_store_path\n"
202 "\t-g Show current serial number and exit.";
203 std::cerr
<< help_string
<< std::endl
;
208 * Proccess new request message.
210 static bool proccessNewRequest(Ssl::CrtdMessage
const & request_message
, std::string
const & db_path
, size_t max_db_size
, size_t fs_block_size
)
212 Ssl::CrtdMessage::BodyParams map
;
213 std::string body_part
;
214 request_message
.parseBody(map
, body_part
);
216 Ssl::CrtdMessage::BodyParams::iterator i
= map
.find(Ssl::CrtdMessage::param_host
);
218 throw std::runtime_error("Cannot find \"" + Ssl::CrtdMessage::param_host
+ "\" parameter in request message.");
219 std::string host
= i
->second
;
221 Ssl::CertificateDb
db(db_path
, max_db_size
, fs_block_size
);
223 Ssl::X509_Pointer cert
;
224 Ssl::EVP_PKEY_Pointer pkey
;
225 db
.find("/CN=" + host
, cert
, pkey
);
227 if (!cert
|| !pkey
) {
228 Ssl::X509_Pointer certToSign
;
229 Ssl::EVP_PKEY_Pointer pkeyToSign
;
230 Ssl::readCertAndPrivateKeyFromMemory(certToSign
, pkeyToSign
, body_part
.c_str());
232 Ssl::BIGNUM_Pointer
serial(db
.getCurrentSerialNumber());
234 if (!Ssl::generateSslCertificateAndPrivateKey(host
.c_str(), certToSign
, pkeyToSign
, cert
, pkey
, serial
.get()))
235 throw std::runtime_error("Cannot create ssl certificate or private key.");
236 if (!db
.addCertAndPrivateKey(cert
, pkey
) && db
.IsEnabledDiskStore())
237 throw std::runtime_error("Cannot add certificate to db.");
240 std::string bufferToWrite
;
241 if (!Ssl::writeCertAndPrivateKeyToMemory(cert
, pkey
, bufferToWrite
))
242 throw std::runtime_error("Cannot write ssl certificate or/and private key to memory.");
244 Ssl::CrtdMessage response_message
;
245 response_message
.setCode("OK");
246 response_message
.setBody(bufferToWrite
);
248 // Use the '\1' char as end-of-message character
249 std::cout
<< response_message
.compose() << '\1' << std::flush
;
256 * This is the external ssl_crtd process.
258 int main(int argc
, char *argv
[])
261 int serial
= (getCurrentTime() - 1200000000);
262 size_t max_db_size
= 0;
263 size_t fs_block_size
= 2048;
265 bool create_new_db
= false;
266 bool show_sn
= false;
269 while ((c
= getopt(argc
, argv
, "dcghvs:M:b:n:")) != -1) {
275 if (!parseBytesOptionValue(&fs_block_size
, optarg
)) {
276 throw std::runtime_error("Error when parsing -b options value");
283 std::stringstream
sn_stream(optarg
);
284 sn_stream
>> std::hex
>> serial
;
288 if (!parseBytesOptionValue(&max_db_size
, optarg
)) {
289 throw std::runtime_error("Error when parsing -M options value");
293 std::cout
<< "ssl_crtd version " << VERSION
<< std::endl
;
297 create_new_db
= true;
311 std::cout
<< "Initialization SSL db..." << std::endl
;
312 Ssl::CertificateDb::create(db_path
, serial
);
313 std::cout
<< "Done" << std::endl
;
318 Ssl::CertificateDb
db(db_path
, 4096, 0);
319 std::cout
<< db
.getSNString() << std::endl
;
323 Ssl::CertificateDb::check(db_path
, max_db_size
);
327 char request
[HELPER_INPUT_BUFFER
];
328 Ssl::CrtdMessage request_message
;
329 Ssl::CrtdMessage::ParseResult parse_result
= Ssl::CrtdMessage::INCOMPLETE
;
331 while (parse_result
== Ssl::CrtdMessage::INCOMPLETE
) {
332 if (fgets(request
, HELPER_INPUT_BUFFER
, stdin
) == NULL
)
334 size_t gcount
= strlen(request
);
335 parse_result
= request_message
.parse(request
, gcount
);
338 if (parse_result
== Ssl::CrtdMessage::ERROR
) {
339 throw std::runtime_error("Cannot parse request message.");
340 } else if (request_message
.getCode() == Ssl::CrtdMessage::code_new_certificate
) {
341 proccessNewRequest(request_message
, db_path
, max_db_size
, fs_block_size
);
343 throw std::runtime_error("Unknown request code: \"" + request_message
.getCode() + "\".");
347 } catch (std::runtime_error
& error
) {
348 std::cerr
<< argv
[0] << ": " << error
.what() << std::endl
;