1c43e99fdSEd Maste /*
2c43e99fdSEd Maste   This is an example of how to hook up evhttp with bufferevent_ssl
3c43e99fdSEd Maste 
4c43e99fdSEd Maste   It just GETs an https URL given on the command-line and prints the response
5c43e99fdSEd Maste   body to stdout.
6c43e99fdSEd Maste 
7c43e99fdSEd Maste   Actually, it also accepts plain http URLs to make it easy to compare http vs
8c43e99fdSEd Maste   https code paths.
9c43e99fdSEd Maste 
10c43e99fdSEd Maste   Loosely based on le-proxy.c.
11c43e99fdSEd Maste  */
12c43e99fdSEd Maste 
13c43e99fdSEd Maste // Get rid of OSX 10.7 and greater deprecation warnings.
14c43e99fdSEd Maste #if defined(__APPLE__) && defined(__clang__)
15c43e99fdSEd Maste #pragma clang diagnostic ignored "-Wdeprecated-declarations"
16c43e99fdSEd Maste #endif
17c43e99fdSEd Maste 
18c43e99fdSEd Maste #include <stdio.h>
19c43e99fdSEd Maste #include <assert.h>
20c43e99fdSEd Maste #include <stdlib.h>
21c43e99fdSEd Maste #include <string.h>
22c43e99fdSEd Maste #include <errno.h>
23c43e99fdSEd Maste 
24c43e99fdSEd Maste #ifdef _WIN32
25c43e99fdSEd Maste #include <winsock2.h>
26c43e99fdSEd Maste #include <ws2tcpip.h>
27c43e99fdSEd Maste 
28c43e99fdSEd Maste #define snprintf _snprintf
29c43e99fdSEd Maste #define strcasecmp _stricmp
30c43e99fdSEd Maste #else
31c43e99fdSEd Maste #include <sys/socket.h>
32c43e99fdSEd Maste #include <netinet/in.h>
33c43e99fdSEd Maste #endif
34c43e99fdSEd Maste 
35c43e99fdSEd Maste #include <event2/bufferevent_ssl.h>
36c43e99fdSEd Maste #include <event2/bufferevent.h>
37c43e99fdSEd Maste #include <event2/buffer.h>
38c43e99fdSEd Maste #include <event2/listener.h>
39c43e99fdSEd Maste #include <event2/util.h>
40c43e99fdSEd Maste #include <event2/http.h>
41c43e99fdSEd Maste 
42c43e99fdSEd Maste #include <openssl/ssl.h>
43c43e99fdSEd Maste #include <openssl/err.h>
44c43e99fdSEd Maste #include <openssl/rand.h>
45c43e99fdSEd Maste 
46c43e99fdSEd Maste #include "openssl_hostname_validation.h"
47c43e99fdSEd Maste 
48c43e99fdSEd Maste static int ignore_cert = 0;
49c43e99fdSEd Maste 
50c43e99fdSEd Maste static void
http_request_done(struct evhttp_request * req,void * ctx)51c43e99fdSEd Maste http_request_done(struct evhttp_request *req, void *ctx)
52c43e99fdSEd Maste {
53c43e99fdSEd Maste 	char buffer[256];
54c43e99fdSEd Maste 	int nread;
55c43e99fdSEd Maste 
56*b50261e2SCy Schubert 	if (!req || !evhttp_request_get_response_code(req)) {
57c43e99fdSEd Maste 		/* If req is NULL, it means an error occurred, but
58c43e99fdSEd Maste 		 * sadly we are mostly left guessing what the error
59c43e99fdSEd Maste 		 * might have been.  We'll do our best... */
60c43e99fdSEd Maste 		struct bufferevent *bev = (struct bufferevent *) ctx;
61c43e99fdSEd Maste 		unsigned long oslerr;
62c43e99fdSEd Maste 		int printed_err = 0;
63c43e99fdSEd Maste 		int errcode = EVUTIL_SOCKET_ERROR();
64c43e99fdSEd Maste 		fprintf(stderr, "some request failed - no idea which one though!\n");
65c43e99fdSEd Maste 		/* Print out the OpenSSL error queue that libevent
66c43e99fdSEd Maste 		 * squirreled away for us, if any. */
67c43e99fdSEd Maste 		while ((oslerr = bufferevent_get_openssl_error(bev))) {
68c43e99fdSEd Maste 			ERR_error_string_n(oslerr, buffer, sizeof(buffer));
69c43e99fdSEd Maste 			fprintf(stderr, "%s\n", buffer);
70c43e99fdSEd Maste 			printed_err = 1;
71c43e99fdSEd Maste 		}
72c43e99fdSEd Maste 		/* If the OpenSSL error queue was empty, maybe it was a
73c43e99fdSEd Maste 		 * socket error; let's try printing that. */
74c43e99fdSEd Maste 		if (! printed_err)
75c43e99fdSEd Maste 			fprintf(stderr, "socket error = %s (%d)\n",
76c43e99fdSEd Maste 				evutil_socket_error_to_string(errcode),
77c43e99fdSEd Maste 				errcode);
78c43e99fdSEd Maste 		return;
79c43e99fdSEd Maste 	}
80c43e99fdSEd Maste 
81c43e99fdSEd Maste 	fprintf(stderr, "Response line: %d %s\n",
82c43e99fdSEd Maste 	    evhttp_request_get_response_code(req),
83c43e99fdSEd Maste 	    evhttp_request_get_response_code_line(req));
84c43e99fdSEd Maste 
85c43e99fdSEd Maste 	while ((nread = evbuffer_remove(evhttp_request_get_input_buffer(req),
86c43e99fdSEd Maste 		    buffer, sizeof(buffer)))
87c43e99fdSEd Maste 	       > 0) {
88c43e99fdSEd Maste 		/* These are just arbitrary chunks of 256 bytes.
89c43e99fdSEd Maste 		 * They are not lines, so we can't treat them as such. */
90c43e99fdSEd Maste 		fwrite(buffer, nread, 1, stdout);
91c43e99fdSEd Maste 	}
92c43e99fdSEd Maste }
93c43e99fdSEd Maste 
94c43e99fdSEd Maste static void
syntax(void)95c43e99fdSEd Maste syntax(void)
96c43e99fdSEd Maste {
97c43e99fdSEd Maste 	fputs("Syntax:\n", stderr);
98c43e99fdSEd Maste 	fputs("   https-client -url <https-url> [-data data-file.bin] [-ignore-cert] [-retries num] [-timeout sec] [-crt crt]\n", stderr);
99c43e99fdSEd Maste 	fputs("Example:\n", stderr);
100c43e99fdSEd Maste 	fputs("   https-client -url https://ip.appspot.com/\n", stderr);
101c43e99fdSEd Maste }
102c43e99fdSEd Maste 
103c43e99fdSEd Maste static void
err(const char * msg)104c43e99fdSEd Maste err(const char *msg)
105c43e99fdSEd Maste {
106c43e99fdSEd Maste 	fputs(msg, stderr);
107c43e99fdSEd Maste }
108c43e99fdSEd Maste 
109c43e99fdSEd Maste static void
err_openssl(const char * func)110c43e99fdSEd Maste err_openssl(const char *func)
111c43e99fdSEd Maste {
112c43e99fdSEd Maste 	fprintf (stderr, "%s failed:\n", func);
113c43e99fdSEd Maste 
114c43e99fdSEd Maste 	/* This is the OpenSSL function that prints the contents of the
115c43e99fdSEd Maste 	 * error stack to the specified file handle. */
116c43e99fdSEd Maste 	ERR_print_errors_fp (stderr);
117c43e99fdSEd Maste 
118c43e99fdSEd Maste 	exit(1);
119c43e99fdSEd Maste }
120c43e99fdSEd Maste 
121c43e99fdSEd Maste /* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */
cert_verify_callback(X509_STORE_CTX * x509_ctx,void * arg)122c43e99fdSEd Maste static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
123c43e99fdSEd Maste {
124c43e99fdSEd Maste 	char cert_str[256];
125c43e99fdSEd Maste 	const char *host = (const char *) arg;
126c43e99fdSEd Maste 	const char *res_str = "X509_verify_cert failed";
127c43e99fdSEd Maste 	HostnameValidationResult res = Error;
128c43e99fdSEd Maste 
129c43e99fdSEd Maste 	/* This is the function that OpenSSL would call if we hadn't called
130c43e99fdSEd Maste 	 * SSL_CTX_set_cert_verify_callback().  Therefore, we are "wrapping"
131c43e99fdSEd Maste 	 * the default functionality, rather than replacing it. */
132c43e99fdSEd Maste 	int ok_so_far = 0;
133c43e99fdSEd Maste 
134c43e99fdSEd Maste 	X509 *server_cert = NULL;
135c43e99fdSEd Maste 
136c43e99fdSEd Maste 	if (ignore_cert) {
137c43e99fdSEd Maste 		return 1;
138c43e99fdSEd Maste 	}
139c43e99fdSEd Maste 
140c43e99fdSEd Maste 	ok_so_far = X509_verify_cert(x509_ctx);
141c43e99fdSEd Maste 
142c43e99fdSEd Maste 	server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
143c43e99fdSEd Maste 
144c43e99fdSEd Maste 	if (ok_so_far) {
145c43e99fdSEd Maste 		res = validate_hostname(host, server_cert);
146c43e99fdSEd Maste 
147c43e99fdSEd Maste 		switch (res) {
148c43e99fdSEd Maste 		case MatchFound:
149c43e99fdSEd Maste 			res_str = "MatchFound";
150c43e99fdSEd Maste 			break;
151c43e99fdSEd Maste 		case MatchNotFound:
152c43e99fdSEd Maste 			res_str = "MatchNotFound";
153c43e99fdSEd Maste 			break;
154c43e99fdSEd Maste 		case NoSANPresent:
155c43e99fdSEd Maste 			res_str = "NoSANPresent";
156c43e99fdSEd Maste 			break;
157c43e99fdSEd Maste 		case MalformedCertificate:
158c43e99fdSEd Maste 			res_str = "MalformedCertificate";
159c43e99fdSEd Maste 			break;
160c43e99fdSEd Maste 		case Error:
161c43e99fdSEd Maste 			res_str = "Error";
162c43e99fdSEd Maste 			break;
163c43e99fdSEd Maste 		default:
164c43e99fdSEd Maste 			res_str = "WTF!";
165c43e99fdSEd Maste 			break;
166c43e99fdSEd Maste 		}
167c43e99fdSEd Maste 	}
168c43e99fdSEd Maste 
169c43e99fdSEd Maste 	X509_NAME_oneline(X509_get_subject_name (server_cert),
170c43e99fdSEd Maste 			  cert_str, sizeof (cert_str));
171c43e99fdSEd Maste 
172c43e99fdSEd Maste 	if (res == MatchFound) {
173c43e99fdSEd Maste 		printf("https server '%s' has this certificate, "
174c43e99fdSEd Maste 		       "which looks good to me:\n%s\n",
175c43e99fdSEd Maste 		       host, cert_str);
176c43e99fdSEd Maste 		return 1;
177c43e99fdSEd Maste 	} else {
178c43e99fdSEd Maste 		printf("Got '%s' for hostname '%s' and certificate:\n%s\n",
179c43e99fdSEd Maste 		       res_str, host, cert_str);
180c43e99fdSEd Maste 		return 0;
181c43e99fdSEd Maste 	}
182c43e99fdSEd Maste }
183*b50261e2SCy Schubert 
184*b50261e2SCy Schubert #ifdef _WIN32
185*b50261e2SCy Schubert static int
add_cert_for_store(X509_STORE * store,const char * name)186*b50261e2SCy Schubert add_cert_for_store(X509_STORE *store, const char *name)
187*b50261e2SCy Schubert {
188*b50261e2SCy Schubert 	HCERTSTORE sys_store = NULL;
189*b50261e2SCy Schubert 	PCCERT_CONTEXT ctx = NULL;
190*b50261e2SCy Schubert 	int r = 0;
191*b50261e2SCy Schubert 
192*b50261e2SCy Schubert 	sys_store = CertOpenSystemStore(0, name);
193*b50261e2SCy Schubert 	if (!sys_store) {
194*b50261e2SCy Schubert 		err("failed to open system certificate store");
195*b50261e2SCy Schubert 		return -1;
196*b50261e2SCy Schubert 	}
197*b50261e2SCy Schubert 	while ((ctx = CertEnumCertificatesInStore(sys_store, ctx))) {
198*b50261e2SCy Schubert 		X509 *x509 = d2i_X509(NULL, (unsigned char const **)&ctx->pbCertEncoded,
199*b50261e2SCy Schubert 			ctx->cbCertEncoded);
200*b50261e2SCy Schubert 		if (x509) {
201*b50261e2SCy Schubert 			X509_STORE_add_cert(store, x509);
202*b50261e2SCy Schubert 			X509_free(x509);
203*b50261e2SCy Schubert 		} else {
204*b50261e2SCy Schubert 			r = -1;
205*b50261e2SCy Schubert 			err_openssl("d2i_X509");
206*b50261e2SCy Schubert 			break;
207*b50261e2SCy Schubert 		}
208*b50261e2SCy Schubert 	}
209*b50261e2SCy Schubert 	CertCloseStore(sys_store, 0);
210*b50261e2SCy Schubert 	return r;
211*b50261e2SCy Schubert }
212c43e99fdSEd Maste #endif
213c43e99fdSEd Maste 
214c43e99fdSEd Maste int
main(int argc,char ** argv)215c43e99fdSEd Maste main(int argc, char **argv)
216c43e99fdSEd Maste {
217c43e99fdSEd Maste 	int r;
218*b50261e2SCy Schubert 	struct event_base *base = NULL;
219c43e99fdSEd Maste 	struct evhttp_uri *http_uri = NULL;
220c43e99fdSEd Maste 	const char *url = NULL, *data_file = NULL;
221*b50261e2SCy Schubert 	const char *crt = NULL;
222c43e99fdSEd Maste 	const char *scheme, *host, *path, *query;
223c43e99fdSEd Maste 	char uri[256];
224c43e99fdSEd Maste 	int port;
225c43e99fdSEd Maste 	int retries = 0;
226c43e99fdSEd Maste 	int timeout = -1;
227c43e99fdSEd Maste 
228c43e99fdSEd Maste 	SSL_CTX *ssl_ctx = NULL;
229c43e99fdSEd Maste 	SSL *ssl = NULL;
230c43e99fdSEd Maste 	struct bufferevent *bev;
231c43e99fdSEd Maste 	struct evhttp_connection *evcon = NULL;
232c43e99fdSEd Maste 	struct evhttp_request *req;
233c43e99fdSEd Maste 	struct evkeyvalq *output_headers;
234c43e99fdSEd Maste 	struct evbuffer *output_buffer;
235c43e99fdSEd Maste 
236c43e99fdSEd Maste 	int i;
237c43e99fdSEd Maste 	int ret = 0;
238c43e99fdSEd Maste 	enum { HTTP, HTTPS } type = HTTP;
239c43e99fdSEd Maste 
240c43e99fdSEd Maste 	for (i = 1; i < argc; i++) {
241c43e99fdSEd Maste 		if (!strcmp("-url", argv[i])) {
242c43e99fdSEd Maste 			if (i < argc - 1) {
243c43e99fdSEd Maste 				url = argv[i + 1];
244c43e99fdSEd Maste 			} else {
245c43e99fdSEd Maste 				syntax();
246c43e99fdSEd Maste 				goto error;
247c43e99fdSEd Maste 			}
248c43e99fdSEd Maste 		} else if (!strcmp("-crt", argv[i])) {
249c43e99fdSEd Maste 			if (i < argc - 1) {
250c43e99fdSEd Maste 				crt = argv[i + 1];
251c43e99fdSEd Maste 			} else {
252c43e99fdSEd Maste 				syntax();
253c43e99fdSEd Maste 				goto error;
254c43e99fdSEd Maste 			}
255c43e99fdSEd Maste 		} else if (!strcmp("-ignore-cert", argv[i])) {
256c43e99fdSEd Maste 			ignore_cert = 1;
257c43e99fdSEd Maste 		} else if (!strcmp("-data", argv[i])) {
258c43e99fdSEd Maste 			if (i < argc - 1) {
259c43e99fdSEd Maste 				data_file = argv[i + 1];
260c43e99fdSEd Maste 			} else {
261c43e99fdSEd Maste 				syntax();
262c43e99fdSEd Maste 				goto error;
263c43e99fdSEd Maste 			}
264c43e99fdSEd Maste 		} else if (!strcmp("-retries", argv[i])) {
265c43e99fdSEd Maste 			if (i < argc - 1) {
266c43e99fdSEd Maste 				retries = atoi(argv[i + 1]);
267c43e99fdSEd Maste 			} else {
268c43e99fdSEd Maste 				syntax();
269c43e99fdSEd Maste 				goto error;
270c43e99fdSEd Maste 			}
271c43e99fdSEd Maste 		} else if (!strcmp("-timeout", argv[i])) {
272c43e99fdSEd Maste 			if (i < argc - 1) {
273c43e99fdSEd Maste 				timeout = atoi(argv[i + 1]);
274c43e99fdSEd Maste 			} else {
275c43e99fdSEd Maste 				syntax();
276c43e99fdSEd Maste 				goto error;
277c43e99fdSEd Maste 			}
278c43e99fdSEd Maste 		} else if (!strcmp("-help", argv[i])) {
279c43e99fdSEd Maste 			syntax();
280c43e99fdSEd Maste 			goto error;
281c43e99fdSEd Maste 		}
282c43e99fdSEd Maste 	}
283c43e99fdSEd Maste 
284c43e99fdSEd Maste 	if (!url) {
285c43e99fdSEd Maste 		syntax();
286c43e99fdSEd Maste 		goto error;
287c43e99fdSEd Maste 	}
288c43e99fdSEd Maste 
289c43e99fdSEd Maste #ifdef _WIN32
290c43e99fdSEd Maste 	{
291c43e99fdSEd Maste 		WORD wVersionRequested;
292c43e99fdSEd Maste 		WSADATA wsaData;
293c43e99fdSEd Maste 		int err;
294c43e99fdSEd Maste 
295c43e99fdSEd Maste 		wVersionRequested = MAKEWORD(2, 2);
296c43e99fdSEd Maste 
297c43e99fdSEd Maste 		err = WSAStartup(wVersionRequested, &wsaData);
298c43e99fdSEd Maste 		if (err != 0) {
299c43e99fdSEd Maste 			printf("WSAStartup failed with error: %d\n", err);
300c43e99fdSEd Maste 			goto error;
301c43e99fdSEd Maste 		}
302c43e99fdSEd Maste 	}
303c43e99fdSEd Maste #endif // _WIN32
304c43e99fdSEd Maste 
305c43e99fdSEd Maste 	http_uri = evhttp_uri_parse(url);
306c43e99fdSEd Maste 	if (http_uri == NULL) {
307c43e99fdSEd Maste 		err("malformed url");
308c43e99fdSEd Maste 		goto error;
309c43e99fdSEd Maste 	}
310c43e99fdSEd Maste 
311c43e99fdSEd Maste 	scheme = evhttp_uri_get_scheme(http_uri);
312c43e99fdSEd Maste 	if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
313c43e99fdSEd Maste 	                       strcasecmp(scheme, "http") != 0)) {
314c43e99fdSEd Maste 		err("url must be http or https");
315c43e99fdSEd Maste 		goto error;
316c43e99fdSEd Maste 	}
317c43e99fdSEd Maste 
318c43e99fdSEd Maste 	host = evhttp_uri_get_host(http_uri);
319c43e99fdSEd Maste 	if (host == NULL) {
320c43e99fdSEd Maste 		err("url must have a host");
321c43e99fdSEd Maste 		goto error;
322c43e99fdSEd Maste 	}
323c43e99fdSEd Maste 
324c43e99fdSEd Maste 	port = evhttp_uri_get_port(http_uri);
325c43e99fdSEd Maste 	if (port == -1) {
326c43e99fdSEd Maste 		port = (strcasecmp(scheme, "http") == 0) ? 80 : 443;
327c43e99fdSEd Maste 	}
328c43e99fdSEd Maste 
329c43e99fdSEd Maste 	path = evhttp_uri_get_path(http_uri);
330c43e99fdSEd Maste 	if (strlen(path) == 0) {
331c43e99fdSEd Maste 		path = "/";
332c43e99fdSEd Maste 	}
333c43e99fdSEd Maste 
334c43e99fdSEd Maste 	query = evhttp_uri_get_query(http_uri);
335c43e99fdSEd Maste 	if (query == NULL) {
336c43e99fdSEd Maste 		snprintf(uri, sizeof(uri) - 1, "%s", path);
337c43e99fdSEd Maste 	} else {
338c43e99fdSEd Maste 		snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query);
339c43e99fdSEd Maste 	}
340c43e99fdSEd Maste 	uri[sizeof(uri) - 1] = '\0';
341c43e99fdSEd Maste 
342*b50261e2SCy Schubert #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
343*b50261e2SCy Schubert 	(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
344c43e99fdSEd Maste 	// Initialize OpenSSL
345c43e99fdSEd Maste 	SSL_library_init();
346c43e99fdSEd Maste 	ERR_load_crypto_strings();
347c43e99fdSEd Maste 	SSL_load_error_strings();
348c43e99fdSEd Maste 	OpenSSL_add_all_algorithms();
349c43e99fdSEd Maste #endif
350c43e99fdSEd Maste 
351c43e99fdSEd Maste 	/* This isn't strictly necessary... OpenSSL performs RAND_poll
352c43e99fdSEd Maste 	 * automatically on first use of random number generator. */
353c43e99fdSEd Maste 	r = RAND_poll();
354c43e99fdSEd Maste 	if (r == 0) {
355c43e99fdSEd Maste 		err_openssl("RAND_poll");
356c43e99fdSEd Maste 		goto error;
357c43e99fdSEd Maste 	}
358c43e99fdSEd Maste 
359c43e99fdSEd Maste 	/* Create a new OpenSSL context */
360c43e99fdSEd Maste 	ssl_ctx = SSL_CTX_new(SSLv23_method());
361c43e99fdSEd Maste 	if (!ssl_ctx) {
362c43e99fdSEd Maste 		err_openssl("SSL_CTX_new");
363c43e99fdSEd Maste 		goto error;
364c43e99fdSEd Maste 	}
365c43e99fdSEd Maste 
366*b50261e2SCy Schubert 	if (crt == NULL) {
367*b50261e2SCy Schubert 		X509_STORE *store;
368*b50261e2SCy Schubert 		/* Attempt to use the system's trusted root certificates. */
369*b50261e2SCy Schubert 		store = SSL_CTX_get_cert_store(ssl_ctx);
370*b50261e2SCy Schubert #ifdef _WIN32
371*b50261e2SCy Schubert 		if (add_cert_for_store(store, "CA") < 0 ||
372*b50261e2SCy Schubert 		    add_cert_for_store(store, "AuthRoot") < 0 ||
373*b50261e2SCy Schubert 		    add_cert_for_store(store, "ROOT") < 0) {
374*b50261e2SCy Schubert 			goto error;
375*b50261e2SCy Schubert 		}
376*b50261e2SCy Schubert #else // _WIN32
377*b50261e2SCy Schubert 		if (X509_STORE_set_default_paths(store) != 1) {
378*b50261e2SCy Schubert 			err_openssl("X509_STORE_set_default_paths");
379*b50261e2SCy Schubert 			goto error;
380*b50261e2SCy Schubert 		}
381*b50261e2SCy Schubert #endif // _WIN32
382*b50261e2SCy Schubert 	} else {
383*b50261e2SCy Schubert 		if (SSL_CTX_load_verify_locations(ssl_ctx, crt, NULL) != 1) {
384c43e99fdSEd Maste 			err_openssl("SSL_CTX_load_verify_locations");
385c43e99fdSEd Maste 			goto error;
386c43e99fdSEd Maste 		}
387*b50261e2SCy Schubert 	}
388c43e99fdSEd Maste 	/* Ask OpenSSL to verify the server certificate.  Note that this
389c43e99fdSEd Maste 	 * does NOT include verifying that the hostname is correct.
390c43e99fdSEd Maste 	 * So, by itself, this means anyone with any legitimate
391c43e99fdSEd Maste 	 * CA-issued certificate for any website, can impersonate any
392c43e99fdSEd Maste 	 * other website in the world.  This is not good.  See "The
393c43e99fdSEd Maste 	 * Most Dangerous Code in the World" article at
394c43e99fdSEd Maste 	 * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
395c43e99fdSEd Maste 	 */
396c43e99fdSEd Maste 	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
397c43e99fdSEd Maste 	/* This is how we solve the problem mentioned in the previous
398c43e99fdSEd Maste 	 * comment.  We "wrap" OpenSSL's validation routine in our
399c43e99fdSEd Maste 	 * own routine, which also validates the hostname by calling
400c43e99fdSEd Maste 	 * the code provided by iSECPartners.  Note that even though
401c43e99fdSEd Maste 	 * the "Everything You've Always Wanted to Know About
402c43e99fdSEd Maste 	 * Certificate Validation With OpenSSL (But Were Afraid to
403c43e99fdSEd Maste 	 * Ask)" paper from iSECPartners says very explicitly not to
404c43e99fdSEd Maste 	 * call SSL_CTX_set_cert_verify_callback (at the bottom of
405c43e99fdSEd Maste 	 * page 2), what we're doing here is safe because our
406c43e99fdSEd Maste 	 * cert_verify_callback() calls X509_verify_cert(), which is
407c43e99fdSEd Maste 	 * OpenSSL's built-in routine which would have been called if
408c43e99fdSEd Maste 	 * we hadn't set the callback.  Therefore, we're just
409c43e99fdSEd Maste 	 * "wrapping" OpenSSL's routine, not replacing it. */
410c43e99fdSEd Maste 	SSL_CTX_set_cert_verify_callback(ssl_ctx, cert_verify_callback,
411c43e99fdSEd Maste 					  (void *) host);
412c43e99fdSEd Maste 
413c43e99fdSEd Maste 	// Create event base
414c43e99fdSEd Maste 	base = event_base_new();
415c43e99fdSEd Maste 	if (!base) {
416c43e99fdSEd Maste 		perror("event_base_new()");
417c43e99fdSEd Maste 		goto error;
418c43e99fdSEd Maste 	}
419c43e99fdSEd Maste 
420c43e99fdSEd Maste 	// Create OpenSSL bufferevent and stack evhttp on top of it
421c43e99fdSEd Maste 	ssl = SSL_new(ssl_ctx);
422c43e99fdSEd Maste 	if (ssl == NULL) {
423c43e99fdSEd Maste 		err_openssl("SSL_new()");
424c43e99fdSEd Maste 		goto error;
425c43e99fdSEd Maste 	}
426c43e99fdSEd Maste 
427c43e99fdSEd Maste 	#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
428c43e99fdSEd Maste 	// Set hostname for SNI extension
429c43e99fdSEd Maste 	SSL_set_tlsext_host_name(ssl, host);
430c43e99fdSEd Maste 	#endif
431c43e99fdSEd Maste 
432c43e99fdSEd Maste 	if (strcasecmp(scheme, "http") == 0) {
433c43e99fdSEd Maste 		bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
434c43e99fdSEd Maste 	} else {
435c43e99fdSEd Maste 		type = HTTPS;
436c43e99fdSEd Maste 		bev = bufferevent_openssl_socket_new(base, -1, ssl,
437c43e99fdSEd Maste 			BUFFEREVENT_SSL_CONNECTING,
438c43e99fdSEd Maste 			BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
439c43e99fdSEd Maste 	}
440c43e99fdSEd Maste 
441c43e99fdSEd Maste 	if (bev == NULL) {
442c43e99fdSEd Maste 		fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
443c43e99fdSEd Maste 		goto error;
444c43e99fdSEd Maste 	}
445c43e99fdSEd Maste 
446c43e99fdSEd Maste 	bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
447c43e99fdSEd Maste 
448c43e99fdSEd Maste 	// For simplicity, we let DNS resolution block. Everything else should be
449c43e99fdSEd Maste 	// asynchronous though.
450c43e99fdSEd Maste 	evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev,
451c43e99fdSEd Maste 		host, port);
452c43e99fdSEd Maste 	if (evcon == NULL) {
453c43e99fdSEd Maste 		fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
454c43e99fdSEd Maste 		goto error;
455c43e99fdSEd Maste 	}
456c43e99fdSEd Maste 
457c43e99fdSEd Maste 	if (retries > 0) {
458c43e99fdSEd Maste 		evhttp_connection_set_retries(evcon, retries);
459c43e99fdSEd Maste 	}
460c43e99fdSEd Maste 	if (timeout >= 0) {
461c43e99fdSEd Maste 		evhttp_connection_set_timeout(evcon, timeout);
462c43e99fdSEd Maste 	}
463c43e99fdSEd Maste 
464c43e99fdSEd Maste 	// Fire off the request
465c43e99fdSEd Maste 	req = evhttp_request_new(http_request_done, bev);
466c43e99fdSEd Maste 	if (req == NULL) {
467c43e99fdSEd Maste 		fprintf(stderr, "evhttp_request_new() failed\n");
468c43e99fdSEd Maste 		goto error;
469c43e99fdSEd Maste 	}
470c43e99fdSEd Maste 
471c43e99fdSEd Maste 	output_headers = evhttp_request_get_output_headers(req);
472c43e99fdSEd Maste 	evhttp_add_header(output_headers, "Host", host);
473c43e99fdSEd Maste 	evhttp_add_header(output_headers, "Connection", "close");
474c43e99fdSEd Maste 
475c43e99fdSEd Maste 	if (data_file) {
476c43e99fdSEd Maste 		/* NOTE: In production code, you'd probably want to use
477c43e99fdSEd Maste 		 * evbuffer_add_file() or evbuffer_add_file_segment(), to
478c43e99fdSEd Maste 		 * avoid needless copying. */
479c43e99fdSEd Maste 		FILE * f = fopen(data_file, "rb");
480c43e99fdSEd Maste 		char buf[1024];
481c43e99fdSEd Maste 		size_t s;
482c43e99fdSEd Maste 		size_t bytes = 0;
483c43e99fdSEd Maste 
484c43e99fdSEd Maste 		if (!f) {
485c43e99fdSEd Maste 			syntax();
486c43e99fdSEd Maste 			goto error;
487c43e99fdSEd Maste 		}
488c43e99fdSEd Maste 
489c43e99fdSEd Maste 		output_buffer = evhttp_request_get_output_buffer(req);
490c43e99fdSEd Maste 		while ((s = fread(buf, 1, sizeof(buf), f)) > 0) {
491c43e99fdSEd Maste 			evbuffer_add(output_buffer, buf, s);
492c43e99fdSEd Maste 			bytes += s;
493c43e99fdSEd Maste 		}
494c43e99fdSEd Maste 		evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes);
495c43e99fdSEd Maste 		evhttp_add_header(output_headers, "Content-Length", buf);
496c43e99fdSEd Maste 		fclose(f);
497c43e99fdSEd Maste 	}
498c43e99fdSEd Maste 
499c43e99fdSEd Maste 	r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
500c43e99fdSEd Maste 	if (r != 0) {
501c43e99fdSEd Maste 		fprintf(stderr, "evhttp_make_request() failed\n");
502c43e99fdSEd Maste 		goto error;
503c43e99fdSEd Maste 	}
504c43e99fdSEd Maste 
505c43e99fdSEd Maste 	event_base_dispatch(base);
506c43e99fdSEd Maste 	goto cleanup;
507c43e99fdSEd Maste 
508c43e99fdSEd Maste error:
509c43e99fdSEd Maste 	ret = 1;
510c43e99fdSEd Maste cleanup:
511c43e99fdSEd Maste 	if (evcon)
512c43e99fdSEd Maste 		evhttp_connection_free(evcon);
513c43e99fdSEd Maste 	if (http_uri)
514c43e99fdSEd Maste 		evhttp_uri_free(http_uri);
515*b50261e2SCy Schubert 	if (base)
516c43e99fdSEd Maste 		event_base_free(base);
517c43e99fdSEd Maste 
518c43e99fdSEd Maste 	if (ssl_ctx)
519c43e99fdSEd Maste 		SSL_CTX_free(ssl_ctx);
520c43e99fdSEd Maste 	if (type == HTTP && ssl)
521c43e99fdSEd Maste 		SSL_free(ssl);
522*b50261e2SCy Schubert #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
523*b50261e2SCy Schubert 	(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
524c43e99fdSEd Maste 	EVP_cleanup();
525c43e99fdSEd Maste 	ERR_free_strings();
526c43e99fdSEd Maste 
527*b50261e2SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10000000L
528c43e99fdSEd Maste 	ERR_remove_state(0);
529*b50261e2SCy Schubert #else
530*b50261e2SCy Schubert 	ERR_remove_thread_state(NULL);
531c43e99fdSEd Maste #endif
532*b50261e2SCy Schubert 
533c43e99fdSEd Maste 	CRYPTO_cleanup_all_ex_data();
534c43e99fdSEd Maste 
535c43e99fdSEd Maste 	sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
536*b50261e2SCy Schubert #endif /* (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
537*b50261e2SCy Schubert 	(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) */
538c43e99fdSEd Maste 
539c43e99fdSEd Maste #ifdef _WIN32
540c43e99fdSEd Maste 	WSACleanup();
541c43e99fdSEd Maste #endif
542c43e99fdSEd Maste 
543c43e99fdSEd Maste 	return ret;
544c43e99fdSEd Maste }
545