Skip to content

[TLS 1.3] Basic Server Implementation#3053

Merged
reneme merged 5 commits intomasterfrom
tls13/server
Dec 30, 2022
Merged

[TLS 1.3] Basic Server Implementation#3053
reneme merged 5 commits intomasterfrom
tls13/server

Conversation

@reneme
Copy link
Copy Markdown
Collaborator

@reneme reneme commented Sep 28, 2022

Pull Request Dependencies

Description

This provides a basic TLS 1.3 server implementation with the most common functionality. Relevant BoGo tests pass already, but many more are still disabled. The ordinary handshake (with or without Hello Retry Request) and subsequent application data exchange works. Also a protocol version downgrade to TLS 1.2 works fine.

For the sake of reviewability, I am planning to stabilize the current feature set and aim for review/merge to master. Further functionality will come. See below.

New Callback: bool tls_peer_closed_connection()

This is called when we received a "close_notify" from the peer. In contrast to older revisions, TLS 1.3 does not mandate an immediate in-kind response in that case. Applications can override this callback to get notified that no more data is to be expected from the peer. Though they could legally continue sending data and finish with Channel::close() at their own discretion.

Returning true from this callback will make TLS 1.3 behave just like 1.2 and reply with a "close_notify" immediately. This is the default behaviour.

Missing Functionality

@reneme reneme force-pushed the tls13/server branch 6 times, most recently from 8f45436 to 1660b3b Compare September 29, 2022 10:38
@reneme reneme added this to the Botan 3.0.0 milestone Oct 11, 2022
@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented Oct 12, 2022

This pull request introduces 1 alert when merging 682ef9a into 26b593c - view on LGTM.com

new alerts:

  • 1 for Unused local variable

@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented Oct 19, 2022

This pull request introduces 1 alert when merging c6e0a21 into 26b593c - view on LGTM.com

new alerts:

  • 1 for Unused local variable

@reneme reneme force-pushed the tls13/server branch 2 times, most recently from 34fed1a to ea33d55 Compare October 20, 2022 06:30
@reneme reneme changed the base branch from tls13/integration to master October 20, 2022 06:30
@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented Oct 20, 2022

This pull request introduces 1 alert when merging ea33d55 into 76089a3 - view on LGTM.com

new alerts:

  • 1 for Unused local variable

@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented Oct 20, 2022

This pull request introduces 1 alert when merging 1057dcc into 76089a3 - view on LGTM.com

new alerts:

  • 1 for Unused local variable

@reneme reneme mentioned this pull request Oct 20, 2022
14 tasks
@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented Oct 21, 2022

This pull request introduces 1 alert when merging 4566be0 into 76089a3 - view on LGTM.com

new alerts:

  • 1 for Unused local variable

@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented Oct 21, 2022

This pull request introduces 1 alert when merging b4682b9 into 76089a3 - view on LGTM.com

new alerts:

  • 1 for Unused local variable

@reneme reneme changed the title [TLS 1.3] Server Implementation [TLS 1.3] Basic Server Implementation Oct 21, 2022
@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented Oct 21, 2022

This pull request introduces 1 alert when merging 6f963a5 into 76089a3 - view on LGTM.com

new alerts:

  • 1 for Unused local variable

@reneme
Copy link
Copy Markdown
Collaborator Author

reneme commented Oct 26, 2022

Milestone: This can now successfully handshake and exchange messages with openssl:

Terminal 1

./botan tls_server src/tests/data/tls_13_rfc8448/server_certificate.pem src/tests/data/tls_13_rfc8448/server_key.pem --port=8443 --policy=src/tests/data/tls-policy/rfc8448_1rtt.txt

Terminal 2

openssl s_client localhost:8443

Next steps: Support for Hello Retry Request and integration with basic BoGo tests. For the latter, I hope we can find a few server tests that don't require resumption support.

@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented Oct 26, 2022

This pull request introduces 1 alert when merging a65fbef into 76089a3 - view on LGTM.com

new alerts:

  • 1 for Unused local variable

@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented Nov 3, 2022

This pull request introduces 2 alerts when merging 0cb6409 into 76089a3 - view on LGTM.com

new alerts:

  • 1 for Futile conditional
  • 1 for Unused local variable

@lgtm-com
Copy link
Copy Markdown

lgtm-com bot commented Nov 4, 2022

This pull request introduces 1 alert when merging f1d2634 into 76089a3 - view on LGTM.com

new alerts:

  • 1 for Unused local variable

@randombit
Copy link
Copy Markdown
Owner

I'm deferring a review on this until #3062 lands

@reneme
Copy link
Copy Markdown
Collaborator Author

reneme commented Dec 15, 2022

I'm deferring a review on this until #3062 lands

Rebased to master. This has no more underlying PR dependencies.

@randombit
Copy link
Copy Markdown
Owner

I will review this asap

