Add documentation for SSL_stateless()
Fixes #4283 Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4435)
This commit is contained in:
parent
dd77962e09
commit
1e6122774a
1 changed files with 70 additions and 40 deletions
|
@ -2,55 +2,69 @@
|
|||
|
||||
=head1 NAME
|
||||
|
||||
DTLSv1_listen - listen for incoming DTLS connections
|
||||
SSL_stateless,
|
||||
DTLSv1_listen
|
||||
- Statelessly listen for incoming connections
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
int SSL_stateless(SSL *s);
|
||||
int DTLSv1_listen(SSL *ssl, BIO_ADDR *peer);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
DTLSv1_listen() listens for new incoming DTLS connections. If a ClientHello is
|
||||
received that does not contain a cookie, then DTLSv1_listen() responds with a
|
||||
HelloVerifyRequest. If a ClientHello is received with a cookie that is verified
|
||||
then control is returned to user code to enable the handshake to be completed
|
||||
(for example by using SSL_accept()).
|
||||
SSL_stateless() statelessly listens for new incoming TLSv1.3 connections.
|
||||
DTLSv1_listen() statelessly listens for new incoming DTLS connections. If a
|
||||
ClientHello is received that does not contain a cookie, then they respond with a
|
||||
request for a new ClientHello that does contain a cookie. If a ClientHello is
|
||||
received with a cookie that is verified then the function returns in order to
|
||||
enable the handshake to be completed (for example by using SSL_accept()).
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
Datagram based protocols can be susceptible to Denial of Service attacks. A
|
||||
DTLS attacker could, for example, submit a series of handshake initiation
|
||||
requests that cause the server to allocate state (and possibly perform
|
||||
cryptographic operations) thus consuming server resources. The attacker could
|
||||
also (with UDP) quite simply forge the source IP address in such an attack.
|
||||
Some transport protocols (such as UDP) can be susceptible to amplification
|
||||
attacks. Unlike TCP there is no initial connection setup in UDP that
|
||||
validates that the client can actually receive messages on its advertised source
|
||||
address. An attacker could forge its source IP address and then send handshake
|
||||
initiation messages to the server. The server would then send its response to
|
||||
the forged source IP. If the response messages are larger than the original
|
||||
message then the amplification attack has succeeded.
|
||||
|
||||
As a counter measure to that DTLS includes a stateless cookie mechanism. The
|
||||
idea is that when a client attempts to connect to a server it sends a
|
||||
ClientHello message. The server responds with a HelloVerifyRequest which
|
||||
contains a unique cookie. The client then resends the ClientHello, but this time
|
||||
includes the cookie in the message thus proving that the client is capable of
|
||||
receiving messages sent to that address. All of this can be done by the server
|
||||
without allocating any state, and thus without consuming expensive resources.
|
||||
If DTLS is used over UDP (or any datagram based protocol that does not validate
|
||||
the source IP) then it is susceptible to this type of attack. TLSv1.3 is
|
||||
designed to operate over a stream-based transport protocol (such as TCP).
|
||||
If TCP is being used then there is no need to use SSL_stateless(). However some
|
||||
stream-based transport protocols (e.g. QUIC) may not validate the source
|
||||
address. In this case a TLSv1.3 application would be susceptible to this attack.
|
||||
|
||||
OpenSSL implements this capability via the DTLSv1_listen() function. The B<ssl>
|
||||
parameter should be a newly allocated SSL object with its read and write BIOs
|
||||
set, in the same way as might be done for a call to SSL_accept(). Typically the
|
||||
read BIO will be in an "unconnected" state and thus capable of receiving
|
||||
messages from any peer.
|
||||
As a counter measure to this issue TLSv1.3 and DTLS include a stateless cookie
|
||||
mechanism. The idea is that when a client attempts to connect to a server it
|
||||
sends a ClientHello message. The server responds with a HelloRetryRequest (in
|
||||
TLSv1.3) or a HelloVerifyRequest (in DTLS) which contains a unique cookie. The
|
||||
client then resends the ClientHello, but this time includes the cookie in the
|
||||
message thus proving that the client is capable of receiving messages sent to
|
||||
that address. All of this can be done by the server without allocating any
|
||||
state, and thus without consuming expensive resources.
|
||||
|
||||
OpenSSL implements this capability via the SSL_stateless() and DTLSv1_listen()
|
||||
functions. The B<ssl> parameter should be a newly allocated SSL object with its
|
||||
read and write BIOs set, in the same way as might be done for a call to
|
||||
SSL_accept(). Typically, for DTLS, the read BIO will be in an "unconnected"
|
||||
state and thus capable of receiving messages from any peer.
|
||||
|
||||
When a ClientHello is received that contains a cookie that has been verified,
|
||||
then DTLSv1_listen() will return with the B<ssl> parameter updated into a state
|
||||
then these functions will return with the B<ssl> parameter updated into a state
|
||||
where the handshake can be continued by a call to (for example) SSL_accept().
|
||||
Additionally the B<BIO_ADDR> pointed to by B<peer> will be filled in with
|
||||
details of the peer that sent the ClientHello. If the underlying BIO is unable
|
||||
to obtain the B<BIO_ADDR> of the peer (for example because the BIO does not
|
||||
support this), then B<*peer> will be cleared and the family set to AF_UNSPEC.
|
||||
Typically user code is expected to "connect" the underlying socket to the peer
|
||||
and continue the handshake in a connected state.
|
||||
Additionally, for DTLSv1_listen(), the B<BIO_ADDR> pointed to by B<peer> will be
|
||||
filled in with details of the peer that sent the ClientHello. If the underlying
|
||||
BIO is unable to obtain the B<BIO_ADDR> of the peer (for example because the BIO
|
||||
does not support this), then B<*peer> will be cleared and the family set to
|
||||
AF_UNSPEC. Typically user code is expected to "connect" the underlying socket to
|
||||
the peer and continue the handshake in a connected state.
|
||||
|
||||
Prior to calling DTLSv1_listen() user code must ensure that cookie generation
|
||||
Prior to calling these functions user code must ensure that cookie generation
|
||||
and verification callbacks have been set up using
|
||||
SSL_CTX_set_cookie_generate_cb() and SSL_CTX_set_cookie_verify_cb()
|
||||
respectively.
|
||||
|
@ -60,25 +74,39 @@ ClientHellos it is unable to process fragmented messages (since this would
|
|||
require the allocation of state). An implication of this is that DTLSv1_listen()
|
||||
B<only> supports ClientHellos that fit inside a single datagram.
|
||||
|
||||
For SSL_stateless() if an entire ClientHello message cannot be read without the
|
||||
"read" BIO becoming empty then the SSL_stateless() call will fail. It is the
|
||||
application's responsibility to ensure that data read from the "read" BIO during
|
||||
a single SSL_stateless() call is all from the same peer.
|
||||
|
||||
SSL_stateless() will fail (with a 0 return value) if some TLS version less than
|
||||
TLSv1.3 is used.
|
||||
|
||||
Both SSL_stateless() and DTLSv1_listen() will clear the error queue when they
|
||||
start.
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
From OpenSSL 1.1.0 a return value of >= 1 indicates success. In this instance
|
||||
the B<peer> value will be filled in and the B<ssl> object set up ready to
|
||||
continue the handshake.
|
||||
For SSL_stateless() a return value of 1 indicates success and the B<ssl> object
|
||||
will be set up ready to continue the handshake. A return value of 0 indicates
|
||||
failure. User code may retry the SSL_stateless() call.
|
||||
|
||||
For DTLSv1_listen() a return value of >= 1 indicates success. The B<ssl> object
|
||||
will be set up ready to continue the handshake. the B<peer> value will also be
|
||||
filled in.
|
||||
|
||||
A return value of 0 indicates a non-fatal error. This could (for
|
||||
example) be because of non-blocking IO, or some invalid message having been
|
||||
received from a peer. Errors may be placed on the OpenSSL error queue with
|
||||
further information if appropriate. Typically user code is expected to retry the
|
||||
call to DTLSv1_listen() in the event of a non-fatal error. Any old errors on the
|
||||
error queue will be cleared in the subsequent call.
|
||||
call to DTLSv1_listen() in the event of a non-fatal error.
|
||||
|
||||
A return value of <0 indicates a fatal error. This could (for example) be
|
||||
because of a failure to allocate sufficient memory for the operation.
|
||||
|
||||
Prior to OpenSSL 1.1.0 fatal and non-fatal errors both produce return codes
|
||||
<= 0 (in typical implementations user code treats all errors as non-fatal),
|
||||
whilst return codes >0 indicate success.
|
||||
For DTLSv1_listen(), prior to OpenSSL 1.1.0, fatal and non-fatal errors both
|
||||
produce return codes <= 0 (in typical implementations user code treats all
|
||||
errors as non-fatal), whilst return codes >0 indicate success.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@ -87,12 +115,14 @@ L<ssl(7)>, L<bio(7)>
|
|||
|
||||
=head1 HISTORY
|
||||
|
||||
SSL_stateless() was first added in OpenSSL 1.1.1.
|
||||
|
||||
DTLSv1_listen() return codes were clarified in OpenSSL 1.1.0. The type of "peer"
|
||||
also changed in OpenSSL 1.1.0.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
Copyright 2015-2017 The OpenSSL Project Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the OpenSSL license (the "License"). You may not use
|
||||
this file except in compliance with the License. You can obtain a copy
|
||||
|
|
Loading…
Reference in a new issue