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,
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,
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)
{
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;