org.panlab.tgw.restclient.PtmInfoParser.java Source code

Java tutorial

Introduction

Here is the source code for org.panlab.tgw.restclient.PtmInfoParser.java

Source

/**
 *  Copyright 2010, Konstantinos Koutsopoulos (k.koutsopoulos@yahoo.gr), Nikos Mouratidis (nmouratid@teemail.gr)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.panlab.tgw.restclient;

import org.panlab.tgw.App;
import org.panlab.tgw.util.XMLElement;
import org.panlab.tgw.util.XMLUtil;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import javax.security.cert.X509Certificate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.netbeans.xml.schema.repo.PtmDocument.Ptm;

/**
 *
 * @author kkoutso
 */
public class PtmInfoParser {

    private static Log log = LogFactory.getLog(PtmInfoParser.class);
    private static String ptmToCheck = null;

    private static byte[] getClientHello() {
        long time = System.currentTimeMillis();
        time /= 1000;
        //System.out.println(time + " ");
        int index = 0;
        String[] suite = ((SSLSocketFactory) SSLSocketFactory.getDefault()).getDefaultCipherSuites();
        for (int j = 0; j < suite.length; j++) {

            if (suites.containsKey(suite[j])) {
                index++;
                //System.out.println(suite[j]);
            }
        }
        int tempIndex = 0;
        byte[] suiteBytes = new byte[index * 3];
        for (int j = 0; j < suite.length; j++) {
            //log.info(j+": ");
            if (suites.containsKey(suite[j])) {
                //log.info(suite[j]);
                suiteBytes[3 * (index - tempIndex) - 3] = suites.get(suite[j])[0];
                suiteBytes[3 * (index - tempIndex) - 2] = suites.get(suite[j])[1];
                suiteBytes[3 * (index - tempIndex) - 1] = suites.get(suite[j])[2];
                tempIndex++;
            }
        }

        byte[] clientHello = { (byte) 0x80, (byte) (41 + suiteBytes.length), //Length
                0x01, //Message Type: Client Hello
                0x03, 0x01, //Version TLSv1.0
                (byte) (suiteBytes.length / 256), (byte) (suiteBytes.length % 256), //Cipher Spec Length
                0x00, 0x00, //Session ID Length
                0x00, 0x20, //Challenge Length
        };
        byte[] clientRandom = { (byte) (time / (256 * 256 * 256)),
                (byte) ((time % (256 * 256 * 256)) / (256 * 256)),
                (byte) (((time % (256 * 256 * 256)) % (256 * 256)) / 256), (byte) (time % 256), 0x00, 0x01, 0x02,
                0x03, 0x04, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x01, 0x02, 0x03,
                0x04, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x01, 0x0f };

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(clientHello, 0, clientHello.length);
        baos.write(suiteBytes, 0, suiteBytes.length);
        baos.write(clientRandom, 0, clientRandom.length);

        return baos.toByteArray();
    }

    private static Hashtable<String, byte[]> suites = new Hashtable<String, byte[]>();

