]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - ssl/record/rec_layer_s3.c
Replaced '{ 0, NULL }' with OSSL_DISPATCH_END in OSSL_DISPATCH arrays
[thirdparty/openssl.git] / ssl / record / rec_layer_s3.c
index 0e2c5b3b3f94fce64650dff0533dadf5c1a9d896..bba8b7fa0265fea1f1637474c9a926aa019fe28e 100644 (file)
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <limits.h>
 #include <errno.h>
+#include <assert.h>
 #include "../ssl_local.h"
 #include <openssl/evp.h>
 #include <openssl/buffer.h>
@@ -48,14 +49,6 @@ void RECORD_LAYER_clear(RECORD_LAYER *rl)
         DTLS_RECORD_LAYER_clear(rl);
 }
 
-void RECORD_LAYER_release(RECORD_LAYER *rl)
-{
-    /*
-     * TODO(RECLAYER): Need a way to release the write buffers in the record
-     * layer on demand
-     */
-}
-
 /* Checks if we have unprocessed read ahead data pending */
 int RECORD_LAYER_read_pending(const RECORD_LAYER *rl)
 {
@@ -74,6 +67,62 @@ int RECORD_LAYER_write_pending(const RECORD_LAYER *rl)
     return rl->wpend_tot > 0;
 }
 
+static uint32_t ossl_get_max_early_data(SSL_CONNECTION *s)
+{
+    uint32_t max_early_data;
+    SSL_SESSION *sess = s->session;
+
+    /*
+     * If we are a client then we always use the max_early_data from the
+     * session/psksession. Otherwise we go with the lowest out of the max early
+     * data set in the session and the configured max_early_data.
+     */
+    if (!s->server && sess->ext.max_early_data == 0) {
+        if (!ossl_assert(s->psksession != NULL
+                         && s->psksession->ext.max_early_data > 0)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        sess = s->psksession;
+    }
+
+    if (!s->server)
+        max_early_data = sess->ext.max_early_data;
+    else if (s->ext.early_data != SSL_EARLY_DATA_ACCEPTED)
+        max_early_data = s->recv_max_early_data;
+    else
+        max_early_data = s->recv_max_early_data < sess->ext.max_early_data
+                         ? s->recv_max_early_data : sess->ext.max_early_data;
+
+    return max_early_data;
+}
+
+static int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length,
+                                    size_t overhead, int send)
+{
+    uint32_t max_early_data;
+
+    max_early_data = ossl_get_max_early_data(s);
+
+    if (max_early_data == 0) {
+        SSLfatal(s, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE,
+                 SSL_R_TOO_MUCH_EARLY_DATA);
+        return 0;
+    }
+
+    /* If we are dealing with ciphertext we need to allow for the overhead */
+    max_early_data += overhead;
+
+    if (s->early_data_count + length > max_early_data) {
+        SSLfatal(s, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE,
+                 SSL_R_TOO_MUCH_EARLY_DATA);
+        return 0;
+    }
+    s->early_data_count += length;
+
+    return 1;
+}
+
 size_t ssl3_pending(const SSL *s)
 {
     size_t i, num = 0;
@@ -267,7 +316,7 @@ int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, size_t len,
     }
 
     /* If we have an alert to send, lets send it */
