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_thread_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 buf = BIO_new(BIO_f_buffer()); 88 if (buf == NULL) { 89 BIO_free_all(out); 90 free(conn); 91 return NULL; 92 } 93 94 BIO_push(out, buf); 95 96 if (BIO_set_conn_hostname(out, hostname) == 0) { 97 BIO_free_all(out); 98 free(conn); 99 return NULL; 100 } 101 102 /* Returns the parsed hostname extracted from the hostname:port string. */ 103 bare_hostname = BIO_get_conn_hostname(out); 104 if (bare_hostname == NULL) { 105 BIO_free_all(out); 106 free(conn); 107 return NULL; 108 } 109 110 /* Tell the SSL object the hostname to check certificates against. */ 111 if (SSL_set1_host(ssl, bare_hostname) <= 0) { 112 BIO_free_all(out); 113 free(conn); 114 return NULL; 115 } 116 117 #ifdef USE_QUIC 118 /* Configure ALPN, which is required for QUIC. */ 119 if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) { 120 /* Note: SSL_set_alpn_protos returns 1 for failure. */ 121 BIO_free_all(out); 122 free(conn); 123 return NULL; 124 } 125 #endif 126 127 /* Make the BIO nonblocking. */ 128 BIO_set_nbio(out, 1); 129 130 conn->ssl_bio = out; 131 return conn; 132 } 133 134 /* 135 * Non-blocking transmission. 136 * 137 * Returns -1 on error. Returns -2 if the function would block (corresponds to 138 * EWOULDBLOCK). 139 */ 140 int tx(APP_CONN *conn, const void *buf, int buf_len) 141 { 142 int l; 143 144 conn->tx_need_rx = 0; 145 146 l = BIO_write(conn->ssl_bio, buf, buf_len); 147 if (l <= 0) { 148 if (BIO_should_retry(conn->ssl_bio)) { 149 conn->tx_need_rx = BIO_should_read(conn->ssl_bio); 150 return -2; 151 } else { 152 return -1; 153 } 154 } 155 156 return l; 157 } 158 159 /* 160 * Non-blocking reception. 161 * 162 * Returns -1 on error. Returns -2 if the function would block (corresponds to 163 * EWOULDBLOCK). 164 */ 165 int rx(APP_CONN *conn, void *buf, int buf_len) 166 { 167 int l; 168 169 conn->rx_need_tx = 0; 170 171 l = BIO_read(conn->ssl_bio, buf, buf_len); 172 if (l <= 0) { 173 if (BIO_should_retry(conn->ssl_bio)) { 174 conn->rx_need_tx = BIO_should_write(conn->ssl_bio); 175 return -2; 176 } else { 177 return -1; 178 } 179 } 180 181 return l; 182 } 183 184 /* 185 * The application wants to know a fd it can poll on to determine when the 186 * SSL state machine needs to be pumped. 187 */ 188 int get_conn_fd(APP_CONN *conn) 189 { 190 #ifdef USE_QUIC 191 BIO_POLL_DESCRIPTOR d; 192 193 if (!BIO_get_rpoll_descriptor(conn->ssl_bio, &d)) 194 return -1; 195 196 return d.value.fd; 197 #else 198 return BIO_get_fd(conn->ssl_bio, NULL); 199 #endif 200 } 201 202 /* 203 * These functions returns zero or more of: 204 * 205 * POLLIN: The SSL state machine is interested in socket readability events. 206 * 207 * POLLOUT: The SSL state machine is interested in socket writeability events. 208 * 209 * POLLERR: The SSL state machine is interested in socket error events. 210 * 211 * get_conn_pending_tx returns events which may cause SSL_write to make 212 * progress and get_conn_pending_rx returns events which may cause SSL_read 213 * to make progress. 214 */ 215 int get_conn_pending_tx(APP_CONN *conn) 216 { 217 #ifdef USE_QUIC 218 return (SSL_net_read_desired(conn->ssl) ? POLLIN : 0) 219 | (SSL_net_write_desired(conn->ssl) ? POLLOUT : 0) 220 | POLLERR; 221 #else 222 return (conn->tx_need_rx ? POLLIN : 0) | POLLOUT | POLLERR; 223 #endif 224 } 225 226 int get_conn_pending_rx(APP_CONN *conn) 227 { 228 #ifdef USE_QUIC 229 return get_conn_pending_tx(conn); 230 #else 231 return (conn->rx_need_tx ? POLLOUT : 0) | POLLIN | POLLERR; 232 #endif 233 } 234 235 /* 236 * The application wants to close the connection and free bookkeeping 237 * structures. 238 */ 239 void teardown(APP_CONN *conn) 240 { 241 BIO_free_all(conn->ssl_bio); 242 free(conn); 243 } 244 245 /* 246 * The application is shutting down and wants to free a previously 247 * created SSL_CTX. 248 */ 249 void teardown_ctx(SSL_CTX *ctx) 250 { 251 SSL_CTX_free(ctx); 252 } 253 254 /* 255 * ============================================================================ 256 * Example driver for the above code. This is just to demonstrate that the code 257 * works and is not intended to be representative of a real application. 258 */ 259 int main(int argc, char **argv) 260 { 261 static char tx_msg[384], host_port[300]; 262 const char *tx_p = tx_msg; 263 char rx_buf[2048]; 264 int res = 1, l, tx_len; 265 int timeout = 2000 /* ms */; 266 APP_CONN *conn = NULL; 267 SSL_CTX *ctx = NULL; 268 269 if (argc < 3) { 270 fprintf(stderr, "usage: %s host port\n", argv[0]); 271 goto fail; 272 } 273 274 snprintf(host_port, sizeof(host_port), "%s:%s", argv[1], argv[2]); 275 tx_len = snprintf(tx_msg, sizeof(tx_msg), 276 "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", argv[1]); 277 278 ctx = create_ssl_ctx(); 279 if (ctx == NULL) { 280 fprintf(stderr, "cannot create SSL context\n"); 281 goto fail; 282 } 283 284 conn = new_conn(ctx, host_port); 285 if (conn == NULL) { 286 fprintf(stderr, "cannot establish connection\n"); 287 goto fail; 288 } 289 290 /* TX */ 291 while (tx_len != 0) { 292 l = tx(conn, tx_p, tx_len); 293 if (l > 0) { 294 tx_p += l; 295 tx_len -= l; 296 } else if (l == -1) { 297 fprintf(stderr, "tx error\n"); 298 } else if (l == -2) { 299 struct pollfd pfd = {0}; 300 pfd.fd = get_conn_fd(conn); 301 pfd.events = get_conn_pending_tx(conn); 302 if (poll(&pfd, 1, timeout) == 0) { 303 fprintf(stderr, "tx timeout\n"); 304 goto fail; 305 } 306 } 307 } 308 309 /* RX */ 310 for (;;) { 311 l = rx(conn, rx_buf, sizeof(rx_buf)); 312 if (l > 0) { 313 fwrite(rx_buf, 1, l, stdout); 314 } else if (l == -1) { 315 break; 316 } else if (l == -2) { 317 struct pollfd pfd = {0}; 318 pfd.fd = get_conn_fd(conn); 319 pfd.events = get_conn_pending_rx(conn); 320 if (poll(&pfd, 1, timeout) == 0) { 321 fprintf(stderr, "rx timeout\n"); 322 goto fail; 323 } 324 } 325 } 326 327 res = 0; 328 fail: 329 if (conn != NULL) 330 teardown(conn); 331 if (ctx != NULL) 332 teardown_ctx(ctx); 333 return res; 334 } 335