@reneme reneme requested a review from lieser December 20, 2022 10:50
@reneme
Copy link
Copy Markdown
Collaborator Author

reneme commented Dec 28, 2022

I left this open despite @lieser approving since you had started a review as well, @randombit.

In case you want to continue reviewing this after your christmas break, please don't hesitate to point that out.

Otherwise, I'd like to merge this soonish and integrate the remaining (approved) PRs. This would particularly simplify development in the resumption PR as it will contain some cross-cutting concerns.

Copy link
Copy Markdown
Owner

@randombit randombit left a comment

Choose a reason for hiding this comment

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

Looks good to me. A few minor questions/comments, approving now to unblock.

std::vector<Named_Group> offered_groups;
std::transform(m_client_shares.cbegin(), m_client_shares.cend(),
std::back_inserter(offered_groups),
[](const auto& share) { return share.group(); });
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Why not just

for(auto& share: m_client_shares)
  offered_groups.push_back(share.group());

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fair. Now that we have C++20 and ranges I thought that's a good opportunity to use it. For reference:

return m_client_shares
   | std::views::transform([](const auto& s){ return s.group(); })
   | to<std::vector<Named_Group>>();

Caveat: the to<>() is actually proposed for C++23 only. We'd need to implement it ourselves; which seems like a reasonable thing to do for the time being. Sigh!
Godbolt: https://godbolt.org/z/771M7PEzK

But certainly not in this PR.

I guess the modern thing to do, is to return the view directly and not create a new owning container at all. These things should happen at least somewhat consistently, though.

// and MUST ignore any unknown versions that are present in that
// extension.
if(!v.known_version() || !policy.acceptable_protocol_version(v))
{ continue; }
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Should we ignore (or reject?) DTLS versions being mixed in here? Or does that happen elsewhere already.

Perhaps for RFC 8446 purposes DTLS counts as an "unknown version" of TLS but that doesn't really seem correct to me.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

DTLS as such is not explicitly filtered out anywhere. TLS 1.2 / 1.3 distinctions are typically done using Protocol_Version::is_pre_tls_13() or ::is_tls_13_or_later() which transparently takes DTLS into account.

That said, DTLS 1.3 won't pass the default implementation of Policy::acceptable_protocol_version() and won't make it into the result vector. For reference:

bool Policy::acceptable_protocol_version(Protocol_Version version) const
   {
#if defined(BOTAN_HAS_TLS_13)
   if(version == Protocol_Version::TLS_V13 && allow_tls13())
      return true;
#endif

#if defined(BOTAN_HAS_TLS_12)
   if(version == Protocol_Version::TLS_V12 && allow_tls12())
      return true;

   if(version == Protocol_Version::DTLS_V12 && allow_dtls12())
      return true;
#endif

   return false;
   }


// SHA-256("HelloRetryRequest")
const std::array<uint8_t, 32> HELLO_RETRY_REQUEST_MARKER =
const std::vector<uint8_t> HELLO_RETRY_REQUEST_MARKER =
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Why this change? Fine with it just curious why it was required.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The c'tor of Server_Hello_Internal takes the random as a std::vector (which is usually provided from make_hello_random(), that returns a std::vector). Leaving this as a std::array would require a conversion or a c'tor overload just for that.

std::make_unique<Server_Hello_Internal>(.... , HELLO_RETRY_REQUEST_MARKER, ....);
// vs.
std::make_unique<Server_Hello_Internal>(.... , make_hello_random(), ....);

Or use a std::span in the Server_Hello_Internal c'tor? But wouldn't that cause UB because the std::span would refer to data in the temporary std::vector falling out of make_hello_random()?

My understanding is, that the temporary gets destroyed at the end of the expression (i.e. after the invoked c'tor returned). So as long as the c'tor copies the data out of the span, there should be no lifetime issues. This quick test does support my view. Side note: An interesting article about views, ranges, life times and dangling pointers: https://tristanbrindle.com/posts/rvalue-ranges-and-views

But it would result in an unnecessary copy (from the temporary, via the span, into a member of Server_Hello_Internal). I think, my vote is to keep the std::vector<> for HELLO_RETRY_REQUEST_MARKER.

reneme and others added 5 commits December 30, 2022 10:32
This provides a basic TLS 1.3 server implementation with the most common
functionality. Relevant BoGo tests pass already, but many more are still
disabled. The ordinary handshake (with or without Hello Retry Request)
and subsequent application data exchange works. Also a protocol version
downgrade to TLS 1.2 works fine.

Missing major functionality:

 * PSK
 * Session Resumption via Tickets
 * Early Data and 0-RTT
 * Client Authentication
 * OCSP Stapling
 * ALPN
 * probably more...

Co-Authored-By: Philippe Lieser <philippe.lieser@rohde-schwarz.com>
@reneme reneme merged commit cb1eb53 into master Dec 30, 2022
@randombit randombit deleted the tls13/server branch December 30, 2022 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants