diff options
-rw-r--r-- | doc/build.info | 12 | ||||
-rw-r--r-- | doc/man7/ossl-guide-quic-client-block.pod | 294 | ||||
-rw-r--r-- | doc/man7/ossl-guide-quic-introduction.pod | 135 | ||||
-rw-r--r-- | doc/man7/ossl-guide-tls-client-block.pod | 7 | ||||
-rw-r--r-- | doc/man7/ossl-guide-tls-introduction.pod | 4 |
5 files changed, 450 insertions, 2 deletions
diff --git a/doc/build.info b/doc/build.info index b8748d073d..24d4050a45 100644 --- a/doc/build.info +++ b/doc/build.info @@ -4757,6 +4757,14 @@ DEPEND[man/man7/openssl_user_macros.7]=man7/openssl_user_macros.pod GENERATE[man/man7/openssl_user_macros.7]=man7/openssl_user_macros.pod DEPEND[man7/openssl_user_macros.pod]{pod}=man7/openssl_user_macros.pod.in GENERATE[man7/openssl_user_macros.pod]=man7/openssl_user_macros.pod.in +DEPEND[html/man7/ossl-guide-quic-client-block.html]=man7/ossl-guide-quic-client-block.pod +GENERATE[html/man7/ossl-guide-quic-client-block.html]=man7/ossl-guide-quic-client-block.pod +DEPEND[man/man7/ossl-guide-quic-client-block.7]=man7/ossl-guide-quic-client-block.pod +GENERATE[man/man7/ossl-guide-quic-client-block.7]=man7/ossl-guide-quic-client-block.pod +DEPEND[html/man7/ossl-guide-quic-introduction.html]=man7/ossl-guide-quic-introduction.pod +GENERATE[html/man7/ossl-guide-quic-introduction.html]=man7/ossl-guide-quic-introduction.pod +DEPEND[man/man7/ossl-guide-quic-introduction.7]=man7/ossl-guide-quic-introduction.pod +GENERATE[man/man7/ossl-guide-quic-introduction.7]=man7/ossl-guide-quic-introduction.pod DEPEND[html/man7/ossl-guide-tls-client-block.html]=man7/ossl-guide-tls-client-block.pod GENERATE[html/man7/ossl-guide-tls-client-block.html]=man7/ossl-guide-tls-client-block.pod DEPEND[man/man7/ossl-guide-tls-client-block.7]=man7/ossl-guide-tls-client-block.pod @@ -4973,6 +4981,8 @@ html/man7/openssl-glossary.html \ html/man7/openssl-quic.html \ html/man7/openssl-threads.html \ html/man7/openssl_user_macros.html \ +html/man7/ossl-guide-quic-client-block.html \ +html/man7/ossl-guide-quic-introduction.html \ html/man7/ossl-guide-tls-client-block.html \ html/man7/ossl-guide-tls-introduction.html \ html/man7/ossl_store-file.html \ @@ -5108,6 +5118,8 @@ man/man7/openssl-glossary.7 \ man/man7/openssl-quic.7 \ man/man7/openssl-threads.7 \ man/man7/openssl_user_macros.7 \ +man/man7/ossl-guide-quic-client-block.7 \ +man/man7/ossl-guide-quic-introduction.7 \ man/man7/ossl-guide-tls-client-block.7 \ man/man7/ossl-guide-tls-introduction.7 \ man/man7/ossl_store-file.7 \ diff --git a/doc/man7/ossl-guide-quic-client-block.pod b/doc/man7/ossl-guide-quic-client-block.pod new file mode 100644 index 0000000000..4506f88516 --- /dev/null +++ b/doc/man7/ossl-guide-quic-client-block.pod @@ -0,0 +1,294 @@ +=pod + +=begin comment + +NB: Changes to the source code samples in this file should also be reflected in +demos/guide/quic-client-block.c + +=end comment + +=head1 NAME + +ossl-guide-quic-client-block +- OpenSSL Guide: Writing a simple blocking QUIC client + +=head1 SIMPLE BLOCKING QUIC CLIENT EXAMPLE + +This page will present various source code samples demonstrating how to write +a simple blocking QUIC client application which connects to a server, sends an +HTTP/1.0 request to it, and reads back the response. Note that HTTP/1.0 over +QUIC is non-standard and will not typically be supported by real world servers. +This is for demonstration purposes only. + +We assume that you already have OpenSSL installed on your system; that you +already have some fundamental understanding of OpenSSL concepts, TLS and QUIC +(see L<crypto(7)>, L<ossl-guide-tls-introduction(7)> and +L<ossl-guide-quic-introduction(7)>); and that you know how to +write and build C code and link it against the libcrypto and libssl libraries +that are provided by OpenSSL. It also assumes that you have a basic +understanding of UDP/IP and sockets. The example code that we build in this +tutorial will amend the blocking TLS client example that is covered in +L<ossl-guide-tls-client-block(7)>. Only the differences between that client and +this one will be discussed so we also assume that you have run through and +understand that tutorial. + +For this tutorial our client will be using a single QUIC stream. A subsequent +tutorial will discuss how to write a multi-stream client. + +The complete source code for this example blocking QUIC client is available in +the C<demos/guide> directory of the OpenSSL source distribution in the file +C<quic-client-block.c>. It is also available online at +L<https://github.com/openssl/openssl/blob/master/demos/guide/quic-client-block.c>. + +=head2 Creating the SSL_CTX and SSL objects + +In the TLS tutorial (L<ossl-guide-tls-client-block(7)>) we created an B<SSL_CTX> +object for our client and used it to create an B<SSL> object to represent the +TLS connection. A QUIC connection works in exactly the same way. We first create +an B<SSL_CTX> object and then use it to create an B<SSL> object to represent the +QUIC connection. + +As in the TLS example the first step is to create an B<SSL_CTX> object for our +client. This is done in the same way as before except that we use a different +"method". OpenSSL offers two different QUIC client methods, i.e. +L<OSSL_QUIC_client_method(3)> and L<OSSL_QUIC_client_thread_method(3)>. + +The first one is the equivalent of L<TLS_client_method(3)> but for the QUIC +protocol. The second one is the same, but it will additionally create a +background thread for handling time based events (known as "thread assisted +mode", see L<ossl-guide-quic-introduction(7)>). For this tutorial we will be +using L<OSSL_QUIC_client_method(3)> because we will not be leaving the QUIC +connection idle in our application and so thread assisted mode is not needed. + + /* + * Create an SSL_CTX which we can use to create SSL objects from. We + * want an SSL_CTX for creating clients so we use OSSL_QUIC_client_method() + * here. + */ + ctx = SSL_CTX_new(OSSL_QUIC_client_method()); + if (ctx == NULL) { + printf("Failed to create the SSL_CTX\n"); + goto end; + } + +The other setup steps that we applied to the B<SSL_CTX> for TLS also apply to +QUIC except for restricting the TLS versions that we are willing to accept. The +QUIC protocol implementation in OpenSSL currently only supports TLSv1.3. There +is no need to call L<SSL_CTX_set_min_proto_version(3)> or +L<SSL_CTX_set_max_proto_version(3)> in an OpenSSL QUIC application, and any such +call will be ignored. + +Once the B<SSL_CTX> is created, the B<SSL> object is constructed in exactly the +same way as for the TLS application. + +=head2 Creating the socket and BIO + +A major difference between TLS and QUIC is the underlying transport protocol. +TLS uses TCP while QUIC uses UDP. The way that the QUIC socket is created in our +example code is much the same as for TLS. We use the L<BIO_lookup_ex(3)> and +L<BIO_socket(3)> helper functions as we did in the previous tutorial except that +we pass B<SOCK_DGRAM> as an argument to indicate UDP (instead of B<SOCK_STREAM> +for TCP). + + /* + * Lookup IP address info for the server. + */ + if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, 0, SOCK_DGRAM, 0, + &res)) + return NULL; + + /* + * Loop through all the possible addresses for the server and find one + * we can connect to. + */ + for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) { + /* + * Create a TCP socket. We could equally use non-OpenSSL calls such + * as "socket" here for this and the subsequent connect and close + * functions. But for portability reasons and also so that we get + * errors on the OpenSSL stack in the event of a failure we use + * OpenSSL's versions of these functions. + */ + sock = BIO_socket(BIO_ADDRINFO_family(ai), SOCK_DGRAM, 0, 0); + if (sock == -1) + continue; + + /* Connect the socket to the server's address */ + if (!BIO_connect(sock, BIO_ADDRINFO_address(ai), 0)) { + BIO_closesocket(sock); + sock = -1; + continue; + } + + /* Set to nonblocking mode */ + if (!BIO_socket_nbio(sock, 1)) { + sock = -1; + continue; + } + + break; + } + + if (sock != -1) { + *peer_addr = BIO_ADDR_dup(BIO_ADDRINFO_address(ai)); + if (*peer_addr == NULL) { + BIO_closesocket(sock); + return NULL; + } + } + + /* Free the address information resources we allocated earlier */ + BIO_ADDRINFO_free(res); + +You may notice a couple of other differences between this code and the version +that we used for TLS. + +Firstly, we set the socket into nonblocking mode. This must always be done for +an OpenSSL QUIC application. This may be surprising considering that we are +trying to write a blocking client. Despite this the B<SSL> object will still +have blocking behaviour. See L<ossl-guide-quic-introduction(7)> for further +information on this. + +Secondly, we take note of the IP address of the peer that we are connecting to. +We store that information away. We will need it later. + +See L<BIO_lookup_ex(3)>, L<BIO_socket(3)>, L<BIO_connect(3)>, +L<BIO_closesocket(3)>, L<BIO_ADDRINFO_next(3)>, L<BIO_ADDRINFO_address(3)>, +L<BIO_ADDRINFO_free(3)> and L<BIO_ADDR_dup(3)> for further information on the +functions used here. In the above example code the B<hostname> and B<port> +variables are strings, e.g. "www.example.com" and "443". + +As for our TLS client, once the socket has been created and connected we need to +associate it with a BIO object: + + BIO *bio; + + /* Create a BIO to wrap the socket*/ + bio = BIO_new(BIO_s_datagram()); + if (bio == NULL) + BIO_closesocket(sock); + + /* + * Associate the newly created BIO with the underlying socket. By + * passing BIO_CLOSE here the socket will be automatically closed when + * the BIO is freed. Alternatively you can use BIO_NOCLOSE, in which + * case you must close the socket explicitly when it is no longer + * needed. + */ + BIO_set_fd(bio, sock, BIO_CLOSE); + +Note the use of L<BIO_s_datagram(3)> here as opposed to L<BIO_s_socket(3)> that +we used for our TLS client. This is again due to the fact that QUIC uses UDP +instead of TCP for its transport layer. See L<BIO_new(3)>, L<BIO_s_datagram(3)> +and L<BIO_set_fd(3)> for further information on these functions. + +=head2 Setting the server's hostname + +As in the TLS tutorial we need to set the server's hostname both for SNI (Server +Name Indication) and for certificate validation purposes. The steps for this are +identical to the TLS tutorial and won't be repeated here. + +=head2 Setting the ALPN + +ALPN (Application-Layer Protocol Negotiation) is a feature of TLS that enables +the application to negotiate which protocol will be used over the connection. +For example, if you intend to use HTTP/3 over the connection then the ALPN value +for that is "h3" (see +L<https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml#alpn-protocol-ids>). +OpenSSL provides the ability for a client to specify the ALPN to use via the +L<SSL_set_alpn_protos(3)> function. This is optional for a TLS client and so our +simple client that we developed in L<ossl-guide-tls-client-block(7)> did not use +it. However QUIC mandates that the TLS handshake used in establishing a QUIC +connection must use ALPN. + + unsigned char alpn[] = { 8, 'h', 't', 't', 'p', '/', '1', '.', '0' }; + + /* SSL_set_alpn_protos returns 0 for success! */ + if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn)) != 0) { + printf("Failed to set the ALPN for the connection\n"); + goto end; + } + +The ALPN is specified using a length prefixed array of unsigned chars (it is not +a NUL terminated string). Our original TLS blocking client demo was using +HTTP/1.0. We will use the same for this example. Unlike most OpenSSL functions +L<SSL_set_alpn_protos(3)> returns zero for success and nonzero for failure. + +=head2 Setting the peer address + +An OpenSSL QUIC application must specify the target address of the server that +is being connected to. In L</Creating the socket and BIO> above we saved that +address away for future use. Now we need to use it via the +L<SSL_set_initial_peer_addr(3)> function. + + if (!SSL_set_initial_peer_addr(ssl, peer_addr)) { + printf("Failed to set the inital peer address\n"); + goto end; + } + +Note that we will need to free the B<peer_addr> value that we allocated via +L<BIO_ADDR_dup(3)> earlier: + + BIO_ADDR_free(peer_addr); + +=head2 The handshake and application data transfer + +Once initial setup of the B<SSL> object is complete then we perform the +handshake via L<SSL_connect(3)> in exactly the same way as we did for the TLS +client, so we won't repeat it here. + +We can also perform data transfer using a default QUIC stream that is +automatically associated with the B<SSL> object for us. We can transmit data +using L<SSL_write_ex(3)>, and receive data using L<SSL_read_ex(3)> in exactly +the same way as for TLS. Again, we won't repeat it here. + +=head2 Shutting down the connection + +As in the TLS tutorial, once we have finished reading data from the server then +we are ready to close the connection down. As before we do this via the +L<SSL_shutdown(3)> function. This example for QUIC is very similar to the TLS +version. However the L<SSL_shutdown(3)> function may need to be called more than +once: + + /* + * Repeatedly call SSL_shutdown() until the connection is fully + * closed. + */ + do { + ret = SSL_shutdown(ssl); + if (ret < 0) { + printf("Error shuting down: %d\n", ret); + goto end; + } + } while (ret != 1); + +The shutdown process is in two stages. First we gracefully shutdown the +connection for sending and secondly we shutdown the connection for receiving. +L<SSL_shutdown(3)> returns 0 once the first stage has been completed, and 1 once +the second stage is finished. This two stage process applies to TLS as well. +However in our blocking TLS client example code we knew that the peer had +already partially closed down due to the B<SSL_ERROR_ZERO_RETURN> that we had +obtained via L<SSL_get_error(3)> after the final L<SSL_read_ex(3)> call. Due to +that return value we knew that the connection was already closed down for +receiving data and hence L<SSL_shutdown(3)> should only need to be called once. + +However, with QUIC, the B<SSL_ERROR_ZERO_RETURN> value only tells us that the +stream (not the connection) is partially closed down. Therefore we need to call +L<SSL_shutdown(3)> more than once to ensure that we progress through both stages +of the shutdown process. + +=head1 SEE ALSO + +L<crypto(7)>, L<ossl-guide-tls-introduction(7)>, +L<ossl-guide-tls-client-block(7)>, L<ossl-guide-quic-introduction(7)> + +=head1 COPYRIGHT + +Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L<https://www.openssl.org/source/license.html>. + +=cut diff --git a/doc/man7/ossl-guide-quic-introduction.pod b/doc/man7/ossl-guide-quic-introduction.pod new file mode 100644 index 0000000000..33f9c3e003 --- /dev/null +++ b/doc/man7/ossl-guide-quic-introduction.pod @@ -0,0 +1,135 @@ +=pod + +=head1 NAME + +ossl-guide-quic-introduction +- OpenSSL Guide: An introduction to QUIC in OpenSSL + +=head1 INTRODUCTION + +This page will provide an introduction to some basic QUIC concepts and +background and how it is used within OpenSSL. It assumes that you have a basic +understanding of UDP/IP and sockets. It also assumes that you are familiar with +some OpenSSL and TLS fundamentals (see L<crypto(7)> and +L<ossl-guide-tls-introduction(7)>). + +=head1 WHAT IS QUIC? + +QUIC is a general purpose protocol for enabling applications to securely +communicate over a network. It is defined in RFC9000 (see +L<https://datatracker.ietf.org/doc/rfc9000/>). QUIC integrates parts of the +TLS protocol for connection establishment but independently protects packets. +It provides similar security guarantees to TLS such as confidentiality, +integrity and authentication (see L<ossl-guide-tls-introduction(7)>). It +additionally provides multiplexing capabilities through the use of "streams" +(see L</QUIC STREAMS> below). + +=head1 QUIC TIME BASED EVENTS + +A key difference between the TLS implementation and the QUIC implementation in +OpenSSL is how time is handled. The QUIC protocol requires various actions to be +performed on a regular basis regardless of whether application data is being +transmitted or received. + +OpenSSL introduces a new function L<SSL_handle_events(3)> that will +automatically process any outstanding time based events that must be handled. +Alternatively calling any I/O function such as L<SSL_read_ex(3)> or +L<SSL_write_ex(3)> will also process these events. There is also +L<SSL_get_event_timeout(3)> which tells an application the amount of time that +remains until L<SSL_handle_events(3)> (or any I/O function) must be called. + +Fortunately a blocking application that does not leave the QUIC connection idle, +and is regularly calling I/O functions does not typically need to worry about +this. However if you are developing a nonblocking application or one that may +leave the QUIC connection idle for a period of time then you will need to +arrange to call these functions. + +OpenSSL provides an optional "thread assisted mode" that will automatically +create a background thread and will regularly call L<SSL_handle_events(3)> in a +thread safe manner. This provides a simple way for an application to satisfy the +QUIC requirements for time based events without having to implement special +logic to accomplish it. + +=head1 QUIC AND TLS + +QUIC reuses parts of the TLS protocol in its implementation. Specifically the +TLS handshake also exists in QUIC. The TLS handshake messages are wrapped up in +QUIC protocol messages in order to send them to the peer. Once the TLS handshake +is complete all application data is sent entirely using QUIC protocol messages +without using TLS - although some TLS handshake messages may still be sent in +some circumstances. + +This relationship between QUIC and TLS means that many of the API functions in +OpenSSL that apply to TLS connections also apply to QUIC connections and +applications can use them in exactly the same way. Some functions do not apply +to QUIC at all, and others have altered semantics. You should refer to the +documentation pages for each function for information on how it applies to QUIC. +Typically if QUIC is not mentioned in the manual pages then the functions apply +to both TLS and QUIC. + +=head1 QUIC STREAMS + +QUIC introduces the concept of "streams". A stream provides a reliable +mechanism for sending and receiving application data between the endpoints. The +bytes transmitted are guaranteed to be received in the same order they were sent +without any loss of data or reordering of the bytes. A TLS application +effectively has one bi-directional stream available to it per TLS connection. A +QUIC application can have multiple uni-directional or bi-directional streams +available to it for each connection. + +In OpenSSL an B<SSL> object is used to represent both connections and streams. +A QUIC application creates an initial B<SSL> object to represent the connection +(known as the connection B<SSL> object). Once the connection is complete +additional B<SSL> objects can be created to represent streams (known as stream +B<SSL> objects). Unless configured otherwise, a "default" stream is also +associated with the connection B<SSL> object so you can still write data and +read data to/from it. Some OpenSSL API functions can only be used with +connection B<SSL> objects, and some can only be used with stream B<SSL> objects. +Check the documentation for each function to confirm what type of B<SSL> object +can be used in any particular context. A connection B<SSL> object that has a +default stream attached to it can be used in contexts that require a connection +B<SSL> object or in contexts that require a stream B<SSL> object. + +=head1 SOCKETS AND BLOCKING + +TLS assumes "stream" type semantics for its underlying transport layer protocol +(usually achieved by using TCP). However QUIC assumes "datagram" type semantics +by using UDP. An OpenSSL application using QUIC is responsible for creating a +BIO to represent the underlying transport layer. This BIO must support datagrams +and is typically L<BIO_s_datagram(3)>, but other B<BIO> choices are available. +See L<bio(7)> for an introduction to OpenSSL's B<BIO> concept. + +A significant difference between OpenSSL TLS applications and OpenSSL QUIC +applications is the way that blocking is implemented. In TLS if your application +expects blocking behaviour then you configure the underlying socket for +blocking. Conversely if your application wants nonblocking behaviour then the +underlying socket is configured to be nonblocking. + +With an OpenSSL QUIC application the underlying socket must always be configured +to be nonblocking. Howevever the B<SSL> object will, by default, still operate +in blocking mode. So, from an application's perspective, calls to functions such +as L<SSL_read_ex(3)>, L<SSL_write_ex(3)> and other I/O functions will still +block. OpenSSL itself provides that blocking capability for QUIC instead of the +socket. If nonblocking behaviour is desired then the application must call +L<SSL_set_blocking_mode(3)>. + +=head1 FURTHER READING + +See L<ossl-guide-quic-client-block(7)> to see an example of applying these +concepts in order to write a simple blocking QUIC client. + +=head1 SEE ALSO + +L<crypto(7)>, L<bio(7)>, L<ossl-guide-tls-introduction(7)>, +L<ossl-guide-tls-client-block(7)>, L<ossl-guide-quic-client-block(7)> + +=head1 COPYRIGHT + +Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the Apache License 2.0 (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L<https://www.openssl.org/source/license.html>. + +=cut diff --git a/doc/man7/ossl-guide-tls-client-block.pod b/doc/man7/ossl-guide-tls-client-block.pod index aab5533f5e..c4c19a98b5 100644 --- a/doc/man7/ossl-guide-tls-client-block.pod +++ b/doc/man7/ossl-guide-tls-client-block.pod @@ -135,7 +135,7 @@ to create an IPv4 TCP socket: int sock; - sock = socket(AF_INET, SOCK_STEAM, 0); + sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) return NULL; @@ -543,6 +543,11 @@ of its intermediate CA certificates) in our trusted certificate store (e.g. because the trusted certificate store is misconfigured, or there are missing intermediate CAs, or the issuer is simply unrecognised). +=head1 FURTHER READING + +See L<ossl-guide-quic-client-block(7)> to read a tutorial on how to modify the +client developed on this page to support QUIC instead of TLS. + =head1 SEE ALSO L<crypto(7)>, L<ossl-guide-tls-introduction(7)> diff --git a/doc/man7/ossl-guide-tls-introduction.pod b/doc/man7/ossl-guide-tls-introduction.pod index 925cc69737..307b5eec91 100644 --- a/doc/man7/ossl-guide-tls-introduction.pod +++ b/doc/man7/ossl-guide-tls-introduction.pod @@ -297,10 +297,12 @@ object. See L<ossl-guide-tls-client-block(7)> to see an example of applying these concepts in order to write a simple TLS client based on a blocking socket. +See L<ossl-guide-quic-introduction(7)> for an introduction to QUIC in OpenSSL. =head1 SEE ALSO -L<crypto(7)>, L<ossl-guide-tls-client-block(7)> +L<crypto(7)>, L<ossl-guide-tls-client-block(7)>, +L<ossl-guide-quic-introduction(7)> =head1 COPYRIGHT |