scapy icon indicating copy to clipboard operation
scapy copied to clipboard

In TLSClientKeyExchange elliptic curve exchange keys include the length byte

Open wasmachensachen98 opened this issue 1 year ago • 2 comments

Brief description

When defining an TLSClientKeyExchange object in the exchangekeys field the length byte is included, although its named "exchkeys"

Scapy version

2.6.0rc1

Python version

3.10.12

Operating system

Ubuntu 22.04.2 LTS

Additional environment information

No response

How to reproduce

clientkeyexchange_bytes = bytes.fromhex(
"100000424104b7378d5a30c8e2e24e58b9b43fae9ec7eae275b04e4e98e6607d937870e375b56f4053e412f5f1d26e9a04c2ffe1821bfbf9ac0b590cc3a337238fb45bd53c0d"
)
tls_client_key_exchange = TLSClientKeyExchange(clientkeyexchange_bytes)
print(tls_client_key_exchange.exchkeys.load.hex())

Actual result

4104b7378d5a30c8e2e24e58b9b43fae9ec7eae275b04e4e98e6607d937870e375b56f4053e412f5f1d26e9a04c2ffe1821bfbf9ac0b590cc3a337238fb45bd53c0d

Expected result

04b7378d5a30c8e2e24e58b9b43fae9ec7eae275b04e4e98e6607d937870e375b56f4053e412f5f1d26e9a04c2ffe1821bfbf9ac0b590cc3a337238fb45bd53c0d The first byte differs

Related resources

No response

wasmachensachen98 avatar Jun 12 '24 08:06 wasmachensachen98

I don't really see why you would be expecting this result. Can you share a pcap, wireshark result or something more explicit?

gpotter2 avatar Jun 15 '24 14:06 gpotter2

The first byte is just the length byte. If you for example try to derive the keys normally it shouldnt be in there. I mean normally as a developer you could just ignore the first length

byte so it isn't really unavoidable to fix this. So you'd need to do this:

EllipticCurvePublicKey.from_encoded_point(curve_func, client_key_exchange.exchkeys.load[1:])

I'll include the wireshark logs. This is the code for the keyexchange:

my_key_exchange = bytes.fromhex('10000042410477ad56d41fe2e9df347001f3e1f9299066b2c78770f5274a28654d1cf6f45e62a67872a37444e72362118332520c8d435cbf70fce701af100028856b9d72ea39')
tls_my_key_exchange = TLSClientKeyExchange(my_key_exchange)
print(tls_my_key_exchange.exchkeys.load.hex())

This would return

410477ad56d41fe2e9df347001f3e1f9299066b2c78770f5274a28654d1cf6f45e62a67872a37444e72362118332520c8d435cbf70fce701af100028856b9d72ea39

As you can see in the wireshark logs: In the client key exchange and EC Diffie-Hellman Client Params the pubkey is:

0477ad56d41fe2e9df347001f3e1f9299066b2c78770f5274a28654d1cf6f45e62a67872a37444e72362118332520c8d435cbf70fce701af100028856b9d72ea39

The first byte 41 is the length in hex (65 bytes length key). Theoretically you could include the length byte (maybe in a separate field?) Technically it is part in the client params (but not part of the publickey) so I'm not exactly sure if you'd consider this a bug.

Sorry for the late response and Regards test_exchange_keys.zip

wasmachensachen98 avatar Jun 18 '24 08:06 wasmachensachen98

That's expected, that's how our implementation sticks to the spec.

You'll notice there isn't a 'len' field in the spec: https://datatracker.ietf.org/doc/html/rfc5246#appendix-A.4.3

In your case, you'd parse it via:

clientkeyexchange_bytes = bytes.fromhex("100000424104b7378d5a30c8e2e24e58b9b43fae9ec7eae275b04e4e98e6607d937870e375b56f4053e412f5f1d26e9a04c2ffe1821bfbf9ac0b590cc3a337238fb45bd53c0d")
tls_client_key_exchange = TLSClientKeyExchange(clientkeyexchange_bytes)
ClientECDiffieHellmanPublic(tls_client_key_exchange.exchkeys.load)

I don't know how you're parsing those blobs, but remember that you can set conf.tls_session_enable = True to have Scapy properly remember how to parse those things.

gpotter2 avatar Jul 14 '24 18:07 gpotter2