2017-07-05 29 views
5

私は、異なるサーバーに接続するハイブリッドコードバ・アプリを開発しています。それらの中にはクライアント証明書が必要なものもあります。適切なクライアント証明書を自動的またはユーザが選択してリクエストする

Androidモバイルでは、対応するルート証明書+クライアント証明書がインストールされています。

Chromeブラウザでは、Web接続に対応するクライアント証明書を選択するための次のダイアログが表示されます。コルドバのプラグインcordova-client-cert-authentication

Choose certificate on Chrome

同じダイアログは、WebViewの内のHTTP(S)要求のためにポップアップ表示されます。

私の質問は、明示的に対応するクライアント証明書を宣言せずにネイティブのAndroidプラットフォーム上でHTTP(S)要求に証明書の自動選択を達成する方法です。または、ユーザーがChromeで実装された証明書のようなものを選んでいますか?

これは、ハンドシェイク例外をスローし、現在の実装で、次のとおりです。URLは開発段階(ない生産版)に残っている場合は、アクセスにインストールし、それらのSSL /非SSL証明書を省略することができます

try { 
    URL url = new URL(versionUrl); 
    HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); 

    urlConnection.setConnectTimeout(10000); 

    InputStream in = urlConnection.getInputStream(); 
} 
catch(Exception e) 
{ 
    //javax.net.ssl.SSLHandshakeException: Handshake failed 
} 
+1

以前にAndroid KeyChain(システムキーストア)にインストールされていた証明書を使用するのか、それとも 'HttpsURLConnection'に証明書を直接渡しますか? – pedrofb

+0

KeyChainから以前にインストールした証明書を使用したいと思います。資格情報を使用してインストールされました。 "VPN and apps" – kerosene

答えて

-1

URL。

SSL検証をスキップする方法は次のとおりです。 アクティビティonCreate()またはURLにアクセスする前に必要な場所を呼び出します。

public static void skipSSLValidation() { 
     try { 
      TrustManager[] trustAllCerts = new TrustManager[]{ 
        new X509TrustManager() { 
         public X509Certificate[] getAcceptedIssuers() { 
        /* Create a new array with room for an additional trusted certificate. */ 
          return new X509Certificate[0]; 
         } 

         @Override 
         public void checkClientTrusted(X509Certificate[] certs, String authType) { 
         } 

         @Override 
         public void checkServerTrusted(X509Certificate[] certs, String authType) { 
         } 
        } 
      }; 

      SSLContext sc = SSLContext.getInstance("SSL"); 
      sc.init(null, trustAllCerts, new SecureRandom()); 
      HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 
      HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { 
       @Override 
       public boolean verify(String arg0, SSLSession arg1) { 
        return true; 
       } 
      }); 
     } catch (Exception e) { 
      // pass 
     } 
    } 

注:HTTPS URLが有効な場合は、サーバー生成の証明書を使用する必要はありません。テスト/開発のためだけにこのメソッドを使用する必要があります。リリース/プロダクションでは、このメソッドを使用する必要はありません。

+1

この解決方法は無効です。サーバー証明書の検証をスキップすると、クライアントはすべての証明書を信頼しますが、サーバーは依然としてクライアントが認証用の証明書を提示する必要があります。 – pedrofb

3

あなたは証明書が必要なエイリアスによって参照されURLConnection

で使用されるSSLContextを設定するには、X509ExtendedKeyManagerを拡張する前にAndroidのキーチェーン(システムのキーストア)に設置された証明書を使用することができます。クロムの使用のようなダイアログで選択のためにユーザに促すために:

KeyChain.choosePrivateKeyAlias(this, this, // Callback 
      new String[] {"RSA", "DSA"}, // Any key types. 
      null, // Any issuers. 
      null, // Any host 
      -1, // Any port 
      DEFAULT_ALIAS); 

これは、カスタムKeyManagerを使用してSSL接続を設定するためのコードです。デフォルトのTrustManagerHostnameVerifierが使用されます。サーバーは、Androidのデフォルトのトラストストアに存在していない自己署名証明書を使用している場合は、あなたが持っている最後に、ここで

//Configure trustManager if needed 
TrustManager[] trustManagers = null; 

//Configure keyManager to select the private key and the certificate chain from KeyChain 
KeyManager keyManager = KeyChainKeyManager.fromAlias(
      context, mClientCertAlias); 

//Configure SSLContext 
SSLContext sslContext = SSLContext.getInstance("TLS"); 
sslContext.init(new KeyManager[] {keyManager}, trustManagers, null); 


//Perform the connection 
URL url = new URL(versionUrl); 
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); 
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory()); 
//urlConnection.setHostnameVerifier(hostnameVerifier); //Configure hostnameVerifier if needed 
urlConnection.setConnectTimeout(10000); 
InputStream in = urlConnection.getInputStream(); 

を(すべての証明書を信頼することは推奨されません)から抽出されたカスタムX509ExtendedKeyManagerの完全な実装にそれらを設定する必要がありますクライアント証明書の選択を担当するhereおよびhere私は必要なコードを抽出しました。

public static class KeyChainKeyManager extends X509ExtendedKeyManager { 
    private final String mClientAlias; 
    private final X509Certificate[] mCertificateChain; 
    private final PrivateKey mPrivateKey; 

     /** 
     * Builds an instance of a KeyChainKeyManager using the given certificate alias. 
     * If for any reason retrieval of the credentials from the system {@link android.security.KeyChain} fails, 
     * a {@code null} value will be returned. 
     */ 
     public static KeyChainKeyManager fromAlias(Context context, String alias) 
       throws CertificateException { 
      X509Certificate[] certificateChain; 
      try { 
       certificateChain = KeyChain.getCertificateChain(context, alias); 
      } catch (KeyChainException e) { 
       throw new CertificateException(e); 
      } catch (InterruptedException e) { 
       throw new CertificateException(e); 
      } 

      PrivateKey privateKey; 
      try { 
       privateKey = KeyChain.getPrivateKey(context, alias); 
      } catch (KeyChainException e) { 
       throw new CertificateException(e); 
      } catch (InterruptedException e) { 
       throw new CertificateException(e); 
      } 

      if (certificateChain == null || privateKey == null) { 
       throw new CertificateException("Can't access certificate from keystore"); 
      } 

      return new KeyChainKeyManager(alias, certificateChain, privateKey); 
     } 

     private KeyChainKeyManager(
       String clientAlias, X509Certificate[] certificateChain, PrivateKey privateKey) { 
      mClientAlias = clientAlias; 
      mCertificateChain = certificateChain; 
      mPrivateKey = privateKey; 
     } 


     @Override 
     public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) { 
      return mClientAlias; 
     } 

     @Override 
     public X509Certificate[] getCertificateChain(String alias) { 
      return mCertificateChain; 
     } 

     @Override 
     public PrivateKey getPrivateKey(String alias) { 
      return mPrivateKey; 
     } 

     @Override 
     public final String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { 
      // not a client SSLSocket callback 
      throw new UnsupportedOperationException(); 
     } 

     @Override 
     public final String[] getClientAliases(String keyType, Principal[] issuers) { 
      // not a client SSLSocket callback 
      throw new UnsupportedOperationException(); 
     } 

     @Override 
     public final String[] getServerAliases(String keyType, Principal[] issuers) { 
      // not a client SSLSocket callback 
      throw new UnsupportedOperationException(); 
     } 
    } 
} 

私はそれをテストしませんでした。エラーを報告してください!

関連する問題