    static {
        suites.put("TLS_RSA_WITH_NULL_MD5", new byte[] { 0x00, 0x00, 0x01 });
        suites.put("TLS_RSA_WITH_NULL_SHA", new byte[] { 0x00, 0x00, 0x02 });
        suites.put("TLS_RSA_WITH_NULL_SHA256", new byte[] { 0x00, 0x00, 0x3B });
        suites.put("TLS_RSA_WITH_RC4_128_MD5", new byte[] { 0x00, 0x00, 0x04 });
        suites.put("TLS_RSA_WITH_RC4_128_SHA", new byte[] { 0x00, 0x00, 0x05 });
        suites.put("TLS_RSA_WITH_3DES_EDE_CBC_SHA", new byte[] { 0x00, 0x00, 0x0A });
        suites.put("TLS_RSA_WITH_AES_128_CBC_SHA", new byte[] { 0x00, 0x00, 0x2F });
        suites.put("TLS_RSA_WITH_AES_256_CBC_SHA", new byte[] { 0x00, 0x00, 0x35 });
        suites.put("TLS_RSA_WITH_AES_128_CBC_SHA256", new byte[] { 0x00, 0x00, 0x3C });
        suites.put("TLS_RSA_WITH_AES_256_CBC_SHA256", new byte[] { 0x00, 0x00, 0x3D });
        suites.put("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", new byte[] { 0x00, 0x00, 0x0D });
        suites.put("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", new byte[] { 0x00, 0x00, 0x10 });
        suites.put("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", new byte[] { 0x00, 0x00, 0x13 });
        suites.put("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", new byte[] { 0x00, 0x00, 0x16 });
        suites.put("TLS_DH_DSS_WITH_AES_128_CBC_SHA", new byte[] { 0x00, 0x00, 0x30 });
        suites.put("TLS_DH_RSA_WITH_AES_128_CBC_SHA", new byte[] { 0x00, 0x00, 0x31 });
        suites.put("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", new byte[] { 0x00, 0x00, 0x32 });
        suites.put("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", new byte[] { 0x00, 0x00, 0x33 });
        suites.put("TLS_DH_DSS_WITH_AES_256_CBC_SHA", new byte[] { 0x00, 0x00, 0x36 });
        suites.put("TLS_DH_RSA_WITH_AES_256_CBC_SHA", new byte[] { 0x00, 0x00, 0x37 });
        suites.put("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", new byte[] { 0x00, 0x00, 0x38 });
        suites.put("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", new byte[] { 0x00, 0x00, 0x39 });
        suites.put("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", new byte[] { 0x00, 0x00, 0x3E });
        suites.put("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", new byte[] { 0x00, 0x00, 0x3F });
        suites.put("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", new byte[] { 0x00, 0x00, 0x40 });
        suites.put("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", new byte[] { 0x00, 0x00, 0x67 });
        suites.put("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", new byte[] { 0x00, 0x00, 0x68 });
        suites.put("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", new byte[] { 0x00, 0x00, 0x69 });
        suites.put("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", new byte[] { 0x00, 0x00, 0x6A });
        suites.put("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", new byte[] { 0x00, 0x00, 0x6B });
        suites.put("TLS_DH_anon_WITH_RC4_128_MD5", new byte[] { 0x00, 0x00, 0x18 });
        suites.put("TLS_DH_anon_WITH_3DES_EDE_CBC_SHA", new byte[] { 0x00, 0x00, 0x1B });
        suites.put("TLS_DH_anon_WITH_AES_128_CBC_SHA", new byte[] { 0x00, 0x00, 0x34 });
        suites.put("TLS_DH_anon_WITH_AES_256_CBC_SHA", new byte[] { 0x00, 0x00, 0x3A });
        suites.put("TLS_DH_anon_WITH_AES_128_CBC_SHA256", new byte[] { 0x00, 0x00, 0x6C });
        suites.put("TLS_DH_anon_WITH_AES_256_CBC_SHA256", new byte[] { 0x00, 0x00, 0x6D });
    }

    private static void getPTMCertificate(String alias, URL url) {
        if (App.ptm_indexes.containsKey(alias))
            return;
        System.out.println("Trying " + alias);

        try {

            Socket socket = new Socket(url.getHost(), url.getPort());

            OutputStream os = socket.getOutputStream();
            os.write(getClientHello());
            os.flush();
            os.flush();

            InputStream is = socket.getInputStream();

            byte[] buffer = new byte[2000];
            int length = 0;
            int tries = 0;
            while (true) {
                length += is.read(buffer, length, buffer.length - length);
                if (length > 0 && tries == 0) {
                    tries++;
                    if (buffer[0] == 0x16) {
                        log.info("TLSv1 Handshake");
                        log.info("Version: " + getText(buffer, 1, 2));
                        log.info("Length: " + getInt(buffer, 3, 2));
                        byte[] tmp = new byte[getInt(buffer, 3, 2) + 5];
                        System.arraycopy(buffer, 0, tmp, 0, length);
                        buffer = tmp;
                    }
                }
                //log.info("Length: "+length);
                if (buffer.length == length) {
                    break;
                }
            }
            //log.info("Length: "+length);
            int index = 0;
            if ((index = locateServerCertificate(buffer)) > 0) {
                log.info("Certificates Section Located at: " + index);
                length = getInt(buffer, index + 1, 3);
                log.info("Certificates length: " + length);
                length = getInt(buffer, index + 7, 3);
                log.info("First Certificate length: " + length);
                //log.info(getText(buffer, index+10, length));

                byte[] cert = new byte[length];
                System.arraycopy(buffer, index + 10, cert, 0, length);

                X509Certificate x509 = X509Certificate.getInstance(cert);
                log.info(x509.getSubjectDN().toString().replace(", ", ","));
                processCertificate(alias, x509, url);

            }
        } catch (Exception error) {
            log.error(error.getMessage());
        }

    }