-    if (s->s3.alert_dispatch) {
+    if (s->s3.alert_dispatch > 0) {
         i = ssl->method->ssl_dispatch_alert(ssl);
         if (i <= 0) {
             /* SSLfatal() already called if appropriate */
@@ -448,16 +497,35 @@ int ossl_tls_handle_rlayer_return(SSL_CONNECTION *s, int writing, int ret,
     return ret;
 }
 
-void ssl_release_record(SSL_CONNECTION *s, TLS_RECORD *rr)
+int ssl_release_record(SSL_CONNECTION *s, TLS_RECORD *rr, size_t length)
 {
+    assert(rr->length >= length);
     if (rr->rechandle != NULL) {
+        if (length == 0)
+            length = rr->length;
         /* The record layer allocated the buffers for this record */
-        s->rlayer.rrlmethod->release_record(s->rlayer.rrl, rr->rechandle);
-    } else {
+        if (HANDLE_RLAYER_READ_RETURN(s,
+                s->rlayer.rrlmethod->release_record(s->rlayer.rrl,
+                                                    rr->rechandle,
+                                                    length)) <= 0) {
+            /* RLAYER_fatal already called */
+            return 0;
+        }
+
+        if (length == rr->length)
+            s->rlayer.curr_rec++;
+    } else if (length == 0 || length == rr->length) {
         /* We allocated the buffers for this record (only happens with DTLS) */
-        OPENSSL_free(rr->data);
+        OPENSSL_free(rr->allocdata);
+        rr->allocdata = NULL;
     }
-    s->rlayer.curr_rec++;
+    rr->length -= length;
+    if (rr->length > 0)
+        rr->off += length;
+    else
+        rr->off = 0;
+
+    return 1;
 }
 
 /*-
@@ -630,7 +698,7 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf,
          * doing a handshake for the first time
          */
         if (SSL_in_init(ssl) && type == SSL3_RT_APPLICATION_DATA
-            && s->enc_read_ctx == NULL) {
+                && SSL_IS_FIRST_HANDSHAKE(s)) {
             SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_APP_DATA_IN_HANDSHAKE);
             return -1;
         }
@@ -651,8 +719,8 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf,
              * SSL_read() with a zero length buffer will eventually cause
              * SSL_pending() to report data as being available.
              */
-            if (rr->length == 0)
-                ssl_release_record(s, rr);
+            if (rr->length == 0 && !ssl_release_record(s, rr, 0))
+                return -1;
 
             return 0;
         }
@@ -669,15 +737,11 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf,
             buf += n;
             if (peek) {
                 /* Mark any zero length record as consumed CVE-2016-6305 */
-                if (rr->length == 0)
-                    ssl_release_record(s, rr);
+                if (rr->length == 0 && !ssl_release_record(s, rr, 0))
+                    return -1;
             } else {
-                if (s->options & SSL_OP_CLEANSE_PLAINTEXT)
-                    OPENSSL_cleanse(&(rr->data[rr->off]), n);
-                rr->length -= n;
-                rr->off += n;
-                if (rr->length == 0)
-                    ssl_release_record(s, rr);
+                if (!ssl_release_record(s, rr, n))
+                    return -1;
             }
             if (rr->length == 0
                 || (peek && n == rr->length)) {
@@ -736,8 +800,7 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf,
 
     if (rr->type == SSL3_RT_ALERT) {
         unsigned int alert_level, alert_descr;
-        unsigned char *alert_bytes = rr->data
-                                     + rr->off;
+        const unsigned char *alert_bytes = rr->data + rr->off;
         PACKET alert;
 
         if (!PACKET_buf_init(&alert, alert_bytes, rr->length)
@@ -765,7 +828,8 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf,
         if ((!is_tls13 && alert_level == SSL3_AL_WARNING)
                 || (is_tls13 && alert_descr == SSL_AD_USER_CANCELLED)) {
             s->s3.warn_alert = alert_descr;
-            ssl_release_record(s, rr);
+            if (!ssl_release_record(s, rr, 0))
+                return -1;
 
             s->rlayer.alert_count++;
             if (s->rlayer.alert_count == MAX_WARN_ALERT_COUNT) {
@@ -792,7 +856,8 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf,
                           SSL_AD_REASON_OFFSET + alert_descr,
                           "SSL alert number %d", alert_descr);
             s->shutdown |= SSL_RECEIVED_SHUTDOWN;
-            ssl_release_record(s, rr);
+            if (!ssl_release_record(s, rr, 0))
+                return -1;
             SSL_CTX_remove_session(s->session_ctx, s->session);
             return 0;
         } else if (alert_descr == SSL_AD_NO_RENEGOTIATION) {
@@ -827,7 +892,8 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf,
              * sent close_notify.
              */
             if (!SSL_CONNECTION_IS_TLS13(s)) {
-                ssl_release_record(s, rr);
+                if (!ssl_release_record(s, rr, 0))
+                    return -1;
 
                 if ((s->mode & SSL_MODE_AUTO_RETRY) != 0)
                     goto start;
@@ -846,7 +912,8 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf,
              * above.
              * No alert sent because we already sent close_notify
              */
-            ssl_release_record(s, rr);
+            if (!ssl_release_record(s, rr, 0))
+                return -1;
             SSLfatal(s, SSL_AD_NO_ALERT,
                      SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY);
             return -1;
@@ -869,12 +936,12 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf,
             n = rr->length; /* available bytes */
 
         /* now move 'n' bytes: */
-        memcpy(dest + *dest_len, rr->data + rr->off, n);
-        rr->off += n;
-        rr->length -= n;
-        *dest_len += n;
-        if (rr->length == 0)
-            ssl_release_record(s, rr);
+        if (n > 0) {
+            memcpy(dest + *dest_len, rr->data + rr->off, n);
+            *dest_len += n;
+            if (!ssl_release_record(s, rr, n))
+                return -1;
+        }
 
         if (*dest_len < dest_maxlen)
             goto start;     /* fragment was too small */
@@ -978,7 +1045,8 @@ int ssl3_read_bytes(SSL *ssl, int type, int *recvd_type, unsigned char *buf,
                 /* SSLfatal() already called */
                 return -1;
             }
-            ssl_release_record(s, rr);
+            if (!ssl_release_record(s, rr, 0))
+                return -1;
             goto start;
         } else {
             SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_UNEXPECTED_RECORD);
@@ -1035,13 +1103,23 @@ static const OSSL_DISPATCH rlayer_dispatch[] = {
     { OSSL_FUNC_RLAYER_MSG_CALLBACK, (void (*)(void))rlayer_msg_callback_wrapper },
     { OSSL_FUNC_RLAYER_SECURITY, (void (*)(void))rlayer_security_wrapper },
     { OSSL_FUNC_RLAYER_PADDING, (void (*)(void))rlayer_padding_wrapper },
-    { 0, NULL }
+    OSSL_DISPATCH_END
 };
 
+void ossl_ssl_set_custom_record_layer(SSL_CONNECTION *s,
+                                      const OSSL_RECORD_METHOD *meth,
+                                      void *rlarg)
+{
+    s->rlayer.custom_rlmethod = meth;
+    s->rlayer.rlarg = rlarg;
+}
+
 static const OSSL_RECORD_METHOD *ssl_select_next_record_layer(SSL_CONNECTION *s,
                                                               int direction,
                                                               int level)
 {
+    if (s->rlayer.custom_rlmethod != NULL)
+        return s->rlayer.custom_rlmethod;
 
     if (level == OSSL_RECORD_PROTECTION_LEVEL_NONE) {
         if (SSL_CONNECTION_IS_DTLS(s))
@@ -1097,12 +1175,13 @@ static int ssl_post_record_layer_select(SSL_CONNECTION *s, int direction)
 
 int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
                              int direction, int level,
+                             unsigned char *secret, size_t secretlen,
                              unsigned char *key, size_t keylen,
                              unsigned char *iv,  size_t ivlen,
                              unsigned char *mackey, size_t mackeylen,
                              const EVP_CIPHER *ciph, size_t taglen,
                              int mactype, const EVP_MD *md,
-                             const SSL_COMP *comp)
+                             const SSL_COMP *comp, const EVP_MD *kdfdigest)
 {
     OSSL_PARAM options[5], *opts = options;
     OSSL_PARAM settings[6], *set =  settings;
@@ -1213,8 +1292,8 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
         max_early_data = ossl_get_max_early_data(s);
 
         if (max_early_data != 0)
-            *set++ = OSSL_PARAM_construct_uint(OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA,
-                                               &max_early_data);
+            *set++ = OSSL_PARAM_construct_uint32(OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA,
+                                                 &max_early_data);
     }
 
     *set = OSSL_PARAM_construct_end();
@@ -1233,9 +1312,11 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
                     && level != OSSL_RECORD_PROTECTION_LEVEL_NONE)
                 epoch =  DTLS_RECORD_LAYER_get_r_epoch(&s->rlayer) + 1; /* new epoch */
 
+#ifndef OPENSSL_NO_DGRAM
             if (SSL_CONNECTION_IS_DTLS(s))
                 next = BIO_new(BIO_s_dgram_mem());
             else
+#endif
                 next = BIO_new(BIO_s_mem());
 
             if (next == NULL) {
@@ -1272,11 +1353,12 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
 
         rlret = meth->new_record_layer(sctx->libctx, sctx->propq, version,
                                        s->server, direction, level, epoch,
-                                       key, keylen, iv, ivlen, mackey,
-                                       mackeylen, ciph, taglen, mactype, md,
-                                       compm, prev, thisbio, next, NULL, NULL,
-                                       settings, options, rlayer_dispatch_tmp,
-                                       s, &newrl);
+                                       secret, secretlen, key, keylen, iv,
+                                       ivlen, mackey, mackeylen, ciph, taglen,
+                                       mactype, md, compm, kdfdigest, prev,
+                                       thisbio, next, NULL, NULL, settings,
+                                       options, rlayer_dispatch_tmp, s,
+                                       s->rlayer.rlarg, &newrl);
         BIO_free(prev);
         switch (rlret) {
         case OSSL_RECORD_RETURN_FATAL:
@@ -1308,11 +1390,14 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
 
     /*
      * Free the old record layer if we have one except in the case of DTLS when
-     * writing. In that case the record layer is still referenced by buffered
-     * messages for potential retransmit. Only when those buffered messages get
-     * freed do we free the record layer object (see dtls1_hm_fragment_free)
+     * writing and there are still buffered sent messages in our queue. In that
+     * case the record layer is still referenced by those buffered messages for
+     * potential retransmit. Only when those buffered messages get freed do we
+     * free the record layer object (see dtls1_hm_fragment_free)
      */
-    if (!SSL_CONNECTION_IS_DTLS(s) || direction == OSSL_RECORD_DIRECTION_READ) {
+    if (!SSL_CONNECTION_IS_DTLS(s)
+            || direction == OSSL_RECORD_DIRECTION_READ
+            || pqueue_peek(s->d1->sent_messages) == NULL) {
         if (*thismethod != NULL && !(*thismethod)->free(*thisrl)) {
             SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
             return 0;