Welcome to mirror list, hosted at ThFree Co, Russian Federation.

HumlaSSLSocketFactory.java « net « humla « lublin « se « java « main « src - gitlab.com/quite/humla.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0a66727baad381db6e3085c6788cfdbf0dd9929d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
 * Copyright (C) 2014 Andrew Comminos
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package se.lublin.humla.net;

import android.util.Log;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class HumlaSSLSocketFactory {
    private static final String TAG = HumlaSSLSocketFactory.class.getName();

    private SSLContext mContext;
    private HumlaTrustManagerWrapper mTrustWrapper;

    public HumlaSSLSocketFactory(KeyStore keystore, String keystorePassword, String trustStorePath, String trustStorePassword, String trustStoreFormat) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException, NoSuchProviderException, IOException, CertificateException {
        mContext = SSLContext.getInstance("TLS");

        KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
        kmf.init(keystore, keystorePassword != null ? keystorePassword.toCharArray() : new char[0]);

        if(trustStorePath != null) {
            KeyStore trustStore = KeyStore.getInstance(trustStoreFormat);
            FileInputStream fis = new FileInputStream(trustStorePath);
            trustStore.load(fis, trustStorePassword.toCharArray());

            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustStore);
            mTrustWrapper = new HumlaTrustManagerWrapper((X509TrustManager) tmf.getTrustManagers()[0]);
            Log.i(TAG, "Using custom trust store " + trustStorePath + " with system trust store");
        } else {
            mTrustWrapper = new HumlaTrustManagerWrapper(null);
            Log.i(TAG, "Using system trust store");
        }

        mContext.init(kmf.getKeyManagers(), new TrustManager[] { mTrustWrapper }, null);
    }

    /**
     * Creates a new SSLSocket that runs through a SOCKS5 proxy to reach its destination.
     */
    public SSLSocket createTorSocket(String host, int port, String proxyHost, int proxyPort) throws IOException {
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(proxyHost, proxyPort));
        Socket socket = new Socket(proxy);
        socket.connect(InetSocketAddress.createUnresolved(host, port));
        return (SSLSocket) mContext.getSocketFactory().createSocket(socket, host, port, true);
    }

    public SSLSocket createSocket(String host, int port) throws IOException {
        return (SSLSocket) mContext.getSocketFactory().createSocket(InetAddress.getByName(host), port);
    }

    /**
     * Gets the certificate chain of the remote host.
     * @return The remote server's certificate chain, or null if a connection has not reached handshake yet.
     */
    public X509Certificate[] getServerChain() {
        return mTrustWrapper.getServerChain();
    }

    /**
     * Wraps around a custom trust manager and stores the certificate chains that did not validate.
     * We can then send the chain to the user for manual validation.
     */
    private static class HumlaTrustManagerWrapper implements X509TrustManager {

        private X509TrustManager mDefaultTrustManager;
        private X509TrustManager mTrustManager;
        private X509Certificate[] mServerChain;

        public HumlaTrustManagerWrapper(X509TrustManager trustManager) throws NoSuchAlgorithmException, KeyStoreException {
            TrustManagerFactory dmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            dmf.init((KeyStore) null);
            mDefaultTrustManager = (X509TrustManager) dmf.getTrustManagers()[0];
            mTrustManager = trustManager;
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            try {
                mDefaultTrustManager.checkClientTrusted(chain, authType);
            } catch (CertificateException e) {
                if(mTrustManager != null) mTrustManager.checkClientTrusted(chain, authType);
                else throw e;
            }
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            mServerChain = chain;
            try {
                mDefaultTrustManager.checkServerTrusted(chain, authType);
            } catch (CertificateException e) {
                if(mTrustManager != null) mTrustManager.checkServerTrusted(chain, authType);
                else throw e;
            }
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return mDefaultTrustManager.getAcceptedIssuers();
        }

        public X509Certificate[] getServerChain() {
            return mServerChain;
        }
    }
}