我有一个.p12证书文件,并且我使用SSL Converter将其转换为.pem证书文件。然后,我在Android代码中使用该pem证书文件,如下所示:
OkHttpClient okHttpClient = new OkHttpClient();
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream instream = context.getResources().openRawResource(R.raw.pem_certificate);
Certificate ca;
ca = cf.generateCertificate(instream);
KeyStore kStore = KeyStore.getInstance(KeyStore.getDefaultType());
kStore.load(null, null);
kStore.setCertificateEntry("ca", ca);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(kStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (CertificateException
| KeyStoreException
| NoSuchAlgorithmException
| IOException
| KeyManagementException e) {
e.printStackTrace();
}
baseURL = endpoint;
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(baseURL)
.setClient(new OkClient(okHttpClient))
.build();
service = restAdapter.create(DishService.class);
但是此代码无效。它在“ ca = cf.generateCertificate(instream);”行失败。带有CertificateException消息。
public class RetrofitBuilder {
private static Retrofit retrofit = null;
private static final String BASE_URL = BuildConfig.BASE_URL;
private static final String API_VERSION = BuildConfig.VERSION;
private static OkHttpClient.Builder httpClientBuilder = null;
public static Retrofit getInstance(Context context) {
if (retrofit == null) {
httpClientBuilder = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS);
initHttpLogging();
initSSL(context);
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(BASE_URL + API_VERSION)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClientBuilder.build());
retrofit = builder.build();
}
return retrofit;
}
private static void initHttpLogging() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
if (BuildConfig.DEBUG) httpClientBuilder.addInterceptor(logging);
}
private static void initSSL(Context context) {
SSLContext sslContext = null;
try {
sslContext = createCertificate(context.getResources().openRawResource(R.raw.cert));
} catch (CertificateException | IOException | KeyStoreException | KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
if(sslContext!=null){
httpClientBuilder.sslSocketFactory(sslContext.getSocketFactory(), systemDefaultTrustManager());
}
}
private static SSLContext createCertificate(InputStream trustedCertificateIS) throws CertificateException, IOException, KeyStoreException, KeyManagementException, NoSuchAlgorithmException{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate ca;
try {
ca = cf.generateCertificate(trustedCertificateIS);
} finally {
trustedCertificateIS.close();
}
// creating a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// creating a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// creating an SSLSocketFactory that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext;
}
private static X509TrustManager systemDefaultTrustManager() {
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
}
return (X509TrustManager) trustManagers[0];
} catch (GeneralSecurityException e) {
throw new AssertionError(); // The system has no TLS. Just give up.
}
}
}
[阅读了很多文章,博客和要点之后,我终于找到了一种方法。这对我有用。
也许您在R.raw.pem_certificate中有问题...
1)尝试使用openssl从服务器获取原始公共证书:openssl s_client -connect {HOSTNAME}:{PORT} -showcerts
((请在此处查看详细信息:https://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file)
2)如何使用自定义SSL证书设置Retrofit2https://adiyatmubarak.wordpress.com/tag/add-ssl-certificate-in-retrofit-2/
或翻新1:https://number1.co.za/use-retrofit-self-signed-unknown-ssl-certificate-android/
PS:它对我有用,请不要将PEM文件转换为BKS。
Jay的回答使我开始,但出现了此错误:Trust anchor for certification path not found
我设法使用KeyTool command将我拥有的p12证书导入到密钥库中。
更具体地说:
步骤1.使用默认证书生成新的密钥库,然后将其删除
keytool -genkey -alias mycert -keyalg RSA -keysize 2048 -keystore mykeystore
keytool -delete -alias mycert -keystore mykeystore
keytool -v -list -keystore mykeystore
步骤2.导入证书
keytool -v -importkeystore -srckeystore <path to certificate> -srcstoretype PKCS12 -destkeystore mykeystore -deststoretype PKCS12
keytool -v -list -keystore mykeystore
第3步,然后使用以下代码加载SSLContext:
// open the keystore
KeyStore keyStore = KeyStore.getInstance(type);
try {
keyStore.load(keystoreInputStream, password.toCharArray());
} finally {
try {
keystoreInputStream.close();
} catch (IOException e) {
// swallow this
}
}
// create and initialise a key manager factory
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
if (password != null && !password.trim().equals("")) {
kmf.init(keyStore, password.toCharArray());
} else {
kmf.init(keyStore, null);
}
// build an SSL context
KeyManager[] keyManagers = kmf.getKeyManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, null, null);
感谢此处的代码:https://chariotsolutions.com/blog/post/https-with-client-certificates-on/