7

Tôi muốn tạo một Ứng dụng kết nối với máy chủ. Máy chủ này sử dụng Xác thực ứng dụng khách SSL. Người dùng ứng dụng sẽ có thể chọn chứng chỉ và cho phép sử dụng chứng chỉ như được triển khai trong ứng dụng trình duyệt.Xác thực ứng dụng khách SSL trong Android 4.x

Trong ứng dụng trình duyệt, xác thực đang hoạt động như mong đợi, vì vậy chứng chỉ tôi sử dụng hợp lệ.

Khi tôi cố gắng kết nối trong App của tôi tôi nhận được lỗi sau:

javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: 
SSL handshake terminated: ssl=0x2a2d3b38: 
Failure in SSL library, usually a protocol error 
error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure 
(external/openssl/ssl/s3_pkt.c:1290 0x2a2df880:0x00000003) 

Tôi cố gắng để làm theo các tài liệu android cho việc thực hiện của tôi.

Đây là mã của Hoạt động mẫu của tôi:

public class ClientCertificateActivity extends Activity implements 
    KeyChainAliasCallback { 

protected static final String TAG = "CERT_TEST"; 
private String alias; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    choseCertificate(); 
    LinearLayout layout = new LinearLayout(this); 
    Button connectToServer = new Button(this); 
    connectToServer.setText("Try to connect to Server"); 
    connectToServer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); 
    connectToServer.setOnClickListener(new OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      connectToServer(); 
     } 
    }); 
    layout.addView(connectToServer); 
    addContentView(layout, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); 
} 

protected void connectToServer() { 
    final Context ctx = this; 
    new AsyncTask<Void, Void, Boolean>() { 

     private Exception error; 

     @Override 
     protected Boolean doInBackground(Void... arg) { 
      try { 
       PrivateKey pk = KeyChain.getPrivateKey(ctx, alias); 
       X509Certificate[] chain = KeyChain.getCertificateChain(ctx, 
         alias); 

       KeyStore keyStore = KeyStore.getInstance("AndroidCAStore"); 
       TrustManagerFactory tmf = TrustManagerFactory 
         .getInstance(TrustManagerFactory 
           .getDefaultAlgorithm()); 
       tmf.init(keyStore); 

       SSLContext context = SSLContext.getInstance("TLS"); 
       context.init(null, tmf.getTrustManagers(), null); 

       URL url = new URL("https://usecert.example.com/"); 
       HttpsURLConnection urlConnection = (HttpsURLConnection) url 
         .openConnection(); 
       urlConnection.setSSLSocketFactory(context 
         .getSocketFactory()); 
       InputStream in = urlConnection.getInputStream(); 

       return true; 
      } catch (Exception e) { 
       e.printStackTrace(); 
       error = e; 
       return false; 
      } 
     } 

     @Override 
     protected void onPostExecute(Boolean valid) { 
      if (error != null) { 
       Toast.makeText(ctx, "Error: " + error.getMessage(), 
         Toast.LENGTH_LONG).show(); 
       return; 
      } 
      Toast.makeText(ctx, "Success: ", Toast.LENGTH_SHORT).show(); 
     } 
    }.execute(); 

} 

protected void choseCertificate() { 
    KeyChain.choosePrivateKeyAlias(this, this, 
      new String[] { "RSA", "DSA" }, null, "m.ergon.ch", 443, null); 
} 

@Override 
public void alias(String alias) { 
    this.alias = alias; 
} 
} 

Các ngoại lệ được ném vào urlConnection.getInputStream();

Đây là việc bắt giữ những cái bắt tay giữa máy chủ và c lient. Network capture of the SSL Handshake

Cảm ơn mọi lời đề nghị và lời nhắn.

Trả lời

4

Bạn chưa bao giờ khởi tạo KeyManager bằng khóa riêng của mình, vì vậy không có cách nào để xác thực ứng dụng khách có thể nhận nó.

Bạn sẽ phải triển khai X509KeyManager để trả lại PrivateKey và một số bí danh được mã hóa cứng. Đây là ứng dụng từ ứng dụng Email cổ phiếu (ICS +) để tham khảo. Bạn có thể cần phải sửa đổi nó một chút, nhưng phải dễ dàng theo dõi: về cơ bản nó chỉ lưu khóa, bí danh và chuỗi chứng chỉ vào các trường và trả về chúng thông qua các phương thức thích hợp (StubKeyManager chỉ ném ngoại lệ cho các phương thức chưa thực hiện và không cần thiết):

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

    public static KeyChainKeyManager fromAlias(Context context, String alias) 
      throws CertificateException { 
     X509Certificate[] certificateChain; 
     try { 
      certificateChain = KeyChain.getCertificateChain(context, alias); 
     } catch (KeyChainException e) { 
      logError(alias, "certificate chain", e); 
      throw new CertificateException(e); 
     } catch (InterruptedException e) { 
      logError(alias, "certificate chain", e); 
      throw new CertificateException(e); 
     } 

     PrivateKey privateKey; 
     try { 
      privateKey = KeyChain.getPrivateKey(context, alias); 
     } catch (KeyChainException e) { 
      logError(alias, "private key", e); 
      throw new CertificateException(e); 
     } catch (InterruptedException e) { 
      logError(alias, "private key", 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; 
    } 
} 
+0

Cảm ơn điều đó. Nhưng làm cách nào tôi có thể tạo KeyManager như vậy bằng khóa riêng của mình? Phần này bị thiếu trong ví dụ tại [Android Doc cho HttpsURLConnection] (http://developer.android.com/reference/javax/net/ssl/HttpsURLConnection.html) – surffan

+0

Có vẻ như không phải là cách trực tiếp để làm điều này. Bạn sẽ phải thực hiện 'X509KeyManager' để trả về' PrivateKey' và một số bí danh mã hóa cứng. Bạn không cần phải triển khai các phương thức liên quan đến máy chủ. http://developer.android.com/reference/javax/net/ssl/X509KeyManager.html –

+0

Xem câu trả lời cập nhật cho mã mẫu. –

Các vấn đề liên quan