2 #include "helpers/defines.h"
3 #include "ssl/certificate_db.h"
4 #include "ssl/crtd_message.h"
16 \defgroup ssl_crtd ssl_crtd
17 \ingroup ExternalPrograms
19 Because the standart generation of ssl certificate for
20 sslBump feature, Squid must use external proccess to
21 actually make these calls. This process generate new ssl
22 certificates and worked with ssl certificates disk cache.
23 Typically there will be five ssl_crtd processes spawned
24 from Squid. Communication occurs via TCP sockets bound
25 to the loopback interface. The class in helper.h are
26 primally concerned with starting and stopping the ssl_crtd.
27 Reading and writing to and from the ssl_crtd occurs in the
28 \link IPCacheAPI IP\endlink and the dnsservers occurs in
29 the \link IPCacheAPI IP\endlink and \link FQDNCacheAPI
30 FQDN\endlink cache modules.
32 \section ssl_crtdInterface Command Line Interface
34 usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size
37 -s ssl_storage_path Path to specific disk storage of ssl server
39 -M storage_max_size max size of ssl certificates storage.
40 -b fs_block_size File system block size in bytes. Need for processing
41 natural size of certificate on disk. Default value is
44 After running write requests in the next format:
45 <request code><whitespace><body_len><whitespace><body>
46 There are two kind of request now:
47 new_certificate 14 host=host.dom
48 Create new private key and selfsigned certificate for "host.dom".
50 new_certificate xxx host=host.dom
51 -----BEGIN CERTIFICATE-----
53 -----END CERTIFICATE-----
54 -----BEGIN RSA PRIVATE KEY-----
56 -----END RSA PRIVATE KEY-----
57 Create new private key and certificate request for "host.dom".
58 Sign new request by received certificate and private key.
60 usage: ssl_crtd -c -s ssl_store_path\n
61 -c Init ssl db directories and exit.
66 static const char *const B_KBYTES_STR
= "KB";
67 static const char *const B_MBYTES_STR
= "MB";
68 static const char *const B_GBYTES_STR
= "GB";
69 static const char *const B_BYTES_STR
= "B";
75 time_t getCurrentTime(void)
77 struct timeval current_time
;
78 #if GETTIMEOFDAY_NO_TZP
79 gettimeofday(¤t_time
);
81 gettimeofday(¤t_time
, NULL
);
83 return current_time
.tv_sec
;
88 * Parse bytes unit. It would be one of the next value: MB, GB, KB or B.
89 * This function is caseinsensitive.
91 static size_t parseBytesUnits(const char * unit
)
93 if (!strncasecmp(unit
, B_BYTES_STR
, strlen(B_BYTES_STR
)) ||
94 !strncasecmp(unit
, "", strlen(unit
)))
97 if (!strncasecmp(unit
, B_KBYTES_STR
, strlen(B_KBYTES_STR
)))
100 if (!strncasecmp(unit
, B_MBYTES_STR
, strlen(B_MBYTES_STR
)))
103 if (!strncasecmp(unit
, B_GBYTES_STR
, strlen(B_GBYTES_STR
)))
106 std::cerr
<< "WARNING: Unknown bytes unit '" << unit
<< "'" << std::endl
;
113 * Parse uninterrapted string of bytes value. It looks like "4MB".
115 static bool parseBytesOptionValue(size_t * bptr
, char const * value
)
117 // Find number from string beginning.
118 char const * number_begin
= value
;
119 char const * number_end
= value
;
121 while ((*number_end
>= '0' && *number_end
<= '9')) {
125 std::string
number(number_begin
, number_end
- number_begin
);
126 std::istringstream
in(number
);
132 if ((m
= parseBytesUnits(number_end
)) == 0) {
136 *bptr
= static_cast<size_t>(m
* d
);
137 if (static_cast<long>(*bptr
* 2) != m
* d
* 2)
145 * Print help using response code.
149 std::string example_host_name
= "host.dom";
150 std::string request_string
= Ssl::CrtdMessage::param_host
+ "=" + example_host_name
;
151 std::stringstream request_string_size_stream
;
152 request_string_size_stream
<< request_string
.length();
153 std::string help_string
=
154 "usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size\n"
157 "\t-s ssl_storage_path Path to specific disk storage of ssl server\n"
159 "\t-M storage_max_size max size of ssl certificates storage.\n"
160 "\t-b fs_block_size File system block size in bytes. Need for processing\n"
161 "\t natural size of certificate on disk. Default value is\n"
164 "After running write requests in the next format:\n"
165 "<request code><whitespace><body_len><whitespace><body>\n"
166 "There are two kind of request now:\n"
167 + Ssl::CrtdMessage::code_new_certificate
+ " " + request_string_size_stream
.str() + " " + request_string
+ "\n" +
168 "\tCreate new private key and selfsigned certificate for \"host.dom\".\n"
169 + Ssl::CrtdMessage::code_new_certificate
+ " xxx " + request_string
+ "\n" +
170 "-----BEGIN CERTIFICATE-----\n"
172 "-----END CERTIFICATE-----\n"
173 "-----BEGIN RSA PRIVATE KEY-----\n"
175 "-----END RSA PRIVATE KEY-----\n"
176 "\tCreate new private key and certificate request for \"host.dom\"\n"
177 "\tSign new request by received certificate and private key.\n"
178 "usage: ssl_crtd -c -s ssl_store_path\n"
179 "\t-c Init ssl db directories and exit.\n";
180 std::cerr
<< help_string
<< std::endl
;
185 * Proccess new request message.
187 static bool proccessNewRequest(Ssl::CrtdMessage
& request_message
, std::string
const & db_path
, size_t max_db_size
, size_t fs_block_size
)
189 Ssl::CertificateProperties certProperties
;
191 if (!request_message
.parseRequest(certProperties
, error
))
192 throw std::runtime_error("Error while parsing the crtd request: " + error
);
194 Ssl::CertificateDb
db(db_path
, max_db_size
, fs_block_size
);
196 Ssl::X509_Pointer cert
;
197 Ssl::EVP_PKEY_Pointer pkey
;
198 std::string
&cert_subject
= certProperties
.dbKey();
200 db
.find(cert_subject
, cert
, pkey
);
203 if (!Ssl::certificateMatchesProperties(cert
.get(), certProperties
)) {
204 // The certificate changed (renewed or other reason).
205 // Generete a new one with the updated fields.
208 db
.purgeCert(cert_subject
);
212 if (!cert
|| !pkey
) {
213 if (!Ssl::generateSslCertificate(cert
, pkey
, certProperties
))
214 throw std::runtime_error("Cannot create ssl certificate or private key.");
216 if (!db
.addCertAndPrivateKey(cert
, pkey
, cert_subject
) && db
.IsEnabledDiskStore())
217 throw std::runtime_error("Cannot add certificate to db.");
220 std::string bufferToWrite
;
221 if (!Ssl::writeCertAndPrivateKeyToMemory(cert
, pkey
, bufferToWrite
))
222 throw std::runtime_error("Cannot write ssl certificate or/and private key to memory.");
224 Ssl::CrtdMessage
response_message(Ssl::CrtdMessage::REPLY
);
225 response_message
.setCode("OK");
226 response_message
.setBody(bufferToWrite
);
228 // Use the '\1' char as end-of-message character
229 std::cout
<< response_message
.compose() << '\1' << std::flush
;
236 * This is the external ssl_crtd process.
238 int main(int argc
, char *argv
[])
241 size_t max_db_size
= 0;
242 size_t fs_block_size
= 2048;
244 bool create_new_db
= false;
247 while ((c
= getopt(argc
, argv
, "dcghvs:M:b:n:")) != -1) {
253 if (!parseBytesOptionValue(&fs_block_size
, optarg
)) {
254 throw std::runtime_error("Error when parsing -b options value");
261 if (!parseBytesOptionValue(&max_db_size
, optarg
)) {
262 throw std::runtime_error("Error when parsing -M options value");
266 std::cout
<< "ssl_crtd version " << VERSION
<< std::endl
;
270 create_new_db
= true;
281 std::cout
<< "Initialization SSL db..." << std::endl
;
282 Ssl::CertificateDb::create(db_path
);
283 std::cout
<< "Done" << std::endl
;
288 Ssl::CertificateDb::check(db_path
, max_db_size
);
292 char request
[HELPER_INPUT_BUFFER
];
293 Ssl::CrtdMessage
request_message(Ssl::CrtdMessage::REQUEST
);
294 Ssl::CrtdMessage::ParseResult parse_result
= Ssl::CrtdMessage::INCOMPLETE
;
296 while (parse_result
== Ssl::CrtdMessage::INCOMPLETE
) {
297 if (fgets(request
, HELPER_INPUT_BUFFER
, stdin
) == NULL
)
299 size_t gcount
= strlen(request
);
300 parse_result
= request_message
.parse(request
, gcount
);
303 if (parse_result
== Ssl::CrtdMessage::ERROR
) {
304 throw std::runtime_error("Cannot parse request message.");
305 } else if (request_message
.getCode() == Ssl::CrtdMessage::code_new_certificate
) {
306 proccessNewRequest(request_message
, db_path
, max_db_size
, fs_block_size
);
308 throw std::runtime_error("Unknown request code: \"" + request_message
.getCode() + "\".");
312 } catch (std::runtime_error
& error
) {
313 std::cerr
<< argv
[0] << ": " << error
.what() << std::endl
;