1

我一直在尋找這個幾個星期,似乎無法在任何地方找到答案。我正在嘗試爲Android進行以下操作。此代碼來自我編寫的C#應用​​程序,但將其移植到Android。 Web端點需要將證書附加到相互驗證請求以進行Web服務調用。Android和客戶端證書

 string certThumbprint = "E1313F6A2D770783868755D016CE748F6A9B0028"; 
     X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser); 
     try 
     { 
      certStore.Open(OpenFlags.ReadOnly); 
     } 
     catch (Exception e) 
     { 
      if (e is CryptographicException) 
      { 
       Console.WriteLine("Error: The store is unreadable."); 
      } 
      else if (e is SecurityException) 
      { 
       Console.WriteLine("Error: You don't have the required permission."); 
      } 
      else if (e is ArgumentException) 
      { 
       Console.WriteLine("Error: Invalid values in the store."); 
      } 
      else 
      { 
       throw; 
      } 
     } 
     X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, certThumbprint, false); 
     certStore.Close(); 
     if (0 == certCollection.Count) 
     { 
      throw new Exception("Error: No certificate found containing thumbprint " + certThumbprint); 
     } 
     X509Certificate2 certificate = certCollection[0]; 
     return certificate; 

我再這樣做(請求是HttpWebRequest的):

request.ClientCertificates.Add(cert); 

但是當我移動到Android我得到的一個「文件未找到」錯誤此作品在C#精getInputStream()調用。這是我的Android代碼:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); 

     StrictMode.setThreadPolicy(policy); 
     CertificateFactory cf = CertificateFactory.getInstance("X.509"); 

     InputStream caInput = new BufferedInputStream(new FileInputStream("/sdcard/Certificate.pfx")); 
     KeyHelper kh = new KeyHelper(); 
     Certificate ca = kh.GetKey("Password"); 
     String keyStoreType = KeyStore.getDefaultType(); 
     keyStore = KeyStore.getInstance(keyStoreType); 
     keyStore.load(null, null); 
     keyStore.setCertificateEntry("ca", ca); 
     KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
     kmf.init(keyStore, "Password".toCharArray()); 
     SSLContext context = SSLContext.getInstance("TLS"); 
     context.init(kmf.getKeyManagers(),null,new SecureRandom()); 
     HttpsURLConnection urlConnection = 
       (HttpsURLConnection)url.openConnection(); 
     urlConnection.setRequestProperty("x-ms-version",AZURE_REST_VERSION); 
     urlConnection.setDoInput(true); 
     urlConnection.setDoOutput(true); 
     urlConnection.setRequestMethod("GET"); 
     urlConnection.setSSLSocketFactory(context.getSocketFactory()); 
     urlConnection.connect(); 

     InputStream in = new BufferedInputStream(urlConnection.getInputStream()); //<-----Blows up here 

    } catch (KeyStoreException e) { 
     throw new KeyStoreException("Keystore Exception",e); 
    } catch (NoSuchAlgorithmException e) { 
     throw new NoSuchAlgorithmException("Algorithm exception",e); 
    } catch (KeyManagementException e) { 
     throw new KeyManagementException("Key Exception", e); 
    } 

我試圖把仿真器和終點之間的提琴手和它回來了200.我想這是因爲我的證書是在我的開發機器上我的本地私人商店。有什麼想法嗎?

回答

2

好的。我找到了這個答案。問題在於自簽名證書只有存在於android TrustStore中才能使用。但是,在應用程序啓動後,默認的TrustStore是隻讀的,因此很難對其進行修改。我設置了自己的自定義信任存儲,但是根證書不是它的一部分,所以向任何https發出呼叫都會失敗。該解決方案從這個博客帖子就來了:

http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html

長話短說,建立包含自簽名證書的自定義信任庫,然後從默認的信任存儲中導出的所有證書,並將其導入自定義信任存儲。然後使用該信任存儲設置您的SSL上下文(也需要使用自定義密鑰存儲,因爲客戶端證書也需要附加到請求中)。我相信,如果我不允許自簽名證書,這將不是什麼大問題,因爲客戶端證書的根證書將存在於默認的TrustStore中(或者至少我希望這樣做)。

0

而且你永遠不應該硬編碼路徑:

InputStream caInput = new BufferedInputStream(new FileInputStream("/sdcard/Certificate.pfx")); 

而是使用:

Environment.getExternalStorageDirectory() 

看看這個:http://developer.android.com/training/basics/data-storage/files.html

也爲證書 在此請看:Using a self-signed certificate to create a secure client-server connection in android

+0

雖然heplful這不是一個實際的解決方案,你必須將密鑰庫添加到android項目本身。這樣做的目的就在於,儘管我已經有了一個證書 - 最終用戶可能會將其上傳到應用程序,但我需要生成密鑰庫並將證書填入其中。實現此代碼後,我現在正在收到SSLPeerUnverifiedError「無對等證書」錯誤。自簽名證書存在於客戶端和服務器端。所以搜索仍在繼續。 – AnthonyBCodes