Skip to content

Comments

TLSv1.3: Add support for the key_share extension#1848

Closed
mattcaswell wants to merge 14 commits intoopenssl:masterfrom
mattcaswell:tls1_3-key-share
Closed

TLSv1.3: Add support for the key_share extension#1848
mattcaswell wants to merge 14 commits intoopenssl:masterfrom
mattcaswell:tls1_3-key-share

Conversation

@mattcaswell
Copy link
Member

Checklist
  • tests are added or updated
  • CLA is signed
Description of change

This adds support for generating and processing the key_share extension on both the client and the server. There are a few restrictions with this current version which will be fixed in later PRs:

  • We just generate one key_share for our most preferred group. Really it should be configurable as to how many we want to send.
  • There is no support yet for the HelloRetryRequest message. Therefore, on the server side if the offered key_share is not suitable then we abort the connection. Similarly on the client side if the server responds with a HelloRetryRequest then we will fail.

The key_share extension does the job of key_exchange which in <=TLSv1.2 is done by the ServerKeyExchange and ClientKeyExchange messages. The TLSv1.3 code in master is still essentially TLSv1.2, so this PR also removes the generation and processing of the SKE and CKE messages. The result is a protocol that is neither TLSv1.2 nor TLSv1.3 but somewhere in the middle. Over time more PRs will move it closer to "real" TLSv1.3.

This PR includes the commits from PRs: #1807, #1808, #1825 and #1847. Therefore please only look at the last 11 commits.

@mattcaswell
Copy link
Member Author

Rebased on the latest master to pick up some of the commits from other PRs that have gone in. This PR is still dependant on #1808 and #1825, so please only look at the last 11 commits.

@mattcaswell
Copy link
Member Author

Rebased again, so now this PR is only dependent on the one commit from #1825. So please ignore the first commit, everything else is in scope.

@mattcaswell
Copy link
Member Author

Rebased this again. All commits are for review now. There is one test failure which is unrelated to this PR (its in current master) and will be fixed by #1894.

@mattcaswell
Copy link
Member Author

#1894 got merged quickly so rebased again to pick it up!

Copy link
Contributor

Choose a reason for hiding this comment

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

I thought we already resolved this :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Oops. This was written before we came to that resolution. Fixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

make the test the same as line 419?

Copy link
Member Author

Choose a reason for hiding this comment

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

It really should be s->s3->tmp.cert_req != 0. cert_req of 0 means "we are not sending a Certificate message". A cert_req of 1 means "we are sending a Certificate message, and it has a certificate in it", a cert_req of 2 means "we are sending a Certificate message, but it has no Certificate in it" (don't shoot the messenger that's the way the existing code works).

Copy link
Contributor

Choose a reason for hiding this comment

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

remove else after return

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Contributor

Choose a reason for hiding this comment

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

remove else after return

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Contributor

Choose a reason for hiding this comment

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

ssl/t1_lib.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

don't need the curly braces. I would do

return i == num_groups ? 0 : 1;
    or
return i < num_groups;

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

ssl/t1_lib.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

should we have a utility function

# define SSLalerterr(a, ap, f, r) (ap=a, SSLerr(f, r), 0)

And then we could do

return SSLalerterr(al, SSL_AD_INTERNAL_ERROR, SSL_F_SCAN_CLIENTHELLO_TLSEXT, SSL_R_LENGTH_MISMATCH)

Obviously a separate MR. But would you be interested in that?

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe...I'm not averse to someone else picking it up, put it that way ;-)

ssl/t1_lib.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

didn't you create a macro for this?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes (after I first created this PR). Fixed now.

ssl/t1_lib.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

move this down to just before line 2865 (with no extra blank line)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe $numtests++ if !disabled("tls1_3"); ? your decision.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Contributor

Choose a reason for hiding this comment

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

A "TODO(TLS1.3): implement the real 1.3 state machine instead of 1.2-that-calls-itself-1.3" would have saved me a bit of confusion.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like TODO(TLS1.3) is the convention

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we assert that this does not happen (or have an error case for it)?

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...we do (see the default case below)

ssl/t1_enc.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

It's also unclear that s->hit is the right thing to be checking here -- I think external (non-resumption) PSK would trigger this conditional as it stasnds.

