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