Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move DTLS code into the new write record layer #19424

Closed
wants to merge 17 commits into from

Conversation

mattcaswell
Copy link
Member

We move the DTLS write side into the new record layer architecture. This represents the last major component in the move to the new architecture. Some subsequent PRs are still required to resolve some loose ends and outstanding "TODO" items.

do_dtls1_write() was never called with a value for create_empty_fragment
that was ever non-zero - so this is dead code and can be removed. The
equivalent code in the TLS processing is used for TLS1.0/SSLv3 to protect
against known IV weaknesses because those protocol versions do not have
an explicit IV. However DTLS1.0 is based on TLSv1.1 and *does* have an
explicit IV - so this is not useful there.
In preparation for moving the DTLS code to use the new write record layer
architecture we first restructure the code to create a dtls_write_records()
function that mirrors the functionality that the record layer will provide.
At the this stage we just move the code and don't restructure it to do it
the record layer way yet.
We now use standard record layer return values for this function. We
also convert the code to use RLAYERfatal instead of SSLfatal.
In practice this just means have a DTLS specific write_records that the
common tls_write_records() just calls. We also replace the use of
ssl3_write_pending() with tls_retry_write_records().
Previously this was writing to the buffers directly. We use the safer
WPACKET instead
We have standard functions for most of the work that dtls_write_records
does - so we convert it to use those functions instead.
Don't calculate the potential record layer expansion outside of the
record layer. We move some code that was doing that into the record
layer.
The sequence counter was incremented in numerous different ways in
numerous different locations. We introduce a single function to do this
inside the record layer.
We already set the record type on the SSL3_RECORD structure. We don't
need to do it again (inconsistently).
This change make dtls_write_records virtuall the same as
tls_write_records_default, which will enable us to merge them in a
subsequent commit.
The dtls_write_records function, after the previous series of commits,
was functionally equivalent to tls_write_records_default - so it can be
removed completely.
We no longer use the old buffer management code now that it has all been
moved to the new record layer.
@mattcaswell mattcaswell added branch: master Merge to master branch approval: review pending This pull request needs review by a committer approval: otc review pending This pull request needs review by an OTC member labels Oct 17, 2022
@github-actions github-actions bot added the severity: fips change The pull request changes FIPS provider sources label Oct 17, 2022
@paulidale
Copy link
Contributor

CI failure looks relevant.

Calling SSL_free() will call BIO_free_all() on the rbio and wbio. We
keep references to the rbio and wbio inside the record layer object.
References to that object are held directly, as well as in fragment
retransmission queues. We need to ensure all record layer objects are
cleaned up before we call BIO_free_all() on rbio/wbio - otherwise the
"top" BIO may not have its reference count drop to 0 when BIO_free_all()
is called. This means that the rest of the BIOs in the chain don't get
freed and a memory leak can occur.
@mattcaswell
Copy link
Member Author

CI failure looks relevant.

Fixed (hopefully).

Copy link
Member

@hlandau hlandau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see anything at issue here.

What are we going to do about the disabled test? Can it be fixed in this PR, or does it need to be deferred?

@hlandau hlandau removed the approval: otc review pending This pull request needs review by an OTC member label Oct 19, 2022
@mattcaswell
Copy link
Member Author

What are we going to do about the disabled test? Can it be fixed in this PR, or does it need to be deferred?

This is one of the "loose ends" I plan to follow up on in subsequent PRs. There are a handful of "TODOs" left over in the code that need some attention - this being one of them. I decided to defer it because it wasn't strictly related to the DTLS code - its a TLSv1.3 test, which was missed in the earlier TLSv1.3 work.