ssl/t1_lib.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

You can has hash

ssl/t1_lib.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it too soon to be worrying about == vs. >=?

Copy link
Member Author

Choose a reason for hiding this comment

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

Should be SSL_IS_TLS13(s)

ssl/t1_lib.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Should the loop body move into a helper function?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

ssl/t1_lib.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Do the 'get_curvelist's need to be inside the loop?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure I follow. We are looping through each of the key_shares sent from the client. For each one we need to check that (1) the group also appears in the supported_groups sent by the client and (2) that it is for a group we can use. If the first fails we abort, and if the second fails then we have to continue the loop on the next key_share...so, yes, it needs to be in the loop?

Copy link
Contributor

Choose a reason for hiding this comment

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

I was thinking that the values stored in &curves and &num_curves are not going to change for a given s and given second argument, so we could have separate local variables for the peer's supported_groups and what we support, and then just make two calls to tls1_get_curvelist (outside the loop), instead of two times the number of key_shares calls.

ssl/t1_lib.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment is too imprecise; is it "Check that the group for this key share is in the supported_groups that the client sent"? (That is probably too long, but for clarity here.)

Copy link
Contributor

Choose a reason for hiding this comment

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

fwiw i think it's fine.

Copy link
Contributor

Choose a reason for hiding this comment

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

You wouldn't even add an "if" to make it grammatical?

Copy link
Contributor

Choose a reason for hiding this comment

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

sure. who cares. but sure.

Copy link
Member Author

Choose a reason for hiding this comment

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

I changed it to "Check if this share is in supported_groups sent from client"

ssl/t1_lib.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

How about "Check if this share is for a group we can use"?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Member Author

Choose a reason for hiding this comment

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

Added

Copy link
Member Author

Choose a reason for hiding this comment

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

Oops. This was written before we came to that resolution. Fixed.

Copy link
Member Author

Choose a reason for hiding this comment

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

tlsext_ticket_expected is boolean, whilst cert_req is not - hence the difference

Copy link
Member Author

Choose a reason for hiding this comment

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

It really should be s->s3->tmp.cert_req != 0. cert_req of 0 means "we are not sending a Certificate message". A cert_req of 1 means "we are sending a Certificate message, and it has a certificate in it", a cert_req of 2 means "we are sending a Certificate message, but it has no Certificate in it" (don't shoot the messenger that's the way the existing code works).

Copy link
Member Author

Choose a reason for hiding this comment

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

We still need the == 1 here (it can be 2)

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Member Author

Choose a reason for hiding this comment

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

I changed this to SSL_IS_TLS13(s)

ssl/t1_lib.c Outdated
Copy link
Member Author

Choose a reason for hiding this comment

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

Changed this (and the instance below to SSL_IS_TLS13(s)

ssl/t1_lib.c Outdated
Copy link
Member Author

Choose a reason for hiding this comment

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

Changed to SSL_IS_TLS13(s)

ssl/t1_lib.c Outdated
Copy link
Member Author

Choose a reason for hiding this comment

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

Changed to SSL_IS_TLS13(s)

@mattcaswell
Copy link
Member Author

New commit pushed addressing feedback comments.

@richsalz
Copy link
Contributor

We should never do DH key exchange; only ECDH. I'd prefer we didnt even have that comment, but okay. Just one or two open questions then I can plus-one.

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.

make update has complaints:

$ $make update
ssl/t1_lib.c:1531:add_client_key_share_ext:ssl_add_serverhello_tlsext
ssl/t1_lib.c:1538:add_client_key_share_ext:ssl_add_serverhello_tlsext
ssl/t1_lib.c:1547:add_client_key_share_ext:ssl_add_serverhello_tlsext
ssl/t1_lib.c:1554:add_client_key_share_ext:ssl_add_serverhello_tlsext
ssl/t1_lib.c:1565:add_client_key_share_ext:ssl_add_serverhello_tlsext
ssl/t1_lib.c:1980:process_key_share_ext:ssl_scan_clienthello_tlsext
ssl/t1_lib.c:1986:process_key_share_ext:ssl_scan_clienthello_tlsext
ssl/t1_lib.c:1996:process_key_share_ext:ssl_scan_clienthello_tlsext
ssl/t1_lib.c:2011:process_key_share_ext:ssl_scan_clienthello_tlsext
ssl/t1_lib.c:2017:process_key_share_ext:ssl_scan_clienthello_tlsext
ssl/t1_lib.c:2025:process_key_share_ext:ssl_scan_clienthello_tlsext
ssl/t1_lib.c:2038:process_key_share_ext:ssl_scan_clienthello_tlsext
ssl/t1_lib.c:2049:process_key_share_ext:ssl_scan_clienthello_tlsext
ssl/t1_lib.c:2063:process_key_share_ext:ssl_scan_clienthello_tlsext
ssl/t1_lib.c:2076:process_key_share_ext:ssl_scan_clienthello_tlsext
FATAL: error discrepancy
make: *** [errors] Error 1

In this commit we just generate the extension on the client side, but don't
yet do anything with it. Subsequent commits, will add the server side
capability.

At the moment we hard code a single key_share. In the future we should make
this configurable.
At the moment the server doesn't yet do anything with this information.
We still need to send the server's key_share info back to the client. That
will happen in subsequent commits.
This is a temporary fix for while we are still using the old session
resumption logic in the TLSv1.3 code. Due to differences in EXTMS support
we can't resume a <=TLSv1.2 session in a TLSv1.3 connection (the EXTMS
consistency check causes the connection to abort). This causes test
failures.

