Move dlts_write_records() function in the record layer
authorMatt Caswell <matt@openssl.org>
Thu, 6 Oct 2022 13:49:16 +0000 (14:49 +0100)
committerMatt Caswell <matt@openssl.org>
Thu, 20 Oct 2022 13:39:32 +0000 (14:39 +0100)
At the this stage we just move the code and don't restructure it to do it
the record layer way yet.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19424)

ssl/record/methods/dtls_meth.c
ssl/record/rec_layer_d1.c

index 3349d16cff142ad2bfe93cf960af83cb63cdb3e6..c2d8030260e117f06d1cba37ac213629426a07f8 100644 (file)
@@ -689,6 +689,253 @@ dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
     return ret;
 }
 
+/*
+ * TODO(RECLAYER): Temporary copy of the old ssl3_write_pending() function now
+ * replaced by tls_retry_write_records(). Needs to be removed when the DTLS code
+ * is converted
+ */
+/* if SSL3_BUFFER_get_left() != 0, we need to call this
+ *
+ * Return values are as per SSL_write()
+ */
+static int ssl3_write_pending(SSL_CONNECTION *s, int type,
+                              const unsigned char *buf, size_t len,
+                              size_t *written)
+{
+    int i;
+    SSL3_BUFFER *wb = s->rlayer.wbuf;
+    size_t currbuf = 0;
+    size_t tmpwrit = 0;
+
+    if ((s->rlayer.wpend_tot > len)
+        || (!(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
+            && (s->rlayer.wpend_buf != buf))
+        || (s->rlayer.wpend_type != type)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_WRITE_RETRY);
+        return -1;
+    }
+
+    for (;;) {
+        clear_sys_error();
+        if (s->wbio != NULL) {
+            s->rwstate = SSL_WRITING;
+
+            /*
+             * To prevent coalescing of control and data messages,
+             * such as in buffer_write, we flush the BIO
+             */
+            if (BIO_get_ktls_send(s->wbio) && type != SSL3_RT_APPLICATION_DATA) {
+                i = BIO_flush(s->wbio);
+                if (i <= 0)
+                    return i;
+                BIO_set_ktls_ctrl_msg(s->wbio, type);
+            }
+            i = BIO_write(s->wbio, (char *)
+                          &(SSL3_BUFFER_get_buf(&wb[currbuf])
+                            [SSL3_BUFFER_get_offset(&wb[currbuf])]),
+                          (unsigned int)SSL3_BUFFER_get_left(&wb[currbuf]));
+            if (i >= 0)
+                tmpwrit = i;
+        } else {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BIO_NOT_SET);
+            i = -1;
+        }
+
+        /*
+         * When an empty fragment is sent on a connection using KTLS,
+         * it is sent as a write of zero bytes.  If this zero byte
+         * write succeeds, i will be 0 rather than a non-zero value.
+         * Treat i == 0 as success rather than an error for zero byte
+         * writes to permit this case.
+         */
+        if (i >= 0 && tmpwrit == SSL3_BUFFER_get_left(&wb[currbuf])) {
+            SSL3_BUFFER_set_left(&wb[currbuf], 0);
+            SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);
+            s->rwstate = SSL_NOTHING;
+            *written = s->rlayer.wpend_ret;
+            return 1;
+        } else if (i <= 0) {
+            if (SSL_CONNECTION_IS_DTLS(s)) {
+                /*
+                 * For DTLS, just drop it. That's kind of the whole point in
+                 * using a datagram service
+                 */
+                SSL3_BUFFER_set_left(&wb[currbuf], 0);
+            }
+            return i;
+        }
+        SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);
+        SSL3_BUFFER_sub_left(&wb[currbuf], tmpwrit);
+    }
+}
+
+static int dtls_write_records(OSSL_RECORD_LAYER *rl, OSSL_RECORD_TEMPLATE *tmpl,
+                              size_t numtmpl)
+{
+    /* TODO(RECLAYER): Remove me */
+    SSL_CONNECTION *sc = (SSL_CONNECTION *)rl->cbarg;
+    unsigned char *p, *pseq;
+    int mac_size, clear = 0;
+    size_t prefix_len = 0, written;
+    int eivlen;
+    SSL3_RECORD wr;
+    SSL3_BUFFER *wb = sc->rlayer.wbuf;
+    SSL_SESSION *sess;
+    SSL *s = SSL_CONNECTION_GET_SSL(sc);
+
+    sess = sc->session;
+
+    if ((sess == NULL)
+            || (sc->enc_write_ctx == NULL)
+            || (EVP_MD_CTX_get0_md(sc->write_hash) == NULL))
+        clear = 1;
+
+    if (clear)
+        mac_size = 0;
+    else {
+        mac_size = EVP_MD_CTX_get_size(sc->write_hash);
+        if (mac_size < 0) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR,
+                     SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE);
+            return -1;
+        }
+    }
+
+    p = SSL3_BUFFER_get_buf(wb) + prefix_len;
+
+    /* write the header */
+
+    *(p++) = tmpl->type & 0xff;
+    SSL3_RECORD_set_type(&wr, tmpl->type);
+    *(p++) = tmpl->version >> 8;
+    *(p++) = tmpl->version & 0xff;
+
+    /* field where we are to write out packet epoch, seq num and len */
+    pseq = p;
+    p += 10;
+
+    /* Explicit IV length, block ciphers appropriate version flag */
+    if (sc->enc_write_ctx) {
+        int mode = EVP_CIPHER_CTX_get_mode(sc->enc_write_ctx);
+        if (mode == EVP_CIPH_CBC_MODE) {
+            eivlen = EVP_CIPHER_CTX_get_iv_length(sc->enc_write_ctx);
+            if (eivlen < 0) {
+                SSLfatal(sc, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG);
+                return -1;
+            }
+            if (eivlen <= 1)
+                eivlen = 0;
+        }
+        /* Need explicit part of IV for GCM mode */
+        else if (mode == EVP_CIPH_GCM_MODE)
+            eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+        else if (mode == EVP_CIPH_CCM_MODE)
+            eivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN;
+        else
+            eivlen = 0;
+    } else
+        eivlen = 0;
+
+    /* lets setup the record stuff. */
+    SSL3_RECORD_set_data(&wr, p + eivlen); /* make room for IV in case of CBC */
+    SSL3_RECORD_set_length(&wr, tmpl->buflen);
+    SSL3_RECORD_set_input(&wr, (unsigned char *)tmpl->buf);
+
+    /*
+     * we now 'read' from wr.input, wr.length bytes into wr.data
+     */
+
+    /* first we compress */
+    if (sc->compress != NULL) {
+        if (!ssl3_do_compress(sc, &wr)) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, SSL_R_COMPRESSION_FAILURE);
+            return -1;
+        }
+    } else {
+        memcpy(SSL3_RECORD_get_data(&wr), SSL3_RECORD_get_input(&wr),
+               SSL3_RECORD_get_length(&wr));
+        SSL3_RECORD_reset_input(&wr);
+    }
+
+    /*
+     * we should still have the output to wr.data and the input from
+     * wr.input.  Length should be wr.length. wr.data still points in the
+     * wb->buf
+     */
+
+    if (!SSL_WRITE_ETM(sc) && mac_size != 0) {
+        if (!s->method->ssl3_enc->mac(sc, &wr,
+                                      &(p[SSL3_RECORD_get_length(&wr) + eivlen]),
+                                      1)) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
+        SSL3_RECORD_add_length(&wr, mac_size);
+    }
+
+    /* this is true regardless of mac size */
+    SSL3_RECORD_set_data(&wr, p);
+    SSL3_RECORD_reset_input(&wr);
+
+    if (eivlen)
+        SSL3_RECORD_add_length(&wr, eivlen);
+
+    if (s->method->ssl3_enc->enc(sc, &wr, 1, 1, NULL, mac_size) < 1) {
+        if (!ossl_statem_in_error(sc)) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        }
+        return -1;
+    }
+
+    if (SSL_WRITE_ETM(sc) && mac_size != 0) {
+        if (!s->method->ssl3_enc->mac(sc, &wr,
+                                      &(p[SSL3_RECORD_get_length(&wr)]), 1)) {
+            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            return -1;
+        }
+        SSL3_RECORD_add_length(&wr, mac_size);
+    }
+
+    /* record length after mac and block padding */
+
+    /* there's only one epoch between handshake and app data */
+
+    s2n(sc->rlayer.d->w_epoch, pseq);
+
+    memcpy(pseq, &(sc->rlayer.write_sequence[2]), 6);
+    pseq += 6;
+    s2n(SSL3_RECORD_get_length(&wr), pseq);
+
+    if (sc->msg_callback)
+        sc->msg_callback(1, 0, SSL3_RT_HEADER, pseq - DTLS1_RT_HEADER_LENGTH,
+                         DTLS1_RT_HEADER_LENGTH, s, sc->msg_callback_arg);
+
+    /*
+     * we should now have wr.data pointing to the encrypted data, which is
+     * wr->length long
+     */
+    SSL3_RECORD_set_type(&wr, tmpl->type); /* not needed but helps for debugging */
+    SSL3_RECORD_add_length(&wr, DTLS1_RT_HEADER_LENGTH);
+
+    ssl3_record_sequence_update(&(sc->rlayer.write_sequence[0]));
+
+    /* now let's set up wb */
+    SSL3_BUFFER_set_left(wb, prefix_len + SSL3_RECORD_get_length(&wr));
+    SSL3_BUFFER_set_offset(wb, 0);
+
+    /*
+     * memorize arguments so that ssl3_write_pending can detect bad write
+     * retries later
+     */
+    sc->rlayer.wpend_tot = tmpl->buflen;
+    sc->rlayer.wpend_buf = tmpl->buf;
+    sc->rlayer.wpend_type = tmpl->type;
+    sc->rlayer.wpend_ret = tmpl->buflen;
+
+    /* we now just need to write the buffer. Calls SSLfatal() as required. */
+    return ssl3_write_pending(sc, tmpl->type, tmpl->buf, tmpl->buflen, &written);
+}
+
 const OSSL_RECORD_METHOD ossl_dtls_record_method = {
     dtls_new_record_layer,
     dtls_free,
@@ -699,7 +946,7 @@ const OSSL_RECORD_METHOD ossl_dtls_record_method = {
     tls_write_pending,
     tls_get_max_record_len,
     tls_get_max_records,
-    tls_write_records,
+    dtls_write_records,
     tls_retry_write_records,
     tls_read_record,
     tls_release_record,
index d1563ea43c2ec85cf0380f58f3ae319e599a3068..9b5334d05a0de1c60dace0a4f2c4661bca4be330 100644 (file)
@@ -633,251 +633,6 @@ int dtls1_write_bytes(SSL_CONNECTION *s, int type, const void *buf,
     return i;
 }
 
-/*
- * TODO(RECLAYER): Temporary copy of the old ssl3_write_pending() function now
- * replaced by tls_retry_write_records(). Needs to be removed when the DTLS code
- * is converted
- */
-/* if SSL3_BUFFER_get_left() != 0, we need to call this
- *
- * Return values are as per SSL_write()
- */
-static int ssl3_write_pending(SSL_CONNECTION *s, int type,
-                              const unsigned char *buf, size_t len,
-                              size_t *written)
-{
-    int i;
-    SSL3_BUFFER *wb = s->rlayer.wbuf;
-    size_t currbuf = 0;
-    size_t tmpwrit = 0;
-
-    if ((s->rlayer.wpend_tot > len)
-        || (!(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
-            && (s->rlayer.wpend_buf != buf))
-        || (s->rlayer.wpend_type != type)) {
-        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_WRITE_RETRY);
-        return -1;
-    }
-
-    for (;;) {
-        clear_sys_error();
-        if (s->wbio != NULL) {
-            s->rwstate = SSL_WRITING;
-
-            /*
-             * To prevent coalescing of control and data messages,
-             * such as in buffer_write, we flush the BIO
-             */
-            if (BIO_get_ktls_send(s->wbio) && type != SSL3_RT_APPLICATION_DATA) {
-                i = BIO_flush(s->wbio);
-                if (i <= 0)
-                    return i;
-                BIO_set_ktls_ctrl_msg(s->wbio, type);
-            }
-            i = BIO_write(s->wbio, (char *)
-                          &(SSL3_BUFFER_get_buf(&wb[currbuf])
-                            [SSL3_BUFFER_get_offset(&wb[currbuf])]),
-                          (unsigned int)SSL3_BUFFER_get_left(&wb[currbuf]));
-            if (i >= 0)
-                tmpwrit = i;
-        } else {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BIO_NOT_SET);
-            i = -1;
-        }
-
-        /*
-         * When an empty fragment is sent on a connection using KTLS,
-         * it is sent as a write of zero bytes.  If this zero byte
-         * write succeeds, i will be 0 rather than a non-zero value.
-         * Treat i == 0 as success rather than an error for zero byte
-         * writes to permit this case.
-         */
-        if (i >= 0 && tmpwrit == SSL3_BUFFER_get_left(&wb[currbuf])) {
-            SSL3_BUFFER_set_left(&wb[currbuf], 0);
-            SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);
-            s->rwstate = SSL_NOTHING;
-            *written = s->rlayer.wpend_ret;
-            return 1;
-        } else if (i <= 0) {
-            if (SSL_CONNECTION_IS_DTLS(s)) {
-                /*
-                 * For DTLS, just drop it. That's kind of the whole point in
-                 * using a datagram service
-                 */
-                SSL3_BUFFER_set_left(&wb[currbuf], 0);
-            }
-            return i;
-        }
-        SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);
-        SSL3_BUFFER_sub_left(&wb[currbuf], tmpwrit);
-    }
-}
-
-static int dtls_write_records(SSL_CONNECTION *sc, OSSL_RECORD_TEMPLATE *tmpl,
-                              size_t numtmpl)
-{
-    unsigned char *p, *pseq;
-    int mac_size, clear = 0;
-    size_t prefix_len = 0, written;
-    int eivlen;
-    SSL3_RECORD wr;
-    SSL3_BUFFER *wb = sc->rlayer.wbuf;
-    SSL_SESSION *sess;
-    SSL *s = SSL_CONNECTION_GET_SSL(sc);
-
-    sess = sc->session;
-
-    if ((sess == NULL)
-            || (sc->enc_write_ctx == NULL)
-            || (EVP_MD_CTX_get0_md(sc->write_hash) == NULL))
-        clear = 1;
-
-    if (clear)
-        mac_size = 0;
-    else {
-        mac_size = EVP_MD_CTX_get_size(sc->write_hash);
-        if (mac_size < 0) {
-            SSLfatal(sc, SSL_AD_INTERNAL_ERROR,
-                     SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE);
-            return -1;
-        }
-    }
-
-    p = SSL3_BUFFER_get_buf(wb) + prefix_len;
-
-    /* write the header */
-
-    *(p++) = tmpl->type & 0xff;
-    SSL3_RECORD_set_type(&wr, tmpl->type);
-    *(p++) = tmpl->version >> 8;
-    *(p++) = tmpl->version & 0xff;
-
-    /* field where we are to write out packet epoch, seq num and len */
-    pseq = p;
-    p += 10;
-
-    /* Explicit IV length, block ciphers appropriate version flag */
-    if (sc->enc_write_ctx) {
-        int mode = EVP_CIPHER_CTX_get_mode(sc->enc_write_ctx);
-        if (mode == EVP_CIPH_CBC_MODE) {
-            eivlen = EVP_CIPHER_CTX_get_iv_length(sc->enc_write_ctx);
-            if (eivlen < 0) {
-                SSLfatal(sc, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG);
-                return -1;
-            }
-            if (eivlen <= 1)
-                eivlen = 0;
-        }
-        /* Need explicit part of IV for GCM mode */
-        else if (mode == EVP_CIPH_GCM_MODE)
-            eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
-        else if (mode == EVP_CIPH_CCM_MODE)
-            eivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN;
-        else
-            eivlen = 0;
-    } else
-        eivlen = 0;
-
-    /* lets setup the record stuff. */
-    SSL3_RECORD_set_data(&wr, p + eivlen); /* make room for IV in case of CBC */
-    SSL3_RECORD_set_length(&wr, tmpl->buflen);
-    SSL3_RECORD_set_input(&wr, (unsigned char *)tmpl->buf);
-
-    /*
-     * we now 'read' from wr.input, wr.length bytes into wr.data
-     */
-
-    /* first we compress */
-    if (sc->compress != NULL) {
-        if (!ssl3_do_compress(sc, &wr)) {
-            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, SSL_R_COMPRESSION_FAILURE);
-            return -1;
-        }
-    } else {
-        memcpy(SSL3_RECORD_get_data(&wr), SSL3_RECORD_get_input(&wr),
-               SSL3_RECORD_get_length(&wr));
-        SSL3_RECORD_reset_input(&wr);
-    }
-
-    /*
-     * we should still have the output to wr.data and the input from
-     * wr.input.  Length should be wr.length. wr.data still points in the
-     * wb->buf
-     */
-
-    if (!SSL_WRITE_ETM(sc) && mac_size != 0) {
-        if (!s->method->ssl3_enc->mac(sc, &wr,
-                                      &(p[SSL3_RECORD_get_length(&wr) + eivlen]),
-                                      1)) {
-            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            return -1;
-        }
-        SSL3_RECORD_add_length(&wr, mac_size);
-    }
-
-    /* this is true regardless of mac size */
-    SSL3_RECORD_set_data(&wr, p);
-    SSL3_RECORD_reset_input(&wr);
-
-    if (eivlen)
-        SSL3_RECORD_add_length(&wr, eivlen);
-
-    if (s->method->ssl3_enc->enc(sc, &wr, 1, 1, NULL, mac_size) < 1) {
-        if (!ossl_statem_in_error(sc)) {
-            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-        }
-        return -1;
-    }
-
-    if (SSL_WRITE_ETM(sc) && mac_size != 0) {
-        if (!s->method->ssl3_enc->mac(sc, &wr,
-                                      &(p[SSL3_RECORD_get_length(&wr)]), 1)) {
-            SSLfatal(sc, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            return -1;
-        }
-        SSL3_RECORD_add_length(&wr, mac_size);
-    }
-
-    /* record length after mac and block padding */
-
-    /* there's only one epoch between handshake and app data */
-
-    s2n(sc->rlayer.d->w_epoch, pseq);
-
-    memcpy(pseq, &(sc->rlayer.write_sequence[2]), 6);
-    pseq += 6;
-    s2n(SSL3_RECORD_get_length(&wr), pseq);
-
-    if (sc->msg_callback)
-        sc->msg_callback(1, 0, SSL3_RT_HEADER, pseq - DTLS1_RT_HEADER_LENGTH,
-                         DTLS1_RT_HEADER_LENGTH, s, sc->msg_callback_arg);
-
-    /*
-     * we should now have wr.data pointing to the encrypted data, which is
-     * wr->length long
-     */
-    SSL3_RECORD_set_type(&wr, tmpl->type); /* not needed but helps for debugging */
-    SSL3_RECORD_add_length(&wr, DTLS1_RT_HEADER_LENGTH);
-
-    ssl3_record_sequence_update(&(sc->rlayer.write_sequence[0]));
-
-    /* now let's set up wb */
-    SSL3_BUFFER_set_left(wb, prefix_len + SSL3_RECORD_get_length(&wr));
-    SSL3_BUFFER_set_offset(wb, 0);
-
-    /*
-     * memorize arguments so that ssl3_write_pending can detect bad write
-     * retries later
-     */
-    sc->rlayer.wpend_tot = tmpl->buflen;
-    sc->rlayer.wpend_buf = tmpl->buf;
-    sc->rlayer.wpend_type = tmpl->type;
-    sc->rlayer.wpend_ret = tmpl->buflen;
-
-    /* we now just need to write the buffer. Calls SSLfatal() as required. */
-    return ssl3_write_pending(sc, tmpl->type, tmpl->buf, tmpl->buflen, &written);
-}
-
 int do_dtls1_write(SSL_CONNECTION *sc, int type, const unsigned char *buf,
                    size_t len, size_t *written)
 {
@@ -929,7 +684,7 @@ int do_dtls1_write(SSL_CONNECTION *sc, int type, const unsigned char *buf,
     tmpl.buf = buf;
     tmpl.buflen = len;
 
-    ret = dtls_write_records(sc, &tmpl, 1);
+    ret = sc->rlayer.wrlmethod->write_records(sc->rlayer.wrl, &tmpl, 1);
 
     if (ret > 0)
         *written = (int)len;