PSK and key_share compliance fixes for RFC 8446#14749
PSK and key_share compliance fixes for RFC 8446#14749kaduk wants to merge 4 commits intoopenssl:masterfrom
Conversation
test/recipes/70-test_tls13kexmodes.t
Outdated
There was a problem hiding this comment.
It's a little unfortunate that we can currently only use checkhandshake() for successful handshakes, as it does a lot of in-depth inspection of the transcript that would be useful to have even for failure cases. In particular, with just the new ok(TLSProxy::Message->fail() test we don't actually get good coverage of the "missing psk kex modes extension" case, since a handshake failure is a failure whether it's detected by the client or the server.
The issue seems to come into play because we pass as the second argument the DEFAULT_HANDSHAKE value, which is part of a bitmask. We'd have to gain a way to be able to exclude specific messages that are not expected and not process those, which the current classification/bitmask scheme doesn't seem a good fit for.
There was a problem hiding this comment.
Hmm, I guess technically with only about 20 handshake message types having ever been defined we could just give each one a bit in the bitmask and make the "DEFAULT_HANDSHAKE" be more than one bit ... that would be a bunch of churn in the @handmessages array in each test that uses checkhandshake(), though. Not an exercise to go through speculatively, probably...
|
Tentatively marking this for 1.1.1, since I believe it is a bugfix. |
ssl/statem/extensions_srvr.c
Outdated
There was a problem hiding this comment.
Is this right? I'm not familiar with this code, but it looks like this gets filled in by tls_parse_ctos_psk_kex_modes, which is the client's PSK capabilities. But the server might not be using a PSK, in which case the server should still send key_share.
I imagine somewhere in the parameter selection process, there's some logic that decides:
- Is the server using a PSK?
- If so, is the server doing so with psk_dhe_ke or psk_ke?
If the answers are (yes, psk_ke), the server should omit key_share. Otherwise, the server should send key_share.
There was a problem hiding this comment.
I think you are correct and we need another check here; thanks for catching it.
This is obscured in the tests because openssl as a client always sends "psk_key_exchange_modes" even if there is no PSK (and the extra testing I did with a patched version that doesn't send psk_ke_dhe was targeted at the behavior during resumption of a different API, and so didn't test full handshakes).
Unfortunately, it looks like there isn't a great way to check for "did we use a PSK" already, so we might have to add a new field for that.
There was a problem hiding this comment.
It is possible that we can use s->hit to stand in for "server used PSK", but I will want to carefully check the various ways we can get a PSK before pushing that patch to the PR. (It is set somewhat far away from the decision on whether or not to use a PSK, which makes me somewhat uneasy about relying on it.)
There was a problem hiding this comment.
Could you please fix this so it can be considered for merge into 3.0?
There was a problem hiding this comment.
Yes, this is near the top of my list again (I feel like I have been staggering from one crisis to the next...)
There was a problem hiding this comment.
It is possible that we can use
s->hitto stand in for "server used PSK"
(we can't.)
There was a problem hiding this comment.
Oops, spoke too soon. Actually we can, since the psk_server_callback and psk_find_session_callback are only called from tls_parse_ctos_psk(), and the bit I forgot was that we specifically process that extension inside ssl_get_prev_session(), and if the latter returns a session it counts as a 'hit'. (If the callbacks find a session but it's not acceptable in a way that's not a fatal error, the session is not used, not associated with the SSL on return, ssl_get_prev_session() returns 0, and it is not a 'hit'.
I should probably tidy up my notes and put them in the tree somewhere...
|
This PR is in a state where it requires action by @openssl/otc but the last update was 30 days ago |
It's a MUST-level requirement that if the client sends a pre_shared_key extension not accompanied by a psk_key_exchange_modes extension, the server must abort the handshake. Prior to this commit the server would continue on.
|
I'm about to push an update, and will put some commentary here first. The main diff from the original version of the PR is: There is also some fallout in the test suite -- the original version of the PR changed a success to an expected failure, which turns out to have been detecting exactly this bug. It can go back to its original (success) formulation, though I updated the commentary slightly. I'm also rebasing onto a fresh master since it's been more than a month. David had in essence asked two questions, and I'll answer them separately. We can use In order to tell which key-exchange mode is being used, we have to jump through some contortions. We rely in a couple ways on the fact that there are only two defined modes at present (pure-psk and psk+DHE). Our server always implements psk+DHE and prefers it if possible, and our server only allows using pure-PSK if [0] The two named callbacks are the only ones relevant for session resumption on the server. Other psk-adjacent functionality exposed to the application includes: |
TLS 1.3 allows for the "psk_ke" and "psk_dhe_ke" key-exchange modes. Only the latter mode introduces a new ephemeral (Diffie-Hellman) key exchange, with the PSK being the only key material used in the former case. It's a compliance requirement of RFC 8446 that the server MUST NOT send a KeyShareEntry when using the "psk_ke" mode, but prior to this commit we would send a key-share based solely on whether the client sent one. This bug goes unnoticed in our internal test suite since openssl communicating with openssl can never negotiate the PSK-only key-exchange mode. However, we should still be compliant with the spec, so check whether the DHE mode was offered and don't send a key-share if it wasn't.
One of the scenarios constructed in these tests was erroneously producing successful handshakes until the previous commits, but should have been failing. Update our expected behavior to match the specification requirements, and adjust the commentary slightly for a test case relevant for the other preceding commit.
|
(and the CI pointed out that the |
|
@t8m I'm not sure if you were personally interested or just relaying the results of OTC triage, but this should be ready now. |
t8m
left a comment
There was a problem hiding this comment.
LGTM. I suppose to merge to 1.1.1 this will require a new PR due to conflicts?
It would be good if @mattcaswell could also look.
|
It actually cherry-picks without code conflicts, but runs into the |
|
IMO that requires a new PR. |
|
24 hours has passed since 'approval: done' was set, but as this PR has been updated in that time the label 'approval: ready to merge' is not being automatically set. Please review the updates and set the label manually. |
It's a MUST-level requirement that if the client sends a pre_shared_key extension not accompanied by a psk_key_exchange_modes extension, the server must abort the handshake. Prior to this commit the server would continue on. Reviewed-by: Tomas Mraz <[email protected]> (Merged from #14749)
Reviewed-by: Tomas Mraz <[email protected]> (Merged from #14749)
TLS 1.3 allows for the "psk_ke" and "psk_dhe_ke" key-exchange modes. Only the latter mode introduces a new ephemeral (Diffie-Hellman) key exchange, with the PSK being the only key material used in the former case. It's a compliance requirement of RFC 8446 that the server MUST NOT send a KeyShareEntry when using the "psk_ke" mode, but prior to this commit we would send a key-share based solely on whether the client sent one. This bug goes unnoticed in our internal test suite since openssl communicating with openssl can never negotiate the PSK-only key-exchange mode. However, we should still be compliant with the spec, so check whether the DHE mode was offered and don't send a key-share if it wasn't. Reviewed-by: Tomas Mraz <[email protected]> (Merged from #14749)
One of the scenarios constructed in these tests was erroneously producing successful handshakes until the previous commits, but should have been failing. Update our expected behavior to match the specification requirements, and adjust the commentary slightly for a test case relevant for the other preceding commit. Reviewed-by: Tomas Mraz <[email protected]> (Merged from #14749)
It's a MUST-level requirement that if the client sends a pre_shared_key extension not accompanied by a psk_key_exchange_modes extension, the server must abort the handshake. Prior to this commit the server would continue on. Reviewed-by: Tomas Mraz <[email protected]> (Merged from #14749) (cherry picked from commit efe0f31)
TLS 1.3 allows for the "psk_ke" and "psk_dhe_ke" key-exchange modes. Only the latter mode introduces a new ephemeral (Diffie-Hellman) key exchange, with the PSK being the only key material used in the former case. It's a compliance requirement of RFC 8446 that the server MUST NOT send a KeyShareEntry when using the "psk_ke" mode, but prior to this commit we would send a key-share based solely on whether the client sent one. This bug goes unnoticed in our internal test suite since openssl communicating with openssl can never negotiate the PSK-only key-exchange mode. However, we should still be compliant with the spec, so check whether the DHE mode was offered and don't send a key-share if it wasn't. Reviewed-by: Tomas Mraz <[email protected]> (Merged from #14749) (cherry picked from commit e776858)
One of the scenarios constructed in these tests was erroneously producing successful handshakes until the previous commits, but should have been failing. Update our expected behavior to match the specification requirements, and adjust the commentary slightly for a test case relevant for the other preceding commit. Reviewed-by: Tomas Mraz <[email protected]> (Merged from #14749) (cherry picked from commit 80c2561)
|
Merged to master, thanks for the review. |
It's a MUST-level requirement that if the client sends a pre_shared_key extension not accompanied by a psk_key_exchange_modes extension, the server must abort the handshake. Prior to this commit the server would continue on. Reviewed-by: Tomas Mraz <[email protected]> (Merged from openssl#14749)
Reviewed-by: Tomas Mraz <[email protected]> (Merged from openssl#14749)
TLS 1.3 allows for the "psk_ke" and "psk_dhe_ke" key-exchange modes. Only the latter mode introduces a new ephemeral (Diffie-Hellman) key exchange, with the PSK being the only key material used in the former case. It's a compliance requirement of RFC 8446 that the server MUST NOT send a KeyShareEntry when using the "psk_ke" mode, but prior to this commit we would send a key-share based solely on whether the client sent one. This bug goes unnoticed in our internal test suite since openssl communicating with openssl can never negotiate the PSK-only key-exchange mode. However, we should still be compliant with the spec, so check whether the DHE mode was offered and don't send a key-share if it wasn't. Reviewed-by: Tomas Mraz <[email protected]> (Merged from openssl#14749)
One of the scenarios constructed in these tests was erroneously producing successful handshakes until the previous commits, but should have been failing. Update our expected behavior to match the specification requirements, and adjust the commentary slightly for a test case relevant for the other preceding commit. Reviewed-by: Tomas Mraz <[email protected]> (Merged from openssl#14749)
While testing some other work I ran across a couple places where we were needlessly out of compliance with RFC 8446.
At the end of https://tools.ietf.org/html/rfc8446#section-4.2.8 :
Prior to these changes, the server would send a KeyShareEntry when the
"psk_ke" mode was used, if the client had actually sent an "key_share".
OpenSSL speaking to OpenSSL will never negotiate the "psk_ke" mode,
since we prefer to have the ephemeral key exchange.
In https://tools.ietf.org/html/rfc8446#section-4.2.9 :
We were not detecting this condition. In practice it seems that the server
would proceed without sending a key share; an openssl client would typically
fail at this point, though any client sending such a malformed ClientHello
might well behave unexpectedly in other ways.