[openssl-commits] [openssl] master update
Matt Caswell
matt at openssl.org
Wed Sep 23 12:55:54 UTC 2015
The branch master has been updated
via 373dc6e196835c06f31ff34cd188471f296126c1 (commit)
via 468f043ece0e7e262ee6166ae6ec1f7683d82220 (commit)
via d8249e99b9477ca059d5ed016fa49389bc0eb9e9 (commit)
via ca7256fbd947870101220735dc375862ec7eb9b1 (commit)
via 35d15a3952d50f243451c5f9fce1e2d9b88b67bb (commit)
via fd4e98ec8423cbcfc09aef62de2b9b0108c875c6 (commit)
via 912c89c529de78de807f58072ae77456b4a251b5 (commit)
via e3d0dae7cf8363ca462ac425b72c7bb31c3b4b7a (commit)
via 01b7851aa27aa144372f5484da916be042d9aa4f (commit)
from 1556d21850aabf31c554d3c6de2363979a965a9f (commit)
- Log -----------------------------------------------------------------
commit 373dc6e196835c06f31ff34cd188471f296126c1
Author: Matt Caswell <matt at openssl.org>
Date: Wed Sep 23 12:57:34 2015 +0100
Sanity check cookie_len
Add a sanity check that the cookie_len returned by app_gen_cookie_cb is
valid.
Reviewed-by: Andy Polyakov <appro at openssl.org>
commit 468f043ece0e7e262ee6166ae6ec1f7683d82220
Author: Matt Caswell <matt at openssl.org>
Date: Wed Sep 23 12:40:09 2015 +0100
Clarify DTLSv1_listen documentation
Clarify that user code is required to allocate sufficient space for the
addressing scheme in use in the call to DTLSv1_listen.
Reviewed-by: Andy Polyakov <appro at openssl.org>
commit d8249e99b9477ca059d5ed016fa49389bc0eb9e9
Author: Matt Caswell <matt at openssl.org>
Date: Wed Sep 23 10:02:18 2015 +0100
Fix s_server DTLSv1_listen issues
Use sockaddr_storage not sockaddr for the client IP address to allow for
IPv6.
Also fixed a section of code which was conditional on OPENSSL_NO_DTLS1
which should not have been.
Reviewed-by: Andy Polyakov <appro at openssl.org>
commit ca7256fbd947870101220735dc375862ec7eb9b1
Author: Matt Caswell <matt at openssl.org>
Date: Fri Apr 10 14:05:19 2015 +0100
Add DTLSv1_listen documentation
Adds a new man page to cover the DTLSv1_listen() function.
Reviewed-by: Andy Polyakov <appro at openssl.org>
commit 35d15a3952d50f243451c5f9fce1e2d9b88b67bb
Author: Matt Caswell <matt at openssl.org>
Date: Fri Apr 10 13:10:05 2015 +0100
Add -listen documentation
This commit adds documentation for the new -listen option to s_server. Along
the way it also adds documentation for -dtls, -dtls1 and -dtls1_2 which was
missing.
Reviewed-by: Andy Polyakov <appro at openssl.org>
commit fd4e98ec8423cbcfc09aef62de2b9b0108c875c6
Author: Matt Caswell <matt at openssl.org>
Date: Thu Apr 9 10:01:05 2015 +0100
Add support for DTLSv1_listen in s_server
DTLSv1_listen is a commonly used function within DTLS solutions for
listening for new incoming connections. This commit adds support to s_server
for using it.
Reviewed-by: Andy Polyakov <appro at openssl.org>
commit 912c89c529de78de807f58072ae77456b4a251b5
Author: Matt Caswell <matt at openssl.org>
Date: Thu Apr 9 23:31:35 2015 +0100
Remove remaining old listen code
The old implementation of DTLSv1_listen which has now been replaced still
had a few vestiges scattered throughout the code. This commit removes them.
Reviewed-by: Andy Polyakov <appro at openssl.org>
commit e3d0dae7cf8363ca462ac425b72c7bb31c3b4b7a
Author: Matt Caswell <matt at openssl.org>
Date: Mon Sep 14 22:49:35 2015 +0100
DTLSv1_listen rewrite
The existing implementation of DTLSv1_listen() is fundamentally flawed. This
function is used in DTLS solutions to listen for new incoming connections
from DTLS clients. A client will send an initial ClientHello. The server
will respond with a HelloVerifyRequest containing a unique cookie. The
client the responds with a second ClientHello - which this time contains the
cookie.
Once the cookie has been verified then DTLSv1_listen() returns to user code,
which is typically expected to continue the handshake with a call to (for
example) SSL_accept().
Whilst listening for incoming ClientHellos, the underlying BIO is usually in
an unconnected state. Therefore ClientHellos can come in from *any* peer.
The arrival of the first ClientHello without the cookie, and the second one
with it, could be interspersed with other intervening messages from
different clients.
The whole purpose of this mechanism is as a defence against DoS attacks. The
idea is to avoid allocating state on the server until the client has
verified that it is capable of receiving messages at the address it claims
to come from. However the existing DTLSv1_listen() implementation completely
fails to do this. It attempts to super-impose itself on the standard state
machine and reuses all of this code. However the standard state machine
expects to operate in a stateful manner with a single client, and this can
cause various problems.
A second more minor issue is that the return codes from this function are
quite confused, with no distinction made between fatal and non-fatal errors.
Most user code treats all errors as non-fatal, and simply retries the call
to DTLSv1_listen().
This commit completely rewrites the implementation of DTLSv1_listen() and
provides a stand alone implementation that does not rely on the existing
state machine. It also provides more consistent return codes.
Reviewed-by: Andy Polyakov <appro at openssl.org>
commit 01b7851aa27aa144372f5484da916be042d9aa4f
Author: Matt Caswell <matt at openssl.org>
Date: Mon Sep 14 22:36:04 2015 +0100
Add BIO_CTRL_DGRAM_SET_PEEK_MODE
Add the ability to peek at a message from the DTLS read BIO. This is needed
for the DTLSv1_listen rewrite.
Reviewed-by: Andy Polyakov <appro at openssl.org>
-----------------------------------------------------------------------
Summary of changes:
apps/s_server.c | 43 +++++-
crypto/bio/bss_dgram.c | 9 +-
doc/apps/s_server.pod | 19 +++
doc/ssl/DTLSv1_listen.pod | 95 ++++++++++++
doc/ssl/ssl.pod | 3 +-
include/openssl/bio.h | 2 +
include/openssl/ssl.h | 5 +
ssl/d1_both.c | 26 ++--
ssl/d1_lib.c | 386 +++++++++++++++++++++++++++++++++++++++++++++-
ssl/d1_srvr.c | 75 ++++-----
ssl/record/rec_layer_d1.c | 11 +-
ssl/record/record.h | 5 +-
ssl/record/ssl3_record.c | 19 +--
ssl/ssl_err.c | 6 +
ssl/ssl_locl.h | 11 +-
15 files changed, 627 insertions(+), 88 deletions(-)
create mode 100644 doc/ssl/DTLSv1_listen.pod
diff --git a/apps/s_server.c b/apps/s_server.c
index bd38373..ec73964 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -262,6 +262,7 @@ static long socket_mtu;
#ifndef OPENSSL_NO_DTLS1
static int cert_chain = 0;
#endif
+static int dtlslisten = 0;
static BIO *serverinfo_in = NULL;
static const char *s_serverinfo_file = NULL;
@@ -807,7 +808,7 @@ typedef enum OPTION_choice {
OPT_SRPUSERSEED, OPT_REV, OPT_WWW, OPT_UPPER_WWW, OPT_HTTP,
OPT_SSL3,
OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1,
- OPT_DTLS1_2, OPT_TIMEOUT, OPT_MTU, OPT_CHAIN,
+ OPT_DTLS1_2, OPT_TIMEOUT, OPT_MTU, OPT_CHAIN, OPT_LISTEN,
OPT_ID_PREFIX, OPT_RAND, OPT_SERVERNAME, OPT_SERVERNAME_FATAL,
OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN, OPT_JPAKE,
OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN,
@@ -937,6 +938,8 @@ OPTIONS s_server_options[] = {
{"timeout", OPT_TIMEOUT, '-', "Enable timeouts"},
{"mtu", OPT_MTU, 'p', "Set link layer MTU"},
{"chain", OPT_CHAIN, '-', "Read a certificate chain"},
+ {"listen", OPT_LISTEN, '-',
+ "Listen for a DTLS ClientHello with a cookie and then connect"},
#endif
#ifndef OPENSSL_NO_DH
{"no_dhe", OPT_NO_DHE, '-', "Disable ephemeral DH"},
@@ -1369,6 +1372,9 @@ int s_server_main(int argc, char *argv[])
case OPT_CHAIN:
cert_chain = 1;
break;
+ case OPT_LISTEN:
+ dtlslisten = 1;
+ break;
#else
case OPT_DTLS:
case OPT_DTLS1:
@@ -1376,6 +1382,7 @@ int s_server_main(int argc, char *argv[])
case OPT_TIMEOUT:
case OPT_MTU:
case OPT_CHAIN:
+ case OPT_LISTEN:
break;
#endif
case OPT_ID_PREFIX:
@@ -1434,6 +1441,11 @@ int s_server_main(int argc, char *argv[])
BIO_printf(bio_err, "Can't use -HTTP, -www or -WWW with DTLS\n");
goto end;
}
+
+ if (dtlslisten && socket_type != SOCK_DGRAM) {
+ BIO_printf(bio_err, "Can only use -listen with DTLS\n");
+ goto end;
+ }
#endif
if (unix_path && (socket_type != SOCK_STREAM)) {
@@ -2383,8 +2395,32 @@ static int init_ssl_connection(SSL *con)
unsigned next_proto_neg_len;
#endif
unsigned char *exportedkeymat;
+ struct sockaddr_storage client;
+
+#ifndef OPENSSL_NO_DTLS1
+ if(dtlslisten) {
+ i = DTLSv1_listen(con, &client);
+ if (i > 0) {
+ BIO *wbio;
+ int fd;
+
+ wbio = SSL_get_wbio(con);
+ if(wbio) {
+ BIO_get_fd(wbio, &fd);
+ }
+
+ if(!wbio || connect(fd, (struct sockaddr *)&client,
+ sizeof(struct sockaddr_storage))) {
+ BIO_printf(bio_err, "ERROR - unable to connect\n");
+ return 0;
+ }
+ dtlslisten = 0;
+ i = SSL_accept(con);
+ }
+ } else
+#endif
+ i = SSL_accept(con);
- i = SSL_accept(con);
#ifdef CERT_CB_TEST_RETRY
{
while (i <= 0 && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP
@@ -2412,7 +2448,8 @@ static int init_ssl_connection(SSL *con)
#endif
if (i <= 0) {
- if (BIO_sock_should_retry(i)) {
+ if ((dtlslisten && i == 0)
+ || (!dtlslisten && BIO_sock_should_retry(i))) {
BIO_printf(bio_s_out, "DELAY\n");
return (1);
}
diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c
index 91474fc..e7371c9 100644
--- a/crypto/bio/bss_dgram.c
+++ b/crypto/bio/bss_dgram.c
@@ -169,6 +169,7 @@ typedef struct bio_dgram_data_st {
unsigned int mtu;
struct timeval next_timeout;
struct timeval socket_timeout;
+ unsigned int peekmode;
} bio_dgram_data;
# ifndef OPENSSL_NO_SCTP
@@ -367,6 +368,7 @@ static int dgram_read(BIO *b, char *out, int outl)
{
int ret = 0;
bio_dgram_data *data = (bio_dgram_data *)b->ptr;
+ int flags = 0;
struct {
/*
@@ -392,7 +394,9 @@ static int dgram_read(BIO *b, char *out, int outl)
clear_socket_error();
memset(&sa.peer, 0, sizeof(sa.peer));
dgram_adjust_rcv_timeout(b);
- ret = recvfrom(b->num, out, outl, 0, &sa.peer.sa, (void *)&sa.len);
+ if (data->peekmode)
+ flags = MSG_PEEK;
+ ret = recvfrom(b->num, out, outl, flags, &sa.peer.sa, (void *)&sa.len);
if (sizeof(sa.len.i) != sizeof(sa.len.s) && sa.len.i == 0) {
OPENSSL_assert(sa.len.s <= sizeof(sa.peer));
sa.len.i = (int)sa.len.s;
@@ -923,6 +927,9 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
ret = dgram_get_mtu_overhead(data);
break;
+ case BIO_CTRL_DGRAM_SET_PEEK_MODE:
+ data->peekmode = (unsigned int)num;
+ break;
default:
ret = 0;
break;
diff --git a/doc/apps/s_server.pod b/doc/apps/s_server.pod
index 567df2c..3fd9a81 100644
--- a/doc/apps/s_server.pod
+++ b/doc/apps/s_server.pod
@@ -67,6 +67,10 @@ B<openssl> B<s_server>
[B<-no_tmp_rsa>]
[B<-ssl3>]
[B<-tls1>]
+[B<-dtls>]
+[B<-dtls1>]
+[B<-dtls1_2>]
+[B<-listen>]
[B<-no_ssl3>]
[B<-no_tls1>]
[B<-no_dhe>]
@@ -283,6 +287,21 @@ these options disable the use of certain SSL or TLS protocols. By default
the initial handshake uses a method which should be compatible with all
servers and permit them to use SSL v3 or TLS as appropriate.
+=item B<-dtls>, B<-dtls1>, B<-dtls1_2>
+
+these options make s_server use DTLS protocols instead of TLS. With B<-dtls>
+s_server will negotiate any supported DTLS protcol version, whilst B<-dtls1> and
+B<-dtls1_2> will only support DTLS1.0 and DTLS1.2 respectively.
+
+=item B<-listen>
+
+this option can only be used in conjunction with one of the DTLS options above.
+With this option s_server will listen on a UDP port for incoming connections.
+Any ClientHellos that arrive will be checked to see if they have a cookie in
+them or not. Any without a cookie will be responded to with a
+HelloVerifyRequest. If a ClientHello with a cookie is received then s_server
+will connect to that peer and complete the handshake.
+
=item B<-bugs>
there are several known bug in SSL and TLS implementations. Adding this
diff --git a/doc/ssl/DTLSv1_listen.pod b/doc/ssl/DTLSv1_listen.pod
new file mode 100644
index 0000000..d5f5a52
--- /dev/null
+++ b/doc/ssl/DTLSv1_listen.pod
@@ -0,0 +1,95 @@
+=pod
+
+=head1 NAME
+
+DTLSv1_listen - listen for incoming DTLS connections.
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ int DTLSv1_listen(SSL *ssl, struct sockaddr *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()).
+
+=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<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.
+
+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
+where the handshake can be continued by a call to (for example) SSL_accept().
+Additionally the B<struct sockaddr> location pointed to by B<peer> will be
+filled in with details of the peer that sent the ClientHello. It is the calling
+code's responsibility to ensure that the B<peer> location is sufficiently large
+to accommodate the addressing scheme in use. For example this might be done by
+allocating space for a struct sockaddr_storage and casting the pointer to it to
+a struct sockaddr * for the call to DTLSv1_listen(). 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
+and verification callbacks have been set up using
+SSL_CTX_set_cookie_generate_cb() and SSL_CTX_set_cookie_verify_cb()
+respectively.
+
+Since DTLSv1_listen() operates entirely statelessly whilst processing incoming
+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.
+
+=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.
+
+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.
+
+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.
+
+=head1 SEE ALSO
+
+L<SSL_get_error(3)|SSL_get_error(3)>, L<SSL_accept(3)|SSL_accept(3)>,
+L<ssl(3)|ssl(3)>, L<bio(3)|bio(3)>
+
+=head1 HISTORY
+
+DTLSv1_listen() was added in OpenSSL 0.9.8. Its return codes were clarified in
+OpenSSL 1.1.0.
+
+=cut
diff --git a/doc/ssl/ssl.pod b/doc/ssl/ssl.pod
index 6443de7..695a13c 100644
--- a/doc/ssl/ssl.pod
+++ b/doc/ssl/ssl.pod
@@ -743,7 +743,8 @@ L<SSL_SESSION_get_time(3)>,
L<d2i_SSL_SESSION(3)>,
L<SSL_CTX_set_psk_client_callback(3)>,
L<SSL_CTX_use_psk_identity_hint(3)>,
-L<SSL_get_psk_identity(3)>
+L<SSL_get_psk_identity(3)>,
+L<DTLSv1_listen(3)|DTLSv1_listen(3)>
=head1 HISTORY
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
index 2da93bd..75d052f 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -178,6 +178,8 @@ extern "C" {
# define BIO_CTRL_DGRAM_GET_MTU_OVERHEAD 49
+# define BIO_CTRL_DGRAM_SET_PEEK_MODE 50
+
# ifndef OPENSSL_NO_SCTP
/* SCTP stuff */
# define BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE 50
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 1334eb6..192640e 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1913,6 +1913,7 @@ void ERR_load_SSL_strings(void);
# define SSL_F_DTLS1_GET_RECORD 254
# define SSL_F_DTLS1_HANDLE_TIMEOUT 297
# define SSL_F_DTLS1_HEARTBEAT 305
+# define SSL_F_DTLS1_LISTEN 350
# define SSL_F_DTLS1_OUTPUT_CERT_CHAIN 255
# define SSL_F_DTLS1_PREPROCESS_FRAGMENT 288
# define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE 256
@@ -2166,6 +2167,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 307
# define SSL_R_COMPRESSION_LIBRARY_ERROR 142
# define SSL_R_CONNECTION_TYPE_NOT_SET 144
+# define SSL_R_COOKIE_GEN_CALLBACK_FAILURE 400
# define SSL_R_COOKIE_MISMATCH 308
# define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 145
# define SSL_R_DATA_LENGTH_TOO_LONG 146
@@ -2189,6 +2191,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151
# define SSL_R_EXCESSIVE_MESSAGE_SIZE 152
# define SSL_R_EXTRA_DATA_IN_MESSAGE 153
+# define SSL_R_FRAGMENTED_CLIENT_HELLO 401
# define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154
# define SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS 355
# define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 356
@@ -2201,6 +2204,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_INVALID_COMPRESSION_ALGORITHM 341
# define SSL_R_INVALID_NULL_CMD_NAME 385
# define SSL_R_INVALID_PURPOSE 278
+# define SSL_R_INVALID_SEQUENCE_NUMBER 402
# define SSL_R_INVALID_SERVERINFO_DATA 388
# define SSL_R_INVALID_SRP_USERNAME 357
# define SSL_R_INVALID_STATUS_RESPONSE 328
@@ -2250,6 +2254,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_NO_SHARED_SIGATURE_ALGORITHMS 376
# define SSL_R_NO_SRTP_PROFILES 359
# define SSL_R_NO_VERIFY_CALLBACK 194
+# define SSL_R_NO_VERIFY_COOKIE_CALLBACK 403
# define SSL_R_NULL_SSL_CTX 195
# define SSL_R_NULL_SSL_METHOD_PASSED 196
# define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 52b7304..02a464e 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -454,15 +454,26 @@ long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
* absence of an optional handshake message
*/
if (s->s3->tmp.reuse_message) {
- s->s3->tmp.reuse_message = 0;
if ((mt >= 0) && (s->s3->tmp.message_type != mt)) {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_DTLS1_GET_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
*ok = 1;
- s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+
+
+ /*
+ * Messages reused from dtls1_listen also have the record header in
+ * the buffer which we need to skip over.
+ */
+ if (s->s3->tmp.reuse_message == DTLS1_SKIP_RECORD_HEADER) {
+ s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH
+ + DTLS1_RT_HEADER_LENGTH;
+ } else {
+ s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+ }
s->init_num = (int)s->s3->tmp.message_size;
+ s->s3->tmp.reuse_message = 0;
return s->init_num;
}
@@ -519,9 +530,8 @@ long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
memset(msg_hdr, 0, sizeof(*msg_hdr));
- /* Don't change sequence numbers while listening */
- if (!s->d1->listen)
- s->d1->handshake_read_seq++;
+ s->d1->handshake_read_seq++;
+
s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
return s->init_num;
@@ -935,8 +945,7 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, int mt, long max, int *ok)
* While listening, we accept seq 1 (ClientHello with cookie)
* although we're still expecting seq 0 (ClientHello)
*/
- if (msg_hdr.seq != s->d1->handshake_read_seq
- && !(s->d1->listen && msg_hdr.seq == 1))
+ if (msg_hdr.seq != s->d1->handshake_read_seq)
return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
if (frag_len && frag_len < len)
@@ -1289,8 +1298,7 @@ void dtls1_set_message_header(SSL *s, unsigned char *p,
unsigned long frag_off,
unsigned long frag_len)
{
- /* Don't change sequence numbers while listening */
- if (frag_off == 0 && !s->d1->listen) {
+ if (frag_off == 0) {
s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
s->d1->next_handshake_write_seq++;
}
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index d3b582a..4bdf90a 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -499,23 +499,395 @@ static void get_current_time(struct timeval *t)
#endif
}
+
+#define LISTEN_SUCCESS 2
+#define LISTEN_SEND_VERIFY_REQUEST 1
+
+
int dtls1_listen(SSL *s, struct sockaddr *client)
{
- int ret;
+ int next, n, ret = 0, clearpkt = 0;
+ unsigned char cookie[DTLS1_COOKIE_LENGTH];
+ unsigned char seq[SEQ_NUM_SIZE];
+ unsigned char *data, *p, *buf;
+ unsigned long reclen, fragoff, fraglen, msglen;
+ unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen;
+ BIO *rbio, *wbio;
+ BUF_MEM *bufm;
+ struct sockaddr_storage tmpclient;
+ PACKET pkt, msgpkt, msgpayload, session, cookiepkt;
/* Ensure there is no state left over from a previous invocation */
if (!SSL_clear(s))
return -1;
+ ERR_clear_error();
+
+ rbio = SSL_get_rbio(s);
+ wbio = SSL_get_wbio(s);
+
+ if(!rbio || !wbio) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_BIO_NOT_SET);
+ return -1;
+ }
+
+ /*
+ * We only peek at incoming ClientHello's until we're sure we are going to
+ * to respond with a HelloVerifyRequest. If its a ClientHello with a valid
+ * cookie then we leave it in the BIO for dtls1_accept to handle.
+ */
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL);
+
+ /*
+ * Note: This check deliberately excludes DTLS1_BAD_VER because that version
+ * requires the MAC to be calculated *including* the first ClientHello
+ * (without the cookie). Since DTLSv1_listen is stateless that cannot be
+ * supported. DTLS1_BAD_VER must use cookies in a stateful manner (e.g. via
+ * SSL_accept)
+ */
+ if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_UNSUPPORTED_SSL_VERSION);
+ return -1;
+ }
+
+ if (s->init_buf == NULL) {
+ if ((bufm = BUF_MEM_new()) == NULL) {
+ SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+
+ if (!BUF_MEM_grow(bufm, SSL3_RT_MAX_PLAIN_LENGTH)) {
+ BUF_MEM_free(bufm);
+ SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ s->init_buf = bufm;
+ }
+ buf = (unsigned char *)s->init_buf->data;
+
+ do {
+ /* Get a packet */
+
+ clear_sys_error();
+ /*
+ * Technically a ClientHello could be SSL3_RT_MAX_PLAIN_LENGTH
+ * + DTLS1_RT_HEADER_LENGTH bytes long. Normally init_buf does not store
+ * the record header as well, but we do here. We've set up init_buf to
+ * be the standard size for simplicity. In practice we shouldn't ever
+ * receive a ClientHello as long as this. If we do it will get dropped
+ * in the record length check below.
+ */
+ n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);
+
+ if (n <= 0) {
+ if(BIO_should_retry(rbio)) {
+ /* Non-blocking IO */
+ goto end;
+ }
+ return -1;
+ }
+
+ /* If we hit any problems we need to clear this packet from the BIO */
+ clearpkt = 1;
+
+ if (!PACKET_buf_init(&pkt, buf, n)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /*
+ * Parse the received record. If there are any problems with it we just
+ * dump it - with no alert. RFC6347 says this "Unlike TLS, DTLS is
+ * resilient in the face of invalid records (e.g., invalid formatting,
+ * length, MAC, etc.). In general, invalid records SHOULD be silently
+ * discarded, thus preserving the association; however, an error MAY be
+ * logged for diagnostic purposes."
+ */
+
+ /* this packet contained a partial record, dump it */
+ if (n < DTLS1_RT_HEADER_LENGTH) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_RECORD_TOO_SMALL);
+ goto end;
+ }
+
+ if (s->msg_callback)
+ s->msg_callback(0, 0, SSL3_RT_HEADER, buf,
+ DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
+ /* Get the record header */
+ if (!PACKET_get_1(&pkt, &rectype)
+ || !PACKET_get_1(&pkt, &versmajor)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_LENGTH_MISMATCH);
+ goto end;
+ }
+
+ if (rectype != SSL3_RT_HANDSHAKE) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
+ goto end;
+ }
+
+ /*
+ * Check record version number. We only check that the major version is
+ * the same.
+ */
+ if (versmajor != DTLS1_VERSION_MAJOR) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
+ goto end;
+ }
+
+ if (!PACKET_forward(&pkt, 1)
+ /* Save the sequence number: 64 bits, with top 2 bytes = epoch */
+ || !PACKET_copy_bytes(&pkt, seq, SEQ_NUM_SIZE)
+ || !PACKET_get_length_prefixed_2(&pkt, &msgpkt)
+ || PACKET_remaining(&pkt) != 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_LENGTH_MISMATCH);
+ goto end;
+ }
+
+ /* This is an initial ClientHello so the epoch has to be 0 */
+ if (seq[0] != 0 || seq[1] != 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
+ goto end;
+ }
+
+ /* Get a pointer to the raw message for the later callback */
+ data = PACKET_data(&msgpkt);
+
+ /* Finished processing the record header, now process the message */
+ if (!PACKET_get_1(&msgpkt, &msgtype)
+ || !PACKET_get_net_3(&msgpkt, &msglen)
+ || !PACKET_get_net_2(&msgpkt, &msgseq)
+ || !PACKET_get_net_3(&msgpkt, &fragoff)
+ || !PACKET_get_net_3(&msgpkt, &fraglen)
+ || !PACKET_get_sub_packet(&msgpkt, &msgpayload, msglen)
+ || PACKET_remaining(&msgpkt) != 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_LENGTH_MISMATCH);
+ goto end;
+ }
+
+ if (msgtype != SSL3_MT_CLIENT_HELLO) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_UNEXPECTED_MESSAGE);
+ goto end;
+ }
+
+ /* Message sequence number can only be 0 or 1 */
+ if(msgseq > 2) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_INVALID_SEQUENCE_NUMBER);
+ goto end;
+ }
+
+ /* We don't support a fragmented ClientHello whilst listening */
+ if (fragoff != 0 || fraglen != msglen) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_FRAGMENTED_CLIENT_HELLO);
+ goto end;
+ }
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, data,
+ msglen + DTLS1_HM_HEADER_LENGTH, s,
+ s->msg_callback_arg);
+
+ if (!PACKET_get_net_2(&msgpayload, &clientvers)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_LENGTH_MISMATCH);
+ goto end;
+ }
+
+ /*
+ * Verify client version is supported
+ */
+ if ((clientvers > (unsigned int)s->method->version &&
+ s->method->version != DTLS_ANY_VERSION)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_WRONG_VERSION_NUMBER);
+ goto end;
+ }
+
+ if (!PACKET_forward(&msgpayload, SSL3_RANDOM_SIZE)
+ || !PACKET_get_length_prefixed_1(&msgpayload, &session)
+ || !PACKET_get_length_prefixed_1(&msgpayload, &cookiepkt)) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_LENGTH_MISMATCH);
+ goto end;
+ }
+
+ /*
+ * Check if we have a cookie or not. If not we need to send a
+ * HelloVerifyRequest.
+ */
+ if (PACKET_remaining(&cookiepkt) == 0) {
+ next = LISTEN_SEND_VERIFY_REQUEST;
+ } else {
+ /*
+ * We have a cookie, so lets check it.
+ */
+ if (s->ctx->app_verify_cookie_cb == NULL) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_NO_VERIFY_COOKIE_CALLBACK);
+ /* This is fatal */
+ return -1;
+ }
+ if (PACKET_remaining(&cookiepkt) > sizeof(s->d1->rcvd_cookie)
+ || s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookiepkt),
+ PACKET_remaining(&cookiepkt)) == 0) {
+ /*
+ * We treat invalid cookies in the same was as no cookie as
+ * per RFC6347
+ */
+ next = LISTEN_SEND_VERIFY_REQUEST;
+ } else {
+ /* Cookie verification succeeded */
+ next = LISTEN_SUCCESS;
+ }
+ }
+
+ if (next == LISTEN_SEND_VERIFY_REQUEST) {
+ /*
+ * There was no cookie in the ClientHello so we need to send a
+ * HelloVerifyRequest. If this fails we do not worry about trying
+ * to resend, we just drop it.
+ */
+
+ /*
+ * Dump the read packet, we don't need it any more. Ignore return
+ * value
+ */
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL);
+ BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL);
+
+ /* Generate the cookie */
+ if (s->ctx->app_gen_cookie_cb == NULL ||
+ s->ctx->app_gen_cookie_cb(s, cookie, &cookielen) == 0 ||
+ cookielen > 255) {
+ SSLerr(SSL_F_DTLS1_LISTEN, SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
+ /* This is fatal */
+ return -1;
+ }
+
+ p = &buf[DTLS1_RT_HEADER_LENGTH];
+ msglen = dtls1_raw_hello_verify_request(p + DTLS1_HM_HEADER_LENGTH,
+ cookie, cookielen);
+
+ *p++ = DTLS1_MT_HELLO_VERIFY_REQUEST;
+
+ /* Message length */
+ l2n3(msglen, p);
+
+ /* Message sequence number is always 0 for a HelloVerifyRequest */
+ s2n(0, p);
+
+ /*
+ * We never fragment a HelloVerifyRequest, so fragment offset is 0
+ * and fragment length is message length
+ */
+ l2n3(0, p);
+ l2n3(msglen, p);
+
+ /* Set reclen equal to length of whole handshake message */
+ reclen = msglen + DTLS1_HM_HEADER_LENGTH;
+
+ /* Add the record header */
+ p = buf;
+
+ *(p++) = SSL3_RT_HANDSHAKE;
+ /*
+ * Special case: for hello verify request, client version 1.0 and we
+ * haven't decided which version to use yet send back using version
+ * 1.0 header: otherwise some clients will ignore it.
+ */
+ if (s->method->version == DTLS_ANY_VERSION) {
+ *(p++) = DTLS1_VERSION >> 8;
+ *(p++) = DTLS1_VERSION & 0xff;
+ } else {
+ *(p++) = s->version >> 8;
+ *(p++) = s->version & 0xff;
+ }
+
+ /*
+ * Record sequence number is always the same as in the received
+ * ClientHello
+ */
+ memcpy(p, seq, SEQ_NUM_SIZE);
+ p += SEQ_NUM_SIZE;
+
+ /* Length */
+ s2n(reclen, p);
+
+ /*
+ * Set reclen equal to length of whole record including record
+ * header
+ */
+ reclen += DTLS1_RT_HEADER_LENGTH;
+
+ if (s->msg_callback)
+ s->msg_callback(1, 0, SSL3_RT_HEADER, buf,
+ DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
+
+ /*
+ * This is unneccessary if rbio and wbio are one and the same - but
+ * maybe they're not.
+ */
+ if(BIO_dgram_get_peer(rbio, &tmpclient) <= 0
+ || BIO_dgram_set_peer(wbio, &tmpclient) <= 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR);
+ goto end;
+ }
+
+ if (BIO_write(wbio, buf, reclen) < (int)reclen) {
+ if(BIO_should_retry(wbio)) {
+ /*
+ * Non-blocking IO...but we're stateless, so we're just
+ * going to drop this packet.
+ */
+ goto end;
+ }
+ return -1;
+ }
+
+ if (BIO_flush(wbio) <= 0) {
+ if(BIO_should_retry(wbio)) {
+ /*
+ * Non-blocking IO...but we're stateless, so we're just
+ * going to drop this packet.
+ */
+ goto end;
+ }
+ return -1;
+ }
+ }
+ } while (next != LISTEN_SUCCESS);
+
+ /*
+ * Set expected sequence numbers to continue the handshake.
+ */
+ s->d1->handshake_read_seq = 1;
+ s->d1->handshake_write_seq = 1;
+ s->d1->next_handshake_write_seq = 1;
+ DTLS_RECORD_LAYER_set_write_sequence(&s->rlayer, seq);
+
+ /*
+ * We are doing cookie exchange, so make sure we set that option in the
+ * SSL object
+ */
SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
- s->d1->listen = 1;
- ret = SSL_accept(s);
- if (ret <= 0)
- return ret;
+ /*
+ * Put us into the "init" state so that dtls1_accept doesn't clear our
+ * state
+ */
+ s->state = SSL_ST_ACCEPT;
+
+ if(BIO_dgram_get_peer(rbio, client) <= 0) {
+ SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
- (void)BIO_dgram_get_peer(SSL_get_rbio(s), client);
- return 1;
+ ret = 1;
+ clearpkt = 0;
+end:
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL);
+ if (clearpkt) {
+ /* Dump this packet. Ignore return value */
+ BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);
+ }
+ return ret;
}
static int dtls1_set_handshake_header(SSL *s, int htype, unsigned long len)
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index f56bf5a..e32c4c1 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -165,7 +165,6 @@ int dtls1_accept(SSL *s)
unsigned long alg_k;
int ret = -1;
int new_state, state, skip = 0;
- int listen;
#ifndef OPENSSL_NO_SCTP
unsigned char sctpauthkey[64];
char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
@@ -180,8 +179,6 @@ int dtls1_accept(SSL *s)
else if (s->ctx->info_callback != NULL)
cb = s->ctx->info_callback;
- listen = s->d1->listen;
-
/* init things to blank */
s->in_handshake++;
if (!SSL_in_init(s) || SSL_in_before(s)) {
@@ -189,7 +186,6 @@ int dtls1_accept(SSL *s)
return -1;
}
- s->d1->listen = listen;
#ifndef OPENSSL_NO_SCTP
/*
* Notify SCTP BIO socket to enter handshake mode and prevent stream
@@ -327,28 +323,6 @@ int dtls1_accept(SSL *s)
s->state = SSL3_ST_SW_SRVR_HELLO_A;
s->init_num = 0;
-
- /*
- * Reflect ClientHello sequence to remain stateless while
- * listening
- */
- if (listen) {
- DTLS_RECORD_LAYER_resync_write(&s->rlayer);
- }
-
- /* If we're just listening, stop here */
- if (listen && s->state == SSL3_ST_SW_SRVR_HELLO_A) {
- ret = 2;
- s->d1->listen = 0;
- /*
- * Set expected sequence numbers to continue the handshake.
- */
- s->d1->handshake_read_seq = 2;
- s->d1->handshake_write_seq = 1;
- s->d1->next_handshake_write_seq = 1;
- goto end;
- }
-
break;
case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
@@ -883,40 +857,55 @@ int dtls1_accept(SSL *s)
return (ret);
}
-int dtls1_send_hello_verify_request(SSL *s)
+unsigned int dtls1_raw_hello_verify_request(unsigned char *buf,
+ unsigned char *cookie,
+ unsigned char cookie_len)
{
unsigned int msg_len;
- unsigned char *msg, *buf, *p;
+ unsigned char *p;
+
+ p = buf;
+ /* Always use DTLS 1.0 version: see RFC 6347 */
+ *(p++) = DTLS1_VERSION >> 8;
+ *(p++) = DTLS1_VERSION & 0xFF;
+
+ *(p++) = (unsigned char)cookie_len;
+ memcpy(p, cookie, cookie_len);
+ p += cookie_len;
+ msg_len = p - buf;
+
+ return msg_len;
+}
+
+
+int dtls1_send_hello_verify_request(SSL *s)
+{
+ unsigned int len;
+ unsigned char *buf;
if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A) {
buf = (unsigned char *)s->init_buf->data;
- msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
- /* Always use DTLS 1.0 version: see RFC 6347 */
- *(p++) = DTLS1_VERSION >> 8;
- *(p++) = DTLS1_VERSION & 0xFF;
-
if (s->ctx->app_gen_cookie_cb == NULL ||
s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
- &(s->d1->cookie_len)) == 0) {
+ &(s->d1->cookie_len)) == 0 ||
+ s->d1->cookie_len > 255) {
SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,
- ERR_R_INTERNAL_ERROR);
+ SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
s->state = SSL_ST_ERR;
return 0;
}
- *(p++) = (unsigned char)s->d1->cookie_len;
- memcpy(p, s->d1->cookie, s->d1->cookie_len);
- p += s->d1->cookie_len;
- msg_len = p - msg;
+ len = dtls1_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH],
+ s->d1->cookie, s->d1->cookie_len);
- dtls1_set_message_header(s, buf,
- DTLS1_MT_HELLO_VERIFY_REQUEST, msg_len, 0,
- msg_len);
+ dtls1_set_message_header(s, buf, DTLS1_MT_HELLO_VERIFY_REQUEST, len, 0,
+ len);
+ len += DTLS1_HM_HEADER_LENGTH;
s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B;
/* number of bytes to write */
- s->init_num = p - buf;
+ s->init_num = len;
s->init_off = 0;
}
diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c
index 74796be..d7d0093 100644
--- a/ssl/record/rec_layer_d1.c
+++ b/ssl/record/rec_layer_d1.c
@@ -226,6 +226,12 @@ void DTLS_RECORD_LAYER_resync_write(RECORD_LAYER *rl)
memcpy(rl->write_sequence, rl->read_sequence, sizeof(rl->write_sequence));
}
+
+void DTLS_RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, unsigned char *seq)
+{
+ memcpy(rl->write_sequence, seq, SEQ_NUM_SIZE);
+}
+
static int have_handshake_fragment(SSL *s, int type, unsigned char *buf,
int len, int peek);
@@ -505,11 +511,6 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
}
}
- if (s->d1->listen && rr->type != SSL3_RT_HANDSHAKE) {
- SSL3_RECORD_set_length(rr, 0);
- goto start;
- }
-
/* we now have a packet which can be read and processed */
if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
diff --git a/ssl/record/record.h b/ssl/record/record.h
index 5c8fead..9637071 100644
--- a/ssl/record/record.h
+++ b/ssl/record/record.h
@@ -288,8 +288,8 @@ typedef struct record_layer_st {
int wpend_ret;
const unsigned char *wpend_buf;
- unsigned char read_sequence[8];
- unsigned char write_sequence[8];
+ unsigned char read_sequence[SEQ_NUM_SIZE];
+ unsigned char write_sequence[SEQ_NUM_SIZE];
DTLS_RECORD_LAYER *d;
} RECORD_LAYER;
@@ -346,6 +346,7 @@ void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_set_saved_w_epoch(RECORD_LAYER *rl, unsigned short e);
void DTLS_RECORD_LAYER_clear(RECORD_LAYER *rl);
void DTLS_RECORD_LAYER_resync_write(RECORD_LAYER *rl);
+void DTLS_RECORD_LAYER_set_write_sequence(RECORD_LAYER *rl, unsigned char *seq);
__owur int dtls1_read_bytes(SSL *s, int type, int *recvd_type,
unsigned char *buf, int len, int peek);
__owur int dtls1_write_bytes(SSL *s, int type, const void *buf, int len);
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index 1fa1710..7383f13 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -1508,18 +1508,8 @@ int dtls1_get_record(SSL *s)
/* Only do replay check if no SCTP bio */
if (!BIO_dgram_is_sctp(SSL_get_rbio(s))) {
#endif
- /*
- * Check whether this is a repeat, or aged record. Don't check if
- * we're listening and this message is a ClientHello. They can look
- * as if they're replayed, since they arrive from different
- * connections and would be dropped unnecessarily.
- */
- if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE &&
- RECORD_LAYER_get_packet_length(&s->rlayer)
- > DTLS1_RT_HEADER_LENGTH &&
- RECORD_LAYER_get_packet(&s->rlayer)[DTLS1_RT_HEADER_LENGTH]
- == SSL3_MT_CLIENT_HELLO) &&
- !dtls1_record_replay_check(s, bitmap)) {
+ /* Check whether this is a repeat, or aged record. */
+ if (!dtls1_record_replay_check(s, bitmap)) {
rr->length = 0;
RECORD_LAYER_reset_packet_length(&s->rlayer); /* dump this record */
goto again; /* get another record */
@@ -1535,11 +1525,10 @@ int dtls1_get_record(SSL *s)
/*
* If this record is from the next epoch (either HM or ALERT), and a
* handshake is currently in progress, buffer it since it cannot be
- * processed at this time. However, do not buffer anything while
- * listening.
+ * processed at this time.
*/
if (is_next_epoch) {
- if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen) {
+ if ((SSL_in_init(s) || s->in_handshake)) {
if (dtls1_buffer_record
(s, &(DTLS_RECORD_LAYER_get_unprocessed_rcds(&s->rlayer)),
rr->seq_num) < 0)
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 21836d8..447bac6 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -87,6 +87,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_DTLS1_GET_RECORD), "dtls1_get_record"},
{ERR_FUNC(SSL_F_DTLS1_HANDLE_TIMEOUT), "dtls1_handle_timeout"},
{ERR_FUNC(SSL_F_DTLS1_HEARTBEAT), "dtls1_heartbeat"},
+ {ERR_FUNC(SSL_F_DTLS1_LISTEN), "DTLS1_LISTEN"},
{ERR_FUNC(SSL_F_DTLS1_OUTPUT_CERT_CHAIN), "dtls1_output_cert_chain"},
{ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT), "DTLS1_PREPROCESS_FRAGMENT"},
{ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE),
@@ -406,6 +407,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"compression id not within private range"},
{ERR_REASON(SSL_R_COMPRESSION_LIBRARY_ERROR), "compression library error"},
{ERR_REASON(SSL_R_CONNECTION_TYPE_NOT_SET), "connection type not set"},
+ {ERR_REASON(SSL_R_COOKIE_GEN_CALLBACK_FAILURE),
+ "cookie gen callback failure"},
{ERR_REASON(SSL_R_COOKIE_MISMATCH), "cookie mismatch"},
{ERR_REASON(SSL_R_DATA_BETWEEN_CCS_AND_FINISHED),
"data between ccs and finished"},
@@ -440,6 +443,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"error in received cipher list"},
{ERR_REASON(SSL_R_EXCESSIVE_MESSAGE_SIZE), "excessive message size"},
{ERR_REASON(SSL_R_EXTRA_DATA_IN_MESSAGE), "extra data in message"},
+ {ERR_REASON(SSL_R_FRAGMENTED_CLIENT_HELLO), "fragmented client hello"},
{ERR_REASON(SSL_R_GOT_A_FIN_BEFORE_A_CCS), "got a fin before a ccs"},
{ERR_REASON(SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS),
"got next proto before a ccs"},
@@ -455,6 +459,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"invalid compression algorithm"},
{ERR_REASON(SSL_R_INVALID_NULL_CMD_NAME), "invalid null cmd name"},
{ERR_REASON(SSL_R_INVALID_PURPOSE), "invalid purpose"},
+ {ERR_REASON(SSL_R_INVALID_SEQUENCE_NUMBER), "invalid sequence number"},
{ERR_REASON(SSL_R_INVALID_SERVERINFO_DATA), "invalid serverinfo data"},
{ERR_REASON(SSL_R_INVALID_SRP_USERNAME), "invalid srp username"},
{ERR_REASON(SSL_R_INVALID_STATUS_RESPONSE), "invalid status response"},
@@ -510,6 +515,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"no shared sigature algorithms"},
{ERR_REASON(SSL_R_NO_SRTP_PROFILES), "no srtp profiles"},
{ERR_REASON(SSL_R_NO_VERIFY_CALLBACK), "no verify callback"},
+ {ERR_REASON(SSL_R_NO_VERIFY_COOKIE_CALLBACK), "no verify cookie callback"},
{ERR_REASON(SSL_R_NULL_SSL_CTX), "null ssl ctx"},
{ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED), "null ssl method passed"},
{ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 32e6338..b7c4fe7 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1376,6 +1376,12 @@ typedef struct ssl3_state_st {
/* Max MTU overhead we know about so far is 40 for IPv6 + 8 for UDP */
# define DTLS1_MAX_MTU_OVERHEAD 48
+/*
+ * Flag used in message reuse to indicate the buffer contains the record
+ * header as well as the the handshake message header.
+ */
+# define DTLS1_SKIP_RECORD_HEADER 2
+
struct dtls1_retransmit_state {
EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
EVP_MD_CTX *write_hash; /* used for mac generation */
@@ -1425,8 +1431,6 @@ typedef struct dtls1_state_st {
/* Buffered (sent) handshake records */
pqueue sent_messages;
- /* Is set when listening for new connections with dtls1_listen() */
- unsigned int listen;
unsigned int link_mtu; /* max on-the-wire DTLS packet size */
unsigned int mtu; /* max DTLS packet size */
struct hm_header_st w_msg_hdr;
@@ -1990,6 +1994,9 @@ void dtls1_start_timer(SSL *s);
void dtls1_stop_timer(SSL *s);
__owur int dtls1_is_timer_expired(SSL *s);
void dtls1_double_timeout(SSL *s);
+__owur unsigned int dtls1_raw_hello_verify_request(unsigned char *buf,
+ unsigned char *cookie,
+ unsigned char cookie_len);
__owur int dtls1_send_newsession_ticket(SSL *s);
__owur unsigned int dtls1_min_mtu(SSL *s);
__owur unsigned int dtls1_link_min_mtu(void);
More information about the openssl-commits
mailing list