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