"Fossies" - the Fresh Open Source Software Archive 
Member "HTTPing-2.9/mssl.c" (29 Oct 2022, 9210 Bytes) of package /linux/www/HTTPing-2.9.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "mssl.c" see the
Fossies "Dox" file reference documentation.
1 /* Released under AGPL v3 with exception for the OpenSSL library. See license.txt */
2 #include <errno.h>
3 #include <libintl.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <sys/types.h>
9 #include <sys/time.h>
10 #include <sys/socket.h>
11 #include <openssl/bio.h>
12 #include <openssl/conf.h>
13 #include <openssl/engine.h>
14 #include <openssl/err.h>
15 #include <openssl/evp.h>
16 #include <openssl/md5.h>
17 #include <openssl/ssl.h>
18 #include <openssl/x509.h>
19
20 #include "error.h"
21 #include "gen.h"
22 #include "mssl.h"
23 #include "tcp.h"
24 #include "io.h"
25 #include "http.h"
26 #include "utils.h"
27 #include "main.h"
28
29 BIO *bio_err = NULL;
30
31 void shutdown_ssl(void)
32 {
33 BIO_free(bio_err);
34
35 ERR_free_strings();
36
37 ERR_remove_state(0);
38 ENGINE_cleanup();
39 CONF_modules_free();
40 EVP_cleanup();
41 CRYPTO_cleanup_all_ex_data();
42 }
43
44 int close_ssl_connection(SSL *const ssl_h)
45 {
46 int rc = SSL_shutdown(ssl_h);
47
48 if (!rc)
49 rc = SSL_shutdown(ssl_h);
50
51 /*
52 ignoring failures: the socket will be closed
53 anyway later on so any openssl failures won't
54 do any harm
55 if (rc == -1)
56 {
57 fprintf(stderr, "SSL_shutdown failed: %s\n", strerror(errno));
58 return -1;
59 }
60 */
61
62 return 0;
63 }
64
65 int READ_SSL(SSL *const ssl_h, char *whereto, int len, const double timeout)
66 {
67 const int cnt = len;
68 const int fd = SSL_get_rfd(ssl_h);
69 double end = get_ts() + timeout;
70
71 while(len > 0 && !got_sigquit)
72 {
73 int rc = -1;
74 fd_set rfds, wfds;
75 struct timeval tv;
76 double now = get_ts(), left = end - now;
77
78 if (left <= 0.0)
79 {
80 set_error(gettext("Time-out on SSL connection"));
81 return -1;
82 }
83
84 FD_ZERO(&rfds);
85 FD_SET(fd, &rfds);
86 FD_ZERO(&wfds); /* yes, see openssl */
87 FD_SET(fd, &wfds);
88
89 tv.tv_sec = left;
90 tv.tv_usec = (left - tv.tv_sec) * 1000000;
91
92 rc = select(fd + 1, &rfds, &wfds, NULL, &tv);
93
94 if (rc == -1)
95 {
96 if (errno != EINTR && errno != EAGAIN)
97 set_error(gettext("READ_SSL: io-error: %s"), strerror(errno));
98
99 return -1;
100 }
101
102 if (rc == 0)
103 {
104 set_error(gettext("Time-out on SSL connection (READ)"));
105 return -1;
106 }
107
108 rc = SSL_read(ssl_h, whereto, len);
109 if (rc == -1)
110 {
111 if (errno != EINTR && errno != EAGAIN)
112 set_error(gettext("READ_SSL: io-error: %s"), strerror(errno));
113
114 return -1;
115 }
116
117 if (rc == 0)
118 return 0;
119
120 whereto += rc;
121 len -= rc;
122 }
123
124 return cnt;
125 }
126
127 int WRITE_SSL(SSL *const ssl_h, const char *wherefrom, int len, const double timeout)
128 {
129 const int cnt = len;
130 const int fd = SSL_get_wfd(ssl_h);
131 double end = get_ts() + timeout;
132
133 while(len > 0 && !got_sigquit)
134 {
135 int rc = -1;
136 fd_set rfds, wfds;
137 struct timeval tv;
138 double now = get_ts(), left = end - now;
139
140 if (left <= 0.0)
141 {
142 set_error(gettext("Time-out on SSL connection"));
143 return -1;
144 }
145
146 FD_ZERO(&rfds); /* yes, that's correct */
147 FD_SET(fd, &rfds);
148 FD_ZERO(&wfds);
149 FD_SET(fd, &wfds);
150
151 tv.tv_sec = left;
152 tv.tv_usec = (left - tv.tv_sec) * 1000000;
153
154 rc = select(fd + 1, &rfds, &wfds, NULL, &tv);
155
156 if (rc == -1)
157 {
158 if (errno != EINTR && errno != EAGAIN)
159 set_error(gettext("WRITE_SSL: io-error: %s"), strerror(errno));
160
161 return -1;
162 }
163
164 if (rc == 0)
165 {
166 set_error(gettext("Time-out on SSL connection (write)"));
167 return -1;
168 }
169
170 rc = SSL_write(ssl_h, wherefrom, len);
171 if (rc == -1)
172 {
173 if (errno != EINTR && errno != EAGAIN)
174 set_error(gettext("WRITE_SSL: io-error: %s"), strerror(errno));
175 return -1;
176 }
177
178 if (rc == 0)
179 return 0;
180
181 wherefrom += rc;
182 len -= rc;
183 }
184
185 return cnt;
186 }
187
188 int connect_ssl(const int fd, SSL_CTX *const client_ctx, SSL **const ssl_h, BIO **const s_bio, const double timeout, double *const ssl_handshake, char *const hostname)
189 {
190 double dstart = get_ts();
191 double end = get_ts() + timeout;
192
193 struct timeval tv;
194 tv.tv_sec = (long)(timeout / 1000.0);
195 tv.tv_usec = (long)(timeout * 1000.0) % 1000000;
196
197 *ssl_handshake = -1.0;
198
199 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv) == -1)
200 {
201 set_error(gettext("problem setting receive timeout (%s)"), strerror(errno));
202 return -1;
203 }
204
205 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv) == -1)
206 {
207 set_error(gettext("problem setting transmit timeout (%s)"), strerror(errno));
208 return -1;
209 }
210
211 *ssl_h = SSL_new(client_ctx);
212 SSL_set_tlsext_host_name(*ssl_h, hostname);
213
214 X509_VERIFY_PARAM *param = SSL_get0_param(*ssl_h);
215 X509_VERIFY_PARAM_set1_host(param, hostname, 0);
216
217 *s_bio = BIO_new_socket(fd, BIO_NOCLOSE);
218 SSL_set_bio(*ssl_h, *s_bio, *s_bio);
219
220 if (set_fd_nonblocking(fd) == -1)
221 return RC_INVAL;
222
223 do
224 {
225 int rc = SSL_connect(*ssl_h);
226
227 if (rc <= 0)
228 {
229 int err = SSL_get_error(*ssl_h, rc);
230
231 if (err == SSL_ERROR_WANT_CONNECT || err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
232 {
233 struct timeval tv;
234 fd_set fds;
235 double left = end - get_ts();
236
237 if (left <= 0)
238 {
239 set_error(gettext("Time-out during SSL handshake"));
240 return -1;
241 }
242
243 tv.tv_sec = left;
244 tv.tv_usec = (left - tv.tv_sec) * 1000000;
245
246 FD_ZERO(&fds);
247 FD_SET(fd, &fds);
248
249 if (err == SSL_ERROR_WANT_READ)
250 rc = select(fd + 1, &fds, NULL, NULL, &tv);
251 else
252 rc = select(fd + 1, NULL, &fds, NULL, &tv);
253 }
254 else
255 {
256 set_error(gettext("SSL handshake error: %s"), ERR_reason_error_string(ERR_get_error()));
257 return -1;
258 }
259 }
260 }
261 while (!SSL_is_init_finished(*ssl_h) && !got_sigquit);
262
263 X509 *cert = SSL_get_peer_certificate(*ssl_h);
264 if (cert)
265 X509_free(cert);
266 else
267 set_error(gettext("SSL no peer certificate"));
268
269 long v = SSL_get_verify_result(*ssl_h);
270 if (v != X509_V_OK)
271 set_error(gettext("SSL certificate validation failed: %s"), X509_verify_cert_error_string(v));
272
273 if (got_sigquit)
274 return -1;
275
276 *ssl_handshake = get_ts() - dstart;
277
278 if (set_fd_blocking(fd) == -1)
279 return -1;
280
281 return 0;
282 }
283
284 SSL_CTX * initialize_ctx(const char ask_compression, const char *ca_path)
285 {
286 const SSL_METHOD *meth = NULL;
287 SSL_CTX *ctx = NULL;
288
289 if (!bio_err)
290 {
291 SSL_library_init();
292 SSL_load_error_strings();
293 ERR_load_crypto_strings();
294
295 /* error write context */
296 bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
297 }
298
299 /* create context */
300 meth = SSLv23_method();
301 ctx = SSL_CTX_new(meth);
302
303 if (ca_path == NULL)
304 #if defined(__NetBSD__)
305 ca_path = "/etc/openssl/certs";
306 #else
307 ca_path = "/etc/ssl/certs";
308 #endif
309
310 SSL_CTX_load_verify_locations(ctx, NULL, ca_path);
311
312 #ifdef SSL_OP_NO_COMPRESSION
313 if (!ask_compression)
314 SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
315 #endif
316
317 return ctx;
318 }
319
320 char * get_fingerprint(SSL *const ssl_h)
321 {
322 char *string = NULL;
323
324 unsigned char fp_digest[EVP_MAX_MD_SIZE];
325 X509 *x509_data = SSL_get_peer_certificate(ssl_h);
326
327 if (x509_data)
328 {
329 unsigned int fp_digest_size = sizeof fp_digest;
330
331 memset(fp_digest, 0x00, fp_digest_size);
332
333 if (X509_digest(x509_data, EVP_md5(), fp_digest, &fp_digest_size))
334 {
335 string = (char *)malloc(MD5_DIGEST_LENGTH * 3 + 1);
336 if (string)
337 {
338 int loop, pos =0;
339
340 for(loop=0; loop<MD5_DIGEST_LENGTH; loop++)
341 {
342 if (loop)
343 pos += sprintf(&string[pos], ":%02x", fp_digest[loop]);
344 else
345 pos = sprintf(&string[pos], "%02x", fp_digest[loop]);
346 }
347 }
348 }
349
350 X509_free(x509_data);
351 }
352
353 return string;
354 }
355
356 int connect_ssl_proxy(const int fd, struct addrinfo *const ai, const double timeout, const char *const proxy_user, const char *const proxy_password, const char *const hostname, const int portnr, char *const tfo)
357 {
358 int rc = -1;
359 char request_headers[4096] = { 0 };
360 int request_headers_len = -1;
361 char rh_sent = 0;
362 char *response_headers = NULL, *code = NULL, *term = NULL;
363
364 request_headers_len = snprintf(request_headers, sizeof request_headers, "CONNECT %s:%d HTTP/1.1\r\nUser-Agent: HTTPing v" VERSION \
365 "\r\nProxy-Connection: keep-alive\r\nConnection: keep-alive\r\nHost: %s\r\n", hostname, portnr, hostname);
366
367 if (proxy_user)
368 {
369 char ppa_string[256] = { 0 };
370 char b64_ppa_string[512] = { 0 };
371
372 sprintf(ppa_string, "%s:%s", proxy_user, proxy_password);
373 enc_b64(ppa_string, strlen(ppa_string), b64_ppa_string);
374 request_headers_len += snprintf(&request_headers[request_headers_len], sizeof request_headers - request_headers_len, "Proxy-Authorization: Basic %s\r\n", b64_ppa_string);
375 }
376
377 request_headers_len += snprintf(&request_headers[request_headers_len], sizeof request_headers - request_headers_len, "\r\n");
378
379 if ((rc = connect_to(fd, ai, timeout, tfo, request_headers, request_headers_len, &rh_sent)) == -1)
380 return rc;
381
382 if (!rh_sent)
383 {
384 if ((rc = mywrite(fd, request_headers, request_headers_len, timeout)) < RC_OK)
385 {
386 set_error(gettext("Problem sending request to proxy"));
387 return rc;
388 }
389 }
390
391 rc = dumb_get_HTTP_headers(fd, &response_headers, timeout);
392 if (rc != RC_OK)
393 {
394 free(response_headers);
395 set_error(gettext("Problem retrieving proxy response"));
396 return rc;
397 }
398
399 term = strchr(response_headers, '\r');
400 if (!term)
401 term = strchr(response_headers, '\n');
402 if (term)
403 *term = 0x00;
404
405 code = strchr(response_headers, ' ');
406 if (!code)
407 {
408 free(response_headers);
409 set_error(gettext("Invalid proxy response headers"));
410 return RC_INVAL;
411 }
412
413 if (atoi(code + 1) != 200)
414 {
415 free(response_headers);
416 set_error(gettext("Proxy indicated error: %s"), code + 1);
417 return RC_INVAL;
418 }
419
420 free(response_headers);
421
422 return RC_OK;
423 }