Fix problem with SCTP close_notify alerts
authorMatt Caswell <matt@openssl.org>
Fri, 21 Apr 2017 15:56:06 +0000 (16:56 +0100)
committerMatt Caswell <matt@openssl.org>
Tue, 25 Apr 2017 13:04:13 +0000 (14:04 +0100)
In SCTP the code was only allowing a send of a close_notify alert if the
socket is dry. If the socket isn't dry then it was attempting to save away
the close_notify alert to resend later when it is dry and then it returned
success. However because the application then thinks that the close_notify
alert has been successfully sent it never re-enters the DTLS code to
actually resend the alert. A much simpler solution is to just fail with a
retryable error in the event that the socket isn't dry. That way the
application knows to retry sending the close_notify alert.

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3287)

crypto/bio/bss_dgram.c

index 6dfcc9ba7b5a0bfd3158aea0bef1b3fd8bd440d9..81730abe4403ade1c40f67e85021e1b11b4dcb4d 100644 (file)
@@ -130,7 +130,6 @@ typedef struct bio_dgram_sctp_data_st {
     int ccs_sent;
     int save_shutdown;
     int peer_auth_tested;
-    bio_dgram_sctp_save_message saved_message;
 } bio_dgram_sctp_data;
 # endif
 
@@ -962,10 +961,8 @@ static int dgram_sctp_free(BIO *a)
         return 0;
 
     data = (bio_dgram_sctp_data *) a->ptr;
-    if (data != NULL) {
-        OPENSSL_free(data->saved_message.data);
+    if (data != NULL)
         OPENSSL_free(data);
-    }
 
     return (1);
 }
@@ -1067,22 +1064,6 @@ static int dgram_sctp_read(BIO *b, char *out, int outl)
                     struct sctp_event_subscribe event;
                     socklen_t eventsize;
 #  endif
-                    /*
-                     * If a message has been delayed until the socket is dry,
-                     * it can be sent now.
-                     */
-                    if (data->saved_message.length > 0) {
-                        i = dgram_sctp_write(data->saved_message.bio,
-                                         data->saved_message.data,
-                                         data->saved_message.length);
-                        if (i < 0) {
-                            ret = i;
-                            break;
-                        }
-                        OPENSSL_free(data->saved_message.data);
-                        data->saved_message.data = NULL;
-                        data->saved_message.length = 0;
-                    }
 
                     /* disable sender dry event */
 #  ifdef SCTP_EVENT
@@ -1265,27 +1246,15 @@ static int dgram_sctp_write(BIO *b, const char *in, int inl)
         sinfo = &handshake_sinfo;
     }
 
-    /*
-     * If we have to send a shutdown alert message and the socket is not dry
-     * yet, we have to save it and send it as soon as the socket gets dry.
-     */
+    /* We can only send a shutdown alert if the socket is dry */
     if (data->save_shutdown) {
         ret = BIO_dgram_sctp_wait_for_dry(b);
-        if (ret < 0) {
+        if (ret < 0)
             return -1;
-        }
         if (ret == 0) {
-            char *tmp;
-            data->saved_message.bio = b;
-            if ((tmp = OPENSSL_malloc(inl)) == NULL) {
-                BIOerr(BIO_F_DGRAM_SCTP_WRITE, ERR_R_MALLOC_FAILURE);
-                return -1;
-            }
-            OPENSSL_free(data->saved_message.data);
-            data->saved_message.data = tmp;
-            memcpy(data->saved_message.data, in, inl);
-            data->saved_message.length = inl;
-            return inl;
+            BIO_clear_retry_flags(b);
+            BIO_set_retry_write(b);
+            return -1;
         }
     }