ossl-guide-quic-client-block.pod 16 KB

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