1=pod 2 3=begin comment 4 5NB: Changes to the source code samples in this file should also be reflected in 6demos/guide/quic-client-block.c 7 8=end comment 9 10=head1 NAME 11 12ossl-guide-quic-client-block 13- OpenSSL Guide: Writing a simple blocking QUIC client 14 15=head1 SIMPLE BLOCKING QUIC CLIENT EXAMPLE 16 17This page will present various source code samples demonstrating how to write 18a simple blocking QUIC client application which connects to a server, sends an 19HTTP/1.0 request to it, and reads back the response. Note that HTTP/1.0 over 20QUIC is non-standard and will not be supported by real world servers. This is 21for demonstration purposes only. 22 23We assume that you already have OpenSSL installed on your system; that you 24already have some fundamental understanding of OpenSSL concepts, TLS and QUIC 25(see L<ossl-guide-libraries-introduction(7)>, L<ossl-guide-tls-introduction(7)> 26and L<ossl-guide-quic-introduction(7)>); and that you know how to 27write and build C code and link it against the libcrypto and libssl libraries 28that are provided by OpenSSL. It also assumes that you have a basic 29understanding of UDP/IP and sockets. The example code that we build in this 30tutorial will amend the blocking TLS client example that is covered in 31L<ossl-guide-tls-client-block(7)>. Only the differences between that client and 32this one will be discussed so we also assume that you have run through and 33understand that tutorial. 34 35For this tutorial our client will be using a single QUIC stream. A subsequent 36tutorial will discuss how to write a multi-stream client (see 37L<ossl-guide-quic-multi-stream(7)>). 38 39The complete source code for this example blocking QUIC client is available in 40the C<demos/guide> directory of the OpenSSL source distribution in the file 41C<quic-client-block.c>. It is also available online at 42L<https://github.com/openssl/openssl/blob/master/demos/guide/quic-client-block.c>. 43 44=head2 Creating the SSL_CTX and SSL objects 45 46In the TLS tutorial (L<ossl-guide-tls-client-block(7)>) we created an B<SSL_CTX> 47object for our client and used it to create an B<SSL> object to represent the 48TLS connection. A QUIC connection works in exactly the same way. We first create 49an B<SSL_CTX> object and then use it to create an B<SSL> object to represent the 50QUIC connection. 51 52As in the TLS example the first step is to create an B<SSL_CTX> object for our 53client. This is done in the same way as before except that we use a different 54"method". OpenSSL offers two different QUIC client methods, i.e. 55L<OSSL_QUIC_client_method(3)> and L<OSSL_QUIC_client_thread_method(3)>. 56 57The first one is the equivalent of L<TLS_client_method(3)> but for the QUIC 58protocol. The second one is the same, but it will additionally create a 59background thread for handling time based events (known as "thread assisted 60mode", see L<ossl-guide-quic-introduction(7)>). For this tutorial we will be 61using L<OSSL_QUIC_client_method(3)> because we will not be leaving the QUIC 62connection idle in our application and so thread assisted mode is not needed. 63 64 /* 65 * Create an SSL_CTX which we can use to create SSL objects from. We 66 * want an SSL_CTX for creating clients so we use OSSL_QUIC_client_method() 67 * here. 68 */ 69 ctx = SSL_CTX_new(OSSL_QUIC_client_method()); 70 if (ctx == NULL) { 71 printf("Failed to create the SSL_CTX\n"); 72 goto end; 73 } 74 75The other setup steps that we applied to the B<SSL_CTX> for TLS also apply to 76QUIC except for restricting the TLS versions that we are willing to accept. The 77QUIC protocol implementation in OpenSSL currently only supports TLSv1.3. There 78is no need to call L<SSL_CTX_set_min_proto_version(3)> or 79L<SSL_CTX_set_max_proto_version(3)> in an OpenSSL QUIC application, and any such 80call will be ignored. 81 82Once the B<SSL_CTX> is created, the B<SSL> object is constructed in exactly the 83same way as for the TLS application. 84 85=head2 Creating the socket and BIO 86 87A major difference between TLS and QUIC is the underlying transport protocol. 88TLS uses TCP while QUIC uses UDP. The way that the QUIC socket is created in our 89example code is much the same as for TLS. We use the L<BIO_lookup_ex(3)> and 90L<BIO_socket(3)> helper functions as we did in the previous tutorial except that 91we pass B<SOCK_DGRAM> as an argument to indicate UDP (instead of B<SOCK_STREAM> 92for TCP). 93 94 /* 95 * Lookup IP address info for the server. 96 */ 97 if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_DGRAM, 0, 98 &res)) 99 return NULL; 100 101 /* 102 * Loop through all the possible addresses for the server and find one 103 * we can connect to. 104 */ 105 for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) { 106 /* 107 * Create a TCP socket. We could equally use non-OpenSSL calls such 108 * as "socket" here for this and the subsequent connect and close 109 * functions. But for portability reasons and also so that we get 110 * errors on the OpenSSL stack in the event of a failure we use 111 * OpenSSL's versions of these functions. 112 */ 113 sock = BIO_socket(BIO_ADDRINFO_family(ai), SOCK_DGRAM, 0, 0); 114 if (sock == -1) 115 continue; 116 117 /* Connect the socket to the server's address */ 118 if (!BIO_connect(sock, BIO_ADDRINFO_address(ai), 0)) { 119 BIO_closesocket(sock); 120 sock = -1; 121 continue; 122 } 123 124 /* Set to nonblocking mode */ 125 if (!BIO_socket_nbio(sock, 1)) { 126 BIO_closesocket(sock); 127 sock = -1; 128 continue; 129 } 130 131 break; 132 } 133 134 if (sock != -1) { 135 *peer_addr = BIO_ADDR_dup(BIO_ADDRINFO_address(ai)); 136 if (*peer_addr == NULL) { 137 BIO_closesocket(sock); 138 return NULL; 139 } 140 } 141 142 /* Free the address information resources we allocated earlier */ 143 BIO_ADDRINFO_free(res); 144 145You may notice a couple of other differences between this code and the version 146that we used for TLS. 147 148Firstly, we set the socket into nonblocking mode. This must always be done for 149an OpenSSL QUIC application. This may be surprising considering that we are 150trying to write a blocking client. Despite this the B<SSL> object will still 151have blocking behaviour. See L<ossl-guide-quic-introduction(7)> for further 152information on this. 153 154Secondly, we take note of the IP address of the peer that we are connecting to. 155We store that information away. We will need it later. 156 157See L<BIO_lookup_ex(3)>, L<BIO_socket(3)>, L<BIO_connect(3)>, 158L<BIO_closesocket(3)>, L<BIO_ADDRINFO_next(3)>, L<BIO_ADDRINFO_address(3)>, 159L<BIO_ADDRINFO_free(3)> and L<BIO_ADDR_dup(3)> for further information on the 160functions used here. In the above example code the B<hostname> and B<port> 161variables are strings, e.g. "www.example.com" and "443". 162 163As for our TLS client, once the socket has been created and connected we need to 164associate it with a BIO object: 165 166 BIO *bio; 167 168 /* Create a BIO to wrap the socket */ 169 bio = BIO_new(BIO_s_datagram()); 170 if (bio == NULL) { 171 BIO_closesocket(sock); 172 return NULL; 173 } 174 175 /* 176 * Associate the newly created BIO with the underlying socket. By 177 * passing BIO_CLOSE here the socket will be automatically closed when 178 * the BIO is freed. Alternatively you can use BIO_NOCLOSE, in which 179 * case you must close the socket explicitly when it is no longer 180 * needed. 181 */ 182 BIO_set_fd(bio, sock, BIO_CLOSE); 183 184Note the use of L<BIO_s_datagram(3)> here as opposed to L<BIO_s_socket(3)> that 185we used for our TLS client. This is again due to the fact that QUIC uses UDP 186instead of TCP for its transport layer. See L<BIO_new(3)>, L<BIO_s_datagram(3)> 187and L<BIO_set_fd(3)> for further information on these functions. 188 189=head2 Setting the server's hostname 190 191As in the TLS tutorial we need to set the server's hostname both for SNI (Server 192Name Indication) and for certificate validation purposes. The steps for this are 193identical to the TLS tutorial and won't be repeated here. 194 195=head2 Setting the ALPN 196 197ALPN (Application-Layer Protocol Negotiation) is a feature of TLS that enables 198the application to negotiate which protocol will be used over the connection. 199For example, if you intend to use HTTP/3 over the connection then the ALPN value 200for that is "h3" (see 201L<https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml#alpn-protocol-ids>). 202OpenSSL provides the ability for a client to specify the ALPN to use via the 203L<SSL_set_alpn_protos(3)> function. This is optional for a TLS client and so our 204simple client that we developed in L<ossl-guide-tls-client-block(7)> did not use 205it. However QUIC mandates that the TLS handshake used in establishing a QUIC 206connection must use ALPN. 207 208 unsigned char alpn[] = { 8, 'h', 't', 't', 'p', '/', '1', '.', '0' }; 209 210 /* SSL_set_alpn_protos returns 0 for success! */ 211 if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn)) != 0) { 212 printf("Failed to set the ALPN for the connection\n"); 213 goto end; 214 } 215 216The ALPN is specified using a length prefixed array of unsigned chars (it is not 217a NUL terminated string). Our original TLS blocking client demo was using 218HTTP/1.0. We will use the same for this example. Unlike most OpenSSL functions 219L<SSL_set_alpn_protos(3)> returns zero for success and nonzero for failure. 220 221=head2 Setting the peer address 222 223An OpenSSL QUIC application must specify the target address of the server that 224is being connected to. In L</Creating the socket and BIO> above we saved that 225address away for future use. Now we need to use it via the 226L<SSL_set1_initial_peer_addr(3)> function. 227 228 /* Set the IP address of the remote peer */ 229 if (!SSL_set1_initial_peer_addr(ssl, peer_addr)) { 230 printf("Failed to set the initial peer address\n"); 231 goto end; 232 } 233 234Note that we will need to free the B<peer_addr> value that we allocated via 235L<BIO_ADDR_dup(3)> earlier: 236 237 BIO_ADDR_free(peer_addr); 238 239=head2 The handshake and application data transfer 240 241Once initial setup of the B<SSL> object is complete then we perform the 242handshake via L<SSL_connect(3)> in exactly the same way as we did for the TLS 243client, so we won't repeat it here. 244 245We can also perform data transfer using a default QUIC stream that is 246automatically associated with the B<SSL> object for us. We can transmit data 247using L<SSL_write_ex(3)>, and receive data using L<SSL_read_ex(3)> in the same 248way as for TLS. The main difference is that we have to account for failures 249slightly differently. With QUIC the stream can be reset by the peer (which is 250fatal for that stream), but the underlying connection itself may still be 251healthy. 252 253 /* 254 * Get up to sizeof(buf) bytes of the response. We keep reading until the 255 * server closes the connection. 256 */ 257 while (SSL_read_ex(ssl, buf, sizeof(buf), &readbytes)) { 258 /* 259 * OpenSSL does not guarantee that the returned data is a string or 260 * that it is NUL terminated so we use fwrite() to write the exact 261 * number of bytes that we read. The data could be non-printable or 262 * have NUL characters in the middle of it. For this simple example 263 * we're going to print it to stdout anyway. 264 */ 265 fwrite(buf, 1, readbytes, stdout); 266 } 267 /* In case the response didn't finish with a newline we add one now */ 268 printf("\n"); 269 270 /* 271 * Check whether we finished the while loop above normally or as the 272 * result of an error. The 0 argument to SSL_get_error() is the return 273 * code we received from the SSL_read_ex() call. It must be 0 in order 274 * to get here. Normal completion is indicated by SSL_ERROR_ZERO_RETURN. In 275 * QUIC terms this means that the peer has sent FIN on the stream to 276 * indicate that no further data will be sent. 277 */ 278 switch (SSL_get_error(ssl, 0)) { 279 case SSL_ERROR_ZERO_RETURN: 280 /* Normal completion of the stream */ 281 break; 282 283 case SSL_ERROR_SSL: 284 /* 285 * Some stream fatal error occurred. This could be because of a stream 286 * reset - or some failure occurred on the underlying connection. 287 */ 288 switch (SSL_get_stream_read_state(ssl)) { 289 case SSL_STREAM_STATE_RESET_REMOTE: 290 printf("Stream reset occurred\n"); 291 /* The stream has been reset but the connection is still healthy. */ 292 break; 293 294 case SSL_STREAM_STATE_CONN_CLOSED: 295 printf("Connection closed\n"); 296 /* Connection is already closed. Skip SSL_shutdown() */ 297 goto end; 298 299 default: 300 printf("Unknown stream failure\n"); 301 break; 302 } 303 break; 304 305 default: 306 /* Some other unexpected error occurred */ 307 printf ("Failed reading remaining data\n"); 308 break; 309 } 310 311In the above code example you can see that B<SSL_ERROR_SSL> indicates a stream 312fatal error. We can use L<SSL_get_stream_read_state(3)> to determine whether the 313stream has been reset, or if some other fatal error has occurred. 314 315=head2 Shutting down the connection 316 317In the TLS tutorial we knew that the server had finished sending data because 318L<SSL_read_ex(3)> returned 0, and L<SSL_get_error(3)> returned 319B<SSL_ERROR_ZERO_RETURN>. The same is true with QUIC except that 320B<SSL_ERROR_ZERO_RETURN> should be interpreted slightly differently. With TLS 321we knew that this meant that the server had sent a "close_notify" alert. No 322more data will be sent from the server on that connection. 323 324With QUIC it means that the server has indicated "FIN" on the stream, meaning 325that it will no longer send any more data on that stream. However this only 326gives us information about the stream itself and does not tell us anything about 327the underlying connection. More data could still be sent from the server on some 328other stream. Additionally, although the server will not send any more data to 329the client, it does not prevent the client from sending more data to the server. 330 331In this tutorial, once we have finished reading data from the server on the one 332stream that we are using, we will close the connection down. As before we do 333this via the L<SSL_shutdown(3)> function. This example for QUIC is very similar 334to the TLS version. However the L<SSL_shutdown(3)> function will need to be 335called more than once: 336 337 /* 338 * Repeatedly call SSL_shutdown() until the connection is fully 339 * closed. 340 */ 341 do { 342 ret = SSL_shutdown(ssl); 343 if (ret < 0) { 344 printf("Error shutting down: %d\n", ret); 345 goto end; 346 } 347 } while (ret != 1); 348 349The shutdown process is in two stages. In the first stage we wait until all the 350data we have buffered for sending on any stream has been successfully sent and 351acknowledged by the peer, and then we send a CONNECTION_CLOSE to the peer to 352indicate that the connection is no longer usable. This immediately closes the 353connection and no more data can be sent or received. L<SSL_shutdown(3)> returns 3540 once the first stage has been completed. 355 356In the second stage the connection enters a "closing" state. Application data 357cannot be sent or received in this state, but late arriving packets coming from 358the peer will be handled appropriately. Once this stage has completed 359successfully L<SSL_shutdown(3)> will return 1 to indicate success. 360 361=head1 FURTHER READING 362 363See L<ossl-guide-quic-multi-stream(7)> to read a tutorial on how to modify the 364client developed on this page to support multiple streams. 365 366=head1 SEE ALSO 367 368L<ossl-guide-introduction(7)>, L<ossl-guide-libraries-introduction(7)>, 369L<ossl-guide-libssl-introduction(7)>, L<ossl-guide-tls-introduction(7)>, 370L<ossl-guide-tls-client-block(7)>, L<ossl-guide-quic-introduction(7)> 371 372=head1 COPYRIGHT 373 374Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. 375 376Licensed under the Apache License 2.0 (the "License"). You may not use 377this file except in compliance with the License. You can obtain a copy 378in the file LICENSE in the source distribution or at 379L<https://www.openssl.org/source/license.html>. 380 381=cut 382