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