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