1 #include <sys/poll.h> 2 #include <openssl/ssl.h> 3 4 /* 5 * Demo 2: Client — Managed Connection — Nonblocking 6 * ============================================================== 7 * 8 * This is an example of (part of) an application which uses libssl in an 9 * asynchronous, nonblocking fashion. The functions show all interactions with 10 * libssl the application makes, and would hypothetically be linked into a 11 * larger application. 12 * 13 * In this example, libssl still makes syscalls directly using an fd, which is 14 * configured in nonblocking mode. As such, the application can still be 15 * abstracted from the details of what that fd is (is it a TCP socket? is it a 16 * UDP socket?); this code passes the application an fd and the application 17 * simply calls back into this code when poll()/etc. indicates it is ready. 18 */ 19 typedef struct app_conn_st { 20 SSL *ssl; 21 BIO *ssl_bio; 22 int rx_need_tx, tx_need_rx; 23 } APP_CONN; 24 25 /* 26 * The application is initializing and wants an SSL_CTX which it will use for 27 * some number of outgoing connections, which it creates in subsequent calls to 28 * new_conn. The application may also call this function multiple times to 29 * create multiple SSL_CTX. 30 */ 31 SSL_CTX *create_ssl_ctx(void) 32 { 33 SSL_CTX *ctx; 34 35 #ifdef USE_QUIC 36 ctx = SSL_CTX_new(OSSL_QUIC_client_method()); 37 #else 38 ctx = SSL_CTX_new(TLS_client_method()); 39 #endif 40 if (ctx == NULL) 41 return NULL; 42 43 /* Enable trust chain verification. */ 44 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 45 46 /* Load default root CA store. */ 47 if (SSL_CTX_set_default_verify_paths(ctx) == 0) { 48 SSL_CTX_free(ctx); 49 return NULL; 50 } 51 52 return ctx; 53 } 54 55 /* 56 * The application wants to create a new outgoing connection using a given 57 * SSL_CTX. 58 * 59 * hostname is a string like "openssl.org:443" or "[::1]:443". 60 */ 61 APP_CONN *new_conn(SSL_CTX *ctx, const char *hostname) 62 { 63 APP_CONN *conn; 64 BIO *out, *buf; 65 SSL *ssl = NULL; 66 const char *bare_hostname; 67 #ifdef USE_QUIC 68 static const unsigned char alpn[] = {5, 'd', 'u', 'm', 'm', 'y'}; 69 #endif 70 71 conn = calloc(1, sizeof(APP_CONN)); 72 if (conn == NULL) 73 return NULL; 74 75 out = BIO_new_ssl_connect(ctx); 76 if (out == NULL) { 77 free(conn); 78 return NULL; 79 } 80 81 if (BIO_get_ssl(out, &ssl) == 0) { 82 BIO_free_all(out); 83 free(conn); 84 return NULL; 85 } 86 87 /* 88 * NOTE: QUIC cannot operate with a buffering BIO between the QUIC SSL 89 * object in the network. In this case, the call to BIO_push() is not 90 * supported by the QUIC SSL object and will be ignored, thus this code 91 * works without removing this line. However, the buffering BIO is not 92 * actually used as a result and should be removed when adapting code to use 93 * QUIC. 94 * 95 * Setting a buffer as the underlying BIO on the QUIC SSL object using 96 * SSL_set_bio() will not work, though BIO_s_dgram_pair is available for 97 * buffering the input and output to the QUIC SSL object on the network side 98 * if desired. 99 */ 100 buf = BIO_new(BIO_f_buffer()); 101 if (buf == NULL) { 102 BIO_free_all(out); 103 free(conn); 104 return NULL; 105 } 106 107 BIO_push(out, buf); 108 109 if (BIO_set_conn_hostname(out, hostname) == 0) { 110 BIO_free_all(out); 111 free(conn); 112 return NULL; 113 } 114 115 /* Returns the parsed hostname extracted from the hostname:port string. */ 116 bare_hostname = BIO_get_conn_hostname(out); 117 if (bare_hostname == NULL) { 118 BIO_free_all(out); 119 free(conn); 120 return NULL; 121 } 122 123 /* Tell the SSL object the hostname to check certificates against. */ 124 if (SSL_set1_host(ssl, bare_hostname) <= 0) { 125 BIO_free_all(out); 126 free(conn); 127 return NULL; 128 } 129 130 #ifdef USE_QUIC 131 /* Configure ALPN, which is required for QUIC. */ 132 if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) { 133 /* Note: SSL_set_alpn_protos returns 1 for failure. */ 134 BIO_free_all(out); 135 return NULL; 136 } 137 #endif 138 139 /* Make the BIO nonblocking. */ 140 BIO_set_nbio(out, 1); 141 142 conn->ssl_bio = out; 143 return conn; 144 } 145 146 /* 147 * Non-blocking transmission. 148 * 149 * Returns -1 on error. Returns -2 if the function would block (corresponds to 150 * EWOULDBLOCK). 151 */ 152 int tx(APP_CONN *conn, const void *buf, int buf_len) 153 { 154 int l; 155 156 conn->tx_need_rx = 0; 157 158 l = BIO_write(conn->ssl_bio, buf, buf_len); 159 if (l <= 0) { 160 if (BIO_should_retry(conn->ssl_bio)) { 161 conn->tx_need_rx = BIO_should_read(conn->ssl_bio); 162 return -2; 163 } else { 164 return -1; 165 } 166 } 167 168 return l; 169 } 170 171 /* 172 * Non-blocking reception. 173 * 174 * Returns -1 on error. Returns -2 if the function would block (corresponds to 175 * EWOULDBLOCK). 176 */ 177 int rx(APP_CONN *conn, void *buf, int buf_len) 178 { 179 int l; 180 181 conn->rx_need_tx = 0; 182 183 l = BIO_read(conn->ssl_bio, buf, buf_len); 184 if (l <= 0) { 185 if (BIO_should_retry(conn->ssl_bio)) { 186 conn->rx_need_tx = BIO_should_write(conn->ssl_bio); 187 return -2; 188 } else { 189 return -1; 190 } 191 } 192 193 return l; 194 } 195 196 /* 197 * The application wants to know a fd it can poll on to determine when the 198 * SSL state machine needs to be pumped. 199 */ 200 int get_conn_fd(APP_CONN *conn) 201 { 202 #ifdef USE_QUIC 203 BIO_POLL_DESCRIPTOR d; 204 205 if (!BIO_get_rpoll_descriptor(conn->ssl_bio, &d)) 206 return -1; 207 208 return d.value.fd; 209 #else 210 return BIO_get_fd(conn->ssl_bio, NULL); 211 #endif 212 } 213 214 /* 215 * These functions returns zero or more of: 216 * 217 * POLLIN: The SSL state machine is interested in socket readability events. 218 * 219 * POLLOUT: The SSL state machine is interested in socket writeability events. 220 * 221 * POLLERR: The SSL state machine is interested in socket error events. 222 * 223 * get_conn_pending_tx returns events which may cause SSL_write to make 224 * progress and get_conn_pending_rx returns events which may cause SSL_read 225 * to make progress. 226 */ 227 int get_conn_pending_tx(APP_CONN *conn) 228 { 229 #ifdef USE_QUIC 230 return (SSL_net_read_desired(conn->ssl) ? POLLIN : 0) 231 | (SSL_net_write_desired(conn->ssl) ? POLLOUT : 0) 232 | POLLERR; 233 #else 234 return (conn->tx_need_rx ? POLLIN : 0) | POLLOUT | POLLERR; 235 #endif 236 } 237 238 int get_conn_pending_rx(APP_CONN *conn) 239 { 240 #ifdef USE_QUIC 241 return get_conn_pending_tx(conn); 242 #else 243 return (conn->rx_need_tx ? POLLOUT : 0) | POLLIN | POLLERR; 244 #endif 245 } 246 247 #ifdef USE_QUIC 248 /* 249 * Returns the number of milliseconds after which some call to libssl must be 250 * made. Any call (BIO_read/BIO_write/BIO_pump) will do. Returns -1 if 251 * there is no need for such a call. This may change after the next call 252 * to libssl. 253 */ 254 static inline int timeval_to_ms(const struct timeval *t); 255 256 int get_conn_pump_timeout(APP_CONN *conn) 257 { 258 struct timeval tv; 259 int is_infinite; 260 261 if (!SSL_get_event_timeout(conn->ssl, &tv, &is_infinite)) 262 return -1; 263 264 return is_infinite ? -1 : timeval_to_ms(&tv); 265 } 266 267 /* 268 * Called to advance internals of libssl state machines without having to 269 * perform an application-level read/write. 270 */ 271 void pump(APP_CONN *conn) 272 { 273 SSL_handle_events(conn->ssl); 274 } 275 #endif 276 277 /* 278 * The application wants to close the connection and free bookkeeping 279 * structures. 280 */ 281 void teardown(APP_CONN *conn) 282 { 283 BIO_free_all(conn->ssl_bio); 284 free(conn); 285 } 286 287 /* 288 * The application is shutting down and wants to free a previously 289 * created SSL_CTX. 290 */ 291 void teardown_ctx(SSL_CTX *ctx) 292 { 293 SSL_CTX_free(ctx); 294 } 295 296 /* 297 * ============================================================================ 298 * Example driver for the above code. This is just to demonstrate that the code 299 * works and is not intended to be representative of a real application. 300 */ 301 #include <sys/time.h> 302 303 static inline void ms_to_timeval(struct timeval *t, int ms) 304 { 305 t->tv_sec = ms < 0 ? -1 : ms/1000; 306 t->tv_usec = ms < 0 ? 0 : (ms%1000)*1000; 307 } 308 309 static inline int timeval_to_ms(const struct timeval *t) 310 { 311 return t->tv_sec*1000 + t->tv_usec/1000; 312 } 313 314 int main(int argc, char **argv) 315 { 316 static char tx_msg[384], host_port[300]; 317 const char *tx_p = tx_msg; 318 char rx_buf[2048]; 319 int res = 1, l, tx_len; 320 #ifdef USE_QUIC 321 struct timeval timeout; 322 #else 323 int timeout = 2000 /* ms */; 324 #endif 325 APP_CONN *conn = NULL; 326 SSL_CTX *ctx = NULL; 327 328 #ifdef USE_QUIC 329 ms_to_timeval(&timeout, 2000); 330 #endif 331 332 if (argc < 3) { 333 fprintf(stderr, "usage: %s host port\n", argv[0]); 334 goto fail; 335 } 336 337 snprintf(host_port, sizeof(host_port), "%s:%s", argv[1], argv[2]); 338 tx_len = snprintf(tx_msg, sizeof(tx_msg), 339 "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", argv[1]); 340 341 ctx = create_ssl_ctx(); 342 if (ctx == NULL) { 343 fprintf(stderr, "cannot create SSL context\n"); 344 goto fail; 345 } 346 347 conn = new_conn(ctx, host_port); 348 if (conn == NULL) { 349 fprintf(stderr, "cannot establish connection\n"); 350 goto fail; 351 } 352 353 /* TX */ 354 while (tx_len != 0) { 355 l = tx(conn, tx_p, tx_len); 356 if (l > 0) { 357 tx_p += l; 358 tx_len -= l; 359 } else if (l == -1) { 360 fprintf(stderr, "tx error\n"); 361 } else if (l == -2) { 362 #ifdef USE_QUIC 363 struct timeval start, now, deadline, t; 364 #endif 365 struct pollfd pfd = {0}; 366 367 #ifdef USE_QUIC 368 ms_to_timeval(&t, get_conn_pump_timeout(conn)); 369 if (t.tv_sec < 0 || timercmp(&t, &timeout, >)) 370 t = timeout; 371 372 gettimeofday(&start, NULL); 373 timeradd(&start, &timeout, &deadline); 374 #endif 375 376 pfd.fd = get_conn_fd(conn); 377 pfd.events = get_conn_pending_tx(conn); 378 #ifdef USE_QUIC 379 if (poll(&pfd, 1, timeval_to_ms(&t)) == 0) 380 #else 381 if (poll(&pfd, 1, timeout) == 0) 382 #endif 383 { 384 #ifdef USE_QUIC 385 pump(conn); 386 387 gettimeofday(&now, NULL); 388 if (timercmp(&now, &deadline, >=)) 389 #endif 390 { 391 fprintf(stderr, "tx timeout\n"); 392 goto fail; 393 } 394 } 395 } 396 } 397 398 /* RX */ 399 for (;;) { 400 l = rx(conn, rx_buf, sizeof(rx_buf)); 401 if (l > 0) { 402 fwrite(rx_buf, 1, l, stdout); 403 } else if (l == -1) { 404 break; 405 } else if (l == -2) { 406 #ifdef USE_QUIC 407 struct timeval start, now, deadline, t; 408 #endif 409 struct pollfd pfd = {0}; 410 411 #ifdef USE_QUIC 412 ms_to_timeval(&t, get_conn_pump_timeout(conn)); 413 if (t.tv_sec < 0 || timercmp(&t, &timeout, >)) 414 t = timeout; 415 416 gettimeofday(&start, NULL); 417 timeradd(&start, &timeout, &deadline); 418 #endif 419 420 pfd.fd = get_conn_fd(conn); 421 pfd.events = get_conn_pending_rx(conn); 422 #ifdef USE_QUIC 423 if (poll(&pfd, 1, timeval_to_ms(&t)) == 0) 424 #else 425 if (poll(&pfd, 1, timeout) == 0) 426 #endif 427 { 428 #ifdef USE_QUIC 429 pump(conn); 430 431 gettimeofday(&now, NULL); 432 if (timercmp(&now, &deadline, >=)) 433 #endif 434 { 435 fprintf(stderr, "rx timeout\n"); 436 goto fail; 437 } 438 } 439 } 440 } 441 442 res = 0; 443 fail: 444 if (conn != NULL) 445 teardown(conn); 446 if (ctx != NULL) 447 teardown_ctx(ctx); 448 return res; 449 } 450