`
lippeng
  • 浏览: 450719 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

在SSL握手之前,拿到服务端的证书

    博客分类:
  • Life
阅读更多

在SSL握手时,客户端需要知道服务端的证书,如果证书必须先存在客户端的KeyStore中,那挺麻烦的!

 

在SSL握手过程中,服务端的确会把证书发给客户端,客户端肯定能拿到!

开始一直想着,一次握手,即拿到证书,又用这个证书来握手,建立连接,后来发现几乎不可行!

 

决定第一次握手时,先把证书拿到,再进行第二次SSL正式握手!用WireShark来看,Chrome访问HTTPS的站点也是这样做的!

 

不废话,直接上可用的代码:

 

import org.apache.http.conn.ssl.SSLContexts;

import javax.net.ssl.*;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * God Bless You!
 * Author: Li Pengpeng
 * Date: 2014-11-05
 */
public class CertUtil {
    /**
     * 目的是加载 HTTPS服务器提供的证书(含公钥)
     * @param keyStore keyStore
     * @param host host
     * @param port port
     * @throws Exception
     */
    public static void checkTrustKey(KeyStore keyStore, String host, int port) throws Exception {
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);
        X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
        SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);

        SSLContext context = SSLContexts.custom().useTLS().loadTrustMaterial(keyStore).build();
        context.init(null, new TrustManager[]{tm}, null);

        SSLSocketFactory factory = context.getSocketFactory();
        SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
        socket.setSoTimeout(10000);
        try {
            socket.startHandshake();
            socket.close();
            // handshake success, need not set Cert
        } catch (SSLException e) {
            X509Certificate[] chain = tm.chain;
            if (chain == null || chain.length == 0) {
                throw e;
            }

            // handshake fail, set Cert
            for (X509Certificate cert : chain) {
                keyStore.setCertificateEntry(host + "_" + cert.getSerialNumber(), cert);
            }
        }
    }

    private static class SavingTrustManager implements X509TrustManager {
        private final X509TrustManager tm;
        private X509Certificate[] chain;

        SavingTrustManager(X509TrustManager tm) {
            this.tm = tm;
        }

        public X509Certificate[] getAcceptedIssuers() {
            throw new UnsupportedOperationException();
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            throw new UnsupportedOperationException();
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            this.chain = chain;
            tm.checkServerTrusted(chain, authType);
        }
    }
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics