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
76 -c Init ssl db directories and exit.
81 static const char *const B_KBYTES_STR
= "KB";
82 static const char *const B_MBYTES_STR
= "MB";
83 static const char *const B_GBYTES_STR
= "GB";
84 static const char *const B_BYTES_STR
= "B";
90 time_t getCurrentTime(void)
92 struct timeval current_time
;
93 #if GETTIMEOFDAY_NO_TZP
94 gettimeofday(¤t_time
);
96 gettimeofday(¤t_time
, NULL
);
98 return current_time
.tv_sec
;
103 * Parse bytes unit. It would be one of the next value: MB, GB, KB or B.
104 * This function is caseinsensitive.
106 static size_t parseBytesUnits(const char * unit
)
108 if (!strncasecmp(unit
, B_BYTES_STR
, strlen(B_BYTES_STR
)) ||
109 !strncasecmp(unit
, "", strlen(unit
)))
112 if (!strncasecmp(unit
, B_KBYTES_STR
, strlen(B_KBYTES_STR
)))
115 if (!strncasecmp(unit
, B_MBYTES_STR
, strlen(B_MBYTES_STR
)))
118 if (!strncasecmp(unit
, B_GBYTES_STR
, strlen(B_GBYTES_STR
)))
121 std::cerr
<< "WARNING: Unknown bytes unit '" << unit
<< "'" << std::endl
;
128 * Parse uninterrapted string of bytes value. It looks like "4MB".
130 static bool parseBytesOptionValue(size_t * bptr
, char const * value
)
132 // Find number from string beginning.
133 char const * number_begin
= value
;
134 char const * number_end
= value
;
136 while ((*number_end
>= '0' && *number_end
<= '9')) {
140 std::string
number(number_begin
, number_end
- number_begin
);
141 std::istringstream
in(number
);
147 if ((m
= parseBytesUnits(number_end
)) == 0) {
151 *bptr
= static_cast<size_t>(m
* d
);
152 if (static_cast<long>(*bptr
* 2) != m
* d
* 2)
160 * Print help using response code.
164 std::string example_host_name
= "host.dom";
165 std::string request_string
= Ssl::CrtdMessage::param_host
+ "=" + example_host_name
;
166 std::stringstream request_string_size_stream
;
167 request_string_size_stream
<< request_string
.length();
168 std::string help_string
=
169 "usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size\n"
172 "\t-s ssl_storage_path Path to specific disk storage of ssl server\n"
174 "\t-M storage_max_size max size of ssl certificates storage.\n"
175 "\t-b fs_block_size File system block size in bytes. Need for processing\n"
176 "\t natural size of certificate on disk. Default value is\n"
179 "After running write requests in the next format:\n"
180 "<request code><whitespace><body_len><whitespace><body>\n"
181 "There are two kind of request now:\n"
182 + Ssl::CrtdMessage::code_new_certificate
+ " " + request_string_size_stream
.str() + " " + request_string
+ "\n" +
183 "\tCreate new private key and selfsigned certificate for \"host.dom\".\n"
184 + Ssl::CrtdMessage::code_new_certificate
+ " xxx " + request_string
+ "\n" +
185 "-----BEGIN CERTIFICATE-----\n"
187 "-----END CERTIFICATE-----\n"
188 "-----BEGIN RSA PRIVATE KEY-----\n"
190 "-----END RSA PRIVATE KEY-----\n"
191 "\tCreate new private key and certificate request for \"host.dom\"\n"
192 "\tSign new request by received certificate and private key.\n"
193 "usage: ssl_crtd -c -s ssl_store_path\n"
194 "\t-c Init ssl db directories and exit.\n";
195 std::cerr
<< help_string
<< std::endl
;
200 * Proccess new request message.
202 static bool proccessNewRequest(Ssl::CrtdMessage
& request_message
, std::string
const & db_path
, size_t max_db_size
, size_t fs_block_size
)
204 Ssl::CertificateProperties certProperties
;
206 if (!request_message
.parseRequest(certProperties
, error
))
207 throw std::runtime_error("Error while parsing the crtd request: " + error
);
209 Ssl::CertificateDb
db(db_path
, max_db_size
, fs_block_size
);
210 Ssl::X509_Pointer cert
;
211 Ssl::EVP_PKEY_Pointer pkey
;
212 std::string
&cert_subject
= certProperties
.dbKey();
214 db
.find(cert_subject
, cert
, pkey
);
216 if (cert
.get() && certProperties
.mimicCert
.get()) {
217 if (!Ssl::ssl_match_certificates(cert
.get(), certProperties
.mimicCert
.get())) {
218 // The certificate changed (renewed or other reason).
219 // Generete a new one with the updated fields.
225 if (!cert
|| !pkey
) {
226 if (!Ssl::generateSslCertificate(cert
, pkey
, certProperties
))
227 throw std::runtime_error("Cannot create ssl certificate or private key.");
229 if (!db
.addCertAndPrivateKey(cert
, pkey
, cert_subject
) && db
.IsEnabledDiskStore())
230 throw std::runtime_error("Cannot add certificate to db.");
233 std::string bufferToWrite
;
234 if (!Ssl::writeCertAndPrivateKeyToMemory(cert
, pkey
, bufferToWrite
))
235 throw std::runtime_error("Cannot write ssl certificate or/and private key to memory.");
237 Ssl::CrtdMessage response_message
;
238 response_message
.setCode("OK");
239 response_message
.setBody(bufferToWrite
);
241 // Use the '\1' char as end-of-message character
242 std::cout
<< response_message
.compose() << '\1' << std::flush
;
249 * This is the external ssl_crtd process.
251 int main(int argc
, char *argv
[])
254 size_t max_db_size
= 0;
255 size_t fs_block_size
= 2048;
257 bool create_new_db
= false;
260 while ((c
= getopt(argc
, argv
, "dcghvs:M:b:n:")) != -1) {
266 if (!parseBytesOptionValue(&fs_block_size
, optarg
)) {
267 throw std::runtime_error("Error when parsing -b options value");
274 if (!parseBytesOptionValue(&max_db_size
, optarg
)) {
275 throw std::runtime_error("Error when parsing -M options value");
279 std::cout
<< "ssl_crtd version " << VERSION
<< std::endl
;
283 create_new_db
= true;
294 std::cout
<< "Initialization SSL db..." << std::endl
;
295 Ssl::CertificateDb::create(db_path
);
296 std::cout
<< "Done" << std::endl
;
301 Ssl::CertificateDb::check(db_path
, max_db_size
);
305 char request
[HELPER_INPUT_BUFFER
];
306 Ssl::CrtdMessage request_message
;
307 Ssl::CrtdMessage::ParseResult parse_result
= Ssl::CrtdMessage::INCOMPLETE
;
309 while (parse_result
== Ssl::CrtdMessage::INCOMPLETE
) {
310 if (fgets(request
, HELPER_INPUT_BUFFER
, stdin
) == NULL
)
312 size_t gcount
= strlen(request
);
313 parse_result
= request_message
.parse(request
, gcount
);
316 if (parse_result
== Ssl::CrtdMessage::ERROR
) {
317 throw std::runtime_error("Cannot parse request message.");
318 } else if (request_message
.getCode() == Ssl::CrtdMessage::code_new_certificate
) {
319 proccessNewRequest(request_message
, db_path
, max_db_size
, fs_block_size
);
321 throw std::runtime_error("Unknown request code: \"" + request_message
.getCode() + "\".");
325 } catch (std::runtime_error
& error
) {
326 std::cerr
<< argv
[0] << ": " << error
.what() << std::endl
;