Android 如何以编程方式将证书添加到信任库,并将其用于验证服务器身份验证
我想使用https连接到使用自签名证书的用户指定服务器。我现在收集到的是Android 如何以编程方式将证书添加到信任库,并将其用于验证服务器身份验证,android,ssl,ssl-certificate,Android,Ssl,Ssl Certificate,我想使用https连接到使用自签名证书的用户指定服务器。我现在收集到的是 自签名证书被拒绝(如预期) android密钥库/信任库不用于应用程序,因此应用程序必须构建并使用自己的信任库 JDK中有一个“keytool”来构建一个可以作为资源提供给应用程序的信任库,但这不是一个解决方案,因为我不知道服务器(以及它的证书) 由于https服务器是用户指定的,因此我事先不知道服务器的证书,因此希望以编程方式将服务器证书添加到应用程序的信任库中(通过向用户显示证书并让用户接受)。一旦添加到信任库,应
- 自签名证书被拒绝(如预期)
- android密钥库/信任库不用于应用程序,因此应用程序必须构建并使用自己的信任库
- JDK中有一个“keytool”来构建一个可以作为资源提供给应用程序的信任库,但这不是一个解决方案,因为我不知道服务器(以及它的证书)
编辑:在中找到解决方案。如果您有相同的问题,我建议您查看一下。您可以使用自签名证书。要使用自签名证书,您可以将其转换为Android支持的bouncy castle格式密钥库,然后将其作为原始资源存储在Android应用程序项目中。如何转换和使用它,所有细节都可以在Bob的博客上找到。这里是相同的链接-。这很有效。希望这有帮助解决方案是前一段时间找到的,但是还没有人创建了答案来帮助指导其他人,所以今天早上我将成为皮条客(ette),并发布添加为解决方案的URL,以及公共源代码中的副本。希望这有助于引导其他人找到解决方案。:)
对于下面的代码
package com.fsck.k9.mail.store;
import android.app.Application;
import android.content.Context;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.helper.DomainNameChecker;
import org.apache.commons.io.IOUtils;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
public final class TrustManagerFactory {
private static final String LOG_TAG = "TrustManagerFactory";
private static X509TrustManager defaultTrustManager;
private static X509TrustManager unsecureTrustManager;
private static X509TrustManager localTrustManager;
private static X509Certificate[] lastCertChain = null;
private static File keyStoreFile;
private static KeyStore keyStore;
private static class SimpleX509TrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
private static class SecureX509TrustManager implements X509TrustManager {
private static final Map<String, SecureX509TrustManager> mTrustManager =
new HashMap<String, SecureX509TrustManager>();
private final String mHost;
private SecureX509TrustManager(String host) {
mHost = host;
}
public synchronized static X509TrustManager getInstance(String host) {
SecureX509TrustManager trustManager;
if (mTrustManager.containsKey(host)) {
trustManager = mTrustManager.get(host);
} else {
trustManager = new SecureX509TrustManager(host);
mTrustManager.put(host, trustManager);
}
return trustManager;
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
defaultTrustManager.checkClientTrusted(chain, authType);
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// FIXME: Using a static field to store the certificate chain is a bad idea. Instead
// create a CertificateException subclass and store the chain there.
TrustManagerFactory.setLastCertChain(chain);
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException e) {
localTrustManager.checkServerTrusted(new X509Certificate[] {chain[0]}, authType);
}
if (!DomainNameChecker.match(chain[0], mHost)) {
try {
String dn = chain[0].getSubjectDN().toString();
if ((dn != null) && (dn.equalsIgnoreCase(keyStore.getCertificateAlias(chain[0])))) {
return;
}
} catch (KeyStoreException e) {
throw new CertificateException("Certificate cannot be verified; KeyStore Exception: " + e);
}
throw new CertificateException("Certificate domain name does not match "
+ mHost);
}
}
public X509Certificate[] getAcceptedIssuers() {
return defaultTrustManager.getAcceptedIssuers();
}
}
static {
java.io.InputStream fis = null;
try {
javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
Application app = K9.app;
keyStoreFile = new File(app.getDir("KeyStore", Context.MODE_PRIVATE) + File.separator + "KeyStore.bks");
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try {
fis = new java.io.FileInputStream(keyStoreFile);
} catch (FileNotFoundException e1) {
fis = null;
}
try {
keyStore.load(fis, "".toCharArray());
} catch (IOException e) {
Log.e(LOG_TAG, "KeyStore IOException while initializing TrustManagerFactory ", e);
keyStore = null;
} catch (CertificateException e) {
Log.e(LOG_TAG, "KeyStore CertificateException while initializing TrustManagerFactory ", e);
keyStore = null;
}
tmf.init(keyStore);
TrustManager[] tms = tmf.getTrustManagers();
if (tms != null) {
for (TrustManager tm : tms) {
if (tm instanceof X509TrustManager) {
localTrustManager = (X509TrustManager)tm;
break;
}
}
}
tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
tmf.init((KeyStore)null);
tms = tmf.getTrustManagers();
if (tms != null) {
for (TrustManager tm : tms) {
if (tm instanceof X509TrustManager) {
defaultTrustManager = (X509TrustManager) tm;
break;
}
}
}
} catch (NoSuchAlgorithmException e) {
Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
} catch (KeyStoreException e) {
Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
} finally {
IOUtils.closeQuietly(fis);
}
unsecureTrustManager = new SimpleX509TrustManager();
}
private TrustManagerFactory() {
}
public static X509TrustManager get(String host, boolean secure) {
return secure ? SecureX509TrustManager.getInstance(host) :
unsecureTrustManager;
}
public static KeyStore getKeyStore() {
return keyStore;
}
public static void setLastCertChain(X509Certificate[] chain) {
lastCertChain = chain;
}
public static X509Certificate[] getLastCertChain() {
return lastCertChain;
}
public static void addCertificateChain(String alias, X509Certificate[] chain) throws CertificateException {
try {
javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance("X509");
for (X509Certificate element : chain) {
keyStore.setCertificateEntry
(element.getSubjectDN().toString(), element);
}
tmf.init(keyStore);
TrustManager[] tms = tmf.getTrustManagers();
if (tms != null) {
for (TrustManager tm : tms) {
if (tm instanceof X509TrustManager) {
localTrustManager = (X509TrustManager) tm;
break;
}
}
}
java.io.OutputStream keyStoreStream = null;
try {
keyStoreStream = new java.io.FileOutputStream(keyStoreFile);
keyStore.store(keyStoreStream, "".toCharArray());
} catch (FileNotFoundException e) {
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
} catch (CertificateException e) {
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
} catch (IOException e) {
throw new CertificateException("Unable to write KeyStore: " + e.getMessage());
} finally {
IOUtils.closeQuietly(keyStoreStream);
}
} catch (NoSuchAlgorithmException e) {
Log.e(LOG_TAG, "Unable to get X509 Trust Manager ", e);
} catch (KeyStoreException e) {
Log.e(LOG_TAG, "Key Store exception while initializing TrustManagerFactory ", e);
}
}
}
package com.fsck.k9.mail.store;
导入android.app.Application;
导入android.content.Context;
导入android.util.Log;
导入com.fsck.k9.k9;
导入com.fsck.k9.helper.DomainNameChecker;
导入org.apache.commons.io.IOUtils;
导入javax.net.ssl.TrustManager;
导入javax.net.ssl.X509TrustManager;
导入java.io.File;
导入java.io.FileNotFoundException;
导入java.io.IOException;
导入java.security.KeyStore;
导入java.security.KeyStoreException;
导入java.security.NoSuchAlgorithmException;
导入java.security.cert.CertificateException;
导入java.security.cert.x509证书;
导入java.util.HashMap;
导入java.util.Map;
公共最终类TrustManagerFactory{
私有静态最终字符串日志\u TAG=“TrustManagerFactory”;
私有静态X509TrustManager defaultTrustManager;
私有静态X509TrustManager非安全TrustManager;
私有静态X509TrustManager localTrustManager;
私有静态X509Certificate[]lastCertChain=null;
私有静态文件密钥库;
私有静态密钥库;
私有静态类SimpleX509TrustManager实现X509TrustManager{
public void checkClientTrusted(X509Certificate[]链,字符串authType)
抛出证书异常{
}
public void checkServerTrusted(X509Certificate[]链,字符串authType)
抛出证书异常{
}
公共X509证书[]getAcceptedIssuers(){
返回null;
}
}
私有静态类SecureX509TrustManager实现X509TrustManager{
私有静态最终映射管理器=
新的HashMap();
私有最终字符串mHost;
专用SecureX509TrustManager(字符串主机){
mHost=主机;
}
公共同步静态X509TrustManager getInstance(字符串主机){
SecureX509TrustManager trustManager;
if(mTrustManager.containsKey(主机)){
trustManager=mTrustManager.get(主机);
}否则{
trustManager=新的SecureX509TrustManager(主机);
mTrustManager.put(主机、信任管理器);
}
返回信任管理器;
}
public void checkClientTrusted(X509Certificate[]链,字符串authType)
抛出证书异常{
defaultTrustManager.checkClientTrusted(链,authType);
}
public void checkServerTrusted(X509Certificate[]链,字符串authType)
抛出证书异常{
//FIXME:使用静态字段存储证书链是个坏主意
//创建一个CertificateException子类并将链存储在那里。
TrustManagerFactory.setLastCertChain(chain);
试一试{
defaultTrustManager.checkServerTrusted(链,authType);
}捕获(证书例外e){
localTrustManager.checkServerTrusted(新的X509Certificate[]{chain[0]},authType);
}
如果(!DomainNameChecker.match(链[0],mHost)){
试一试{
字符串dn=链[0]。getSubjectDN().toString();
if((dn!=null)&&(dn.equalsIgnoreCase(keyStore.getCertificateAlias(链[0])){
返回;
}
}捕获(KeyStoreException e){
抛出新的CertificateException(“无法验证证书;密钥库异常:”+e);
}
抛出新的CertificateException(“证书域名不匹配”