Mamoon Ahmed
Mamoon Ahmed

Reputation: 133

tls 1.2 strange cipher suites

I am developing an application i java which will implement a TLS protocol. As i have started implementing it recently. while developing a Record Protocol implementation of type handshake, i got strange cipher suites from google chrome and mozilla firefox. As this document says, in a handshake protocol there is type, handshake length, version , random , session id length , session id, cipher suite length , cipher suites .......

I am getting all the fields correct ( before cipher suites ) but on the cipher suites i am getting strange values from google chrome and firefox.

Here is my code that accepts the connection on port 4040.

   package server;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.*;
import java.security.KeyStore;
import java.security.SecureRandom;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class Server extends ServerSocket {
    public Server() throws IOException {
        super();
        // TODO Auto-generated constructor stub
    }
    public static void main(String args[]) 
    {
        System.setProperty("java.net.ssl.trustStore", "mam.store");
        System.setProperty("java.net.ssl.keyStorePassword", "mamoon");
        try {
            /*KeyStore ks  = KeyStore.getInstance("JKS");
            InputStream in = new FileInputStream("/Users/Ahmed/Desktop/mam.store");
            ks.load(in, "mamoon".toCharArray());
            in.close();
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(ks,"mamoon".toCharArray());
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(ks);
            SSLContext con = SSLContext.getInstance("TLSv1.2");
            con.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

            SSLServerSocket socket = (SSLServerSocket)con.getServerSocketFactory().createServerSocket(4040);
            */
            ServerSocket socket = new ServerSocket(4040);
            System.out.println("Server is up.");

            Socket s = socket.accept();
            PrintWriter w = new PrintWriter(s.getOutputStream());
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream(),"ISO-8859-1"));
            String line;
            String packet = "";
            int l=0;
            while((line = br.readLine()) != null)
            {
                packet += line;
                System.out.println(line.length());
                if(packet.length() >= 100)
                {
                for(char c:packet.toCharArray())
                    System.out.print((int)c + "   ");
                System.out.println();
                new TLS(packet);
                break;
                }
            }
            System.out.println(l);
            //w.write("<html><body>hello world</body> </html>");
            //s.close();
            socket.close();

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

And here is the class that decodes the TLS packet.

package server;

import java.math.BigInteger;
import java.nio.ByteBuffer;

public class TLS {
    String start = (char)22 + "" + (char)3;
    float version;
    int packetLength,handshakeLength,sessionIdLength;
    String random = "",sessionId = "";
    String message;
    String packetType,encryption;
    int cipherSuitsLength;
    int cipherSuitesId[];

    TLS(String packet) throws Exception
    {
        if(packet.startsWith(start))
        {
            version = Float.parseFloat((int)packet.charAt(1) + "."+(int)packet.charAt(2));
            packetLength = new BigInteger(new byte[]{(byte)packet.charAt(3),(byte)packet.charAt(4)}).intValue();
            System.out.println(packetLength);
                    //(byte)packet.charAt(3) << 8 | ((byte)packet.charAt(4) & 0xFF);
            if((int)packet.charAt(5) == 1)
                packetType = "Client Hello";
            else if((int)packet.charAt(5) == 2)
                packetType = "Server Hello";
            else if((int)packet.charAt(5) == 11)
                packetType = "Certificate";
            else if((int)packet.charAt(5) == 12)
                packetType = "Server Key Exchange";
            else if((int)packet.charAt(5) == 13)
                packetType = "Certificate Request";
            else if((int)packet.charAt(5) == 14)
                packetType = "Server Done";
            else if((int)packet.charAt(5) == 15)
                packetType = "Certificate Verify";
            else if((int)packet.charAt(5) == 16)
                packetType = "Client Key Exchange";
            else if((int)packet.charAt(5) == 20)
                packetType = "Finished";
            handshakeLength = new BigInteger(new byte[] {(byte)packet.charAt(6) , (byte)packet.charAt(7), (byte)packet.charAt(8)}).intValue(); 
                    //(byte)packet.charAt(7) << 16 | ((byte)packet.charAt(8) << 8 & 0xFF) | ((byte));
            System.out.println(handshakeLength);
            version = Float.parseFloat((int)packet.charAt(9) + "."+(int)packet.charAt(10));
            System.out.println(version);
            for(int a=11;a<11+32;a++)
            {   random += packet.charAt(a);
            System.out.println((int)packet.charAt(a));
            }
            System.out.println(random.length());
            sessionIdLength = (int)packet.charAt(43);
            System.out.println(sessionIdLength);
            int c = 44+sessionIdLength;
            for(int a=44;a<44+sessionIdLength;a++)
            {
                sessionId += packet.charAt(a);
            }
            System.out.println(sessionId);
            cipherSuitsLength = new BigInteger(new byte[] {(byte)packet.charAt(c),(byte) packet.charAt(c+1)}).intValue();
            System.out.println(cipherSuitsLength);
            cipherSuitesId = new int[cipherSuitsLength/2];
            c+=2;
            for(int a=0;a<cipherSuitesId.length;a++)
            {
                cipherSuitesId[a] = new BigInteger(new byte[]{(byte)packet.charAt(c),(byte)packet.charAt(c+1)}).intValue();
                c+=2;
                System.out.println(cipherSuitesId[a]);
            }
        }
        else
            throw new Exception("Not a TLS packet.");
    }
    public void processTLS(String packet)
    {

    }
}

the output of my code is

Server is up.
51
19
14
61
22   3   1   0   168   1   0   0   164   3   3   57   220   109   126   106   16   106   75   232   65   206   177   89   90   5   241   76   167   135   150   97   51   67   213   33   60   209   73   137   119   119   80   0   0   30   192   43   192   47   192   192   9   192   19   192   20   192   7   192   17   0   51   0   57   0   47   0   53   0   0   5   0   4   1   0   0   93   255   1   0   1   0   0   0   8   0   6   0   23   0   24   0   25   0   11   0   2   1   0   0   35   0   0   51   116   0   0   0   16   0   23   0   21   2   104   50   8   115   112   100   121   47   51   46   49   8   104   116   116   112   47   49   46   49   0   5   0   5   1   0   0   0   0   0   
168
164
3.3
57
220
109
126
106
16
106
75
232
65
206
177
89
90
5
241
76
167
135
150
97
51
67
213
33
60
209
73
137
119
119
80
32
0

30
-16341
-16337
-16192
2496
5056
5312
1984
4352
13056
14592
12032
13568
5
4
256
0

as you can see, cipher suites length is 0 30 which means 15 cipher suites received. but i am sure there is no cipher suite id like 192 43 and so on. Please help me with this.

Upvotes: 0

Views: 840

Answers (3)

Mamoon Ahmed
Mamoon Ahmed

Reputation: 133

And yes there is another problem, third cipher suit id is 192 192 but there no such cipher suite exists. that is because of br.readLine() statement. it will skip the character 10 and consider it as a line break but its actually information. using byte array to read data is the right way.

DataInputStream s = new DataInputStream(socket.getInputStream());
byte data[] = new byte[s.available()];
s.readFully(data);

This implementation will give the actual data.

Upvotes: 0

Mamoon Ahmed
Mamoon Ahmed

Reputation: 133

192 43 is the id for TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.

Wireshark packet capture. TLS 1.2 client hello packet.

Here is the complete list of cipher suite ids.

Upvotes: 1

user207421
user207421

Reputation: 310903

You're parsing every packet as though it contains cipher suites. They don't.

You've also started off completely on the wrong foot. TLS records are binary, and String is not a container for binary data.

And you're really never going to get anywhere with code structured like this. Quit while you're ahead, or have a look at how real implementations are coded. Nothing like this whatsoever.

Upvotes: 1

Related Questions