2010-10-31 58 views
49

Tôi đang viết một ứng dụng Android yêu cầu xác thực ứng dụng khách SSL. Tôi biết cách tạo một kho khóa JKS cho một ứng dụng Java trên máy tính để bàn, nhưng Android chỉ hỗ trợ định dạng BKS. Mọi cách tôi đã cố tạo kết quả kho khóa trong lỗi sau:
handling exception: javax.net.ssl.SSLHandshakeException: null cert chainCách tạo một kho khóa Java có định dạng BKS (BouncyCastle) có chứa chuỗi chứng chỉ ứng dụng khách

Vì vậy, có vẻ như khách hàng không bao giờ gửi chuỗi chứng chỉ phù hợp, có lẽ vì tôi không tạo kho khóa đúng cách. Tôi không thể bật gỡ lỗi SSL như tôi có thể trên dekstop, do đó, điều này làm cho điều này khó khăn hơn nhiều so với nó.

Để tham khảo sau đây là lệnh đó đang làm việc để tạo ra một BKS truststore:
keytool -importcert -v -trustcacerts -file "cacert.pem" -alias ca -keystore "mySrvTruststore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass testtest


Đây là lệnh tôi đã cố gắng có nghĩa là không làm việc để tạo ra một client BKS keystore:

cat clientkey.pem clientcert.pem cacert.pem > client.pem 

keytool -import -v -file <(openssl x509 -in client.pem) -alias client -keystore "clientkeystore" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass testtest 
+17

Nghiêm túc không ai có kinh nghiệm với định dạng BKS? Argh, tại sao Android không thể sử dụng định dạng JKS chuẩn, hoặc ít nhất là tài liệu định dạng này vì tất cả chúng đều hỗ trợ? Điều này phải đơn giản ... –

Trả lời

58