    public static void refreshPTMs() {
        try {
            Ptm ptm[] = RepoAdapter.getPtms();
            for (int i = 0; i < ptm.length; i++) {
                {
                    if (ptmToCheck == null || ptmToCheck.equalsIgnoreCase(ptm[i].getCommonName())) {
                        log.info(ptm[i].getCommonName() + " " + ptm[i].getUrl());
                        URL url = new URL(ptm[i].getUrl());
                        getPTMCertificate(ptm[i].getCommonName(), url);
                    }
                }
            }

        } catch (Exception error) {
            error.printStackTrace();
        }
    }

    public static void main(String args[]) {
        try {
            if (args != null && args.length > 0)
                ptmToCheck = args[0];
            refreshPTMs();

        } catch (Exception error) {
            log.error(error.getMessage());
        }
    }

    private static String getText(byte[] array, int start, int length) {
        int i;
        String str = "0x", tmp;
        for (i = start; i < start + length; i++) {
            tmp = Integer.toHexString(array[i]);
            str += tmp.length() == 2 ? tmp : (tmp.length() == 1 ? "0" + tmp : tmp.substring(6));
        }
        return str;
    }

    private static int getInt(byte[] buffer, int start, int length) {
        int result = 0;
        int tmp;
        for (int j = start; j < start + length; j++) {
            if (buffer[j] < 0) {
                tmp = 256 + buffer[j];
            } else {
                tmp = buffer[j];
            }

            result += (int) (tmp * Math.pow(256, start + length - 1 - j));
        }
        return result;
    }

    private static int locateServerCertificate(byte[] buffer) {
        int index = 5;
        while (buffer[index] != 0x0b) {
            index += 4 + getInt(buffer, index + 1, 3);
            if (index > buffer.length) {
                return -1;
            }
            log.info("" + index);
        }
        return index;

    }

    private static void processCertificate(String alias, X509Certificate x509, URL url) {
        try {
            String store = System.getProperty("javax.net.ssl.trustStore");
            String password = System.getProperty("javax.net.ssl.trustStorePassword");

            KeyStore keystore = KeyStore.getInstance("JKS");
            keystore.load(new FileInputStream(store), password.toCharArray());

            Enumeration<String> en = keystore.aliases();
            while (en.hasMoreElements()) {
                log.info(en.nextElement());
            }

            if (!keystore.containsAlias(alias)) {
                ByteArrayInputStream bais = new ByteArrayInputStream(x509.getEncoded());
                Certificate cert = CertificateFactory.getInstance("x509").generateCertificate(bais);
                keystore.setCertificateEntry(alias, cert);

                storeNewPTM(alias, url, x509.getSubjectDN().toString().replace(", ", ","));

                en = keystore.aliases();
                while (en.hasMoreElements()) {
                    log.info(en.nextElement());
                }
                keystore.store(new FileOutputStream(store), password.toCharArray());

                TrustManagerFactory.getInstance("PKIX").init(keystore);
            }

        } catch (Exception error) {
            log.error(error.getMessage());
        }
    }

    private static void storeNewPTM(String alias, URL url, String dn) {
        try {

            File file = new File("conf.xml");
            String content;
            if (file.exists()) {
                FileInputStream fis = new FileInputStream(file);
                int length = fis.available();
                byte bArray[] = new byte[length];
                fis.read(bArray);
                fis.close();
                content = new String(bArray);
            } else
                content = "<ptms></ptms>";

            Object objs[] = XMLUtil.getElements(content);
            FileOutputStream fos = new FileOutputStream("conf.xml");

            fos.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".getBytes());
            fos.write("<ptms>\n".getBytes());

            if (objs != null) {
                for (int i = 0; i < objs.length; i++) {
                    XMLElement element = (XMLElement) (objs[i]);
                    fos.write((element.toString() + "\n").getBytes());
                }
            }
            XMLElement elem = new XMLElement(alias, "cert", "\"" + dn + "\"", url.toString());
            fos.write((elem.toString() + "\n").getBytes());
            fos.write("</ptms>\n".getBytes());
            fos.close();

        } catch (Exception error) {
            log.error(error.getMessage());
        }
    }
}