From 1e6122774a75ee4a59b5de129eac122222905b52 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 28 Sep 2017 15:05:58 +0100 Subject: [PATCH] Add documentation for SSL_stateless() Fixes #4283 Reviewed-by: Ben Kaduk (Merged from https://github.com/openssl/openssl/pull/4435) --- doc/man3/DTLSv1_listen.pod | 116 +++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 43 deletions(-) diff --git a/doc/man3/DTLSv1_listen.pod b/doc/man3/DTLSv1_listen.pod index 3e0e25107a..02c1200268 100644 --- a/doc/man3/DTLSv1_listen.pod +++ b/doc/man3/DTLSv1_listen.pod @@ -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 + 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. - -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. - -OpenSSL implements this capability via the DTLSv1_listen() function. The B -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. +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. + +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. + +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 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 parameter updated into a state +then these functions will return with the B parameter updated into a state where the handshake can be continued by a call to (for example) SSL_accept(). -Additionally the B pointed to by B will be filled in with -details of the peer that sent the ClientHello. If the underlying BIO is unable -to obtain the B 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 +Additionally, for DTLSv1_listen(), the B pointed to by B will be +filled in with details of the peer that sent the ClientHello. If the underlying +BIO is unable to obtain the B 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 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 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 value will be filled in and the B object set up ready to -continue the handshake. +For SSL_stateless() a return value of 1 indicates success and the B 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 object +will be set up ready to continue the handshake. the B 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, L =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 -- 2.25.1