Bước Chi tiết hướng dẫn bởi Bước tôi theo sau để đạt được điều này

  • Tải BouncyCastle JAR từ http://repo2.maven.org/maven2/org/bouncycastle/bcprov-ext-jdk15on/1.46/bcprov-ext-jdk15on-1.46.jar hoặc mang nó từ thư mục "doc".
  • Định cấu hình BouncyCastle cho PC bằng một trong các phương pháp dưới đây.
    • Thêm Provider BC Tĩnh (Recommended)
      • Sao chép bcprov-ext-jdk15on-1.46.jar cho mỗi
        • D: \ tools \ jdk1.5.0_09 \ jre \ lib \ ext (JDK (kèm JRE)
        • D: \ tools \ jre1.5.0_09 \ lib \ ext (JRE)
        • C: \ (vị trí được sử dụng trong biến env)
      • Sửa đổi các tập tin java.security dưới
        • D: \ tools \ jdk1.5.0_09 \ jre \ lib \ security
        • D: \ tools \ jre1.5.0_09 \ lib \ security
        • và thêm các mục sau đây
          • security.provider .7 = org.bouncycastle.jce.provider.BouncyCastleProvider
      • Thêm biến môi trường sau đây trong "biến tài" phần
        • CL ASSPATH =% CLASSPATH%; c: \ bcprov-ext-jdk15on-1.46.jar
    • Thêm bcprov-ext-jdk15on-1,46.jar vào CLASSPATH của dự án của bạn và Thêm dòng sau vào mã của bạn
      • Security.addProvider (new BouncyCastleProvider());
  • Tạo Keystore sử dụng Bouncy Castle
    • Chạy lệnh sau
      • keytool -genkey -alias myproject -keystore C: /myproject.keystore -storepass myproject -storetype BKS -provider org .bouncycastle.jce.provider.BouncyCastleProvider
    • Điều này tạo tệp C: \ myproject.keystore
    • Chạy lệnh sau để kiểm tra xem nó được tạo ra đúng hay không
      • keytool -list -keystore C: \ myproject.keystore -storetype BKS
  • Configure BouncyCastle cho TOMCAT

    • Mở D: \ tools \ apache-tomcat-6.0.35 \ conf \ server.xml và thêm mục nhập sau

      • < nối port = "8443" keystorePass = "myproject" alias = "myproject" keystore = "c: /myproject.keystore" keystoreType = "BKS" SSLEnabled = "true" clientAuth =" false" giao thức = "HTTP/1.1" chương trình = "https" an toàn = "true" sslProtocol = "TLS" sslImplementationName = "org.bouncycastle.jce.provider.BouncyCastleProvider"/ >
    • Khởi động lại máy chủ sau những thay đổi này.

  • Configure BouncyCastle dành cho Android Khách hàng
    • Không cần phải cấu hình từ Android hỗ trợ Bouncy Castle Version 1,46 trong nội bộ cung cấp "android.jar".
    • Chỉ cần thực hiện các phiên bản của HTTP Client (MyHttpClient.java có thể được tìm thấy dưới đây) và thiết lập như sau trong mã
      • SSLSocketFactory.setHostnameVerifier (SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    • Nếu bạn không làm điều này, nó mang lại cho một ngoại lệ như sau
      • javax.net.ssl.SSLException: hostname trong giấy chứng nhận không phù hợp: < 192.168.104.66> =
    • Ở chế độ sản xuất, hãy thay đổi mã trên thành
      • SSLSocketFactory.setHostnameVerifier (SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);

MyHttpClient.java

package com.arisglobal.aglite.network; 

import java.io.InputStream; 
import java.security.KeyStore; 

import org.apache.http.conn.ClientConnectionManager; 
import org.apache.http.conn.scheme.PlainSocketFactory; 
import org.apache.http.conn.scheme.Scheme; 
import org.apache.http.conn.scheme.SchemeRegistry; 
import org.apache.http.conn.ssl.SSLSocketFactory; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.impl.conn.SingleClientConnManager; 

import com.arisglobal.aglite.activity.R; 

import android.content.Context; 

public class MyHttpClient extends DefaultHttpClient { 

    final Context context; 

    public MyHttpClient(Context context) { 
     this.context = context; 
    } 

    @Override 
    protected ClientConnectionManager createClientConnectionManager() { 
     SchemeRegistry registry = new SchemeRegistry(); 

     registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 

     // Register for port 443 our SSLSocketFactory with our keystore to the ConnectionManager 
     registry.register(new Scheme("https", newSslSocketFactory(), 443)); 
     return new SingleClientConnManager(getParams(), registry); 
    } 

    private SSLSocketFactory newSslSocketFactory() { 
     try { 
      // Get an instance of the Bouncy Castle KeyStore format 
      KeyStore trusted = KeyStore.getInstance("BKS"); 

      // Get the raw resource, which contains the keystore with your trusted certificates (root and any intermediate certs) 
      InputStream in = context.getResources().openRawResource(R.raw.aglite); 
      try { 
       // Initialize the keystore with the provided trusted certificates. 
       // Also provide the password of the keystore 
       trusted.load(in, "aglite".toCharArray()); 
      } finally { 
       in.close(); 
      } 

      // Pass the keystore to the SSLSocketFactory. The factory is responsible for the verification of the server certificate. 
      SSLSocketFactory sf = new SSLSocketFactory(trusted); 

      // Hostname verification from certificate 
      // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 
      sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
      return sf; 
     } catch (Exception e) { 
      throw new AssertionError(e); 
     } 
    } 
} 

Làm thế nào để gọi mã trên trong lớp Hoạt động của bạn:

DefaultHttpClient client = new MyHttpClient(getApplicationContext()); 
HttpResponse response = client.execute(...); 
+0

Tôi đang làm theo quy trình trên, tôi đã làm tốt đến bước "Tạo kho khóa bằng cách sử dụng Lâu đài Bouncy", tại đây khi chạy lệnh keytool, lỗi cho sau, lỗi keytool: java.lang.ClassNotFoundException: org.bouncycastle.jce. provider.BouncyCastleProvider, vui lòng đề nghị – candy

+0

Tôi đã hoàn thành bước này, bằng cách chỉ định đường dẫn thư viện BouncyCastle cũng trong lệnh keytool, cảm ơn – candy

+0

Tôi không còn làm việc với dự án này nữa. như câu trả lời bởi vì bạn xứng đáng được một số điểm cho câu trả lời chi tiết như vậy và theo kẹo và kinh nghiệm của bạn, nó dường như là một giải pháp làm việc. Cảm ơn bạn đã đóng góp. –

0

Lệnh của bạn để tạo kho khóa BKS có vẻ chính xác cho m e.

Cách bạn khởi tạo kho khóa.

Bạn cần phải tham gia và vượt qua SSLSocketFactory của riêng bạn. Dưới đây là một ví dụ trong đó sử dụng Apache org.apache.http.conn.ssl.SSLSocketFactory

Nhưng tôi nghĩ rằng bạn có thể làm khá giống nhau trên các javax.net.ssl.SSLSocketFactory

private SSLSocketFactory newSslSocketFactory() { 
    try { 
     // Get an instance of the Bouncy Castle KeyStore format 
     KeyStore trusted = KeyStore.getInstance("BKS"); 
     // Get the raw resource, which contains the keystore with 
     // your trusted certificates (root and any intermediate certs) 
     InputStream in = context.getResources().openRawResource(R.raw.mykeystore); 
     try { 
      // Initialize the keystore with the provided trusted certificates 
      // Also provide the password of the keystore 
      trusted.load(in, "testtest".toCharArray()); 
     } finally { 
      in.close(); 
     } 
     // Pass the keystore to the SSLSocketFactory. The factory is responsible 
     // for the verification of the server certificate. 
     SSLSocketFactory sf = new SSLSocketFactory(trusted); 
     // Hostname verification from certificate 
     // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 
     sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); 
     return sf; 
    } catch (Exception e) { 
     throw new AssertionError(e); 
    } 
} 

Xin vui lòng cho tôi biết nếu nó làm việc.

+0

Lệnh mà tôi đã đăng là chính xác để tạo kho lưu trữ tin cậy. Và nó đang làm việc cho mục đích đó. Tôi đang cố tạo một kho lưu trữ khóa để sử dụng xác thực ứng dụng khách không hoạt động. Tôi đã cập nhật câu hỏi của mình để bao gồm lệnh mà tôi đã thử không hoạt động. –

4

Tôi không nghĩ rằng sự cố của bạn là với kho khóa BouncyCastle; Tôi nghĩ rằng vấn đề là với một gói javax.net.ssl ​​bị hỏng trong Android. Các kho khóa BouncyCastle là một phiền toái tối cao bởi vì Android đã thay đổi một hành vi Java mặc định mà không cần ghi lại nó ở bất cứ đâu - và loại bỏ nhà cung cấp mặc định - nhưng nó hoạt động.

Lưu ý rằng để xác thực SSL, bạn có thể yêu cầu 2 keystores. Kho lưu trữ "TrustManager", chứa các chứng chỉ CA và kho khóa "KeyManager", chứa các khóa công khai/riêng tư của khách hàng của bạn. (Tài liệu có phần mơ hồ về những gì cần phải có trong kho khóa KeyManager.) Về lý thuyết, bạn không nên cần kho khóa TrustManager nếu tất cả các chứng nhận của bạn được ký bởi "Cơ quan chứng nhận" nổi tiếng, ví dụ như Verisign, Thawte, và vân vân. Hãy cho tôi biết làm thế nào mà làm việc cho bạn. Máy chủ của bạn cũng sẽ yêu cầu CA cho bất kỳ thứ gì được sử dụng để ký tên cho khách hàng của bạn.

Tôi không thể tạo kết nối SSL bằng cách sử dụng javax.net.ssl. Tôi đã tắt xác thực SSL ứng dụng khách ở phía máy chủ và tôi vẫn không thể tạo kết nối. Vì mục tiêu cuối cùng của tôi là HTTPS GET, tôi đã punted và thử sử dụng Apache HTTP Client đi kèm với Android. Đó là loại công việc. Tôi có thể thực hiện giao thức HTTPS, nhưng tôi vẫn không thể sử dụng SSL auth. Nếu tôi đã bật xác thực SSL máy khách trên máy chủ của tôi, kết nối sẽ không thành công. Tôi đã không kiểm tra mã Apache HTTP Client, nhưng tôi nghi ngờ họ đang sử dụng triển khai SSL của riêng họ và không sử dụng javax.net.ssl.

+0

Có Tôi đang sử dụng một kho lưu trữ riêng (được tạo bằng lệnh trong câu hỏi của tôi) cũng như kho khóa mà tôi đã tạo bằng lệnh thứ hai trong câu hỏi của mình (cũng đã thử tạo một vài cách khác mà không thành công). Tôi đã không nhận ra rằng gói ssl trong Android có thể là thủ phạm. Tôi sẽ xem liệu tôi có thể nhận được phản hồi từ những người dùng Android hay không. –

22

Tôi sử dụng Portecle và nó hoạt động như một sự quyến rũ.

+0

Tôi đang sử dụng nó, vì tôi cũng đang làm việc với KeyStore và nó hoạt động. Ok, nó không hoàn hảo, nhưng nó giúp ích rất nhiều. – gnclmorais

+2

Tôi cũng đã sử dụng Portecle và xác nhận rằng nó đã khắc phục được sự cố của tôi !!! Tôi đã phải sử dụng HTTPSUrlConnection trong dự án Android của tôi và lộn xộn xung quanh với TrustManagerFactory một chút mặc dù. – Exegesis

+1

Tôi chỉ muốn lưu ý rằng Portecle 1.7 mà, bằng văn bản, là mới nhất, có một bouncycastle lỗi thời mà không có khả năng mở bks keystores mới hơn. – Chris

4

Không chắc bạn giải quyết vấn đề này hay không, nhưng đây là cách tôi làm điều đó và nó hoạt động trên Android:

  1. Sử dụng openssl sáp nhập của khách hàng cert (cert phải có chữ ký của một CA mà chấp nhận bởi máy chủ) và khóa cá nhân vào cặp khóa định dạng PCKS12: openssl pkcs12 -export -in clientcert.pem -inkey clientkey.pem -out client.p12
  2. Bạn có thể cần vá mã JRE của bạn để mã hóa cường độ umlimited tùy thuộc vào khóa của bạn sức mạnh: sao chép các tệp jar từ JCE 5.0 unlimited strength Jurisdiction Policy FIles và ghi đè các tệp đó trong JRE của bạn (ví dụ: C. Program Files \ Java \ jre6 \ lib \ securi ty)
  3. Sử dụng công cụ Portecle được đề cập ở trên và tạo kho khóa mới với định dạng BKS
  4. Nhập cặp khóa PCKS12 được tạo ở bước 1 và lưu nó làm kho khóa BKS. Keystore này hoạt động với xác thực ứng dụng khách Android.
  5. Nếu bạn cần thực hiện chuỗi chứng chỉ, bạn có thể sử dụng công cụ IBM này: KeyMan để hợp nhất cặp khóa PCKS12 của máy khách với CA cert. Nhưng nó chỉ tạo ra kho khóa JKS, vì vậy bạn lại cần Protecle để chuyển đổi nó sang định dạng BKS.
2

dòng lệnh:

keytool -genseckey -alias aliasName -keystore truststore.bks -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath /path/to/jar/bcprov-jdk16-1.46.jar -storetype BKS 
0

Sử dụng sách hướng dẫn này http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/ Hướng dẫn này thực sự đã giúp tôi. Điều quan trọng là phải quan sát một chuỗi các chứng chỉ trong cửa hàng. Ví dụ: nhập chứng chỉ CA trung gian thấp nhất trước và sau đó chuyển đến chứng chỉ CA gốc.

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