A local copy of OpenSSL from GitHub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

965 lines
29 KiB

17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
Fix DTLS buffered message DoS attack DTLS can handle out of order record delivery. Additionally since handshake messages can be bigger than will fit into a single packet, the messages can be fragmented across multiple records (as with normal TLS). That means that the messages can arrive mixed up, and we have to reassemble them. We keep a queue of buffered messages that are "from the future", i.e. messages we're not ready to deal with yet but have arrived early. The messages held there may not be full yet - they could be one or more fragments that are still in the process of being reassembled. The code assumes that we will eventually complete the reassembly and when that occurs the complete message is removed from the queue at the point that we need to use it. However, DTLS is also tolerant of packet loss. To get around that DTLS messages can be retransmitted. If we receive a full (non-fragmented) message from the peer after previously having received a fragment of that message, then we ignore the message in the queue and just use the non-fragmented version. At that point the queued message will never get removed. Additionally the peer could send "future" messages that we never get to in order to complete the handshake. Each message has a sequence number (starting from 0). We will accept a message fragment for the current message sequence number, or for any sequence up to 10 into the future. However if the Finished message has a sequence number of 2, anything greater than that in the queue is just left there. So, in those two ways we can end up with "orphaned" data in the queue that will never get removed - except when the connection is closed. At that point all the queues are flushed. An attacker could seek to exploit this by filling up the queues with lots of large messages that are never going to be used in order to attempt a DoS by memory exhaustion. I will assume that we are only concerned with servers here. It does not seem reasonable to be concerned about a memory exhaustion attack on a client. They are unlikely to process enough connections for this to be an issue. A "long" handshake with many messages might be 5 messages long (in the incoming direction), e.g. ClientHello, Certificate, ClientKeyExchange, CertificateVerify, Finished. So this would be message sequence numbers 0 to 4. Additionally we can buffer up to 10 messages in the future. Therefore the maximum number of messages that an attacker could send that could get orphaned would typically be 15. The maximum size that a DTLS message is allowed to be is defined by max_cert_list, which by default is 100k. Therefore the maximum amount of "orphaned" memory per connection is 1500k. Message sequence numbers get reset after the Finished message, so renegotiation will not extend the maximum number of messages that can be orphaned per connection. As noted above, the queues do get cleared when the connection is closed. Therefore in order to mount an effective attack, an attacker would have to open many simultaneous connections. Issue reported by Quan Luo. CVE-2016-2179 Reviewed-by: Richard Levitte <levitte@openssl.org>
6 years ago
17 years ago
17 years ago
17 years ago
Fix DTLS buffered message DoS attack DTLS can handle out of order record delivery. Additionally since handshake messages can be bigger than will fit into a single packet, the messages can be fragmented across multiple records (as with normal TLS). That means that the messages can arrive mixed up, and we have to reassemble them. We keep a queue of buffered messages that are "from the future", i.e. messages we're not ready to deal with yet but have arrived early. The messages held there may not be full yet - they could be one or more fragments that are still in the process of being reassembled. The code assumes that we will eventually complete the reassembly and when that occurs the complete message is removed from the queue at the point that we need to use it. However, DTLS is also tolerant of packet loss. To get around that DTLS messages can be retransmitted. If we receive a full (non-fragmented) message from the peer after previously having received a fragment of that message, then we ignore the message in the queue and just use the non-fragmented version. At that point the queued message will never get removed. Additionally the peer could send "future" messages that we never get to in order to complete the handshake. Each message has a sequence number (starting from 0). We will accept a message fragment for the current message sequence number, or for any sequence up to 10 into the future. However if the Finished message has a sequence number of 2, anything greater than that in the queue is just left there. So, in those two ways we can end up with "orphaned" data in the queue that will never get removed - except when the connection is closed. At that point all the queues are flushed. An attacker could seek to exploit this by filling up the queues with lots of large messages that are never going to be used in order to attempt a DoS by memory exhaustion. I will assume that we are only concerned with servers here. It does not seem reasonable to be concerned about a memory exhaustion attack on a client. They are unlikely to process enough connections for this to be an issue. A "long" handshake with many messages might be 5 messages long (in the incoming direction), e.g. ClientHello, Certificate, ClientKeyExchange, CertificateVerify, Finished. So this would be message sequence numbers 0 to 4. Additionally we can buffer up to 10 messages in the future. Therefore the maximum number of messages that an attacker could send that could get orphaned would typically be 15. The maximum size that a DTLS message is allowed to be is defined by max_cert_list, which by default is 100k. Therefore the maximum amount of "orphaned" memory per connection is 1500k. Message sequence numbers get reset after the Finished message, so renegotiation will not extend the maximum number of messages that can be orphaned per connection. As noted above, the queues do get cleared when the connection is closed. Therefore in order to mount an effective attack, an attacker would have to open many simultaneous connections. Issue reported by Quan Luo. CVE-2016-2179 Reviewed-by: Richard Levitte <levitte@openssl.org>
6 years ago
17 years ago
17 years ago
17 years ago
Fix DTLS buffered message DoS attack DTLS can handle out of order record delivery. Additionally since handshake messages can be bigger than will fit into a single packet, the messages can be fragmented across multiple records (as with normal TLS). That means that the messages can arrive mixed up, and we have to reassemble them. We keep a queue of buffered messages that are "from the future", i.e. messages we're not ready to deal with yet but have arrived early. The messages held there may not be full yet - they could be one or more fragments that are still in the process of being reassembled. The code assumes that we will eventually complete the reassembly and when that occurs the complete message is removed from the queue at the point that we need to use it. However, DTLS is also tolerant of packet loss. To get around that DTLS messages can be retransmitted. If we receive a full (non-fragmented) message from the peer after previously having received a fragment of that message, then we ignore the message in the queue and just use the non-fragmented version. At that point the queued message will never get removed. Additionally the peer could send "future" messages that we never get to in order to complete the handshake. Each message has a sequence number (starting from 0). We will accept a message fragment for the current message sequence number, or for any sequence up to 10 into the future. However if the Finished message has a sequence number of 2, anything greater than that in the queue is just left there. So, in those two ways we can end up with "orphaned" data in the queue that will never get removed - except when the connection is closed. At that point all the queues are flushed. An attacker could seek to exploit this by filling up the queues with lots of large messages that are never going to be used in order to attempt a DoS by memory exhaustion. I will assume that we are only concerned with servers here. It does not seem reasonable to be concerned about a memory exhaustion attack on a client. They are unlikely to process enough connections for this to be an issue. A "long" handshake with many messages might be 5 messages long (in the incoming direction), e.g. ClientHello, Certificate, ClientKeyExchange, CertificateVerify, Finished. So this would be message sequence numbers 0 to 4. Additionally we can buffer up to 10 messages in the future. Therefore the maximum number of messages that an attacker could send that could get orphaned would typically be 15. The maximum size that a DTLS message is allowed to be is defined by max_cert_list, which by default is 100k. Therefore the maximum amount of "orphaned" memory per connection is 1500k. Message sequence numbers get reset after the Finished message, so renegotiation will not extend the maximum number of messages that can be orphaned per connection. As noted above, the queues do get cleared when the connection is closed. Therefore in order to mount an effective attack, an attacker would have to open many simultaneous connections. Issue reported by Quan Luo. CVE-2016-2179 Reviewed-by: Richard Levitte <levitte@openssl.org>
6 years ago
17 years ago
Fix DTLS buffered message DoS attack DTLS can handle out of order record delivery. Additionally since handshake messages can be bigger than will fit into a single packet, the messages can be fragmented across multiple records (as with normal TLS). That means that the messages can arrive mixed up, and we have to reassemble them. We keep a queue of buffered messages that are "from the future", i.e. messages we're not ready to deal with yet but have arrived early. The messages held there may not be full yet - they could be one or more fragments that are still in the process of being reassembled. The code assumes that we will eventually complete the reassembly and when that occurs the complete message is removed from the queue at the point that we need to use it. However, DTLS is also tolerant of packet loss. To get around that DTLS messages can be retransmitted. If we receive a full (non-fragmented) message from the peer after previously having received a fragment of that message, then we ignore the message in the queue and just use the non-fragmented version. At that point the queued message will never get removed. Additionally the peer could send "future" messages that we never get to in order to complete the handshake. Each message has a sequence number (starting from 0). We will accept a message fragment for the current message sequence number, or for any sequence up to 10 into the future. However if the Finished message has a sequence number of 2, anything greater than that in the queue is just left there. So, in those two ways we can end up with "orphaned" data in the queue that will never get removed - except when the connection is closed. At that point all the queues are flushed. An attacker could seek to exploit this by filling up the queues with lots of large messages that are never going to be used in order to attempt a DoS by memory exhaustion. I will assume that we are only concerned with servers here. It does not seem reasonable to be concerned about a memory exhaustion attack on a client. They are unlikely to process enough connections for this to be an issue. A "long" handshake with many messages might be 5 messages long (in the incoming direction), e.g. ClientHello, Certificate, ClientKeyExchange, CertificateVerify, Finished. So this would be message sequence numbers 0 to 4. Additionally we can buffer up to 10 messages in the future. Therefore the maximum number of messages that an attacker could send that could get orphaned would typically be 15. The maximum size that a DTLS message is allowed to be is defined by max_cert_list, which by default is 100k. Therefore the maximum amount of "orphaned" memory per connection is 1500k. Message sequence numbers get reset after the Finished message, so renegotiation will not extend the maximum number of messages that can be orphaned per connection. As noted above, the queues do get cleared when the connection is closed. Therefore in order to mount an effective attack, an attacker would have to open many simultaneous connections. Issue reported by Quan Luo. CVE-2016-2179 Reviewed-by: Richard Levitte <levitte@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
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@openssl.org>
6 years ago
  1. /*
  2. * Copyright 2005-2021 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include "e_os.h"
  10. #include <stdio.h>
  11. #include <openssl/objects.h>
  12. #include <openssl/rand.h>
  13. #include "ssl_local.h"
  14. static void get_current_time(struct timeval *t);
  15. static int dtls1_handshake_write(SSL *s);
  16. static size_t dtls1_link_min_mtu(void);
  17. /* XDTLS: figure out the right values */
  18. static const size_t g_probable_mtu[] = { 1500, 512, 256 };
  19. const SSL3_ENC_METHOD DTLSv1_enc_data = {
  20. tls1_enc,
  21. tls1_mac,
  22. tls1_setup_key_block,
  23. tls1_generate_master_secret,
  24. tls1_change_cipher_state,
  25. tls1_final_finish_mac,
  26. TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE,
  27. TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
  28. tls1_alert_code,
  29. tls1_export_keying_material,
  30. SSL_ENC_FLAG_DTLS | SSL_ENC_FLAG_EXPLICIT_IV,
  31. dtls1_set_handshake_header,
  32. dtls1_close_construct_packet,
  33. dtls1_handshake_write
  34. };
  35. const SSL3_ENC_METHOD DTLSv1_2_enc_data = {
  36. tls1_enc,
  37. tls1_mac,
  38. tls1_setup_key_block,
  39. tls1_generate_master_secret,
  40. tls1_change_cipher_state,
  41. tls1_final_finish_mac,
  42. TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE,
  43. TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
  44. tls1_alert_code,
  45. tls1_export_keying_material,
  46. SSL_ENC_FLAG_DTLS | SSL_ENC_FLAG_EXPLICIT_IV | SSL_ENC_FLAG_SIGALGS
  47. | SSL_ENC_FLAG_SHA256_PRF | SSL_ENC_FLAG_TLS1_2_CIPHERS,
  48. dtls1_set_handshake_header,
  49. dtls1_close_construct_packet,
  50. dtls1_handshake_write
  51. };
  52. long dtls1_default_timeout(void)
  53. {
  54. /*
  55. * 2 hours, the 24 hours mentioned in the DTLSv1 spec is way too long for
  56. * http, the cache would over fill
  57. */
  58. return (60 * 60 * 2);
  59. }
  60. int dtls1_new(SSL *s)
  61. {
  62. DTLS1_STATE *d1;
  63. if (!DTLS_RECORD_LAYER_new(&s->rlayer)) {
  64. return 0;
  65. }
  66. if (!ssl3_new(s))
  67. return 0;
  68. if ((d1 = OPENSSL_zalloc(sizeof(*d1))) == NULL) {
  69. ssl3_free(s);
  70. return 0;
  71. }
  72. d1->buffered_messages = pqueue_new();
  73. d1->sent_messages = pqueue_new();
  74. if (s->server) {
  75. d1->cookie_len = sizeof(s->d1->cookie);
  76. }
  77. d1->link_mtu = 0;
  78. d1->mtu = 0;
  79. if (d1->buffered_messages == NULL || d1->sent_messages == NULL) {
  80. pqueue_free(d1->buffered_messages);
  81. pqueue_free(d1->sent_messages);
  82. OPENSSL_free(d1);
  83. ssl3_free(s);
  84. return 0;
  85. }
  86. s->d1 = d1;
  87. if (!s->method->ssl_clear(s))
  88. return 0;
  89. return 1;
  90. }
  91. static void dtls1_clear_queues(SSL *s)
  92. {
  93. dtls1_clear_received_buffer(s);
  94. dtls1_clear_sent_buffer(s);
  95. }
  96. void dtls1_clear_received_buffer(SSL *s)
  97. {
  98. pitem *item = NULL;
  99. hm_fragment *frag = NULL;
  100. while ((item = pqueue_pop(s->d1->buffered_messages)) != NULL) {
  101. frag = (hm_fragment *)item->data;
  102. dtls1_hm_fragment_free(frag);
  103. pitem_free(item);
  104. }
  105. }
  106. void dtls1_clear_sent_buffer(SSL *s)
  107. {
  108. pitem *item = NULL;
  109. hm_fragment *frag = NULL;
  110. while ((item = pqueue_pop(s->d1->sent_messages)) != NULL) {
  111. frag = (hm_fragment *)item->data;
  112. dtls1_hm_fragment_free(frag);
  113. pitem_free(item);
  114. }
  115. }
  116. void dtls1_free(SSL *s)
  117. {
  118. DTLS_RECORD_LAYER_free(&s->rlayer);
  119. ssl3_free(s);
  120. if (s->d1 != NULL) {
  121. dtls1_clear_queues(s);
  122. pqueue_free(s->d1->buffered_messages);
  123. pqueue_free(s->d1->sent_messages);
  124. }
  125. OPENSSL_free(s->d1);
  126. s->d1 = NULL;
  127. }
  128. int dtls1_clear(SSL *s)
  129. {
  130. pqueue *buffered_messages;
  131. pqueue *sent_messages;
  132. size_t mtu;
  133. size_t link_mtu;
  134. DTLS_RECORD_LAYER_clear(&s->rlayer);
  135. if (s->d1) {
  136. DTLS_timer_cb timer_cb = s->d1->timer_cb;
  137. buffered_messages = s->d1->buffered_messages;
  138. sent_messages = s->d1->sent_messages;
  139. mtu = s->d1->mtu;
  140. link_mtu = s->d1->link_mtu;
  141. dtls1_clear_queues(s);
  142. memset(s->d1, 0, sizeof(*s->d1));
  143. /* Restore the timer callback from previous state */
  144. s->d1->timer_cb = timer_cb;
  145. if (s->server) {
  146. s->d1->cookie_len = sizeof(s->d1->cookie);
  147. }
  148. if (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU) {
  149. s->d1->mtu = mtu;
  150. s->d1->link_mtu = link_mtu;
  151. }
  152. s->d1->buffered_messages = buffered_messages;
  153. s->d1->sent_messages = sent_messages;
  154. }
  155. if (!ssl3_clear(s))
  156. return 0;
  157. if (s->method->version == DTLS_ANY_VERSION)
  158. s->version = DTLS_MAX_VERSION_INTERNAL;
  159. #ifndef OPENSSL_NO_DTLS1_METHOD
  160. else if (s->options & SSL_OP_CISCO_ANYCONNECT)
  161. s->client_version = s->version = DTLS1_BAD_VER;
  162. #endif
  163. else
  164. s->version = s->method->version;
  165. return 1;
  166. }
  167. long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg)
  168. {
  169. int ret = 0;
  170. switch (cmd) {
  171. case DTLS_CTRL_GET_TIMEOUT:
  172. if (dtls1_get_timeout(s, (struct timeval *)parg) != NULL) {
  173. ret = 1;
  174. }
  175. break;
  176. case DTLS_CTRL_HANDLE_TIMEOUT:
  177. ret = dtls1_handle_timeout(s);
  178. break;
  179. case DTLS_CTRL_SET_LINK_MTU:
  180. if (larg < (long)dtls1_link_min_mtu())
  181. return 0;
  182. s->d1->link_mtu = larg;
  183. return 1;
  184. case DTLS_CTRL_GET_LINK_MIN_MTU:
  185. return (long)dtls1_link_min_mtu();
  186. case SSL_CTRL_SET_MTU:
  187. /*
  188. * We may not have a BIO set yet so can't call dtls1_min_mtu()
  189. * We'll have to make do with dtls1_link_min_mtu() and max overhead
  190. */
  191. if (larg < (long)dtls1_link_min_mtu() - DTLS1_MAX_MTU_OVERHEAD)
  192. return 0;
  193. s->d1->mtu = larg;
  194. return larg;
  195. default:
  196. ret = ssl3_ctrl(s, cmd, larg, parg);
  197. break;
  198. }
  199. return ret;
  200. }
  201. void dtls1_start_timer(SSL *s)
  202. {
  203. unsigned int sec, usec;
  204. #ifndef OPENSSL_NO_SCTP
  205. /* Disable timer for SCTP */
  206. if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
  207. memset(&s->d1->next_timeout, 0, sizeof(s->d1->next_timeout));
  208. return;
  209. }
  210. #endif
  211. /*
  212. * If timer is not set, initialize duration with 1 second or
  213. * a user-specified value if the timer callback is installed.
  214. */
  215. if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) {
  216. if (s->d1->timer_cb != NULL)
  217. s->d1->timeout_duration_us = s->d1->timer_cb(s, 0);
  218. else
  219. s->d1->timeout_duration_us = 1000000;
  220. }
  221. /* Set timeout to current time */
  222. get_current_time(&(s->d1->next_timeout));
  223. /* Add duration to current time */
  224. sec = s->d1->timeout_duration_us / 1000000;
  225. usec = s->d1->timeout_duration_us - (sec * 1000000);
  226. s->d1->next_timeout.tv_sec += sec;
  227. s->d1->next_timeout.tv_usec += usec;
  228. if (s->d1->next_timeout.tv_usec >= 1000000) {
  229. s->d1->next_timeout.tv_sec++;
  230. s->d1->next_timeout.tv_usec -= 1000000;
  231. }
  232. BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
  233. &(s->d1->next_timeout));
  234. }
  235. struct timeval *dtls1_get_timeout(SSL *s, struct timeval *timeleft)
  236. {
  237. struct timeval timenow;
  238. /* If no timeout is set, just return NULL */
  239. if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) {
  240. return NULL;
  241. }
  242. /* Get current time */
  243. get_current_time(&timenow);
  244. /* If timer already expired, set remaining time to 0 */
  245. if (s->d1->next_timeout.tv_sec < timenow.tv_sec ||
  246. (s->d1->next_timeout.tv_sec == timenow.tv_sec &&
  247. s->d1->next_timeout.tv_usec <= timenow.tv_usec)) {
  248. memset(timeleft, 0, sizeof(*timeleft));
  249. return timeleft;
  250. }
  251. /* Calculate time left until timer expires */
  252. memcpy(timeleft, &(s->d1->next_timeout), sizeof(struct timeval));
  253. timeleft->tv_sec -= timenow.tv_sec;
  254. timeleft->tv_usec -= timenow.tv_usec;
  255. if (timeleft->tv_usec < 0) {
  256. timeleft->tv_sec--;
  257. timeleft->tv_usec += 1000000;
  258. }
  259. /*
  260. * If remaining time is less than 15 ms, set it to 0 to prevent issues
  261. * because of small divergences with socket timeouts.
  262. */
  263. if (timeleft->tv_sec == 0 && timeleft->tv_usec < 15000) {
  264. memset(timeleft, 0, sizeof(*timeleft));
  265. }
  266. return timeleft;
  267. }
  268. int dtls1_is_timer_expired(SSL *s)
  269. {
  270. struct timeval timeleft;
  271. /* Get time left until timeout, return false if no timer running */
  272. if (dtls1_get_timeout(s, &timeleft) == NULL) {
  273. return 0;
  274. }
  275. /* Return false if timer is not expired yet */
  276. if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0) {
  277. return 0;
  278. }
  279. /* Timer expired, so return true */
  280. return 1;
  281. }
  282. static void dtls1_double_timeout(SSL *s)
  283. {
  284. s->d1->timeout_duration_us *= 2;
  285. if (s->d1->timeout_duration_us > 60000000)
  286. s->d1->timeout_duration_us = 60000000;
  287. }
  288. void dtls1_stop_timer(SSL *s)
  289. {
  290. /* Reset everything */
  291. s->d1->timeout_num_alerts = 0;
  292. memset(&s->d1->next_timeout, 0, sizeof(s->d1->next_timeout));
  293. s->d1->timeout_duration_us = 1000000;
  294. BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
  295. &(s->d1->next_timeout));
  296. /* Clear retransmission buffer */
  297. dtls1_clear_sent_buffer(s);
  298. }
  299. int dtls1_check_timeout_num(SSL *s)
  300. {
  301. size_t mtu;
  302. s->d1->timeout_num_alerts++;
  303. /* Reduce MTU after 2 unsuccessful retransmissions */
  304. if (s->d1->timeout_num_alerts > 2
  305. && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
  306. mtu =
  307. BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL);
  308. if (mtu < s->d1->mtu)
  309. s->d1->mtu = mtu;
  310. }
  311. if (s->d1->timeout_num_alerts > DTLS1_TMO_ALERT_COUNT) {
  312. /* fail the connection, enough alerts have been sent */
  313. SSLfatal(s, SSL_AD_NO_ALERT, SSL_R_READ_TIMEOUT_EXPIRED);
  314. return -1;
  315. }
  316. return 0;
  317. }
  318. int dtls1_handle_timeout(SSL *s)
  319. {
  320. /* if no timer is expired, don't do anything */
  321. if (!dtls1_is_timer_expired(s)) {
  322. return 0;
  323. }
  324. if (s->d1->timer_cb != NULL)
  325. s->d1->timeout_duration_us = s->d1->timer_cb(s, s->d1->timeout_duration_us);
  326. else
  327. dtls1_double_timeout(s);
  328. if (dtls1_check_timeout_num(s) < 0) {
  329. /* SSLfatal() already called */
  330. return -1;
  331. }
  332. dtls1_start_timer(s);
  333. /* Calls SSLfatal() if required */
  334. return dtls1_retransmit_buffered_messages(s);
  335. }
  336. static void get_current_time(struct timeval *t)
  337. {
  338. #if defined(_WIN32)
  339. SYSTEMTIME st;
  340. union {
  341. unsigned __int64 ul;
  342. FILETIME ft;
  343. } now;
  344. GetSystemTime(&st);
  345. SystemTimeToFileTime(&st, &now.ft);
  346. /* re-bias to 1/1/1970 */
  347. # ifdef __MINGW32__
  348. now.ul -= 116444736000000000ULL;
  349. # else
  350. /* *INDENT-OFF* */
  351. now.ul -= 116444736000000000UI64;
  352. /* *INDENT-ON* */
  353. # endif
  354. t->tv_sec = (long)(now.ul / 10000000);
  355. t->tv_usec = ((int)(now.ul % 10000000)) / 10;
  356. #else
  357. gettimeofday(t, NULL);
  358. #endif
  359. }
  360. #define LISTEN_SUCCESS 2
  361. #define LISTEN_SEND_VERIFY_REQUEST 1
  362. #ifndef OPENSSL_NO_SOCK
  363. int DTLSv1_listen(SSL *s, BIO_ADDR *client)
  364. {
  365. int next, n, ret = 0;
  366. unsigned char cookie[DTLS1_COOKIE_LENGTH];
  367. unsigned char seq[SEQ_NUM_SIZE];
  368. const unsigned char *data;
  369. unsigned char *buf, *wbuf;
  370. size_t fragoff, fraglen, msglen, reclen, align = 0;
  371. unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen;
  372. BIO *rbio, *wbio;
  373. BIO_ADDR *tmpclient = NULL;
  374. PACKET pkt, msgpkt, msgpayload, session, cookiepkt;
  375. if (s->handshake_func == NULL) {
  376. /* Not properly initialized yet */
  377. SSL_set_accept_state(s);
  378. }
  379. /* Ensure there is no state left over from a previous invocation */
  380. if (!SSL_clear(s))
  381. return -1;
  382. ERR_clear_error();
  383. rbio = SSL_get_rbio(s);
  384. wbio = SSL_get_wbio(s);
  385. if (!rbio || !wbio) {
  386. ERR_raise(ERR_LIB_SSL, SSL_R_BIO_NOT_SET);
  387. return -1;
  388. }
  389. /*
  390. * Note: This check deliberately excludes DTLS1_BAD_VER because that version
  391. * requires the MAC to be calculated *including* the first ClientHello
  392. * (without the cookie). Since DTLSv1_listen is stateless that cannot be
  393. * supported. DTLS1_BAD_VER must use cookies in a stateful manner (e.g. via
  394. * SSL_accept)
  395. */
  396. if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00)) {
  397. ERR_raise(ERR_LIB_SSL, SSL_R_UNSUPPORTED_SSL_VERSION);
  398. return -1;
  399. }
  400. if (!ssl3_setup_buffers(s)) {
  401. /* ERR_raise() already called */
  402. return -1;
  403. }
  404. buf = RECORD_LAYER_get_rbuf(&s->rlayer)->buf;
  405. wbuf = RECORD_LAYER_get_wbuf(&s->rlayer)[0].buf;
  406. #if defined(SSL3_ALIGN_PAYLOAD)
  407. # if SSL3_ALIGN_PAYLOAD != 0
  408. /*
  409. * Using SSL3_RT_HEADER_LENGTH here instead of DTLS1_RT_HEADER_LENGTH for
  410. * consistency with ssl3_read_n. In practice it should make no difference
  411. * for sensible values of SSL3_ALIGN_PAYLOAD because the difference between
  412. * SSL3_RT_HEADER_LENGTH and DTLS1_RT_HEADER_LENGTH is exactly 8
  413. */
  414. align = (size_t)buf + SSL3_RT_HEADER_LENGTH;
  415. align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
  416. # endif
  417. #endif
  418. buf += align;
  419. do {
  420. /* Get a packet */
  421. clear_sys_error();
  422. n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH
  423. + DTLS1_RT_HEADER_LENGTH);
  424. if (n <= 0) {
  425. if (BIO_should_retry(rbio)) {
  426. /* Non-blocking IO */
  427. goto end;
  428. }
  429. return -1;
  430. }
  431. if (!PACKET_buf_init(&pkt, buf, n)) {
  432. ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
  433. return -1;
  434. }
  435. /*
  436. * Parse the received record. If there are any problems with it we just
  437. * dump it - with no alert. RFC6347 says this "Unlike TLS, DTLS is
  438. * resilient in the face of invalid records (e.g., invalid formatting,
  439. * length, MAC, etc.). In general, invalid records SHOULD be silently
  440. * discarded, thus preserving the association; however, an error MAY be
  441. * logged for diagnostic purposes."
  442. */
  443. /* this packet contained a partial record, dump it */
  444. if (n < DTLS1_RT_HEADER_LENGTH) {
  445. ERR_raise(ERR_LIB_SSL, SSL_R_RECORD_TOO_SMALL);
  446. goto end;
  447. }
  448. if (s->msg_callback)
  449. s->msg_callback(0, 0, SSL3_RT_HEADER, buf,
  450. DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
  451. /* Get the record header */
  452. if (!PACKET_get_1(&pkt, &rectype)
  453. || !PACKET_get_1(&pkt, &versmajor)) {
  454. ERR_raise(ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH);
  455. goto end;
  456. }
  457. if (rectype != SSL3_RT_HANDSHAKE) {
  458. ERR_raise(ERR_LIB_SSL, SSL_R_UNEXPECTED_MESSAGE);
  459. goto end;
  460. }
  461. /*
  462. * Check record version number. We only check that the major version is
  463. * the same.
  464. */
  465. if (versmajor != DTLS1_VERSION_MAJOR) {
  466. ERR_raise(ERR_LIB_SSL, SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
  467. goto end;
  468. }
  469. if (!PACKET_forward(&pkt, 1)
  470. /* Save the sequence number: 64 bits, with top 2 bytes = epoch */
  471. || !PACKET_copy_bytes(&pkt, seq, SEQ_NUM_SIZE)
  472. || !PACKET_get_length_prefixed_2(&pkt, &msgpkt)) {
  473. ERR_raise(ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH);
  474. goto end;
  475. }
  476. reclen = PACKET_remaining(&msgpkt);
  477. /*
  478. * We allow data remaining at the end of the packet because there could
  479. * be a second record (but we ignore it)
  480. */
  481. /* This is an initial ClientHello so the epoch has to be 0 */
  482. if (seq[0] != 0 || seq[1] != 0) {
  483. ERR_raise(ERR_LIB_SSL, SSL_R_UNEXPECTED_MESSAGE);
  484. goto end;
  485. }
  486. /* Get a pointer to the raw message for the later callback */
  487. data = PACKET_data(&msgpkt);
  488. /* Finished processing the record header, now process the message */
  489. if (!PACKET_get_1(&msgpkt, &msgtype)
  490. || !PACKET_get_net_3_len(&msgpkt, &msglen)
  491. || !PACKET_get_net_2(&msgpkt, &msgseq)
  492. || !PACKET_get_net_3_len(&msgpkt, &fragoff)
  493. || !PACKET_get_net_3_len(&msgpkt, &fraglen)
  494. || !PACKET_get_sub_packet(&msgpkt, &msgpayload, fraglen)
  495. || PACKET_remaining(&msgpkt) != 0) {
  496. ERR_raise(ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH);
  497. goto end;
  498. }
  499. if (msgtype != SSL3_MT_CLIENT_HELLO) {
  500. ERR_raise(ERR_LIB_SSL, SSL_R_UNEXPECTED_MESSAGE);
  501. goto end;
  502. }
  503. /* Message sequence number can only be 0 or 1 */
  504. if (msgseq > 2) {
  505. ERR_raise(ERR_LIB_SSL, SSL_R_INVALID_SEQUENCE_NUMBER);
  506. goto end;
  507. }
  508. /*
  509. * We don't support fragment reassembly for ClientHellos whilst
  510. * listening because that would require server side state (which is
  511. * against the whole point of the ClientHello/HelloVerifyRequest
  512. * mechanism). Instead we only look at the first ClientHello fragment
  513. * and require that the cookie must be contained within it.
  514. */
  515. if (fragoff != 0 || fraglen > msglen) {
  516. /* Non initial ClientHello fragment (or bad fragment) */
  517. ERR_raise(ERR_LIB_SSL, SSL_R_FRAGMENTED_CLIENT_HELLO);
  518. goto end;
  519. }
  520. if (s->msg_callback)
  521. s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, data,
  522. fraglen + DTLS1_HM_HEADER_LENGTH, s,
  523. s->msg_callback_arg);
  524. if (!PACKET_get_net_2(&msgpayload, &clientvers)) {
  525. ERR_raise(ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH);
  526. goto end;
  527. }
  528. /*
  529. * Verify client version is supported
  530. */
  531. if (DTLS_VERSION_LT(clientvers, (unsigned int)s->method->version) &&
  532. s->method->version != DTLS_ANY_VERSION) {
  533. ERR_raise(ERR_LIB_SSL, SSL_R_WRONG_VERSION_NUMBER);
  534. goto end;
  535. }
  536. if (!PACKET_forward(&msgpayload, SSL3_RANDOM_SIZE)
  537. || !PACKET_get_length_prefixed_1(&msgpayload, &session)
  538. || !PACKET_get_length_prefixed_1(&msgpayload, &cookiepkt)) {
  539. /*
  540. * Could be malformed or the cookie does not fit within the initial
  541. * ClientHello fragment. Either way we can't handle it.
  542. */
  543. ERR_raise(ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH);
  544. goto end;
  545. }
  546. /*
  547. * Check if we have a cookie or not. If not we need to send a
  548. * HelloVerifyRequest.
  549. */
  550. if (PACKET_remaining(&cookiepkt) == 0) {
  551. next = LISTEN_SEND_VERIFY_REQUEST;
  552. } else {
  553. /*
  554. * We have a cookie, so lets check it.
  555. */
  556. if (s->ctx->app_verify_cookie_cb == NULL) {
  557. ERR_raise(ERR_LIB_SSL, SSL_R_NO_VERIFY_COOKIE_CALLBACK);
  558. /* This is fatal */
  559. return -1;
  560. }
  561. if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookiepkt),
  562. (unsigned int)PACKET_remaining(&cookiepkt)) == 0) {
  563. /*
  564. * We treat invalid cookies in the same was as no cookie as
  565. * per RFC6347
  566. */
  567. next = LISTEN_SEND_VERIFY_REQUEST;
  568. } else {
  569. /* Cookie verification succeeded */
  570. next = LISTEN_SUCCESS;
  571. }
  572. }
  573. if (next == LISTEN_SEND_VERIFY_REQUEST) {
  574. WPACKET wpkt;
  575. unsigned int version;
  576. size_t wreclen;
  577. /*
  578. * There was no cookie in the ClientHello so we need to send a
  579. * HelloVerifyRequest. If this fails we do not worry about trying
  580. * to resend, we just drop it.
  581. */
  582. /* Generate the cookie */
  583. if (s->ctx->app_gen_cookie_cb == NULL ||
  584. s->ctx->app_gen_cookie_cb(s, cookie, &cookielen) == 0 ||
  585. cookielen > 255) {
  586. ERR_raise(ERR_LIB_SSL, SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
  587. /* This is fatal */
  588. return -1;
  589. }
  590. /*
  591. * Special case: for hello verify request, client version 1.0 and we
  592. * haven't decided which version to use yet send back using version
  593. * 1.0 header: otherwise some clients will ignore it.
  594. */
  595. version = (s->method->version == DTLS_ANY_VERSION) ? DTLS1_VERSION
  596. : s->version;
  597. /* Construct the record and message headers */
  598. if (!WPACKET_init_static_len(&wpkt,
  599. wbuf,
  600. ssl_get_max_send_fragment(s)
  601. + DTLS1_RT_HEADER_LENGTH,
  602. 0)
  603. || !WPACKET_put_bytes_u8(&wpkt, SSL3_RT_HANDSHAKE)
  604. || !WPACKET_put_bytes_u16(&wpkt, version)
  605. /*
  606. * Record sequence number is always the same as in the
  607. * received ClientHello
  608. */
  609. || !WPACKET_memcpy(&wpkt, seq, SEQ_NUM_SIZE)
  610. /* End of record, start sub packet for message */
  611. || !WPACKET_start_sub_packet_u16(&wpkt)
  612. /* Message type */
  613. || !WPACKET_put_bytes_u8(&wpkt,
  614. DTLS1_MT_HELLO_VERIFY_REQUEST)
  615. /*
  616. * Message length - doesn't follow normal TLS convention:
  617. * the length isn't the last thing in the message header.
  618. * We'll need to fill this in later when we know the
  619. * length. Set it to zero for now
  620. */
  621. || !WPACKET_put_bytes_u24(&wpkt, 0)
  622. /*
  623. * Message sequence number is always 0 for a
  624. * HelloVerifyRequest
  625. */
  626. || !WPACKET_put_bytes_u16(&wpkt, 0)
  627. /*
  628. * We never fragment a HelloVerifyRequest, so fragment
  629. * offset is 0
  630. */
  631. || !WPACKET_put_bytes_u24(&wpkt, 0)
  632. /*
  633. * Fragment length is the same as message length, but
  634. * this *is* the last thing in the message header so we
  635. * can just start a sub-packet. No need to come back
  636. * later for this one.
  637. */
  638. || !WPACKET_start_sub_packet_u24(&wpkt)
  639. /* Create the actual HelloVerifyRequest body */
  640. || !dtls_raw_hello_verify_request(&wpkt, cookie, cookielen)
  641. /* Close message body */
  642. || !WPACKET_close(&wpkt)
  643. /* Close record body */
  644. || !WPACKET_close(&wpkt)
  645. || !WPACKET_get_total_written(&wpkt, &wreclen)
  646. || !WPACKET_finish(&wpkt)) {
  647. ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
  648. WPACKET_cleanup(&wpkt);
  649. /* This is fatal */
  650. return -1;
  651. }
  652. /*
  653. * Fix up the message len in the message header. Its the same as the
  654. * fragment len which has been filled in by WPACKET, so just copy
  655. * that. Destination for the message len is after the record header
  656. * plus one byte for the message content type. The source is the
  657. * last 3 bytes of the message header
  658. */
  659. memcpy(&wbuf[DTLS1_RT_HEADER_LENGTH + 1],
  660. &wbuf[DTLS1_RT_HEADER_LENGTH + DTLS1_HM_HEADER_LENGTH - 3],
  661. 3);
  662. if (s->msg_callback)
  663. s->msg_callback(1, 0, SSL3_RT_HEADER, buf,
  664. DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg);
  665. if ((tmpclient = BIO_ADDR_new()) == NULL) {
  666. ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
  667. goto end;
  668. }
  669. /*
  670. * This is unnecessary if rbio and wbio are one and the same - but
  671. * maybe they're not. We ignore errors here - some BIOs do not
  672. * support this.
  673. */
  674. if (BIO_dgram_get_peer(rbio, tmpclient) > 0) {
  675. (void)BIO_dgram_set_peer(wbio, tmpclient);
  676. }
  677. BIO_ADDR_free(tmpclient);
  678. tmpclient = NULL;
  679. if (BIO_write(wbio, wbuf, wreclen) < (int)wreclen) {
  680. if (BIO_should_retry(wbio)) {
  681. /*
  682. * Non-blocking IO...but we're stateless, so we're just
  683. * going to drop this packet.
  684. */
  685. goto end;
  686. }
  687. return -1;
  688. }
  689. if (BIO_flush(wbio) <= 0) {
  690. if (BIO_should_retry(wbio)) {
  691. /*
  692. * Non-blocking IO...but we're stateless, so we're just
  693. * going to drop this packet.
  694. */
  695. goto end;
  696. }
  697. return -1;
  698. }
  699. }
  700. } while (next != LISTEN_SUCCESS);
  701. /*
  702. * Set expected sequence numbers to continue the handshake.
  703. */
  704. s->d1->handshake_read_seq = 1;
  705. s->d1->handshake_write_seq = 1;
  706. s->d1->next_handshake_write_seq = 1;
  707. DTLS_RECORD_LAYER_set_write_sequence(&s->rlayer, seq);
  708. /*
  709. * We are doing cookie exchange, so make sure we set that option in the
  710. * SSL object
  711. */
  712. SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
  713. /*
  714. * Tell the state machine that we've done the initial hello verify
  715. * exchange
  716. */
  717. ossl_statem_set_hello_verify_done(s);
  718. /*
  719. * Some BIOs may not support this. If we fail we clear the client address
  720. */
  721. if (BIO_dgram_get_peer(rbio, client) <= 0)
  722. BIO_ADDR_clear(client);
  723. /* Buffer the record in the processed_rcds queue */
  724. if (!dtls_buffer_listen_record(s, reclen, seq, align))
  725. return -1;
  726. ret = 1;
  727. end:
  728. BIO_ADDR_free(tmpclient);
  729. return ret;
  730. }
  731. #endif
  732. static int dtls1_handshake_write(SSL *s)
  733. {
  734. return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
  735. }
  736. int dtls1_shutdown(SSL *s)
  737. {
  738. int ret;
  739. #ifndef OPENSSL_NO_SCTP
  740. BIO *wbio;
  741. wbio = SSL_get_wbio(s);
  742. if (wbio != NULL && BIO_dgram_is_sctp(wbio) &&
  743. !(s->shutdown & SSL_SENT_SHUTDOWN)) {
  744. ret = BIO_dgram_sctp_wait_for_dry(wbio);
  745. if (ret < 0)
  746. return -1;
  747. if (ret == 0)
  748. BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1,
  749. NULL);
  750. }
  751. #endif
  752. ret = ssl3_shutdown(s);
  753. #ifndef OPENSSL_NO_SCTP
  754. BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL);
  755. #endif
  756. return ret;
  757. }
  758. int dtls1_query_mtu(SSL *s)
  759. {
  760. if (s->d1->link_mtu) {
  761. s->d1->mtu =
  762. s->d1->link_mtu - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
  763. s->d1->link_mtu = 0;
  764. }
  765. /* AHA! Figure out the MTU, and stick to the right size */
  766. if (s->d1->mtu < dtls1_min_mtu(s)) {
  767. if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
  768. s->d1->mtu =
  769. BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
  770. /*
  771. * I've seen the kernel return bogus numbers when it doesn't know
  772. * (initial write), so just make sure we have a reasonable number
  773. */
  774. if (s->d1->mtu < dtls1_min_mtu(s)) {
  775. /* Set to min mtu */
  776. s->d1->mtu = dtls1_min_mtu(s);
  777. BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU,
  778. (long)s->d1->mtu, NULL);
  779. }
  780. } else
  781. return 0;
  782. }
  783. return 1;
  784. }
  785. static size_t dtls1_link_min_mtu(void)
  786. {
  787. return (g_probable_mtu[(sizeof(g_probable_mtu) /
  788. sizeof(g_probable_mtu[0])) - 1]);
  789. }
  790. size_t dtls1_min_mtu(SSL *s)
  791. {
  792. return dtls1_link_min_mtu() - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
  793. }
  794. size_t DTLS_get_data_mtu(const SSL *s)
  795. {
  796. size_t mac_overhead, int_overhead, blocksize, ext_overhead;
  797. const SSL_CIPHER *ciph = SSL_get_current_cipher(s);
  798. size_t mtu = s->d1->mtu;
  799. if (ciph == NULL)
  800. return 0;
  801. if (!ssl_cipher_get_overhead(ciph, &mac_overhead, &int_overhead,
  802. &blocksize, &ext_overhead))
  803. return 0;
  804. if (SSL_READ_ETM(s))
  805. ext_overhead += mac_overhead;
  806. else
  807. int_overhead += mac_overhead;
  808. /* Subtract external overhead (e.g. IV/nonce, separate MAC) */
  809. if (ext_overhead + DTLS1_RT_HEADER_LENGTH >= mtu)
  810. return 0;
  811. mtu -= ext_overhead + DTLS1_RT_HEADER_LENGTH;
  812. /* Round encrypted payload down to cipher block size (for CBC etc.)
  813. * No check for overflow since 'mtu % blocksize' cannot exceed mtu. */
  814. if (blocksize)
  815. mtu -= (mtu % blocksize);
  816. /* Subtract internal overhead (e.g. CBC padding len byte) */
  817. if (int_overhead >= mtu)
  818. return 0;
  819. mtu -= int_overhead;
  820. return mtu;
  821. }
  822. void DTLS_set_timer_cb(SSL *s, DTLS_timer_cb cb)
  823. {
  824. s->d1->timer_cb = cb;
  825. }