» 首頁 » 討論區 » Android程式設計 »Android SSL 私簽憑證連線(使用自簽名的SSL / TLS )

Android SSL 私簽憑證連線(使用自簽名的SSL / TLS )

發表人: Seachaos
積分: 2432
發表時間: 2015-11-08 18:03:03
有些時候基於安全性但又不想買 SSL/TLS 憑證
這時就可以用自簽的憑證 (self signed certificate ) 來讓Android建立安全連線

以下使用Google的網址來做範例,
先使用FireFox來建立一個私有的憑證(DER)

1. 在網址列點一下鎖頭,然後按更多資訊
Image

2. 移到「安全」頁面,然後按下「檢視憑證」
Image

3.再按「詳細資訊」,然後按下「匯出」
Image

4.然後將他命名成cert.crt,放置到Android的assets下,讓我們的程式可以去讀取到這個憑證檔
格式記得選X.509 憑證 ( DER )
Image

以下是http connect class範列:
[sea:javaCode]
import android.content.Context;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

/**
* Created by seachaos on 11/8/15.
*/
public class SSLSelfSender {
KeyStore trustStore = null;

public String send(Context context, String urlString){
//建立 ssl context
SSLContext sslContext = prepareSelfSign(context);
if(trustStore==null||sslContext==null){
return null;
}
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = null;
try {
url = new URL(urlString);
} catch (MalformedURLException e) {
e.printStackTrace();
}
if(url==null){
return null;
}
try {
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
// 使用ssl context
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());

// 讀取結果
InputStream is = urlConnection.getInputStream();
if (is != null) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte data[] = new byte[256];
int length = 0, getPer = 0;
while ((getPer = is.read(data)) != -1) {
length += getPer;
byteArrayOutputStream.write(data, 0, getPer);
}
is.close();
byteArrayOutputStream.close();
String utf8 = new String(byteArrayOutputStream.toByteArray(), "UTF-8").trim();
return utf8;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

public SSLContext prepareSelfSign(Context context){

try {
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
} catch (KeyStoreException e) {
e.printStackTrace();
}
if(trustStore==null){
return null;
}
SSLContext sslContext = null;
InputStream crtInput = null;
try {
// 載入憑證檔
crtInput = context.getAssets().open("cert.crt");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(crtInput);
Certificate ca = cf.generateCertificate(caInput);
trustStore.load(null, null);
trustStore.setCertificateEntry("ca", ca);

String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(trustStore);

sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} finally {
if(crtInput!=null) {
try {
crtInput.close();
} catch (IOException e) {
}
}
}
return sslContext;
}
}
[/sea]

使用此Class的範例:

[sea:javaCode]
public void sslTest(){
SSLSelfSender https = new SSLSelfSender();
String resp = https.send(this, "https://www.google.com.tw");
debug("resp:" + resp);
}
[/sea]

以上是用google的來做測試,所以這個寫法如果去連接其他的網站就會得到錯誤
但適合用在自簽的ssl憑證上