Ultimately we will rewrite the session resumption logic for TLSv1.3 so this
problem will go away. But until then we need a quick fix to keep the tests
happy.
The previous commits put in place the logic to exchange key_share data. We
now need to do something with that information. In <= TLSv1.2 the equivalent
of the key_share extension is the ServerKeyExchange and ClientKeyExchange
messages. With key_share those two messages are no longer necessary.

The commit removes the SKE and CKE messages from the TLSv1.3 state machine.
TLSv1.3 is completely different to TLSv1.2 in the messages that it sends
and the transitions that are allowed. Therefore, rather than extend the
existing <=TLS1.2 state transition functions, we create a whole new set for
TLSv1.3. Intially these are still based on the TLSv1.2 ones, but over time
they will be amended.

The new TLSv1.3 transitions remove SKE and CKE completely. There's also some
cleanup for some stuff which is not relevant to TLSv1.3 and is easy to
remove, e.g. the DTLS support (we're not doing DTLSv1.3 yet) and NPN.

I also disable EXTMS for TLSv1.3. Using it was causing some added
complexity, so rather than fix it I removed it, since eventually it will not
be needed anyway.
Numerous style issues as well as references to TLS1_3_VERSION instead of
SSL_IS_TLS13(s)
No need to continually get the list of supported curves for the client
and server. Just do it once.
@mattcaswell
Copy link
Member Author

@kaduk:

I was thinking that the values stored in &curves and &num_curves are not going to change for a given s and given second argument, so we could have separate local variables for the peer's supported_groups and what we support, and then just make two calls to tls1_get_curvelist (outside the loop), instead of two times the number of key_shares calls.

I can't locate this comment anymore in github. Anyway, I moved the two tls1_get_curvelist() calls outside of the loop.

@mattcaswell
Copy link
Member Author

New commits pushed, addressing all feedback and fixing make update. I also rebased on latest master.

@richsalz
Copy link
Contributor

+1

@richsalz richsalz closed this Nov 15, 2016
@richsalz richsalz reopened this Nov 15, 2016
@mattcaswell
Copy link
Member Author

My s->hit remark must have been intended for the other inline comment where Rich was complaining about the name looking like excrement; sorry for the mis-click.

Gah! Github has totally screwed up the threading on this particular discussion, and its quite difficult to follow....however, I think you are referring to this comment:

It's also unclear that s->hit is the right thing to be checking here -- I think external (non-resumption) PSK would trigger this conditional as it stasnds.

Which (I think) is in reference to this code in statem_srvr.c:

    if (s->version == TLS1_3_VERSION && s->s3->peer_tmp == NULL && !s->hit) {

There is no PSK support yet for TLSv1.3. We'll sort that out when we get to it.

@mattcaswell
Copy link
Member Author

Pushed. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

branch: master Applies to master branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants