I'm trying to bring an old TLS 1.0 implementation (that I did not write) up to date to speak TLS 1.2.
As a first step I integrated the TLS 1.1 change of putting the plaintext initialization vector in the record. That was no problem. It seemed to work well enough that I could read https://example.com
in TLS 1.1, as well as SSL Labs viewMyClient.html.
Then I adapted to the TLS 1.2 change of the pseudorandom function to (for most practical purposes) P_SHA256 instead of the (more complex and bizarre) half and half MD5/SHA1 rigamarole. I did it wrong the first time and got an invalid MAC error, but it was more or less a typo on my part and I fixed it. Then the invalid MAC error went away.
But despite that, after sending the ClientKeyExchange->ChangeCipherSpec messages, I'm getting a "Decrypt Error" back from the server(s) (same Alert regardless, https://google.com
or anything I try). I gather the ChangeCipherSpec message is encrypting just one byte, putting it into a message with padding and the MAC, etc.
If I tweak the MAC randomly by one byte, it goes back to complaining about invalid MAC. What confuses me is that the MAC itself is encrypted as part of GenericBlockCipher:
struct {
opaque IV[SecurityParameters.record_iv_length];
block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length]; // <-- server reads this fine!
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length;
};
} GenericBlockCipher;
UPDATE: FWIW, I've added a Wireshark log of the failing 1.2 read of
https://example.com
, as well as a log of a functioning 1.1 session running what is the same code, not counting the P_SHA256 MAC update:http://hostilefork.com/media/shared/stackoverflow/example-com-tls-1.2.pcapng (fails) http://hostilefork.com/media/shared/stackoverflow/example-com-tls-1.1.pcapng (succeeds)
So, what exactly is it having trouble decrypting? The padding seems correct, as if add or subtract 1 to the byte I get an invalid MAC error. (The spec says "The receiver MUST check this padding and MUST use the bad_record_mac alert to indicate padding errors.", so that is to be expected.) If I corrupt the client-iv in the message from what I used to encrypt (just put a bad byte in the transmitted version), doing so also gives me Bad Record MAC. I'd expect that to wreck the decryption also.
So I'm puzzled on what could be the problem:
- The server demonstrates discernment of valid MAC vs. not, so it must have decrypted. How's it getting the right MAC -and- having a decrypt error?
- Cipher suite is an old one (TLS_RSA_WITH_AES_256_CBC_SHA) but I'm just tackling one issue at a time...and if I'm not mistaken, that shouldn't matter.
Does anyone with relevant experience have a theory of how TLS 1.2 could throw a wrench into code that otherwise works in TLS 1.1? (Perhaps someone who's done a similar updating to a codebase, and had to change more than the two things I've changed to get it working?) Am I missing another crucial technical change? What recourse do I have to find out what is making the server unhappy?
CBC
mode, incorrectIV
only cause incorrect decryption on 1st block. it is true that it is strange that it is working in 1.1 but not 1.2, but without debugging, I can only think of these 2 problem. – Havenot