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