@t8m t8m added the triaged: refactor The issue/pr requests/implements refactoring label Oct 19, 2022
/*
* TODO(RECLAYER): Need a way to release the write buffers in the record
* layer on demand
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did notice the change from a RECORD_LAYER_get_wbuf() call to direct memory allocation in ssl/d1_lib.c, I assume that this comment is kinda sorta connected to that change...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well kinda sorta, but only indirectly.

Previously the record layer write buffers were entirely open and available for any of libssl to dive into and play around with. Part of what the refactor has done is make the record layer opaque to the rest of libssl. We want it to be this way to ensure we can "plug in" any alternative implementation of the record layer. Therefore the write buffers used by the record layer are no longer accessible to the rest of libssl.

The change in ssl/d1_lib.c that you are referring to is in the implementation of DTLSv1_listen(). This function is a bit of an oddball because it works quite independently form the rest of libssl. It works entirely statelessly and does not use the record layer at all. Nonetheless in the old implementation it "reused" the record layer write buffers - simply because they were handy and already allocated - but not because it was using the record layer code at all. The change I made was so that DTLSv1_listen() would use its own temporary buffer rather than reusing a buffer that it had no real business touching.

That change was necessary because DTLSv1_listen() was actually using the old record layer's write buffers. Those get deleted by this PR because (apart from that one remaining usage) they were no longer being used.

This TODO is in RECORD_LAYER_release(). That function historically had a number of roles - but the one remaining one was to free the record layer write buffers. But that was the old write buffers which are no longer used, and are deleted by this PR. So this function becomes a no-op. It could actually be completely removed except for one call site in the public API function SSL_free_buffers(). Apart from in test code we never call that function ourselves - but external applications might do so. By making RECORD_LAYER_release() a no-op we also make SSL_free_buffers() a no-op. Really though what it ought to do is tell the new record layer code to release its buffers. That's what this TODO is reminding us.

Copy link
Member

@levitte levitte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment aside, LGTM

@levitte levitte removed the approval: review pending This pull request needs review by a committer label Oct 19, 2022
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
We now use standard record layer return values for this function. We
also convert the code to use RLAYERfatal instead of SSLfatal.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
In practice this just means have a DTLS specific write_records that the
common tls_write_records() just calls. We also replace the use of
ssl3_write_pending() with tls_retry_write_records().

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
Previously this was writing to the buffers directly. We use the safer
WPACKET instead

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
We have standard functions for most of the work that dtls_write_records
does - so we convert it to use those functions instead.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
Don't calculate the potential record layer expansion outside of the
record layer. We move some code that was doing that into the record
layer.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
The sequence counter was incremented in numerous different ways in
numerous different locations. We introduce a single function to do this
inside the record layer.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
We already set the record type on the SSL3_RECORD structure. We don't
need to do it again (inconsistently).

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
This change make dtls_write_records virtuall the same as
tls_write_records_default, which will enable us to merge them in a
subsequent commit.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
The dtls_write_records function, after the previous series of commits,
was functionally equivalent to tls_write_records_default - so it can be
removed completely.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
We no longer use the old buffer management code now that it has all been
moved to the new record layer.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
openssl-machine pushed a commit that referenced this pull request Oct 20, 2022
Calling SSL_free() will call BIO_free_all() on the rbio and wbio. We
keep references to the rbio and wbio inside the record layer object.
References to that object are held directly, as well as in fragment
retransmission queues. We need to ensure all record layer objects are
cleaned up before we call BIO_free_all() on rbio/wbio - otherwise the
"top" BIO may not have its reference count drop to 0 when BIO_free_all()
is called. This means that the rest of the BIOs in the chain don't get
freed and a memory leak can occur.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from #19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
do_dtls1_write() was never called with a value for create_empty_fragment
that was ever non-zero - so this is dead code and can be removed. The
equivalent code in the TLS processing is used for TLS1.0/SSLv3 to protect
against known IV weaknesses because those protocol versions do not have
an explicit IV. However DTLS1.0 is based on TLSv1.1 and *does* have an
explicit IV - so this is not useful there.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
In preparation for moving the DTLS code to use the new write record layer
architecture we first restructure the code to create a dtls_write_records()
function that mirrors the functionality that the record layer will provide.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
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 openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
We now use standard record layer return values for this function. We
also convert the code to use RLAYERfatal instead of SSLfatal.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
In practice this just means have a DTLS specific write_records that the
common tls_write_records() just calls. We also replace the use of
ssl3_write_pending() with tls_retry_write_records().

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
Previously this was writing to the buffers directly. We use the safer
WPACKET instead

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
We have standard functions for most of the work that dtls_write_records
does - so we convert it to use those functions instead.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
Don't calculate the potential record layer expansion outside of the
record layer. We move some code that was doing that into the record
layer.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
The sequence counter was incremented in numerous different ways in
numerous different locations. We introduce a single function to do this
inside the record layer.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
We already set the record type on the SSL3_RECORD structure. We don't
need to do it again (inconsistently).

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
This change make dtls_write_records virtuall the same as
tls_write_records_default, which will enable us to merge them in a
subsequent commit.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
The dtls_write_records function, after the previous series of commits,
was functionally equivalent to tls_write_records_default - so it can be
removed completely.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
We no longer use the old buffer management code now that it has all been
moved to the new record layer.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
beldmit pushed a commit to beldmit/openssl that referenced this pull request Dec 26, 2022
Calling SSL_free() will call BIO_free_all() on the rbio and wbio. We
keep references to the rbio and wbio inside the record layer object.
References to that object are held directly, as well as in fragment
retransmission queues. We need to ensure all record layer objects are
cleaned up before we call BIO_free_all() on rbio/wbio - otherwise the
"top" BIO may not have its reference count drop to 0 when BIO_free_all()
is called. This means that the rest of the BIOs in the chain don't get
freed and a memory leak can occur.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from openssl#19424)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approval: ready to merge The 24 hour grace period has passed, ready to merge branch: master Merge to master branch severity: fips change The pull request changes FIPS provider sources triaged: refactor The issue/pr requests/implements refactoring
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants