xref: /src/contrib/ntp/sntp/libevent/sample/https-client.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
126fd3d56SCy Schubert /*
226fd3d56SCy Schubert   This is an example of how to hook up evhttp with bufferevent_ssl
326fd3d56SCy Schubert 
426fd3d56SCy Schubert   It just GETs an https URL given on the command-line and prints the response
526fd3d56SCy Schubert   body to stdout.
626fd3d56SCy Schubert 
726fd3d56SCy Schubert   Actually, it also accepts plain http URLs to make it easy to compare http vs
826fd3d56SCy Schubert   https code paths.
926fd3d56SCy Schubert 
1026fd3d56SCy Schubert   Loosely based on le-proxy.c.
1126fd3d56SCy Schubert  */
1226fd3d56SCy Schubert 
1326fd3d56SCy Schubert // Get rid of OSX 10.7 and greater deprecation warnings.
1426fd3d56SCy Schubert #if defined(__APPLE__) && defined(__clang__)
1526fd3d56SCy Schubert #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1626fd3d56SCy Schubert #endif
1726fd3d56SCy Schubert 
1826fd3d56SCy Schubert #include <stdio.h>
1926fd3d56SCy Schubert #include <assert.h>
2026fd3d56SCy Schubert #include <stdlib.h>
2126fd3d56SCy Schubert #include <string.h>
2226fd3d56SCy Schubert #include <errno.h>
2326fd3d56SCy Schubert 
2426fd3d56SCy Schubert #ifdef _WIN32
2526fd3d56SCy Schubert #include <winsock2.h>
2626fd3d56SCy Schubert #include <ws2tcpip.h>
2726fd3d56SCy Schubert 
2826fd3d56SCy Schubert #define snprintf _snprintf
2926fd3d56SCy Schubert #define strcasecmp _stricmp
3026fd3d56SCy Schubert #else
3126fd3d56SCy Schubert #include <sys/socket.h>
3226fd3d56SCy Schubert #include <netinet/in.h>
3326fd3d56SCy Schubert #endif
3426fd3d56SCy Schubert 
3526fd3d56SCy Schubert #include <event2/bufferevent_ssl.h>
3626fd3d56SCy Schubert #include <event2/bufferevent.h>
3726fd3d56SCy Schubert #include <event2/buffer.h>
3826fd3d56SCy Schubert #include <event2/listener.h>
3926fd3d56SCy Schubert #include <event2/util.h>
4026fd3d56SCy Schubert #include <event2/http.h>
4126fd3d56SCy Schubert 
4226fd3d56SCy Schubert #include <openssl/ssl.h>
4326fd3d56SCy Schubert #include <openssl/err.h>
4426fd3d56SCy Schubert #include <openssl/rand.h>
4526fd3d56SCy Schubert 
4626fd3d56SCy Schubert #include "openssl_hostname_validation.h"
4726fd3d56SCy Schubert 
4826fd3d56SCy Schubert static int ignore_cert = 0;
4926fd3d56SCy Schubert 
5026fd3d56SCy Schubert static void
http_request_done(struct evhttp_request * req,void * ctx)5126fd3d56SCy Schubert http_request_done(struct evhttp_request *req, void *ctx)
5226fd3d56SCy Schubert {
5326fd3d56SCy Schubert 	char buffer[256];
5426fd3d56SCy Schubert 	int nread;
5526fd3d56SCy Schubert 
5626fd3d56SCy Schubert 	if (!req || !evhttp_request_get_response_code(req)) {
5726fd3d56SCy Schubert 		/* If req is NULL, it means an error occurred, but
5826fd3d56SCy Schubert 		 * sadly we are mostly left guessing what the error
5926fd3d56SCy Schubert 		 * might have been.  We'll do our best... */
6026fd3d56SCy Schubert 		struct bufferevent *bev = (struct bufferevent *) ctx;
6126fd3d56SCy Schubert 		unsigned long oslerr;
6226fd3d56SCy Schubert 		int printed_err = 0;
6326fd3d56SCy Schubert 		int errcode = EVUTIL_SOCKET_ERROR();
6426fd3d56SCy Schubert 		fprintf(stderr, "some request failed - no idea which one though!\n");
6526fd3d56SCy Schubert 		/* Print out the OpenSSL error queue that libevent
6626fd3d56SCy Schubert 		 * squirreled away for us, if any. */
6726fd3d56SCy Schubert 		while ((oslerr = bufferevent_get_openssl_error(bev))) {
6826fd3d56SCy Schubert 			ERR_error_string_n(oslerr, buffer, sizeof(buffer));
6926fd3d56SCy Schubert 			fprintf(stderr, "%s\n", buffer);
7026fd3d56SCy Schubert 			printed_err = 1;
7126fd3d56SCy Schubert 		}
7226fd3d56SCy Schubert 		/* If the OpenSSL error queue was empty, maybe it was a
7326fd3d56SCy Schubert 		 * socket error; let's try printing that. */
7426fd3d56SCy Schubert 		if (! printed_err)
7526fd3d56SCy Schubert 			fprintf(stderr, "socket error = %s (%d)\n",
7626fd3d56SCy Schubert 				evutil_socket_error_to_string(errcode),
7726fd3d56SCy Schubert 				errcode);
7826fd3d56SCy Schubert 		return;
7926fd3d56SCy Schubert 	}
8026fd3d56SCy Schubert 
8126fd3d56SCy Schubert 	fprintf(stderr, "Response line: %d %s\n",
8226fd3d56SCy Schubert 	    evhttp_request_get_response_code(req),
8326fd3d56SCy Schubert 	    evhttp_request_get_response_code_line(req));
8426fd3d56SCy Schubert 
8526fd3d56SCy Schubert 	while ((nread = evbuffer_remove(evhttp_request_get_input_buffer(req),
8626fd3d56SCy Schubert 		    buffer, sizeof(buffer)))
8726fd3d56SCy Schubert 	       > 0) {
8826fd3d56SCy Schubert 		/* These are just arbitrary chunks of 256 bytes.
8926fd3d56SCy Schubert 		 * They are not lines, so we can't treat them as such. */
9026fd3d56SCy Schubert 		fwrite(buffer, nread, 1, stdout);
9126fd3d56SCy Schubert 	}
9226fd3d56SCy Schubert }
9326fd3d56SCy Schubert 
9426fd3d56SCy Schubert static void
syntax(void)9526fd3d56SCy Schubert syntax(void)
9626fd3d56SCy Schubert {
9726fd3d56SCy Schubert 	fputs("Syntax:\n", stderr);
9826fd3d56SCy Schubert 	fputs("   https-client -url <https-url> [-data data-file.bin] [-ignore-cert] [-retries num] [-timeout sec] [-crt crt]\n", stderr);
9926fd3d56SCy Schubert 	fputs("Example:\n", stderr);
10026fd3d56SCy Schubert 	fputs("   https-client -url https://ip.appspot.com/\n", stderr);
10126fd3d56SCy Schubert }
10226fd3d56SCy Schubert 
10326fd3d56SCy Schubert static void
err(const char * msg)10426fd3d56SCy Schubert err(const char *msg)
10526fd3d56SCy Schubert {
10626fd3d56SCy Schubert 	fputs(msg, stderr);
10726fd3d56SCy Schubert }
10826fd3d56SCy Schubert 
10926fd3d56SCy Schubert static void
err_openssl(const char * func)11026fd3d56SCy Schubert err_openssl(const char *func)
11126fd3d56SCy Schubert {
11226fd3d56SCy Schubert 	fprintf (stderr, "%s failed:\n", func);
11326fd3d56SCy Schubert 
11426fd3d56SCy Schubert 	/* This is the OpenSSL function that prints the contents of the
11526fd3d56SCy Schubert 	 * error stack to the specified file handle. */
11626fd3d56SCy Schubert 	ERR_print_errors_fp (stderr);
11726fd3d56SCy Schubert 
11826fd3d56SCy Schubert 	exit(1);
11926fd3d56SCy Schubert }
12026fd3d56SCy Schubert 
12126fd3d56SCy Schubert /* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */
cert_verify_callback(X509_STORE_CTX * x509_ctx,void * arg)12226fd3d56SCy Schubert static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
12326fd3d56SCy Schubert {
12426fd3d56SCy Schubert 	char cert_str[256];
12526fd3d56SCy Schubert 	const char *host = (const char *) arg;
12626fd3d56SCy Schubert 	const char *res_str = "X509_verify_cert failed";
12726fd3d56SCy Schubert 	HostnameValidationResult res = Error;
12826fd3d56SCy Schubert 
12926fd3d56SCy Schubert 	/* This is the function that OpenSSL would call if we hadn't called
13026fd3d56SCy Schubert 	 * SSL_CTX_set_cert_verify_callback().  Therefore, we are "wrapping"
13126fd3d56SCy Schubert 	 * the default functionality, rather than replacing it. */
13226fd3d56SCy Schubert 	int ok_so_far = 0;
13326fd3d56SCy Schubert 
13426fd3d56SCy Schubert 	X509 *server_cert = NULL;
13526fd3d56SCy Schubert 
13626fd3d56SCy Schubert 	if (ignore_cert) {
13726fd3d56SCy Schubert 		return 1;
13826fd3d56SCy Schubert 	}
13926fd3d56SCy Schubert 
14026fd3d56SCy Schubert 	ok_so_far = X509_verify_cert(x509_ctx);
14126fd3d56SCy Schubert 
14226fd3d56SCy Schubert 	server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
14326fd3d56SCy Schubert 
14426fd3d56SCy Schubert 	if (ok_so_far) {
14526fd3d56SCy Schubert 		res = validate_hostname(host, server_cert);
14626fd3d56SCy Schubert 
14726fd3d56SCy Schubert 		switch (res) {
14826fd3d56SCy Schubert 		case MatchFound:
14926fd3d56SCy Schubert 			res_str = "MatchFound";
15026fd3d56SCy Schubert 			break;
15126fd3d56SCy Schubert 		case MatchNotFound:
15226fd3d56SCy Schubert 			res_str = "MatchNotFound";
15326fd3d56SCy Schubert 			break;
15426fd3d56SCy Schubert 		case NoSANPresent:
15526fd3d56SCy Schubert 			res_str = "NoSANPresent";
15626fd3d56SCy Schubert 			break;
15726fd3d56SCy Schubert 		case MalformedCertificate:
15826fd3d56SCy Schubert 			res_str = "MalformedCertificate";
15926fd3d56SCy Schubert 			break;
16026fd3d56SCy Schubert 		case Error:
16126fd3d56SCy Schubert 			res_str = "Error";
16226fd3d56SCy Schubert 			break;
16326fd3d56SCy Schubert 		default:
16426fd3d56SCy Schubert 			res_str = "WTF!";
16526fd3d56SCy Schubert 			break;
16626fd3d56SCy Schubert 		}
16726fd3d56SCy Schubert 	}
16826fd3d56SCy Schubert 
16926fd3d56SCy Schubert 	X509_NAME_oneline(X509_get_subject_name (server_cert),
17026fd3d56SCy Schubert 			  cert_str, sizeof (cert_str));
17126fd3d56SCy Schubert 
17226fd3d56SCy Schubert 	if (res == MatchFound) {
17326fd3d56SCy Schubert 		printf("https server '%s' has this certificate, "
17426fd3d56SCy Schubert 		       "which looks good to me:\n%s\n",
17526fd3d56SCy Schubert 		       host, cert_str);
17626fd3d56SCy Schubert 		return 1;
17726fd3d56SCy Schubert 	} else {
17826fd3d56SCy Schubert 		printf("Got '%s' for hostname '%s' and certificate:\n%s\n",
17926fd3d56SCy Schubert 		       res_str, host, cert_str);
18026fd3d56SCy Schubert 		return 0;
18126fd3d56SCy Schubert 	}
18226fd3d56SCy Schubert }
18326fd3d56SCy Schubert 
18426fd3d56SCy Schubert #ifdef _WIN32
18526fd3d56SCy Schubert static int
add_cert_for_store(X509_STORE * store,const char * name)18626fd3d56SCy Schubert add_cert_for_store(X509_STORE *store, const char *name)
18726fd3d56SCy Schubert {
18826fd3d56SCy Schubert 	HCERTSTORE sys_store = NULL;
18926fd3d56SCy Schubert 	PCCERT_CONTEXT ctx = NULL;
19026fd3d56SCy Schubert 	int r = 0;
19126fd3d56SCy Schubert 
19226fd3d56SCy Schubert 	sys_store = CertOpenSystemStore(0, name);
19326fd3d56SCy Schubert 	if (!sys_store) {
19426fd3d56SCy Schubert 		err("failed to open system certificate store");
19526fd3d56SCy Schubert 		return -1;
19626fd3d56SCy Schubert 	}
19726fd3d56SCy Schubert 	while ((ctx = CertEnumCertificatesInStore(sys_store, ctx))) {
19826fd3d56SCy Schubert 		X509 *x509 = d2i_X509(NULL, (unsigned char const **)&ctx->pbCertEncoded,
19926fd3d56SCy Schubert 			ctx->cbCertEncoded);
20026fd3d56SCy Schubert 		if (x509) {
20126fd3d56SCy Schubert 			X509_STORE_add_cert(store, x509);
20226fd3d56SCy Schubert 			X509_free(x509);
20326fd3d56SCy Schubert 		} else {
20426fd3d56SCy Schubert 			r = -1;
20526fd3d56SCy Schubert 			err_openssl("d2i_X509");
20626fd3d56SCy Schubert 			break;
20726fd3d56SCy Schubert 		}
20826fd3d56SCy Schubert 	}
20926fd3d56SCy Schubert 	CertCloseStore(sys_store, 0);
21026fd3d56SCy Schubert 	return r;
21126fd3d56SCy Schubert }
21226fd3d56SCy Schubert #endif
21326fd3d56SCy Schubert 
21426fd3d56SCy Schubert int
main(int argc,char ** argv)21526fd3d56SCy Schubert main(int argc, char **argv)
21626fd3d56SCy Schubert {
21726fd3d56SCy Schubert 	int r;
21826fd3d56SCy Schubert 	struct event_base *base = NULL;
21926fd3d56SCy Schubert 	struct evhttp_uri *http_uri = NULL;
22026fd3d56SCy Schubert 	const char *url = NULL, *data_file = NULL;
22126fd3d56SCy Schubert 	const char *crt = NULL;
22226fd3d56SCy Schubert 	const char *scheme, *host, *path, *query;
22326fd3d56SCy Schubert 	char uri[256];
22426fd3d56SCy Schubert 	int port;
22526fd3d56SCy Schubert 	int retries = 0;
22626fd3d56SCy Schubert 	int timeout = -1;
22726fd3d56SCy Schubert 
22826fd3d56SCy Schubert 	SSL_CTX *ssl_ctx = NULL;
22926fd3d56SCy Schubert 	SSL *ssl = NULL;
23026fd3d56SCy Schubert 	struct bufferevent *bev;
23126fd3d56SCy Schubert 	struct evhttp_connection *evcon = NULL;
23226fd3d56SCy Schubert 	struct evhttp_request *req;
23326fd3d56SCy Schubert 	struct evkeyvalq *output_headers;
23426fd3d56SCy Schubert 	struct evbuffer *output_buffer;
23526fd3d56SCy Schubert 
23626fd3d56SCy Schubert 	int i;
23726fd3d56SCy Schubert 	int ret = 0;
23826fd3d56SCy Schubert 	enum { HTTP, HTTPS } type = HTTP;
23926fd3d56SCy Schubert 
24026fd3d56SCy Schubert 	for (i = 1; i < argc; i++) {
24126fd3d56SCy Schubert 		if (!strcmp("-url", argv[i])) {
24226fd3d56SCy Schubert 			if (i < argc - 1) {
24326fd3d56SCy Schubert 				url = argv[i + 1];
24426fd3d56SCy Schubert 			} else {
24526fd3d56SCy Schubert 				syntax();
24626fd3d56SCy Schubert 				goto error;
24726fd3d56SCy Schubert 			}
24826fd3d56SCy Schubert 		} else if (!strcmp("-crt", argv[i])) {
24926fd3d56SCy Schubert 			if (i < argc - 1) {
25026fd3d56SCy Schubert 				crt = argv[i + 1];
25126fd3d56SCy Schubert 			} else {
25226fd3d56SCy Schubert 				syntax();
25326fd3d56SCy Schubert 				goto error;
25426fd3d56SCy Schubert 			}
25526fd3d56SCy Schubert 		} else if (!strcmp("-ignore-cert", argv[i])) {
25626fd3d56SCy Schubert 			ignore_cert = 1;
25726fd3d56SCy Schubert 		} else if (!strcmp("-data", argv[i])) {
25826fd3d56SCy Schubert 			if (i < argc - 1) {
25926fd3d56SCy Schubert 				data_file = argv[i + 1];
26026fd3d56SCy Schubert 			} else {
26126fd3d56SCy Schubert 				syntax();
26226fd3d56SCy Schubert 				goto error;
26326fd3d56SCy Schubert 			}
26426fd3d56SCy Schubert 		} else if (!strcmp("-retries", argv[i])) {
26526fd3d56SCy Schubert 			if (i < argc - 1) {
26626fd3d56SCy Schubert 				retries = atoi(argv[i + 1]);
26726fd3d56SCy Schubert 			} else {
26826fd3d56SCy Schubert 				syntax();
26926fd3d56SCy Schubert 				goto error;
27026fd3d56SCy Schubert 			}
27126fd3d56SCy Schubert 		} else if (!strcmp("-timeout", argv[i])) {
27226fd3d56SCy Schubert 			if (i < argc - 1) {
27326fd3d56SCy Schubert 				timeout = atoi(argv[i + 1]);
27426fd3d56SCy Schubert 			} else {
27526fd3d56SCy Schubert 				syntax();
27626fd3d56SCy Schubert 				goto error;
27726fd3d56SCy Schubert 			}
27826fd3d56SCy Schubert 		} else if (!strcmp("-help", argv[i])) {
27926fd3d56SCy Schubert 			syntax();
28026fd3d56SCy Schubert 			goto error;
28126fd3d56SCy Schubert 		}
28226fd3d56SCy Schubert 	}
28326fd3d56SCy Schubert 
28426fd3d56SCy Schubert 	if (!url) {
28526fd3d56SCy Schubert 		syntax();
28626fd3d56SCy Schubert 		goto error;
28726fd3d56SCy Schubert 	}
28826fd3d56SCy Schubert 
28926fd3d56SCy Schubert #ifdef _WIN32
29026fd3d56SCy Schubert 	{
29126fd3d56SCy Schubert 		WORD wVersionRequested;
29226fd3d56SCy Schubert 		WSADATA wsaData;
29326fd3d56SCy Schubert 		int err;
29426fd3d56SCy Schubert 
29526fd3d56SCy Schubert 		wVersionRequested = MAKEWORD(2, 2);
29626fd3d56SCy Schubert 
29726fd3d56SCy Schubert 		err = WSAStartup(wVersionRequested, &wsaData);
29826fd3d56SCy Schubert 		if (err != 0) {
29926fd3d56SCy Schubert 			printf("WSAStartup failed with error: %d\n", err);
30026fd3d56SCy Schubert 			goto error;
30126fd3d56SCy Schubert 		}
30226fd3d56SCy Schubert 	}
30326fd3d56SCy Schubert #endif // _WIN32
30426fd3d56SCy Schubert 
30526fd3d56SCy Schubert 	http_uri = evhttp_uri_parse(url);
30626fd3d56SCy Schubert 	if (http_uri == NULL) {
30726fd3d56SCy Schubert 		err("malformed url");
30826fd3d56SCy Schubert 		goto error;
30926fd3d56SCy Schubert 	}
31026fd3d56SCy Schubert 
31126fd3d56SCy Schubert 	scheme = evhttp_uri_get_scheme(http_uri);
31226fd3d56SCy Schubert 	if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
31326fd3d56SCy Schubert 	                       strcasecmp(scheme, "http") != 0)) {
31426fd3d56SCy Schubert 		err("url must be http or https");
31526fd3d56SCy Schubert 		goto error;
31626fd3d56SCy Schubert 	}
31726fd3d56SCy Schubert 
31826fd3d56SCy Schubert 	host = evhttp_uri_get_host(http_uri);
31926fd3d56SCy Schubert 	if (host == NULL) {
32026fd3d56SCy Schubert 		err("url must have a host");
32126fd3d56SCy Schubert 		goto error;
32226fd3d56SCy Schubert 	}
32326fd3d56SCy Schubert 
32426fd3d56SCy Schubert 	port = evhttp_uri_get_port(http_uri);
32526fd3d56SCy Schubert 	if (port == -1) {
32626fd3d56SCy Schubert 		port = (strcasecmp(scheme, "http") == 0) ? 80 : 443;
32726fd3d56SCy Schubert 	}
32826fd3d56SCy Schubert 
32926fd3d56SCy Schubert 	path = evhttp_uri_get_path(http_uri);
33026fd3d56SCy Schubert 	if (strlen(path) == 0) {
33126fd3d56SCy Schubert 		path = "/";
33226fd3d56SCy Schubert 	}
33326fd3d56SCy Schubert 
33426fd3d56SCy Schubert 	query = evhttp_uri_get_query(http_uri);
33526fd3d56SCy Schubert 	if (query == NULL) {
33626fd3d56SCy Schubert 		snprintf(uri, sizeof(uri) - 1, "%s", path);
33726fd3d56SCy Schubert 	} else {
33826fd3d56SCy Schubert 		snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query);
33926fd3d56SCy Schubert 	}
34026fd3d56SCy Schubert 	uri[sizeof(uri) - 1] = '\0';
34126fd3d56SCy Schubert 
34226fd3d56SCy Schubert #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
34326fd3d56SCy Schubert 	(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
34426fd3d56SCy Schubert 	// Initialize OpenSSL
34526fd3d56SCy Schubert 	SSL_library_init();
34626fd3d56SCy Schubert 	ERR_load_crypto_strings();
34726fd3d56SCy Schubert 	SSL_load_error_strings();
34826fd3d56SCy Schubert 	OpenSSL_add_all_algorithms();
34926fd3d56SCy Schubert #endif
35026fd3d56SCy Schubert 
35126fd3d56SCy Schubert 	/* This isn't strictly necessary... OpenSSL performs RAND_poll
35226fd3d56SCy Schubert 	 * automatically on first use of random number generator. */
35326fd3d56SCy Schubert 	r = RAND_poll();
35426fd3d56SCy Schubert 	if (r == 0) {
35526fd3d56SCy Schubert 		err_openssl("RAND_poll");
35626fd3d56SCy Schubert 		goto error;
35726fd3d56SCy Schubert 	}
35826fd3d56SCy Schubert 
35926fd3d56SCy Schubert 	/* Create a new OpenSSL context */
36026fd3d56SCy Schubert 	ssl_ctx = SSL_CTX_new(SSLv23_method());
36126fd3d56SCy Schubert 	if (!ssl_ctx) {
36226fd3d56SCy Schubert 		err_openssl("SSL_CTX_new");
36326fd3d56SCy Schubert 		goto error;
36426fd3d56SCy Schubert 	}
36526fd3d56SCy Schubert 
36626fd3d56SCy Schubert 	if (crt == NULL) {
36726fd3d56SCy Schubert 		X509_STORE *store;
36826fd3d56SCy Schubert 		/* Attempt to use the system's trusted root certificates. */
36926fd3d56SCy Schubert 		store = SSL_CTX_get_cert_store(ssl_ctx);
37026fd3d56SCy Schubert #ifdef _WIN32
37126fd3d56SCy Schubert 		if (add_cert_for_store(store, "CA") < 0 ||
37226fd3d56SCy Schubert 		    add_cert_for_store(store, "AuthRoot") < 0 ||
37326fd3d56SCy Schubert 		    add_cert_for_store(store, "ROOT") < 0) {
37426fd3d56SCy Schubert 			goto error;
37526fd3d56SCy Schubert 		}
37626fd3d56SCy Schubert #else // _WIN32
37726fd3d56SCy Schubert 		if (X509_STORE_set_default_paths(store) != 1) {
37826fd3d56SCy Schubert 			err_openssl("X509_STORE_set_default_paths");
37926fd3d56SCy Schubert 			goto error;
38026fd3d56SCy Schubert 		}
38126fd3d56SCy Schubert #endif // _WIN32
38226fd3d56SCy Schubert 	} else {
38326fd3d56SCy Schubert 		if (SSL_CTX_load_verify_locations(ssl_ctx, crt, NULL) != 1) {
38426fd3d56SCy Schubert 			err_openssl("SSL_CTX_load_verify_locations");
38526fd3d56SCy Schubert 			goto error;
38626fd3d56SCy Schubert 		}
38726fd3d56SCy Schubert 	}
38826fd3d56SCy Schubert 	/* Ask OpenSSL to verify the server certificate.  Note that this
38926fd3d56SCy Schubert 	 * does NOT include verifying that the hostname is correct.
39026fd3d56SCy Schubert 	 * So, by itself, this means anyone with any legitimate
39126fd3d56SCy Schubert 	 * CA-issued certificate for any website, can impersonate any
39226fd3d56SCy Schubert 	 * other website in the world.  This is not good.  See "The
39326fd3d56SCy Schubert 	 * Most Dangerous Code in the World" article at
39426fd3d56SCy Schubert 	 * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
39526fd3d56SCy Schubert 	 */
39626fd3d56SCy Schubert 	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
39726fd3d56SCy Schubert 	/* This is how we solve the problem mentioned in the previous
39826fd3d56SCy Schubert 	 * comment.  We "wrap" OpenSSL's validation routine in our
39926fd3d56SCy Schubert 	 * own routine, which also validates the hostname by calling
40026fd3d56SCy Schubert 	 * the code provided by iSECPartners.  Note that even though
40126fd3d56SCy Schubert 	 * the "Everything You've Always Wanted to Know About
40226fd3d56SCy Schubert 	 * Certificate Validation With OpenSSL (But Were Afraid to
40326fd3d56SCy Schubert 	 * Ask)" paper from iSECPartners says very explicitly not to
40426fd3d56SCy Schubert 	 * call SSL_CTX_set_cert_verify_callback (at the bottom of
40526fd3d56SCy Schubert 	 * page 2), what we're doing here is safe because our
40626fd3d56SCy Schubert 	 * cert_verify_callback() calls X509_verify_cert(), which is
40726fd3d56SCy Schubert 	 * OpenSSL's built-in routine which would have been called if
40826fd3d56SCy Schubert 	 * we hadn't set the callback.  Therefore, we're just
40926fd3d56SCy Schubert 	 * "wrapping" OpenSSL's routine, not replacing it. */
41026fd3d56SCy Schubert 	SSL_CTX_set_cert_verify_callback(ssl_ctx, cert_verify_callback,
41126fd3d56SCy Schubert 					  (void *) host);
41226fd3d56SCy Schubert 
41326fd3d56SCy Schubert 	// Create event base
41426fd3d56SCy Schubert 	base = event_base_new();
41526fd3d56SCy Schubert 	if (!base) {
41626fd3d56SCy Schubert 		perror("event_base_new()");
41726fd3d56SCy Schubert 		goto error;
41826fd3d56SCy Schubert 	}
41926fd3d56SCy Schubert 
42026fd3d56SCy Schubert 	// Create OpenSSL bufferevent and stack evhttp on top of it
42126fd3d56SCy Schubert 	ssl = SSL_new(ssl_ctx);
42226fd3d56SCy Schubert 	if (ssl == NULL) {
42326fd3d56SCy Schubert 		err_openssl("SSL_new()");
42426fd3d56SCy Schubert 		goto error;
42526fd3d56SCy Schubert 	}
42626fd3d56SCy Schubert 
42726fd3d56SCy Schubert 	#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
42826fd3d56SCy Schubert 	// Set hostname for SNI extension
42926fd3d56SCy Schubert 	SSL_set_tlsext_host_name(ssl, host);
43026fd3d56SCy Schubert 	#endif
43126fd3d56SCy Schubert 
43226fd3d56SCy Schubert 	if (strcasecmp(scheme, "http") == 0) {
43326fd3d56SCy Schubert 		bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
43426fd3d56SCy Schubert 	} else {
43526fd3d56SCy Schubert 		type = HTTPS;
43626fd3d56SCy Schubert 		bev = bufferevent_openssl_socket_new(base, -1, ssl,
43726fd3d56SCy Schubert 			BUFFEREVENT_SSL_CONNECTING,
43826fd3d56SCy Schubert 			BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
43926fd3d56SCy Schubert 	}
44026fd3d56SCy Schubert 
44126fd3d56SCy Schubert 	if (bev == NULL) {
44226fd3d56SCy Schubert 		fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
44326fd3d56SCy Schubert 		goto error;
44426fd3d56SCy Schubert 	}
44526fd3d56SCy Schubert 
44626fd3d56SCy Schubert 	bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
44726fd3d56SCy Schubert 
44826fd3d56SCy Schubert 	// For simplicity, we let DNS resolution block. Everything else should be
44926fd3d56SCy Schubert 	// asynchronous though.
45026fd3d56SCy Schubert 	evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev,
45126fd3d56SCy Schubert 		host, port);
45226fd3d56SCy Schubert 	if (evcon == NULL) {
45326fd3d56SCy Schubert 		fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
45426fd3d56SCy Schubert 		goto error;
45526fd3d56SCy Schubert 	}
45626fd3d56SCy Schubert 
45726fd3d56SCy Schubert 	if (retries > 0) {
45826fd3d56SCy Schubert 		evhttp_connection_set_retries(evcon, retries);
45926fd3d56SCy Schubert 	}
46026fd3d56SCy Schubert 	if (timeout >= 0) {
46126fd3d56SCy Schubert 		evhttp_connection_set_timeout(evcon, timeout);
46226fd3d56SCy Schubert 	}
46326fd3d56SCy Schubert 
46426fd3d56SCy Schubert 	// Fire off the request
46526fd3d56SCy Schubert 	req = evhttp_request_new(http_request_done, bev);
46626fd3d56SCy Schubert 	if (req == NULL) {
46726fd3d56SCy Schubert 		fprintf(stderr, "evhttp_request_new() failed\n");
46826fd3d56SCy Schubert 		goto error;
46926fd3d56SCy Schubert 	}
47026fd3d56SCy Schubert 
47126fd3d56SCy Schubert 	output_headers = evhttp_request_get_output_headers(req);
47226fd3d56SCy Schubert 	evhttp_add_header(output_headers, "Host", host);
47326fd3d56SCy Schubert 	evhttp_add_header(output_headers, "Connection", "close");
47426fd3d56SCy Schubert 
47526fd3d56SCy Schubert 	if (data_file) {
47626fd3d56SCy Schubert 		/* NOTE: In production code, you'd probably want to use
47726fd3d56SCy Schubert 		 * evbuffer_add_file() or evbuffer_add_file_segment(), to
47826fd3d56SCy Schubert 		 * avoid needless copying. */
47926fd3d56SCy Schubert 		FILE * f = fopen(data_file, "rb");
48026fd3d56SCy Schubert 		char buf[1024];
48126fd3d56SCy Schubert 		size_t s;
48226fd3d56SCy Schubert 		size_t bytes = 0;
48326fd3d56SCy Schubert 
48426fd3d56SCy Schubert 		if (!f) {
48526fd3d56SCy Schubert 			syntax();
48626fd3d56SCy Schubert 			goto error;
48726fd3d56SCy Schubert 		}
48826fd3d56SCy Schubert 
48926fd3d56SCy Schubert 		output_buffer = evhttp_request_get_output_buffer(req);
49026fd3d56SCy Schubert 		while ((s = fread(buf, 1, sizeof(buf), f)) > 0) {
49126fd3d56SCy Schubert 			evbuffer_add(output_buffer, buf, s);
49226fd3d56SCy Schubert 			bytes += s;
49326fd3d56SCy Schubert 		}
49426fd3d56SCy Schubert 		evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes);
49526fd3d56SCy Schubert 		evhttp_add_header(output_headers, "Content-Length", buf);
49626fd3d56SCy Schubert 		fclose(f);
49726fd3d56SCy Schubert 	}
49826fd3d56SCy Schubert 
49926fd3d56SCy Schubert 	r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
50026fd3d56SCy Schubert 	if (r != 0) {
50126fd3d56SCy Schubert 		fprintf(stderr, "evhttp_make_request() failed\n");
50226fd3d56SCy Schubert 		goto error;
50326fd3d56SCy Schubert 	}
50426fd3d56SCy Schubert 
50526fd3d56SCy Schubert 	event_base_dispatch(base);
50626fd3d56SCy Schubert 	goto cleanup;
50726fd3d56SCy Schubert 
50826fd3d56SCy Schubert error:
50926fd3d56SCy Schubert 	ret = 1;
51026fd3d56SCy Schubert cleanup:
51126fd3d56SCy Schubert 	if (evcon)
51226fd3d56SCy Schubert 		evhttp_connection_free(evcon);
51326fd3d56SCy Schubert 	if (http_uri)
51426fd3d56SCy Schubert 		evhttp_uri_free(http_uri);
51526fd3d56SCy Schubert 	if (base)
51626fd3d56SCy Schubert 		event_base_free(base);
51726fd3d56SCy Schubert 
51826fd3d56SCy Schubert 	if (ssl_ctx)
51926fd3d56SCy Schubert 		SSL_CTX_free(ssl_ctx);
52026fd3d56SCy Schubert 	if (type == HTTP && ssl)
52126fd3d56SCy Schubert 		SSL_free(ssl);
52226fd3d56SCy Schubert #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
52326fd3d56SCy Schubert 	(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
52426fd3d56SCy Schubert 	EVP_cleanup();
52526fd3d56SCy Schubert 	ERR_free_strings();
52626fd3d56SCy Schubert 
52726fd3d56SCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10000000L
52826fd3d56SCy Schubert 	ERR_remove_state(0);
52926fd3d56SCy Schubert #else
53026fd3d56SCy Schubert 	ERR_remove_thread_state(NULL);
53126fd3d56SCy Schubert #endif
53226fd3d56SCy Schubert 
53326fd3d56SCy Schubert 	CRYPTO_cleanup_all_ex_data();
53426fd3d56SCy Schubert 
53526fd3d56SCy Schubert 	sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
53626fd3d56SCy Schubert #endif /* (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
53726fd3d56SCy Schubert 	(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) */
53826fd3d56SCy Schubert 
53926fd3d56SCy Schubert #ifdef _WIN32
54026fd3d56SCy Schubert 	WSACleanup();
54126fd3d56SCy Schubert #endif
54226fd3d56SCy Schubert 
54326fd3d56SCy Schubert 	return ret;
54426fd3d56SCy Schubert }
545