openssl: Wrong MAC calculation for certain plaintext lengths with AES128_CBC_SHA256 ciphersuites in TLS

When connecting to openssl server with a vanilla connection (i.e. no Encrypt then MAC, no Extended Master Secret) and TLS_*_AES_128_CBC_SHA256 ciphersuites, OpenSSL generates records with incorrect MAC, but only for certain sizes. The ones I’ve tested were between 1000-1024 bytes and 2000-2048 bytes (inclusive). Of those 2032-2047 and 1008-1023 (inclusive) generate incorrect MAC values.

Reproducer:

cat > make-files.py << EOF
for i in range(1000, 1025):
    with open("data-{0}.txt".format(i), "wb+") as f:
        f.write(b"A" * (i-1) + b"\n")
EOF
python3 make-files.py
openssl req -x509 -newkey rsa -keyout /tmp/localhost.key -out /tmp/localhost.crt -subj /CN=localhost -nodes -batch
openssl s_server -key /tmp/localhost.key -cert /tmp/localhost.crt -HTTP -cipher @SECLEVEL=0:AES128-SHA256

in another console:

git clone https://github.com/tomato42/tlsfuzzer
pushd tlsfuzzer
# won't be needed after https://github.com/tlsfuzzer/tlsfuzzer/pull/762 gets merged
git checkout length-testing
git clone https://github.com/tlsfuzzer/tlslite-ng .tlslite-ng
ln -s .tlslite-ng/tlslite tlslite
git clone https://github.com/tlsfuzzer/python-ecdsa .python-ecdsa
ln -s .python-ecdsa/src/ecdsa ecdsa
PYTHONPATH=. python3 scripts/test-lengths.py

(alternatively the server can be set up with either ECDHE-RSA-AES128-SHA256 or DHE-RSA-AES128-SHA256 ciphersuite and tlsfuzzer script executed with the -d option)

tlsfuzzer output:

...
length: 1008 ...
Error encountered while processing node <tlsfuzzer.expect.ExpectApplicationData object at 0x7f061e6d0cd0> (child: <tlsfuzzer.messages.AlertGenerator object at 0x7f061e6d0d00>) with last message being: None
Error while processing
Traceback (most recent call last):
  File "scripts/test-lengths.py", line 229, in main
    runner.run()
  File "/home/hkario/dev/tlsfuzzer/tlsfuzzer/runner.py", line 196, in run
    header, parser = self.state.msg_sock.\
  File "/home/hkario/dev/tlsfuzzer/tlslite/messagesocket.py", line 102, in recvMessageBlocking
    for res in self.recvMessage():
  File "/home/hkario/dev/tlsfuzzer/tlslite/messagesocket.py", line 84, in recvMessage
    for ret in self.recvRecord():
  File "/home/hkario/dev/tlsfuzzer/tlslite/recordlayer.py", line 927, in recvRecord
    data = self._decryptThenMAC(header.type, data)
  File "/home/hkario/dev/tlsfuzzer/tlslite/recordlayer.py", line 702, in _decryptThenMAC
    raise TLSBadRecordMAC()
tlslite.errors.TLSBadRecordMAC

length: 1010 ...
Error encountered while processing node <tlsfuzzer.expect.ExpectApplicationData object at 0x7f061e6d5730> (child: <tlsfuzzer.messages.AlertGenerator object at 0x7f061e6d5760>) with last message being: None
Error while processing
Traceback (most recent call last):
  File "scripts/test-lengths.py", line 229, in main
    runner.run()
  File "/home/hkario/dev/tlsfuzzer/tlsfuzzer/runner.py", line 196, in run
    header, parser = self.state.msg_sock.\
  File "/home/hkario/dev/tlsfuzzer/tlslite/messagesocket.py", line 102, in recvMessageBlocking
    for res in self.recvMessage():
  File "/home/hkario/dev/tlsfuzzer/tlslite/messagesocket.py", line 84, in recvMessage
    for ret in self.recvRecord():
  File "/home/hkario/dev/tlsfuzzer/tlslite/recordlayer.py", line 927, in recvRecord
    data = self._decryptThenMAC(header.type, data)
  File "/home/hkario/dev/tlsfuzzer/tlslite/recordlayer.py", line 702, in _decryptThenMAC
    raise TLSBadRecordMAC()
tlslite.errors.TLSBadRecordMAC
...

====================
version: 1
====================
TOTAL: 27
SKIP: 0
PASS: 11
XFAIL: 0
FAIL: 16
XPASS: 0
====================
FAILED:
        'length: 1008'
        'length: 1009'
        'length: 1010'
        'length: 1011'
        'length: 1012'
        'length: 1013'
        'length: 1014'
        'length: 1015'
        'length: 1016'
        'length: 1017'
        'length: 1018'
        'length: 1019'
        'length: 1020'
        'length: 1021'
        'length: 1022'
        'length: 1023'

While debugging it, @beldmit and me suspect the assembly aesni_cbc_sha256_enc() method.

Update: I’ve tested all lengths between 1 and 8192, and the ones that fail are: 240-255, 496-511, 752-767, etc. every 256

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 17 (16 by maintainers)

Commits related to this issue

Most upvoted comments