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  */
create_ssl_ctx(void)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  */
new_conn(SSL_CTX * ctx,int fd,const char * bare_hostname)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  */
tx(APP_CONN * conn,const void * buf,int buf_len)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  */
rx(APP_CONN * conn,void * buf,int buf_len)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  */
get_conn_fd(APP_CONN * conn)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  */
get_conn_pending_tx(APP_CONN * conn)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 
get_conn_pending_rx(APP_CONN * conn)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 
get_conn_pump_timeout(APP_CONN * conn)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  */
pump(APP_CONN * conn)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  */
teardown(APP_CONN * conn)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  */
teardown_ctx(SSL_CTX * ctx)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 
ms_to_timeval(struct timeval * t,int ms)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 
timeval_to_ms(const struct timeval * t)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 
main(int argc,char ** argv)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