diff options
Diffstat (limited to 'upstream/debian-unstable/man7/ossl-guide-quic-client-block.7ssl')
-rw-r--r-- | upstream/debian-unstable/man7/ossl-guide-quic-client-block.7ssl | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/upstream/debian-unstable/man7/ossl-guide-quic-client-block.7ssl b/upstream/debian-unstable/man7/ossl-guide-quic-client-block.7ssl new file mode 100644 index 00000000..73ef8d9b --- /dev/null +++ b/upstream/debian-unstable/man7/ossl-guide-quic-client-block.7ssl @@ -0,0 +1,436 @@ +.\" -*- mode: troff; coding: utf-8 -*- +.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. +.ie n \{\ +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{\ +. if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" ======================================================================== +.\" +.IX Title "OSSL-GUIDE-QUIC-CLIENT-BLOCK 7SSL" +.TH OSSL-GUIDE-QUIC-CLIENT-BLOCK 7SSL 2024-04-04 3.2.2-dev OpenSSL +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH NAME +ossl\-guide\-quic\-client\-block +\&\- OpenSSL Guide: Writing a simple blocking QUIC client +.SH "SIMPLE BLOCKING QUIC CLIENT EXAMPLE" +.IX Header "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 be supported by real world servers. This is +for demonstration purposes only. +.PP +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 \fBossl\-guide\-libraries\-introduction\fR\|(7), \fBossl\-guide\-tls\-introduction\fR\|(7) +and \fBossl\-guide\-quic\-introduction\fR\|(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 +\&\fBossl\-guide\-tls\-client\-block\fR\|(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. +.PP +For this tutorial our client will be using a single QUIC stream. A subsequent +tutorial will discuss how to write a multi-stream client (see +\&\fBossl\-guide\-quic\-multi\-stream\fR\|(7)). +.PP +The complete source code for this example blocking QUIC client is available in +the \f(CW\*(C`demos/guide\*(C'\fR directory of the OpenSSL source distribution in the file +\&\f(CW\*(C`quic\-client\-block.c\*(C'\fR. It is also available online at +<https://github.com/openssl/openssl/blob/master/demos/guide/quic\-client\-block.c>. +.SS "Creating the SSL_CTX and SSL objects" +.IX Subsection "Creating the SSL_CTX and SSL objects" +In the TLS tutorial (\fBossl\-guide\-tls\-client\-block\fR\|(7)) we created an \fBSSL_CTX\fR +object for our client and used it to create an \fBSSL\fR object to represent the +TLS connection. A QUIC connection works in exactly the same way. We first create +an \fBSSL_CTX\fR object and then use it to create an \fBSSL\fR object to represent the +QUIC connection. +.PP +As in the TLS example the first step is to create an \fBSSL_CTX\fR 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. +\&\fBOSSL_QUIC_client_method\fR\|(3) and \fBOSSL_QUIC_client_thread_method\fR\|(3). +.PP +The first one is the equivalent of \fBTLS_client_method\fR\|(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 \fBossl\-guide\-quic\-introduction\fR\|(7)). For this tutorial we will be +using \fBOSSL_QUIC_client_method\fR\|(3) because we will not be leaving the QUIC +connection idle in our application and so thread assisted mode is not needed. +.PP +.Vb 10 +\& /* +\& * 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\en"); +\& goto end; +\& } +.Ve +.PP +The other setup steps that we applied to the \fBSSL_CTX\fR 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 \fBSSL_CTX_set_min_proto_version\fR\|(3) or +\&\fBSSL_CTX_set_max_proto_version\fR\|(3) in an OpenSSL QUIC application, and any such +call will be ignored. +.PP +Once the \fBSSL_CTX\fR is created, the \fBSSL\fR object is constructed in exactly the +same way as for the TLS application. +.SS "Creating the socket and BIO" +.IX Subsection "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 \fBBIO_lookup_ex\fR\|(3) and +\&\fBBIO_socket\fR\|(3) helper functions as we did in the previous tutorial except that +we pass \fBSOCK_DGRAM\fR as an argument to indicate UDP (instead of \fBSOCK_STREAM\fR +for TCP). +.PP +.Vb 6 +\& /* +\& * Lookup IP address info for the server. +\& */ +\& if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, 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\*(Aqs 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\*(Aqs 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)) { +\& BIO_closesocket(sock); +\& 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); +.Ve +.PP +You may notice a couple of other differences between this code and the version +that we used for TLS. +.PP +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 \fBSSL\fR object will still +have blocking behaviour. See \fBossl\-guide\-quic\-introduction\fR\|(7) for further +information on this. +.PP +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. +.PP +See \fBBIO_lookup_ex\fR\|(3), \fBBIO_socket\fR\|(3), \fBBIO_connect\fR\|(3), +\&\fBBIO_closesocket\fR\|(3), \fBBIO_ADDRINFO_next\fR\|(3), \fBBIO_ADDRINFO_address\fR\|(3), +\&\fBBIO_ADDRINFO_free\fR\|(3) and \fBBIO_ADDR_dup\fR\|(3) for further information on the +functions used here. In the above example code the \fBhostname\fR and \fBport\fR +variables are strings, e.g. "www.example.com" and "443". +.PP +As for our TLS client, once the socket has been created and connected we need to +associate it with a BIO object: +.PP +.Vb 1 +\& BIO *bio; +\& +\& /* Create a BIO to wrap the socket */ +\& bio = BIO_new(BIO_s_datagram()); +\& if (bio == NULL) { +\& BIO_closesocket(sock); +\& return NULL; +\& } +\& +\& /* +\& * 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); +.Ve +.PP +Note the use of \fBBIO_s_datagram\fR\|(3) here as opposed to \fBBIO_s_socket\fR\|(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 \fBBIO_new\fR\|(3), \fBBIO_s_datagram\fR\|(3) +and \fBBIO_set_fd\fR\|(3) for further information on these functions. +.SS "Setting the server's hostname" +.IX Subsection "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. +.SS "Setting the ALPN" +.IX Subsection "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 +<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 +\&\fBSSL_set_alpn_protos\fR\|(3) function. This is optional for a TLS client and so our +simple client that we developed in \fBossl\-guide\-tls\-client\-block\fR\|(7) did not use +it. However QUIC mandates that the TLS handshake used in establishing a QUIC +connection must use ALPN. +.PP +.Vb 1 +\& unsigned char alpn[] = { 8, \*(Aqh\*(Aq, \*(Aqt\*(Aq, \*(Aqt\*(Aq, \*(Aqp\*(Aq, \*(Aq/\*(Aq, \*(Aq1\*(Aq, \*(Aq.\*(Aq, \*(Aq0\*(Aq }; +\& +\& /* 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\en"); +\& goto end; +\& } +.Ve +.PP +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 +\&\fBSSL_set_alpn_protos\fR\|(3) returns zero for success and nonzero for failure. +.SS "Setting the peer address" +.IX Subsection "Setting the peer address" +An OpenSSL QUIC application must specify the target address of the server that +is being connected to. In "Creating the socket and BIO" above we saved that +address away for future use. Now we need to use it via the +\&\fBSSL_set1_initial_peer_addr\fR\|(3) function. +.PP +.Vb 5 +\& /* Set the IP address of the remote peer */ +\& if (!SSL_set1_initial_peer_addr(ssl, peer_addr)) { +\& printf("Failed to set the initial peer address\en"); +\& goto end; +\& } +.Ve +.PP +Note that we will need to free the \fBpeer_addr\fR value that we allocated via +\&\fBBIO_ADDR_dup\fR\|(3) earlier: +.PP +.Vb 1 +\& BIO_ADDR_free(peer_addr); +.Ve +.SS "The handshake and application data transfer" +.IX Subsection "The handshake and application data transfer" +Once initial setup of the \fBSSL\fR object is complete then we perform the +handshake via \fBSSL_connect\fR\|(3) in exactly the same way as we did for the TLS +client, so we won't repeat it here. +.PP +We can also perform data transfer using a default QUIC stream that is +automatically associated with the \fBSSL\fR object for us. We can transmit data +using \fBSSL_write_ex\fR\|(3), and receive data using \fBSSL_read_ex\fR\|(3) in the same +way as for TLS. The main difference is that we have to account for failures +slightly differently. With QUIC the stream can be reset by the peer (which is +fatal for that stream), but the underlying connection itself may still be +healthy. +.PP +.Vb 10 +\& /* +\& * Get up to sizeof(buf) bytes of the response. We keep reading until the +\& * server closes the connection. +\& */ +\& while (SSL_read_ex(ssl, buf, sizeof(buf), &readbytes)) { +\& /* +\& * OpenSSL does not guarantee that the returned data is a string or +\& * that it is NUL terminated so we use fwrite() to write the exact +\& * number of bytes that we read. The data could be non\-printable or +\& * have NUL characters in the middle of it. For this simple example +\& * we\*(Aqre going to print it to stdout anyway. +\& */ +\& fwrite(buf, 1, readbytes, stdout); +\& } +\& /* In case the response didn\*(Aqt finish with a newline we add one now */ +\& printf("\en"); +\& +\& /* +\& * Check whether we finished the while loop above normally or as the +\& * result of an error. The 0 argument to SSL_get_error() is the return +\& * code we received from the SSL_read_ex() call. It must be 0 in order +\& * to get here. Normal completion is indicated by SSL_ERROR_ZERO_RETURN. In +\& * QUIC terms this means that the peer has sent FIN on the stream to +\& * indicate that no further data will be sent. +\& */ +\& switch (SSL_get_error(ssl, 0)) { +\& case SSL_ERROR_ZERO_RETURN: +\& /* Normal completion of the stream */ +\& break; +\& +\& case SSL_ERROR_SSL: +\& /* +\& * Some stream fatal error occurred. This could be because of a stream +\& * reset \- or some failure occurred on the underlying connection. +\& */ +\& switch (SSL_get_stream_read_state(ssl)) { +\& case SSL_STREAM_STATE_RESET_REMOTE: +\& printf("Stream reset occurred\en"); +\& /* The stream has been reset but the connection is still healthy. */ +\& break; +\& +\& case SSL_STREAM_STATE_CONN_CLOSED: +\& printf("Connection closed\en"); +\& /* Connection is already closed. Skip SSL_shutdown() */ +\& goto end; +\& +\& default: +\& printf("Unknown stream failure\en"); +\& break; +\& } +\& break; +\& +\& default: +\& /* Some other unexpected error occurred */ +\& printf ("Failed reading remaining data\en"); +\& break; +\& } +.Ve +.PP +In the above code example you can see that \fBSSL_ERROR_SSL\fR indicates a stream +fatal error. We can use \fBSSL_get_stream_read_state\fR\|(3) to determine whether the +stream has been reset, or if some other fatal error has occurred. +.SS "Shutting down the connection" +.IX Subsection "Shutting down the connection" +In the TLS tutorial we knew that the server had finished sending data because +\&\fBSSL_read_ex\fR\|(3) returned 0, and \fBSSL_get_error\fR\|(3) returned +\&\fBSSL_ERROR_ZERO_RETURN\fR. The same is true with QUIC except that +\&\fBSSL_ERROR_ZERO_RETURN\fR should be interpreted slightly differently. With TLS +we knew that this meant that the server had sent a "close_notify" alert. No +more data will be sent from the server on that connection. +.PP +With QUIC it means that the server has indicated "FIN" on the stream, meaning +that it will no longer send any more data on that stream. However this only +gives us information about the stream itself and does not tell us anything about +the underlying connection. More data could still be sent from the server on some +other stream. Additionally, although the server will not send any more data to +the client, it does not prevent the client from sending more data to the server. +.PP +In this tutorial, once we have finished reading data from the server on the one +stream that we are using, we will close the connection down. As before we do +this via the \fBSSL_shutdown\fR\|(3) function. This example for QUIC is very similar +to the TLS version. However the \fBSSL_shutdown\fR\|(3) function will need to be +called more than once: +.PP +.Vb 11 +\& /* +\& * Repeatedly call SSL_shutdown() until the connection is fully +\& * closed. +\& */ +\& do { +\& ret = SSL_shutdown(ssl); +\& if (ret < 0) { +\& printf("Error shutting down: %d\en", ret); +\& goto end; +\& } +\& } while (ret != 1); +.Ve +.PP +The shutdown process is in two stages. In the first stage we wait until all the +data we have buffered for sending on any stream has been successfully sent and +acknowledged by the peer, and then we send a CONNECTION_CLOSE to the peer to +indicate that the connection is no longer usable. This immediately closes the +connection and no more data can be sent or received. \fBSSL_shutdown\fR\|(3) returns +0 once the first stage has been completed. +.PP +In the second stage the connection enters a "closing" state. Application data +cannot be sent or received in this state, but late arriving packets coming from +the peer will be handled appropriately. Once this stage has completed +successfully \fBSSL_shutdown\fR\|(3) will return 1 to indicate success. +.SH "FURTHER READING" +.IX Header "FURTHER READING" +See \fBossl\-guide\-quic\-multi\-stream\fR\|(7) to read a tutorial on how to modify the +client developed on this page to support multiple streams. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBossl\-guide\-introduction\fR\|(7), \fBossl\-guide\-libraries\-introduction\fR\|(7), +\&\fBossl\-guide\-libssl\-introduction\fR\|(7), \fBossl\-guide\-tls\-introduction\fR\|(7), +\&\fBossl\-guide\-tls\-client\-block\fR\|(7), \fBossl\-guide\-quic\-introduction\fR\|(7) +.SH COPYRIGHT +.IX Header "COPYRIGHT" +Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. +.PP +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 +<https://www.openssl.org/source/license.html>. |