2 #include "helpers/defines.h"
3 #include "ssl/gadgets.h"
4 #include "ssl/crtd_message.h"
5 #include "ssl/certificate_db.h"
27 \defgroup ssl_crtd ssl_crtd
28 \ingroup ExternalPrograms
30 Because the standart generation of ssl certificate for
31 sslBump feature, Squid must use external proccess to
32 actually make these calls. This process generate new ssl
33 certificates and worked with ssl certificates disk cache.
34 Typically there will be five ssl_crtd processes spawned
35 from Squid. Communication occurs via TCP sockets bound
36 to the loopback interface. The class in helper.h are
37 primally concerned with starting and stopping the ssl_crtd.
38 Reading and writing to and from the ssl_crtd occurs in the
39 \link IPCacheAPI IP\endlink and the dnsservers occurs in
40 the \link IPCacheAPI IP\endlink and \link FQDNCacheAPI
41 FQDN\endlink cache modules.
43 \section ssl_crtdInterface Command Line Interface
45 usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size
48 -s ssl_storage_path Path to specific disk storage of ssl server
50 -M storage_max_size max size of ssl certificates storage.
51 -b fs_block_size File system block size in bytes. Need for processing
52 natural size of certificate on disk. Default value is
55 After running write requests in the next format:
56 <request code><whitespace><body_len><whitespace><body>
57 There are two kind of request now:
58 new_certificate 14 host=host.dom
59 Create new private key and selfsigned certificate for "host.dom".
61 new_certificate xxx host=host.dom
62 -----BEGIN CERTIFICATE-----
64 -----END CERTIFICATE-----
65 -----BEGIN RSA PRIVATE KEY-----
67 -----END RSA PRIVATE KEY-----
68 Create new private key and certificate request for "host.dom".
69 Sign new request by received certificate and private key.
71 usage: ssl_crtd -c -s ssl_store_path\n
72 -c Init ssl db directories and exit.
77 static const char *const B_KBYTES_STR
= "KB";
78 static const char *const B_MBYTES_STR
= "MB";
79 static const char *const B_GBYTES_STR
= "GB";
80 static const char *const B_BYTES_STR
= "B";
86 time_t getCurrentTime(void)
88 struct timeval current_time
;
89 #if GETTIMEOFDAY_NO_TZP
90 gettimeofday(¤t_time
);
92 gettimeofday(¤t_time
, NULL
);
94 return current_time
.tv_sec
;
99 * Parse bytes unit. It would be one of the next value: MB, GB, KB or B.
100 * This function is caseinsensitive.
102 static size_t parseBytesUnits(const char * unit
)
104 if (!strncasecmp(unit
, B_BYTES_STR
, strlen(B_BYTES_STR
)) ||
105 !strncasecmp(unit
, "", strlen(unit
)))
108 if (!strncasecmp(unit
, B_KBYTES_STR
, strlen(B_KBYTES_STR
)))
111 if (!strncasecmp(unit
, B_MBYTES_STR
, strlen(B_MBYTES_STR
)))
114 if (!strncasecmp(unit
, B_GBYTES_STR
, strlen(B_GBYTES_STR
)))
117 std::cerr
<< "WARNING: Unknown bytes unit '" << unit
<< "'" << std::endl
;
124 * Parse uninterrapted string of bytes value. It looks like "4MB".
126 static bool parseBytesOptionValue(size_t * bptr
, char const * value
)
128 // Find number from string beginning.
129 char const * number_begin
= value
;
130 char const * number_end
= value
;
132 while ((*number_end
>= '0' && *number_end
<= '9')) {
136 std::string
number(number_begin
, number_end
- number_begin
);
137 std::istringstream
in(number
);
143 if ((m
= parseBytesUnits(number_end
)) == 0) {
147 *bptr
= static_cast<size_t>(m
* d
);
148 if (static_cast<long>(*bptr
* 2) != m
* d
* 2)
156 * Print help using response code.
160 std::string example_host_name
= "host.dom";
161 std::string request_string
= Ssl::CrtdMessage::param_host
+ "=" + example_host_name
;
162 std::stringstream request_string_size_stream
;
163 request_string_size_stream
<< request_string
.length();
164 std::string help_string
=
165 "usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size\n"
168 "\t-s ssl_storage_path Path to specific disk storage of ssl server\n"
170 "\t-M storage_max_size max size of ssl certificates storage.\n"
171 "\t-b fs_block_size File system block size in bytes. Need for processing\n"
172 "\t natural size of certificate on disk. Default value is\n"
175 "After running write requests in the next format:\n"
176 "<request code><whitespace><body_len><whitespace><body>\n"
177 "There are two kind of request now:\n"
178 + Ssl::CrtdMessage::code_new_certificate
+ " " + request_string_size_stream
.str() + " " + request_string
+ "\n" +
179 "\tCreate new private key and selfsigned certificate for \"host.dom\".\n"
180 + Ssl::CrtdMessage::code_new_certificate
+ " xxx " + request_string
+ "\n" +
181 "-----BEGIN CERTIFICATE-----\n"
183 "-----END CERTIFICATE-----\n"
184 "-----BEGIN RSA PRIVATE KEY-----\n"
186 "-----END RSA PRIVATE KEY-----\n"
187 "\tCreate new private key and certificate request for \"host.dom\"\n"
188 "\tSign new request by received certificate and private key.\n"
189 "usage: ssl_crtd -c -s ssl_store_path\n"
190 "\t-c Init ssl db directories and exit.\n";
191 std::cerr
<< help_string
<< std::endl
;
196 * Proccess new request message.
198 static bool proccessNewRequest(Ssl::CrtdMessage
& request_message
, std::string
const & db_path
, size_t max_db_size
, size_t fs_block_size
)
200 Ssl::CertificateProperties certProperties
;
202 if (!request_message
.parseRequest(certProperties
, error
))
203 throw std::runtime_error("Error while parsing the crtd request: " + error
);
205 Ssl::CertificateDb
db(db_path
, max_db_size
, fs_block_size
);
207 Ssl::X509_Pointer cert
;
208 Ssl::EVP_PKEY_Pointer pkey
;
209 std::string
&cert_subject
= certProperties
.dbKey();
211 db
.find(cert_subject
, cert
, pkey
);
214 if (!Ssl::certificateMatchesProperties(cert
.get(), certProperties
)) {
215 // The certificate changed (renewed or other reason).
216 // Generete a new one with the updated fields.
219 db
.purgeCert(cert_subject
);
223 if (!cert
|| !pkey
) {
224 if (!Ssl::generateSslCertificate(cert
, pkey
, certProperties
))
225 throw std::runtime_error("Cannot create ssl certificate or private key.");
227 if (!db
.addCertAndPrivateKey(cert
, pkey
, cert_subject
) && db
.IsEnabledDiskStore())
228 throw std::runtime_error("Cannot add certificate to db.");
231 std::string bufferToWrite
;
232 if (!Ssl::writeCertAndPrivateKeyToMemory(cert
, pkey
, bufferToWrite
))
233 throw std::runtime_error("Cannot write ssl certificate or/and private key to memory.");
235 Ssl::CrtdMessage response_message
;
236 response_message
.setCode("OK");
237 response_message
.setBody(bufferToWrite
);
239 // Use the '\1' char as end-of-message character
240 std::cout
<< response_message
.compose() << '\1' << std::flush
;
247 * This is the external ssl_crtd process.
249 int main(int argc
, char *argv
[])
252 size_t max_db_size
= 0;
253 size_t fs_block_size
= 2048;
255 bool create_new_db
= false;
258 while ((c
= getopt(argc
, argv
, "dcghvs:M:b:n:")) != -1) {
264 if (!parseBytesOptionValue(&fs_block_size
, optarg
)) {
265 throw std::runtime_error("Error when parsing -b options value");
272 if (!parseBytesOptionValue(&max_db_size
, optarg
)) {
273 throw std::runtime_error("Error when parsing -M options value");
277 std::cout
<< "ssl_crtd version " << VERSION
<< std::endl
;
281 create_new_db
= true;
292 std::cout
<< "Initialization SSL db..." << std::endl
;
293 Ssl::CertificateDb::create(db_path
);
294 std::cout
<< "Done" << std::endl
;
299 Ssl::CertificateDb::check(db_path
, max_db_size
);
303 char request
[HELPER_INPUT_BUFFER
];
304 Ssl::CrtdMessage request_message
;
305 Ssl::CrtdMessage::ParseResult parse_result
= Ssl::CrtdMessage::INCOMPLETE
;
307 while (parse_result
== Ssl::CrtdMessage::INCOMPLETE
) {
308 if (fgets(request
, HELPER_INPUT_BUFFER
, stdin
) == NULL
)
310 size_t gcount
= strlen(request
);
311 parse_result
= request_message
.parse(request
, gcount
);
314 if (parse_result
== Ssl::CrtdMessage::ERROR
) {
315 throw std::runtime_error("Cannot parse request message.");
316 } else if (request_message
.getCode() == Ssl::CrtdMessage::code_new_certificate
) {
317 proccessNewRequest(request_message
, db_path
, max_db_size
, fs_block_size
);
319 throw std::runtime_error("Unknown request code: \"" + request_message
.getCode() + "\".");
323 } catch (std::runtime_error
& error
) {
324 std::cerr
<< argv
[0] << ": " << error
.what() << std::endl
;