Home | History | Annotate | Line # | Download | only in guide
      1 /*
      2  *  Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  *  Licensed under the Apache License 2.0 (the "License").  You may not use
      5  *  this file except in compliance with the License.  You can obtain a copy
      6  *  in the file LICENSE in the source distribution or at
      7  *  https://www.openssl.org/source/license.html
      8  */
      9 
     10 /*
     11  * NB: Changes to this file should also be reflected in
     12  * doc/man7/ossl-guide-quic-multi-stream.pod
     13  */
     14 
     15 #include <string.h>
     16 
     17 /* Include the appropriate header file for SOCK_DGRAM */
     18 #ifdef _WIN32 /* Windows */
     19 #include <winsock2.h>
     20 #else /* Linux/Unix */
     21 #include <sys/socket.h>
     22 #endif
     23 
     24 #include <openssl/bio.h>
     25 #include <openssl/ssl.h>
     26 #include <openssl/err.h>
     27 
     28 /* Helper function to create a BIO connected to the server */
     29 static BIO *create_socket_bio(const char *hostname, const char *port,
     30     int family, BIO_ADDR **peer_addr)
     31 {
     32     int sock = -1;
     33     BIO_ADDRINFO *res;
     34     const BIO_ADDRINFO *ai = NULL;
     35     BIO *bio;
     36 
     37     /*
     38      * Lookup IP address info for the server.
     39      */
     40     if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_DGRAM, 0,
     41             &res))
     42         return NULL;
     43 
     44     /*
     45      * Loop through all the possible addresses for the server and find one
     46      * we can connect to.
     47      */
     48     for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) {
     49         /*
     50          * Create a UDP socket. We could equally use non-OpenSSL calls such
     51          * as "socket" here for this and the subsequent connect and close
     52          * functions. But for portability reasons and also so that we get
     53          * errors on the OpenSSL stack in the event of a failure we use
     54          * OpenSSL's versions of these functions.
     55          */
     56         sock = BIO_socket(BIO_ADDRINFO_family(ai), SOCK_DGRAM, 0, 0);
     57         if (sock == -1)
     58             continue;
     59 
     60         /* Connect the socket to the server's address */
     61         if (!BIO_connect(sock, BIO_ADDRINFO_address(ai), 0)) {
     62             BIO_closesocket(sock);
     63             sock = -1;
     64             continue;
     65         }
     66 
     67         /* Set to nonblocking mode */
     68         if (!BIO_socket_nbio(sock, 1)) {
     69             BIO_closesocket(sock);
     70             sock = -1;
     71             continue;
     72         }
     73 
     74         break;
     75     }
     76 
     77     if (sock != -1) {
     78         *peer_addr = BIO_ADDR_dup(BIO_ADDRINFO_address(ai));
     79         if (*peer_addr == NULL) {
     80             BIO_closesocket(sock);
     81             return NULL;
     82         }
     83     }
     84 
     85     /* Free the address information resources we allocated earlier */
     86     BIO_ADDRINFO_free(res);
     87 
     88     /* If sock is -1 then we've been unable to connect to the server */
     89     if (sock == -1)
     90         return NULL;
     91 
     92     /* Create a BIO to wrap the socket */
     93     bio = BIO_new(BIO_s_datagram());
     94     if (bio == NULL) {
     95         BIO_closesocket(sock);
     96         return NULL;
     97     }
     98 
     99     /*
    100      * Associate the newly created BIO with the underlying socket. By
    101      * passing BIO_CLOSE here the socket will be automatically closed when
    102      * the BIO is freed. Alternatively you can use BIO_NOCLOSE, in which
    103      * case you must close the socket explicitly when it is no longer
    104      * needed.
    105      */
    106     BIO_set_fd(bio, sock, BIO_CLOSE);
    107 
    108     return bio;
    109 }
    110 
    111 static int write_a_request(SSL *stream, const char *request_start,
    112     const char *hostname)
    113 {
    114     const char *request_end = "\r\n\r\n";
    115     size_t written;
    116 
    117     if (!SSL_write_ex(stream, request_start, strlen(request_start),
    118             &written))
    119         return 0;
    120     if (!SSL_write_ex(stream, hostname, strlen(hostname), &written))
    121         return 0;
    122     if (!SSL_write_ex(stream, request_end, strlen(request_end), &written))
    123         return 0;
    124 
    125     return 1;
    126 }
    127 
    128 /*
    129  * Simple application to send basic HTTP/1.0 requests to a server and print the
    130  * response on the screen. Note that HTTP/1.0 over QUIC is not a real protocol
    131  * and will not be supported by real world servers. This is for demonstration
    132  * purposes only.
    133  */
    134 int main(int argc, char *argv[])
    135 {
    136     SSL_CTX *ctx = NULL;
    137     SSL *ssl = NULL;
    138     SSL *stream1 = NULL, *stream2 = NULL, *stream3 = NULL;
    139     BIO *bio = NULL;
    140     int res = EXIT_FAILURE;
    141     int ret;
    142     unsigned char alpn[] = { 8, 'h', 't', 't', 'p', '/', '1', '.', '0' };
    143     const char *request1_start = "GET /request1.html HTTP/1.0\r\nConnection: close\r\nHost: ";
    144     const char *request2_start = "GET /request2.html HTTP/1.0\r\nConnection: close\r\nHost: ";
    145     size_t readbytes;
    146     char buf[160];
    147     BIO_ADDR *peer_addr = NULL;
    148     char *hostname, *port;
    149     int argnext = 1;
    150     int ipv6 = 0;
    151 
    152     if (argc < 3) {
    153         printf("Usage: quic-client-non-block [-6] hostname port\n");
    154         goto end;
    155     }
    156 
    157     if (!strcmp(argv[argnext], "-6")) {
    158         if (argc < 4) {
    159             printf("Usage: quic-client-non-block [-6] hostname port\n");
    160             goto end;
    161         }
    162         ipv6 = 1;
    163         argnext++;
    164     }
    165     hostname = argv[argnext++];
    166     port = argv[argnext];
    167 
    168     /*
    169      * Create an SSL_CTX which we can use to create SSL objects from. We
    170      * want an SSL_CTX for creating clients so we use
    171      * OSSL_QUIC_client_method() here.
    172      */
    173     ctx = SSL_CTX_new(OSSL_QUIC_client_method());
    174     if (ctx == NULL) {
    175         printf("Failed to create the SSL_CTX\n");
    176         goto end;
    177     }
    178 
    179     /*
    180      * Configure the client to abort the handshake if certificate
    181      * verification fails. Virtually all clients should do this unless you
    182      * really know what you are doing.
    183      */
    184     SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    185 
    186     /* Use the default trusted certificate store */
    187     if (!SSL_CTX_set_default_verify_paths(ctx)) {
    188         printf("Failed to set the default trusted certificate store\n");
    189         goto end;
    190     }
    191 
    192     /* Create an SSL object to represent the TLS connection */
    193     ssl = SSL_new(ctx);
    194     if (ssl == NULL) {
    195         printf("Failed to create the SSL object\n");
    196         goto end;
    197     }
    198 
    199     /*
    200      * We will use multiple streams so we will disable the default stream mode.
    201      * This is not a requirement for using multiple streams but is recommended.
    202      */
    203     if (!SSL_set_default_stream_mode(ssl, SSL_DEFAULT_STREAM_MODE_NONE)) {
    204         printf("Failed to disable the default stream mode\n");
    205         goto end;
    206     }
    207 
    208     /*
    209      * Create the underlying transport socket/BIO and associate it with the
    210      * connection.
    211      */
    212     bio = create_socket_bio(hostname, port, ipv6 ? AF_INET6 : AF_INET, &peer_addr);
    213     if (bio == NULL) {
    214         printf("Failed to crete the BIO\n");
    215         goto end;
    216     }
    217     SSL_set_bio(ssl, bio, bio);
    218 
    219     /*
    220      * Tell the server during the handshake which hostname we are attempting
    221      * to connect to in case the server supports multiple hosts.
    222      */
    223     if (!SSL_set_tlsext_host_name(ssl, hostname)) {
    224         printf("Failed to set the SNI hostname\n");
    225         goto end;
    226     }
    227 
    228     /*
    229      * Ensure we check during certificate verification that the server has
    230      * supplied a certificate for the hostname that we were expecting.
    231      * Virtually all clients should do this unless you really know what you
    232      * are doing.
    233      */
    234     if (!SSL_set1_host(ssl, hostname)) {
    235         printf("Failed to set the certificate verification hostname");
    236         goto end;
    237     }
    238 
    239     /* SSL_set_alpn_protos returns 0 for success! */
    240     if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn)) != 0) {
    241         printf("Failed to set the ALPN for the connection\n");
    242         goto end;
    243     }
    244 
    245     /* Set the IP address of the remote peer */
    246     if (!SSL_set1_initial_peer_addr(ssl, peer_addr)) {
    247         printf("Failed to set the initial peer address\n");
    248         goto end;
    249     }
    250 
    251     /* Do the handshake with the server */
    252     if (SSL_connect(ssl) < 1) {
    253         printf("Failed to connect to the server\n");
    254         /*
    255          * If the failure is due to a verification error we can get more
    256          * information about it from SSL_get_verify_result().
    257          */
    258         if (SSL_get_verify_result(ssl) != X509_V_OK)
    259             printf("Verify error: %s\n",
    260                 X509_verify_cert_error_string(SSL_get_verify_result(ssl)));
    261         goto end;
    262     }
    263 
    264     /*
    265      * We create two new client initiated streams. The first will be
    266      * bi-directional, and the second will be uni-directional.
    267      */
    268     stream1 = SSL_new_stream(ssl, 0);
    269     stream2 = SSL_new_stream(ssl, SSL_STREAM_FLAG_UNI);
    270     if (stream1 == NULL || stream2 == NULL) {
    271         printf("Failed to create streams\n");
    272         goto end;
    273     }
    274 
    275     /* Write an HTTP GET request on each of our streams to the peer */
    276     if (!write_a_request(stream1, request1_start, hostname)) {
    277         printf("Failed to write HTTP request on stream 1\n");
    278         goto end;
    279     }
    280 
    281     if (!write_a_request(stream2, request2_start, hostname)) {
    282         printf("Failed to write HTTP request on stream 2\n");
    283         goto end;
    284     }
    285 
    286     /*
    287      * In this demo we read all the data from one stream before reading all the
    288      * data from the next stream for simplicity. In practice there is no need to
    289      * do this. We can interleave IO on the different streams if we wish, or
    290      * manage the streams entirely separately on different threads.
    291      */
    292 
    293     printf("Stream 1 data:\n");
    294     /*
    295      * Get up to sizeof(buf) bytes of the response from stream 1 (which is a
    296      * bidirectional stream). We keep reading until the server closes the
    297      * connection.
    298      */
    299     while (SSL_read_ex(stream1, buf, sizeof(buf), &readbytes)) {
    300         /*
    301          * OpenSSL does not guarantee that the returned data is a string or
    302          * that it is NUL terminated so we use fwrite() to write the exact
    303          * number of bytes that we read. The data could be non-printable or
    304          * have NUL characters in the middle of it. For this simple example
    305          * we're going to print it to stdout anyway.
    306          */
    307         fwrite(buf, 1, readbytes, stdout);
    308     }
    309     /* In case the response didn't finish with a newline we add one now */
    310     printf("\n");
    311 
    312     /*
    313      * Check whether we finished the while loop above normally or as the
    314      * result of an error. The 0 argument to SSL_get_error() is the return
    315      * code we received from the SSL_read_ex() call. It must be 0 in order
    316      * to get here. Normal completion is indicated by SSL_ERROR_ZERO_RETURN. In
    317      * QUIC terms this means that the peer has sent FIN on the stream to
    318      * indicate that no further data will be sent.
    319      */
    320     switch (SSL_get_error(stream1, 0)) {
    321     case SSL_ERROR_ZERO_RETURN:
    322         /* Normal completion of the stream */
    323         break;
    324 
    325     case SSL_ERROR_SSL:
    326         /*
    327          * Some stream fatal error occurred. This could be because of a stream
    328          * reset - or some failure occurred on the underlying connection.
    329          */
    330         switch (SSL_get_stream_read_state(stream1)) {
    331         case SSL_STREAM_STATE_RESET_REMOTE:
    332             printf("Stream reset occurred\n");
    333             /* The stream has been reset but the connection is still healthy. */
    334             break;
    335 
    336         case SSL_STREAM_STATE_CONN_CLOSED:
    337             printf("Connection closed\n");
    338             /* Connection is already closed. Skip SSL_shutdown() */
    339             goto end;
    340 
    341         default:
    342             printf("Unknown stream failure\n");
    343             break;
    344         }
    345         break;
    346 
    347     default:
    348         /* Some other unexpected error occurred */
    349         printf("Failed reading remaining data\n");
    350         break;
    351     }
    352 
    353     /*
    354      * In our hypothetical HTTP/1.0 over QUIC protocol that we are using we
    355      * assume that the server will respond with a server initiated stream
    356      * containing the data requested in our uni-directional stream. This doesn't
    357      * really make sense to do in a real protocol, but its just for
    358      * demonstration purposes.
    359      *
    360      * We're using blocking mode so this will block until a stream becomes
    361      * available. We could override this behaviour if we wanted to by setting
    362      * the SSL_ACCEPT_STREAM_NO_BLOCK flag in the second argument below.
    363      */
    364     stream3 = SSL_accept_stream(ssl, 0);
    365     if (stream3 == NULL) {
    366         printf("Failed to accept a new stream\n");
    367         goto end;
    368     }
    369 
    370     printf("Stream 3 data:\n");
    371     /*
    372      * Read the data from stream 3 like we did for stream 1 above. Note that
    373      * stream 2 was uni-directional so there is no data to be read from that
    374      * one.
    375      */
    376     while (SSL_read_ex(stream3, buf, sizeof(buf), &readbytes))
    377         fwrite(buf, 1, readbytes, stdout);
    378     printf("\n");
    379 
    380     /* Check for errors on the stream */
    381     switch (SSL_get_error(stream3, 0)) {
    382     case SSL_ERROR_ZERO_RETURN:
    383         /* Normal completion of the stream */
    384         break;
    385 
    386     case SSL_ERROR_SSL:
    387         switch (SSL_get_stream_read_state(stream3)) {
    388         case SSL_STREAM_STATE_RESET_REMOTE:
    389             printf("Stream reset occurred\n");
    390             break;
    391 
    392         case SSL_STREAM_STATE_CONN_CLOSED:
    393             printf("Connection closed\n");
    394             goto end;
    395 
    396         default:
    397             printf("Unknown stream failure\n");
    398             break;
    399         }
    400         break;
    401 
    402     default:
    403         printf("Failed reading remaining data\n");
    404         break;
    405     }
    406 
    407     /*
    408      * Repeatedly call SSL_shutdown() until the connection is fully
    409      * closed.
    410      */
    411     do {
    412         ret = SSL_shutdown(ssl);
    413         if (ret < 0) {
    414             printf("Error shutting down: %d\n", ret);
    415             goto end;
    416         }
    417     } while (ret != 1);
    418 
    419     /* Success! */
    420     res = EXIT_SUCCESS;
    421 end:
    422     /*
    423      * If something bad happened then we will dump the contents of the
    424      * OpenSSL error stack to stderr. There might be some useful diagnostic
    425      * information there.
    426      */
    427     if (res == EXIT_FAILURE)
    428         ERR_print_errors_fp(stderr);
    429 
    430     /*
    431      * Free the resources we allocated. We do not free the BIO object here
    432      * because ownership of it was immediately transferred to the SSL object
    433      * via SSL_set_bio(). The BIO will be freed when we free the SSL object.
    434      */
    435     SSL_free(ssl);
    436     SSL_free(stream1);
    437     SSL_free(stream2);
    438     SSL_free(stream3);
    439     SSL_CTX_free(ctx);
    440     BIO_ADDR_free(peer_addr);
    441     return res;
    442 }
    443