duyojiぶろぐ

技術系ときどき日常系

SSLExeptionが出た時の対処法

原因はおそらく自己署名証明かも(じゃないかも)

とりあえずSSLで接続した時にエラーが起きたのでいろいろ
対処法を探していたら解決出来そうなソースコードを見つけたから
今後も使う場面が出てくるかもしれないのでメモとしてコードを記述

import java.security.KeyStore;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;


public class SSLHttpClient {
 
    HttpClient httpclient = new DefaultHttpClient();
    HttpContext httpcontext = new BasicHttpContext();
    StringBuilder sb;
 
    SSLHttpClient(StringBuilder _sb) throws Exception
    {
        sb = _sb;
 
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);
        SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        Scheme https = new Scheme("https", sf, 443);
        httpclient.getConnectionManager().getSchemeRegistry().register(https);
 
        httpcontext.setAttribute(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
        httpcontext.setAttribute(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
        httpcontext.setAttribute(CoreProtocolPNames.HTTP_CONTENT_CHARSET, HTTP.UTF_8);
    }
 
    SSLHttpClient test_get(String url) throws Exception
    {
        HttpGet httpget = new HttpGet(url);
        HttpResponse response = httpclient.execute(httpget, httpcontext);
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            sb.append(EntityUtils.toString(entity));
        }
        return this;
    }
}
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
 
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
 
import org.apache.http.conn.ssl.SSLSocketFactory;
 
public class MySSLSocketFactory extends SSLSocketFactory {
 
    SSLContext sslContext = SSLContext.getInstance("TLS");
 
    public MySSLSocketFactory(KeyStore truststore)
            throws NoSuchAlgorithmException, KeyManagementException,
            KeyStoreException, UnrecoverableKeyException {
        super(truststore);
        
        // 自己署名証明書を受け付けるカスタムSSLContextの準備
        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain,
                    String authType) throws CertificateException {
            }
 
            public void checkServerTrusted(X509Certificate[] chain,
                    String authType) throws CertificateException {
            }
 
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        sslContext.init(null, new TrustManager[] { tm }, null);
    }
 
    @Override
    public Socket createSocket(Socket socket, String host, int port,
            boolean autoClose) throws IOException, UnknownHostException {
        // カスタムSSLContext経由で生成したSSLソケットを返す。
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }
 
    @Override
    public Socket createSocket() throws IOException {
        // カスタムSSLContext経由で生成したSSLソケットを返す。
        return sslContext.getSocketFactory().createSocket();
    }
}
private String testHttpClient(String req_url){
        StringBuilder sb = new StringBuilder();
        String jsonString = null;
        try {
            SSLHttpClient testHttpClient = new SSLHttpClient(sb).test_get(req_url);
            jsonString = new String(testHttpClient.sb);
            return jsonString;
        } catch (Throwable t) {
            Log.e("Main", "testHttpClient", t);
            return null;
        }
}

private void hoge(){
   JSONObject json = new JSONObject(testHttpClient(req_url));
}


今回はJSONをAPIを叩いてJSONを取得したかったのでJSONObjectに変換して
そこから使うデータを取得しました。

こんな感じでやれば自己署名SSLに対処できるっぽいけどちゃんとソースコード
理解していないので間違っているかもしれないので、うまく行かない場合は
ごめんなさい。


参考URLは以下のURLでそのままコピペして欲しいデータはJSON形式だったので
そこだけ手を加えました。
http://www.glamenv-septzen.net/view/981