0

A while ago I implemented a client and server using SChannel to encrypt communication. Recently I made the required switch from the SCHANNEL_CRED struct to the SCH_CREDENTIALS one so that TLS 1.3 support is provided in Windows 11. However, I encountered a situation that my code didn't originally account for and that I've resolved but can't explain.

The negotiation flow is as follows:

  • I call InitializeSecurityContext on the client and get SEC_I_CONTINUE_NEEDED with some data to send to the server (264 bytes for example). This would be the client hello, cipher suites, and key share.
  • I call AcceptSecurityContext on the server and pass in the received data, getting SEC_I_CONTINUE_NEEDED with some data to send to the client (785 bytes for example). This would be the server hello, key agreement protocol, key share, and an indication that the server has finished.
  • I call InitializeSecurityContext on the client, pass in the received data, and get SEC_E_OK with some data to send to the server (80 bytes for example). This would be the client finished indication.

At this point I call AcceptSecurityContext on the server and pass in the received data and I would expect to get SEC_E_OK and no data to pass back to the client. Both sides have indicated that they've finished and, by all accounts that I've read, the negotiation is complete. However what actually happens is:

  • I call AcceptSecurityContext on the server and pass in the received data, getting SEC_E_OK with some data to send to the client (103 bytes for example). I don't know what this message could be.

My original implementation would fail at this point because once a given side returned SEC_E_OK I didn't expect the peer to provide it with any more messages for the negotiation. The client already returned that, and yet the server has more data to send it.

  • At this point I call InitializeSecurityContext on the client with the extra data and get SEC_E_OK with no more data to send to the server. Negotiation is finally actually complete.

Can anyone explain what this additional message is?

Kemp
  • 3,467
  • 1
  • 18
  • 27

1 Answers1

1

I would have put this in as a comment, but my reputation isn't high enough. I can't tell you what the additional token represents, in terms of the TLS protocol, but I can tell you that it's not specific to TLS 1.3 (I haven't done anything with 1.3, and my implementation allows for this final token), and that it is documented.

SEC_E_OK 0x00000000L The function succeeded. The security context received from the client was accepted. If an output token was generated by the function, it must be sent to the client process.

tyotypic
  • 61
  • 1
  • 1
  • 8
  • The issue isn't that the token is generated as such, it's that the token is generated *after* the peer has already indicated that it has successfully finished the negotiation and that the descriptions I can find of TLS 1.3 negotiation don't include this additional message. With SChannel negotiating TLS 1.1 or TLS 1.2 this didn't happen, as the documentation largely implies it shouldn't. Once one side returns `SEC_E_OK` it means it has received everything it needs to and the other side no longer has anything to send. If it's expecting the peer to send more it returns `SEC_I_CONTINUE_NEEDED`. – Kemp Jul 08 '22 at 08:38
  • I already accommodate sending the additional token when `SEC_E_OK` is returned, but what I didn't accommodate was the peer then sending another token to the side that had already returned `SEC_E_OK`. Hopefully I'm being clear enough about my actual point of confusion. (For reference, my third bullet included `SEC_E_OK` being returned with a final token to send.) – Kemp Jul 08 '22 at 08:42