dtls.c: Do not generate Decrypt Alert on unexpected Epoch#85
dtls.c: Do not generate Decrypt Alert on unexpected Epoch#85mrdeep1 wants to merge 1 commit intoeclipse-tinydtls:developfrom
Conversation
cd47b8d to
01fe6cb
Compare
dtls.c
Outdated
| if ((uint16_t)(peer->handshake_params->hs_epoch + 1) == msg_epoch) { | ||
| dtls_info("Next epoch packet arrived before handshake complete\n"); | ||
| /* Just validate the packet, reporting any issues */ | ||
| decrypt_verify(peer, msg, rlen, &data); |
There was a problem hiding this comment.
I am not sure if this extra operation is a good idea. Why do you think it is necessary?
There was a problem hiding this comment.
The decrypt_verify() would otherwise not take place on finished in the new epoch following receipt of change cipher spec and throw up any errors as this packet is not buffered. I agree that subsequent decryption of application packets would fail if there is an error here, but this may not be correctly detected at this point.
There was a problem hiding this comment.
The decrypt_verify() essentially just removes the "other security parameter" slot that is used internally to store values from the last epoch (it is a noop if there are none or if values for the next epoch are available). I still wonder why it would make a difference whether this is done here or in the next call to decrypt_verify().
There was a problem hiding this comment.
|
Wouldn't suppress the MAC error (decrypt_verify()) in epochs > 0 help? |
Maybe, but I am operating at the edge of my limited DTLS knowledge here. |
|
Let me try to sum up my view: The usage of the If a FINISH passes that MAC test, but the contained For epoch 0 itself, it's hard to say, what the intention is. For some, that period is that short, that an attack is considered to be very rare. Even assuming such an attack, it would still be very difficult (up to impossible) to distinguish the right messages from that attack ones. With that, ignoring or not, the handshakes will fail in my opinion ... |
|
Understood. There are 2 issues here - packets sent in right sequence but arrive in wrong order, and deliberate sending of packets in funny order with perhaps mismanagement of message seq etc. verifying handshake order with epoch 0 along with buffering out of order epoch 0 will catch most things. The challenge is with the early arrival of epoch 1 packets while still finishing off the epoch 0 part of the handshake. Ideally these should be buffered as well, but need to be decrypted to do that based on the message seq as opposed to the packet seq which may include retries. If insufficient of the epoch 0 handshake have arrived, then the premature epoch 1 cannot be decrypted - I guess it is game over at that point unless a different strategy of buffering epoch 1 is done. bottomline is that the right answer is to fully buffer epoch 1 somehow. This PR fixes the invalid generate of decrypt alert and checks the simple case of a simple arrival reorder. |
So the My feeling is, it's not only about expecting, its about "having received and verified that FINISH". |
|
Thanks @boaks for your very good summary. I think the main rationale here is indeed to drop packets that have not been expected yet. |
|
If Turns: into (Return 0 is required in order to keep libcoap from closing the connection. ) The other topic, not to process other data, until the FINISH has not be verified yet, is something not addressed. handle_handshake_msg: seems to be wrong. If the server's flight 6 gets lost, the client will repeat flight 5, but, as far as I understand the code (without testing ;-) ) the server will not accept that flight 5 any longer. So, if this PR should Fix "don't generate that alert", then in my opinion that should be done by |
We still need to detect a new ClientHello using epoch 0, so i do not think it safe to reduce the code as you have done. If you apply your code reduction to the DTLS_ALERT_DECRYPT_ERROR should only be used as per RFC8446 (RFC5246 is similar):- and so should be generated in check_finished() as DTLS_ALERT_DECRYPT_ERROR, not DTLS_ALERT_HANDSHAKE_FAILURE. Hmm. |
Of course! But therefore:
Only, if the (record-)MAC of a FINISH is valid, then in "check_finished" report a mismatch in the "verify_data" as DTLS_ALERT_DECRYPT_ERROR (instead of DTLS_ALERT_HANDSHAKE_FAILURE). That's the "validate a Finished message" part. And for other details of the handshake, lets do that in other PRs. |
Just to mention, the record-MAC failure is the "record layer cryptographic operation failed". the "handshake cryptographic operation failed". |
|
Code pushed - needs the separate #91 to handle other Decrypt Alert cases. |
|
#91 and #92 are good to go. However, if ChangeCipherSpec and Finished arrive in the wrong order (as highlighted in #79) and the Finished is not dropped or buffered, then kicks in. So, we do need to drop the Finished (this PR - hence the need in this PR to save the handshake epoch as well) or buffer the Finished - without doing this Finish drop we get (#91 and #92 added to develop) |
Agreed, that there is more to do about the FINISH. Seems for me to be a work-around. and in |
|
I have no issues with doing the generic correct thing. I see that the draft DTLS1.3 allocates dedicated epochs to the handshake phase https://tools.ietf.org/id/draft-ietf-tls-dtls13-34.html#rfc.section.6.1 presumable to get around what we are trying to sort out here. The closest that I can find the DTL1.2 spec gets to handling Finished arriving before the rest of the epoch 0 HS messages is ... but the Finished message is in the next epoch following the ChangeCipherSpec! Hence the fix in this PR for dropping things from the next epoch. I will look to see if it is possible to sensibly buffer the Finished message, given that it may not be possible to decrypt if HS messages other than ChangeCipherSpec also arrive in the wrong order. |
|
I prepare PR #94 in order to process the records according a specific read-epoch. In the meantime, the "separated stateless client_hello epoch 0 processing" gets more and more important, to remove complexity out of the other parts. |
As per RFC5246
decrypt_error
A handshake cryptographic operation failed, including being unable
to correctly verify a signature or validate a Finished message.
This message is always fatal.
Does not cover a change in Epoch when the previous Epoch's handshakes have
not completed. Silently ignore the unexpected Epoch.
RFC6347 does not add any clarity here, other than
Implementations MUST either
discard or buffer all application data packets for the new epoch
until they have received the Finished message for that epoch.
New Epoch buffering is not currently supported, but the Finished is checked.
Signed-off-by: Jon Shallow <supjps-libcoap@jpshallow.com>
|
Superceeded by #89 |
As per RFC5246
decrypt_error
A handshake cryptographic operation failed, including being unable
to correctly verify a signature or validate a Finished message.
This message is always fatal.
Does not cover a change in Epoch when the previous Epoch's handshakes have
not completed. Silently ignore the unexpected Epoch.
RFC6347 does not add any clarity here, other than
Implementations MUST either
discard or buffer all application data packets for the new epoch
until they have received the Finished message for that epoch.
New Epoch buffering is not currently supported.
Signed-off-by: Jon Shallow supjps-libcoap@jpshallow.com