xref: /freebsd/crypto/openssl/doc/man7/ossl-guide-quic-server-block.pod (revision e7be843b4a162e68651d3911f0357ed464915629)
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-server-block.c
7
8=end comment
9
10=head1 NAME
11
12ossl-guide-quic-server-block
13- OpenSSL Guide: Writing a simple blocking QUIC server
14
15=head1 SIMPLE BLOCKING QUIC SERVER EXAMPLE
16
17This page will present various source code samples demonstrating how to write a
18simple, non-concurrent, QUIC "echo" server application which accepts one client
19connection at a time, echoing input from the client back to the same client.
20Once the current client disconnects, the next client connection is accepted.
21
22The server only accepts HTTP/1.0 requests, which is non-standard and will not
23be supported by real world servers.  This is for demonstration purposes only.
24
25Both the accepting socket and client connections are "blocking".  A more typical
26server might use nonblocking sockets with an event loop and callbacks for I/O
27events.
28
29The complete source code for this example blocking QUIC server is available in
30the B<demos/guide> directory of the OpenSSL source distribution in the file
31B<quic-server-block.c>.  It is also available online at
32L<https://github.com/openssl/openssl/blob/master/demos/guide/quic-server-block.c>.
33
34We assume that you already have OpenSSL installed on your system; that you
35already have some fundamental understanding of OpenSSL concepts and QUIC (see
36L<ossl-guide-libraries-introduction(7)> and L<ossl-guide-quic-introduction(7)>);
37and that you know how to write and build C code and link it against the
38libcrypto and libssl libraries that are provided by OpenSSL. It also assumes
39that you have a basic understanding of UDP/IP and sockets.
40
41=head2 Creating the SSL_CTX and SSL objects
42
43The first step is to create an B<SSL_CTX> object for our server. We use the
44L<SSL_CTX_new(3)> function for this purpose.  We pass as an argument the return
45value of the function L<OSSL_QUIC_server_method(3)>.  You should use this method
46whenever you are writing a QUIC server.
47
48    /*
49     * An SSL_CTX holds shared configuration information for multiple
50     * subsequent per-client SSL connections. We specifically load a QUIC
51     * server method here.
52     */
53    ctx = SSL_CTX_new(OSSL_QUIC_server_method());
54    if (ctx == NULL)
55        goto err;
56
57Servers need a private key and certificate.  Intermediate issuer CA
58certificates are often required, and both the server (end-entity or EE)
59certificate and the issuer ("chain") certificates are most easily configured in
60a single "chain file".  Below we load such a chain file (the EE certificate
61must appear first), and then load the corresponding private key, checking that
62it matches the server certificate.  No checks are performed to check the
63integrity of the chain (CA signatures or certificate expiration dates, for
64example), but we do verify the consistency of the private key with the
65corresponding certificate.
66
67    /*
68     * Load the server's certificate *chain* file (PEM format), which includes
69     * not only the leaf (end-entity) server certificate, but also any
70     * intermediate issuer-CA certificates.  The leaf certificate must be the
71     * first certificate in the file.
72     *
73     * In advanced use-cases this can be called multiple times, once per public
74     * key algorithm for which the server has a corresponding certificate.
75     * However, the corresponding private key (see below) must be loaded first,
76     * *before* moving on to the next chain file.
77     */
78    if (SSL_CTX_use_certificate_chain_file(ctx, cert_path) <= 0) {
79        fprintf(stderr, "couldn't load certificate file: %s\n", cert_path);
80        goto err;
81    }
82
83    /*
84     * Load the corresponding private key, this also checks that the private
85     * key matches the just loaded end-entity certificate.  It does not check
86     * whether the certificate chain is valid, the certificates could be
87     * expired, or may otherwise fail to form a chain that a client can
88     * validate.
89     */
90    if (SSL_CTX_use_PrivateKey_file(ctx, key_path, SSL_FILETYPE_PEM) <= 0) {
91        fprintf(stderr, "couldn't load key file: %s\n", key_path);
92        goto err;
93    }
94
95Most servers, including this one, do not solicit client certificates.  We
96therefore do not need a "trust store" and allow the handshake to complete even
97when the client does not present a certificate.  Note: Even if a client did
98present a trusted certificate, for it to be useful, the server application
99would still need custom code to use the verified identity to grant nondefault
100access to that particular client.  Some servers grant access to all clients
101with certificates from a private CA, this then requires processing of
102certificate revocation lists to deauthorise a client.  It is often simpler and
103more secure to instead keep a list of authorised public keys.
104
105Though this is the default setting, we explicitly call the
106L<SSL_CTX_set_verify(3)> function and pass the B<SSL_VERIFY_NONE> value to it.
107The final argument to this function is a callback that you can optionally
108supply to override the default handling for certificate verification.  Most
109applications do not need to do this so this can safely be set to NULL to get
110the default handling.
111
112    /*
113     * Clients rarely employ certificate-based authentication, and so we don't
114     * require "mutual" TLS authentication (indeed there's no way to know
115     * whether or how the client authenticated the server, so the term "mutual"
116     * is potentially misleading).
117     *
118     * Since we're not soliciting or processing client certificates, we don't
119     * need to configure a trusted-certificate store, so no call to
120     * SSL_CTX_set_default_verify_paths() is needed.  The server's own
121     * certificate chain is assumed valid.
122     */
123    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
124
125QUIC also dictates using Application-Layer Protocol Negotiation (ALPN) to select
126an application protocol.  We use L<SSL_CTX_set_alpn_select_cb(3)> for this
127purpose.  We can pass a callback which will be called for each connection to
128select an ALPN the server considers acceptable.
129
130    /* Setup ALPN negotiation callback to decide which ALPN is accepted. */
131    SSL_CTX_set_alpn_select_cb(ctx, select_alpn, NULL);
132
133In this case, we only accept "http/1.0" and "hq-interop".
134
135    /*
136    * ALPN strings for TLS handshake. Only 'http/1.0' and 'hq-interop'
137    * are accepted.
138    */
139    static const unsigned char alpn_ossltest[] = {
140        8,  'h', 't', 't', 'p', '/', '1', '.', '0',
141        10, 'h', 'q', '-', 'i', 'n', 't', 'e', 'r', 'o', 'p',
142    };
143
144    static int select_alpn(SSL *ssl, const unsigned char **out,
145                           unsigned char *out_len, const unsigned char *in,
146                           unsigned int in_len, void *arg)
147    {
148        if (SSL_select_next_proto((unsigned char **)out, out_len, alpn_ossltest,
149                                  sizeof(alpn_ossltest), in,
150                                  in_len) == OPENSSL_NPN_NEGOTIATED)
151            return SSL_TLSEXT_ERR_OK;
152        return SSL_TLSEXT_ERR_ALERT_FATAL;
153    }
154
155That is all the setup that we need to do for the B<SSL_CTX>.  Next, we create a
156UDP socket and bind to it on localhost.
157
158    /* Retrieve the file descriptor for a new UDP socket */
159    if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
160        fprintf(stderr, "cannot create socket");
161        goto err;
162    }
163
164    sa.sin_family = AF_INET;
165    sa.sin_port = htons(port);
166
167    /* Bind to the new UDP socket on localhost */
168    if (bind(fd, (const struct sockaddr *)&sa, sizeof(sa)) < 0) {
169        fprintf(stderr, "cannot bind to %u\n", port);
170        BIO_closesocket(fd);
171        goto err;
172    }
173
174To run the QUIC server, we create an B<SSL_LISTENER> to listen for incoming
175connections.  We provide it with the bound UDP port to then explicitly begin
176listening for new connections.
177
178    /*
179     * Create a new QUIC listener. Listeners, and other QUIC objects, default
180     * to operating in blocking mode. The configured behaviour is inherited by
181     * child objects.
182     */
183    if ((listener = SSL_new_listener(ctx, 0)) == NULL) {
184        goto err;
185    }
186
187    /* Provide the listener with our UDP socket. */
188    if (!SSL_set_fd(listener, fd))
189        goto err;
190
191    /* Begin listening. */
192    if (!SSL_listen(listener))
193        goto err;
194
195=head2 Server loop
196
197The server now enters a "forever" loop, handling one client connection at a
198time.  Before each connection, we clear the OpenSSL error stack so that any
199error reports are related to just the new connection.
200
201    /* Pristine error stack for each new connection */
202    ERR_clear_error();
203
204At this point, the server blocks to accept the next client.
205L<SSL_accept_connection(3)> will return an accepted connection within a fresh
206SSL, in which the handshake will have already occurred.
207
208    /* Block while waiting for a client connection */
209    conn = SSL_accept_connection(listener, 0);
210    if (conn == NULL) {
211        fprintf(stderr, "error while accepting connection\n");
212        goto err;
213    }
214
215With the handshake complete, the server echoes client input back to the client
216in a loop.
217
218    while (SSL_read_ex(conn, buf, sizeof(buf), &nread) > 0) {
219        if (SSL_write_ex(conn, buf, nread, &nwritten) > 0 &&
220            nwritten == nread) {
221            continue;
222        }
223        fprintf(stderr, "Error echoing client input");
224        break;
225    }
226
227Once the client closes its connection, we signal the end of the stream by using
228L<SSL_stream_conclude(3)>.  This will send a final Finished packet to the
229client.
230
231    /* Signal the end of the stream. */
232    if (SSL_stream_conclude(conn, 0) != 1) {
233        fprintf(stderr, "Unable to conclude stream\n");
234        SSL_free(conn);
235        goto err;
236    }
237
238We then shut down the connection with L<SSL_shutdown_ex(3)>, which may need
239to be called multiple times to ensure the connection is shutdown completely.
240
241    while (SSL_shutdown_ex(conn, 0, &shutdown_args,
242                           sizeof(SSL_SHUTDOWN_EX_ARGS)) != 1) {
243        fprintf(stderr, "Re-attempting SSL shutdown\n");
244    }
245
246Finally, we free the SSL connection, and the server is now ready to accept the
247next client connection.
248
249    SSL_free(conn);
250
251=head2 Final clean up
252
253If the server somehow manages to break out of the infinite loop and
254be ready to exit, it would deallocate the constructed B<SSL>.
255
256    SSL_free(listener);
257
258And in the main function, it would deallocate the constructed B<SSL_CTX>.
259
260    SSL_CTX_free(ctx);
261    BIO_closesocket(fd);
262    res = EXIT_SUCCESS;
263    return res;
264
265=head1 SEE ALSO
266
267L<ossl-guide-introduction(7)>, L<ossl-guide-libraries-introduction(7)>,
268L<ossl-guide-libssl-introduction(7)>, L<ossl-guide-quic-introduction(7)>,
269L<ossl-guide-quic-client-non-block(7)>, L<ossl-guide-quic-client-block(7)>,
270L<ossl-guide-tls-server-block(7)>, L<ossl-guide-quic-server-non-block(7)>
271
272=head1 COPYRIGHT
273
274Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
275
276Licensed under the Apache License 2.0 (the "License").  You may not use
277this file except in compliance with the License.  You can obtain a copy
278in the file LICENSE in the source distribution or at
279L<https://www.openssl.org/source/license.html>.
280
281=cut
282