2 #include "helpers/defines.h"
3 #include "ssl/certificate_db.h"
4 #include "ssl/crtd_message.h"
26 \defgroup ssl_crtd ssl_crtd
27 \ingroup ExternalPrograms
29 Because the standart generation of ssl certificate for
30 sslBump feature, Squid must use external proccess to
31 actually make these calls. This process generate new ssl
32 certificates and worked with ssl certificates disk cache.
33 Typically there will be five ssl_crtd processes spawned
34 from Squid. Communication occurs via TCP sockets bound
35 to the loopback interface. The class in helper.h are
36 primally concerned with starting and stopping the ssl_crtd.
37 Reading and writing to and from the ssl_crtd occurs in the
38 \link IPCacheAPI IP\endlink and the dnsservers occurs in
39 the \link IPCacheAPI IP\endlink and \link FQDNCacheAPI
40 FQDN\endlink cache modules.
42 \section ssl_crtdInterface Command Line Interface
44 usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size
47 -s ssl_storage_path Path to specific disk storage of ssl server
49 -M storage_max_size max size of ssl certificates storage.
50 -b fs_block_size File system block size in bytes. Need for processing
51 natural size of certificate on disk. Default value is
54 After running write requests in the next format:
55 <request code><whitespace><body_len><whitespace><body>
56 There are two kind of request now:
57 new_certificate 14 host=host.dom
58 Create new private key and selfsigned certificate for "host.dom".
60 new_certificate xxx host=host.dom
61 -----BEGIN CERTIFICATE-----
63 -----END CERTIFICATE-----
64 -----BEGIN RSA PRIVATE KEY-----
66 -----END RSA PRIVATE KEY-----
67 Create new private key and certificate request for "host.dom".
68 Sign new request by received certificate and private key.
70 usage: ssl_crtd -c -s ssl_store_path\n
71 -c Init ssl db directories and exit.
76 static const char *const B_KBYTES_STR
= "KB";
77 static const char *const B_MBYTES_STR
= "MB";
78 static const char *const B_GBYTES_STR
= "GB";
79 static const char *const B_BYTES_STR
= "B";
85 time_t getCurrentTime(void)
87 struct timeval current_time
;
88 #if GETTIMEOFDAY_NO_TZP
89 gettimeofday(¤t_time
);
91 gettimeofday(¤t_time
, NULL
);
93 return current_time
.tv_sec
;
98 * Parse bytes unit. It would be one of the next value: MB, GB, KB or B.
99 * This function is caseinsensitive.
101 static size_t parseBytesUnits(const char * unit
)
103 if (!strncasecmp(unit
, B_BYTES_STR
, strlen(B_BYTES_STR
)) ||
104 !strncasecmp(unit
, "", strlen(unit
)))
107 if (!strncasecmp(unit
, B_KBYTES_STR
, strlen(B_KBYTES_STR
)))
110 if (!strncasecmp(unit
, B_MBYTES_STR
, strlen(B_MBYTES_STR
)))
113 if (!strncasecmp(unit
, B_GBYTES_STR
, strlen(B_GBYTES_STR
)))
116 std::cerr
<< "WARNING: Unknown bytes unit '" << unit
<< "'" << std::endl
;
123 * Parse uninterrapted string of bytes value. It looks like "4MB".
125 static bool parseBytesOptionValue(size_t * bptr
, char const * value
)
127 // Find number from string beginning.
128 char const * number_begin
= value
;
129 char const * number_end
= value
;
131 while ((*number_end
>= '0' && *number_end
<= '9')) {
135 std::string
number(number_begin
, number_end
- number_begin
);
136 std::istringstream
in(number
);
142 if ((m
= parseBytesUnits(number_end
)) == 0) {
146 *bptr
= static_cast<size_t>(m
* d
);
147 if (static_cast<long>(*bptr
* 2) != m
* d
* 2)
155 * Print help using response code.
159 std::string example_host_name
= "host.dom";
160 std::string request_string
= Ssl::CrtdMessage::param_host
+ "=" + example_host_name
;
161 std::stringstream request_string_size_stream
;
162 request_string_size_stream
<< request_string
.length();
163 std::string help_string
=
164 "usage: ssl_crtd -hv -s ssl_storage_path -M storage_max_size\n"
167 "\t-s ssl_storage_path Path to specific disk storage of ssl server\n"
169 "\t-M storage_max_size max size of ssl certificates storage.\n"
170 "\t-b fs_block_size File system block size in bytes. Need for processing\n"
171 "\t natural size of certificate on disk. Default value is\n"
174 "After running write requests in the next format:\n"
175 "<request code><whitespace><body_len><whitespace><body>\n"
176 "There are two kind of request now:\n"
177 + Ssl::CrtdMessage::code_new_certificate
+ " " + request_string_size_stream
.str() + " " + request_string
+ "\n" +
178 "\tCreate new private key and selfsigned certificate for \"host.dom\".\n"
179 + Ssl::CrtdMessage::code_new_certificate
+ " xxx " + request_string
+ "\n" +
180 "-----BEGIN CERTIFICATE-----\n"
182 "-----END CERTIFICATE-----\n"
183 "-----BEGIN RSA PRIVATE KEY-----\n"
185 "-----END RSA PRIVATE KEY-----\n"
186 "\tCreate new private key and certificate request for \"host.dom\"\n"
187 "\tSign new request by received certificate and private key.\n"
188 "usage: ssl_crtd -c -s ssl_store_path\n"
189 "\t-c Init ssl db directories and exit.\n";
190 std::cerr
<< help_string
<< std::endl
;
195 * Proccess new request message.
197 static bool proccessNewRequest(Ssl::CrtdMessage
& request_message
, std::string
const & db_path
, size_t max_db_size
, size_t fs_block_size
)
199 Ssl::CertificateProperties certProperties
;
201 if (!request_message
.parseRequest(certProperties
, error
))
202 throw std::runtime_error("Error while parsing the crtd request: " + error
);
204 Ssl::CertificateDb
db(db_path
, max_db_size
, fs_block_size
);
206 Ssl::X509_Pointer cert
;
207 Ssl::EVP_PKEY_Pointer pkey
;
208 std::string
&cert_subject
= certProperties
.dbKey();
210 db
.find(cert_subject
, cert
, pkey
);
213 if (!Ssl::certificateMatchesProperties(cert
.get(), certProperties
)) {
214 // The certificate changed (renewed or other reason).
215 // Generete a new one with the updated fields.
218 db
.purgeCert(cert_subject
);
222 if (!cert
|| !pkey
) {
223 if (!Ssl::generateSslCertificate(cert
, pkey
, certProperties
))
224 throw std::runtime_error("Cannot create ssl certificate or private key.");
226 if (!db
.addCertAndPrivateKey(cert
, pkey
, cert_subject
) && db
.IsEnabledDiskStore())
227 throw std::runtime_error("Cannot add certificate to db.");
230 std::string bufferToWrite
;
231 if (!Ssl::writeCertAndPrivateKeyToMemory(cert
, pkey
, bufferToWrite
))
232 throw std::runtime_error("Cannot write ssl certificate or/and private key to memory.");
234 Ssl::CrtdMessage
response_message(Ssl::CrtdMessage::REPLY
);
235 response_message
.setCode("OK");
236 response_message
.setBody(bufferToWrite
);
238 // Use the '\1' char as end-of-message character
239 std::cout
<< response_message
.compose() << '\1' << std::flush
;
246 * This is the external ssl_crtd process.
248 int main(int argc
, char *argv
[])
251 size_t max_db_size
= 0;
252 size_t fs_block_size
= 2048;
254 bool create_new_db
= false;
257 while ((c
= getopt(argc
, argv
, "dcghvs:M:b:n:")) != -1) {
263 if (!parseBytesOptionValue(&fs_block_size
, optarg
)) {
264 throw std::runtime_error("Error when parsing -b options value");
271 if (!parseBytesOptionValue(&max_db_size
, optarg
)) {
272 throw std::runtime_error("Error when parsing -M options value");
276 std::cout
<< "ssl_crtd version " << VERSION
<< std::endl
;
280 create_new_db
= true;
291 std::cout
<< "Initialization SSL db..." << std::endl
;
292 Ssl::CertificateDb::create(db_path
);
293 std::cout
<< "Done" << std::endl
;
298 Ssl::CertificateDb::check(db_path
, max_db_size
);
302 char request
[HELPER_INPUT_BUFFER
];
303 Ssl::CrtdMessage
request_message(Ssl::CrtdMessage::REQUEST
);
304 Ssl::CrtdMessage::ParseResult parse_result
= Ssl::CrtdMessage::INCOMPLETE
;
306 while (parse_result
== Ssl::CrtdMessage::INCOMPLETE
) {
307 if (fgets(request
, HELPER_INPUT_BUFFER
, stdin
) == NULL
)
309 size_t gcount
= strlen(request
);
310 parse_result
= request_message
.parse(request
, gcount
);
313 if (parse_result
== Ssl::CrtdMessage::ERROR
) {
314 throw std::runtime_error("Cannot parse request message.");
315 } else if (request_message
.getCode() == Ssl::CrtdMessage::code_new_certificate
) {
316 proccessNewRequest(request_message
, db_path
, max_db_size
, fs_block_size
);
318 throw std::runtime_error("Unknown request code: \"" + request_message
.getCode() + "\".");
322 } catch (std::runtime_error
& error
) {
323 std::cerr
<< argv
[0] << ": " << error
.what() << std::endl
;