.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.
}
}
}
たくさんの投稿、ブログ、Gistを読んだ後、ようやく方法を見つけました。これは私にとってはうまくいきます。
多分あなたは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証明書を使用してRetrofit2をセットアップする方法 https://adiyatmubarak.wordpress.com/tag/add-ssl-certificate-in-retrofit-2/
またはRetrofit1: https://number1.co.za/use-retrofit-self-signed-unknown-ssl-certificate-Android/
PS:それは私のために働きます、PEMファイルをBKSに変換しないでください。
Jayからの回答で始めましたが、次のエラーが発生しました: 認証パスの信頼アンカーが見つかりません
KeyToolコマンド を使用して、持っていた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/
Step1:src/main/res/raw/client_certificate.cerのようにrawディレクトリ内にセキュリティ証明書を配置します
Step2:この証明書を使用してSSLContextオブジェクトを作成します。
SSLContext sslContext = createCertificate(getApplicationContext().getResources().openRawResource(R.raw.client_certificate));
Step3:作成したSSLContextオブジェクトをOkHttpClientビルダーに追加します。
addClientCertificate(okHttpClientBuilder);
Step4: OkHttpClientビルダーをクライアントのように改造するように設定します。
retrofitBuilder.client(okHttpClientBuilder.build());
次に、RetrofitManager.Javaファイルでの上記のすべてのステップの完全な実装を示します。
RetrofitManager.Java
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import Java.io.IOException;
import Java.io.InputStream;
import Java.security.GeneralSecurityException;
import Java.security.KeyManagementException;
import Java.security.KeyStore;
import Java.security.KeyStoreException;
import Java.security.NoSuchAlgorithmException;
import Java.security.cert.CertificateException;
import Java.security.cert.CertificateFactory;
import Java.security.cert.X509Certificate;
import Java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import Java.security.cert.Certificate;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by Rajoo Kannaujiya on 02/16/2020.
*/
public class RetrofitManager {
private static final String URL = "https://stackoverflow.com"; // Fetch url from config file.
private static final String TLS = "TLS";
private static final String SSL = "SSL";
private static final String CA = "ca";
private static final String X_509 = "X.509";
private static final String PROD = "prod";
private static X509TrustManager trustManager = null;
private static final String CONTENT_TYPE = "Content-Type";
private static final String CONTENT_TYPE_VALUE = "application/json";
public static final String BUILD_TYPE = "prod"; // Fetch build type from config file (Whether it is a dev, qa, stage or prod build).
public static Retrofit getRetrofitForAPIUrl() {
return getRetrofit(URL);
}
private static Retrofit getRetrofit(String url) {
Gson gson = new GsonBuilder().setLenient().create();
Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(url);
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.level(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.addInterceptor(chain -> {
Request origReq = chain.request();
Request.Builder requestBuilder = origReq.newBuilder()
.addHeader(CONTENT_TYPE, CONTENT_TYPE_VALUE);
Request request = requestBuilder.build();
return chain.proceed(request);
});
addClientCertificate(okHttpClientBuilder);
OkHttpClient.Builder okHttpBuilder = okHttpClientBuilder
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor(logging);
retrofitBuilder.client(okHttpBuilder.build());
return retrofitBuilder.build();
}
/**
* Method to create SSLContext object for the client certificate and return it.
*
* @param clientCertificate
* @return SSLContext Object
*/
private static SSLContext getSSLContextForClientCertificate(InputStream clientCertificate) {
SSLContext sslContext = null;
// If given client certificate is for production environment only, Then check put check for build type.
if (PROD.contentEquals(BUILD_TYPE)) {
// Creating X.509 certificate factory instance
CertificateFactory cf = null;
try {
cf = CertificateFactory.getInstance(X_509);
} catch (CertificateException e) {
e.printStackTrace();
}
// Generating client certificate
Certificate ca = null;
try {
try {
if (cf != null) {
ca = cf.generateCertificate(clientCertificate);
}
} catch (CertificateException e) {
e.printStackTrace();
}
} finally {
try {
clientCertificate.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Creating a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance(keyStoreType);
} catch (KeyStoreException e) {
e.printStackTrace();
}
if (keyStore != null) {
try {
keyStore.load(null, null);
} catch (CertificateException | IOException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
try {
keyStore.setCertificateEntry(CA, ca);
} catch (KeyStoreException e) {
e.printStackTrace();
}
}
// Creating a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = null;
try {
tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
try {
if (tmf != null) {
tmf.init(keyStore);
}
} catch (KeyStoreException e) {
e.printStackTrace();
}
// Creating an SSLContext instance that uses our TrustManager
try {
sslContext = SSLContext.getInstance(TLS);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
try {
if (sslContext != null && tmf != null) {
sslContext.init(null, tmf.getTrustManagers(), null);
}
} catch (KeyManagementException e) {
e.printStackTrace();
}
} else { // For non prod environment build. This section is useful only if you don't have client certificate for lower environment.
try {
sslContext = SSLContext.getInstance(SSL);
sslContext.init(null, new TrustManager[]{getTrustManager()}, new Java.security.SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
}
trustManager = getTrustManager();
return sslContext;
}
/**
* Method to add client certificate to OkHttpClient.Builder object.
*
* @param okHttpClientBuilder
* @return void
*/
private static void addClientCertificate(OkHttpClient.Builder okHttpClientBuilder) {
SSLContext sslContext = getSSLContextForClientCertificate(getApplicationContext().getResources().openRawResource(R.raw.myaccount_coxbusiness_com));
if (sslContext != null) {
okHttpClientBuilder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);
okHttpClientBuilder.hostnameVerifier((hostname, session) -> true);
}
}
private static X509TrustManager getTrustManager() {
X509TrustManager trustManager = null;
if (PROD.contentEquals(BUILD_TYPE)) { // If client certificate is only available for prod environment.
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers[0] instanceof X509TrustManager) {
trustManager = (X509TrustManager) trustManagers[0];
}
} catch (GeneralSecurityException e) {
throw new AssertionError();
}
} else { // For non prod environment build. This section is useful only if you don't have client certificate for lower environment.
trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
}
return trustManager;
}
}