tls-attacker / TLS-Attacker

TLS-Attacker is a Java-based framework for analyzing TLS libraries. It can be used to manually test TLS clients and servers or as as a software library for more advanced tools.
Apache License 2.0
789 stars 136 forks source link

Empty KeyShareExtension in ClientHello, TLS 1.3 #153

Closed Nellta closed 1 year ago

Nellta commented 1 year ago

Hello!

I am trying to run TLS-Client.jar to connect to a server and just do a TLS 1.3 Full handshake. I am using the default tls13_conf.xml file in resources and then define my own workflow_input file like below:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workflowTrace>
    <Send>
        <messages>
            <ClientHello>
                <extensions>
                    <EllipticCurves/>
                    <SignatureAndHashAlgorithmsExtension/>
                    <SupportedVersions/>
                    <KeyShareExtension/>
                </extensions>
            </ClientHello>
        </messages>
    </Send>
    <Receive>
        <expectedMessages>
            <ServerHello>
                <extensions>
                    <KeyShareExtension>
                    </KeyShareExtension>
                    <SupportedVersions/>
                </extensions>
            </ServerHello>
            <ChangeCipherSpec/>
            <EncryptedExtensions/>
            <Certificate>
                <extensions/>
            </Certificate>
            <CertificateVerify/>
            <Finished/>
        </expectedMessages>
    </Receive>
    <Send>
        <messages>
            <ChangeCipherSpec/>
            <Finished/>
            <Application>
                <dataConfig>68656c6c6f</dataConfig> <!--"hello"-->
            </Application>
            <Alert/>
        </messages>
    </Send>
</workflowTrace>

The problem is that when I then look at the workflow_output log I see that the KeyShareExtension tag under HelloClient is empty, i.e.

.
.
.
                    <KeyShareExtension>
                        <extensionBytes>
                            <originalValue>00 33 00 02 00 00</originalValue>
                        </extensionBytes>
                        <extensionContent>
                            <originalValue>00 00</originalValue>
                        </extensionContent>
                        <extensionLength>
                            <originalValue>2</originalValue>
                        </extensionLength>
                        <extensionType>
                            <originalValue>00 33</originalValue>
                        </extensionType>
                        <keyShareListLength>
                            <originalValue>0</originalValue>
                        </keyShareListLength>
                        <keyShareListBytes>
                            <originalValue/>
                        </keyShareListBytes>
                    </KeyShareExtension>
.
.
.

Which makes the Server respond with a SERVER_HELLO(HRR) and the workflow doesn't execute as it should.

On the other hand, If I don't specify a workflow_input file and run the same command on the same server with the same config then it executes as it should and my KeyShareExtension tag is not empty when I look at the log (as defined in the config file).

I somehow managed a workaround by explicitly setting the values in KeyShareExtension by copying the values from when I ran the client with no workflow_input file:

                    <KeyShareExtension>
                        <extensionBytes>
                                <ByteArrayExplicitValueModification>
                                    <explicitValue>00 33 00 26 00 24 00 1D 00 20 B1 E8 23 6B 63 1E 19 D8 6B 28 A6 FF 4D 5F 4B 39 D4 1E DD F4 7A B7 D3 A9 57 95 06 DE C3 DA 27 2A</explicitValue>
                                </ByteArrayExplicitValueModification>
                        </extensionBytes>
                    </KeyShareExtension>

But I would really rather not have to resort to that, as that doesn't really solve my underlying problem.

Any help or suggestion with this would be greatly appreciated.

Also, It seems that when no workflow_input is given I will always get the exact same keyshare values, even if I specifically specify another parameter for -named_group, like SECP521R1 (i still get only ECDH_X25519)

ic0ns commented 1 year ago

This is related to TLS-Attacker handling of structs in the TLS-Workflowtrace. If you provide your own WorkflowTrace, TLS-Attacker tries to avoid creating its own substructures in provided messages. For example, if you define a CH message with some extensions, TLS-Attacker will not create more extensions in the ClientHello, even if you specified to do so in the config. The Keyshare entries inside of your Keyshare extension are treated just like that, meaning since you provided your own keyshare extension, TLS-Attacker assumes you wanted to have an empty one. If you add entries, you should see them aswell.

Nellta commented 1 year ago

Ok, I got it to work by just adding

                    <KeyShareExtension>
                        <keyShareList>
                            <groupConfig>SECP521R1</groupConfig>
                            <privateKey>65535</privateKey>
                        </keyShareList>
                    </KeyShareExtension>

And If I want more supported groups I can just repeat the keyShareList tag with another groupConfig, thanks!

My only remaining question is about the private key value, I can see that it is defined in the default_config.xml, which I'm guessing isn't being automatically added because I have my own WorkflowTrace like you explained. Is there any way for me to have another value or should it always be 65535?

Nellta commented 1 year ago

Either way, thanks for the solve!

ic0ns commented 1 year ago

For the private key you should be able to just choose your own value. We usually choose a small value such that the computation is fast, but not so small that it becomes obvious that we are using a small private key if FFDHE is used.

Nellta commented 1 year ago

Hmm, but if I choose any other privatekey value (2, 65555, 65534,...) I get a warning that says RecordAEADCipher -Tag invalid and that data could not be decrypted. Then the workflow doesn't execute as it should.

TESTPRIVATEKEY.txt

ic0ns commented 1 year ago

Did you only change it in the WorkflowTrace? I think that value is used to compute the public key - but the value in the config will be used for the shared secret computation. This is because when you have multiple keyshare entries with the same named group tls-attacker would not know which private key to use... This behavior is a little against the spirit of TLS-Attacker to prefer values from the context over the config. I will need to change this in the future... Can you try with the defaultKeySharePrivateKey in the config aswell?

Nellta commented 1 year ago

Yes, I only changed the value in the workflow_input file.

When I then added the the defaultkeyshareprivatekey tag with my own value to the config as well, then it worked fine!