標籤:目錄 ict 解析 inpu 校正 gets getname col length
package com.cetcs.logreport.utils;import android.content.Context;import org.apache.http.conn.ssl.SSLSocketFactory;import java.io.BufferedInputStream;import java.io.IOException;import java.io.InputStream;import java.net.Socket;import java.net.UnknownHostException;import java.security.InvalidKeyException;import java.security.KeyStore;import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException;import java.security.SignatureException;import java.security.cert.CertificateException;import java.security.cert.CertificateFactory;import java.security.cert.X509Certificate;import javax.net.ssl.SSLContext;import javax.net.ssl.TrustManager;import javax.net.ssl.X509TrustManager;/** * * 解析伺服器憑證的類,對伺服器端的認證serv.crt進行解析,其中server.crt檔案是使用 * openssl產生的自簽名的認證* */public class SSLVerifyLogServerCrtSocketFactory extends SSLSocketFactory { private static final String TAG = "SSLTrustAllSocketFactory"; private SSLContext mCtx; private Context context; public SSLVerifyLogServerCrtSocketFactory(String crtName, KeyStore truststore, Context context) throws Throwable { super(truststore); this.context = context; try { InputStream certInputStream = new BufferedInputStream(context.getAssets().open(crtName)); CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); final X509Certificate serverCertificate = (X509Certificate) certificateFactory.generateCertificate(certInputStream); mCtx = SSLContext.getInstance("TLS"); mCtx.init(null, new TrustManager[]{new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] x509Certificates, String authType) throws CertificateException { if(x509Certificates == null){ throw new IllegalArgumentException("checkServerTrusted x509Certificates is null "); } if(x509Certificates.length < 0){ throw new IllegalArgumentException("checkServerTrusted x509Certificates is null "); } for(X509Certificate cert :x509Certificates){ cert.checkValidity(); try { cert.verify(serverCertificate.getPublicKey()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (NoSuchProviderException e) { e.printStackTrace(); } catch (SignatureException e) { e.printStackTrace(); } } } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }}, null); } catch (Exception ex) { } } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { return mCtx.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return mCtx.getSocketFactory().createSocket(); } //第一個參數是伺服器憑證的名字例如:server.crt,第二個參數是應用的上下文 public static SSLSocketFactory getSocketFactory( String crtName,Context context) { try { if(crtName == null || "".equalsIgnoreCase(crtName)){ throw new IllegalArgumentException(" getSocketFactory crtName is null"); } if(context == null){ throw new IllegalArgumentException(" getSocketFactory context is null"); } InputStream certInputStream = new BufferedInputStream(context.getAssets().open(crtName)); CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); X509Certificate serverCertificate = (X509Certificate) certificateFactory.generateCertificate(certInputStream); //產生一個保護伺服器憑證的keystore String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); String alias = serverCertificate.getSubjectX500Principal().getName(); keyStore.setCertificateEntry(alias, serverCertificate); //產生SSLSocketFactory SSLSocketFactory factory = new SSLVerifyLogServerCrtSocketFactory(crtName,keyStore,context); return factory; } catch (Throwable e) { e.printStackTrace(); } return null; }}
需求使用:實現用戶端對伺服器的校正,需要證明伺服器認證的合法性,當https在握手的協議中返回給用戶端的認證應該和儲存在用戶端本地的認證解析出來的網域名稱應該一樣,說明伺服器返回的認證給保證在本地的認證是一樣的,說明伺服器是合法的
try { String crtName = "server.crt"; SSLSocketFactory sf = SSLVerifyLogServerCrtSocketFactory.getSocketFactory(crtName, mContext); //對主機的有效網域名稱進行嚴格校正 sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);return new DefaultHttpClient(ccm, params);
其中server.crt就是儲存在手機app 例如assert目錄下的認證,是app本地保證的認證,這個認證必須和配置到後台例如tomacat伺服器中的認證是一模一樣,這裡為了用戶端驗證伺服器憑證的合法性,在手機app用戶端儲存了一個認證
mContext是activity或者context對應的手機的上下文,如果這裡用戶端和伺服器在建立https的過程中,如果伺服器返回給用戶端的認證的網域名稱和app本地儲存的認證解析出來的網域名稱是一樣的,說明伺服器是合法的。
如果用戶端在和伺服器建立https協議的時候,不對伺服器的合法性做校正,信任所有的伺服器
package com.cetcs.logreport.utils;/** * Created by wei.yuan on 2016/8/2. * * 該類主要是用於對伺服器憑證的單項驗證 */import org.apache.http.conn.ssl.SSLSocketFactory;import java.io.IOException;import java.lang.reflect.Field;import java.net.InetAddress;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;public class SSLSocketFactoryEx extends SSLSocketFactory { SSLContext sslContext = SSLContext.getInstance("TLS"); public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); // set up a TrustManager that trusts everything TrustManager tm = new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { //return new X509Certificate[]{}; return null; } @Override public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { // TODO Auto-generated method stub } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { // TODO Auto-generated method stub } }; sslContext.init(null, new TrustManager[] { tm }, new java.security.SecureRandom()); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { injectHostname(socket, host); return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); } private void injectHostname(Socket socket, String host) { try { Field field = InetAddress.class.getDeclaredField("hostName"); field.setAccessible(true); field.set(socket.getInetAddress(), host); } catch (Exception ignored) { } }}
提示:
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore); sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
這樣大體就是一個使用心得
android中使用https是否對服務憑證合法性校正的新的體會