3

我正在开发一个企业 android 应用程序,因此有必要在我的测试阶段在客户端(android 模拟器/测试手机)和服务器之间创建一个安全连接,即使服务器的证书是自签名的同时购买了合法证书由公司(目前我无法控制)。

我需要信任服务器的自签名证书及其证书颁发机构,当然,android 操作系统本身不信任它。我几乎一字不差 地遵循谷歌关于在这种情况下创建 HTTPS 环境的建议。

我目前面临的问题是我无法.crt像谷歌示例中的这一行那样访问我的文件:

InputStream caInput = new BufferedInputStream(
    new FileInputStream("load-der.crt"));

代替上述内容,我正在使用:

InputStream caInput = new BufferedInputStream(
getResources().openRawResource(R.raw.mycrtfile));

打开InputStream派生自mycrtfile.crt,其中.crt文件存在于/res/raw/mycrtfile.crt. 但是,我NullPointerException在那条线上得到了一个。

与存储在目录中的原始资源相比,InputStream是否有更好的方法来存储和访问我需要加载的证书文件?FileInputStreamres

4

3 回答 3

7

有多种方法可以解决您的问题,但这是我使用的一种方法:所有步骤都在此链接中http://blog.antoine.li/2010/10/22/android-trusting-ssl-certificates/ 但有些部分可能会感到困惑,所以我将解释所有过程:

1.-将 mycrtfile.crt 存储在已知路径中,我会说 c:BKS/mycrtfile.crt。

2.-要创建您的 BKS 或密钥库,您需要文件 bcprov-jdk15on-146.jar,这个类将为我们完成所有工作,有不同的版本,但这个适用于我http://www.bouncycastle .org/download/bcprov-jdk15on-146.jar也将此文件存储到 C:BKS/

3.-现在您将使用 Keytool(keytool 随附于 Java SDK。您应该在包含 javac 的目录中找到它)来生成我们的密钥库并确保它正在工作,进入您的 cmd 并输入“Keytool”,您将看到可用的命令,这意味着正在运行,或者您可以通过“C:\Program Files (x86)\Java\jre7\bin>keytool”访问。

4.-现在一切就绪,我们可以使用以下命令行生成密钥库:

keytool -importcert -v -trustcacerts -file "c:\BKS/mycrtfile.crt" -alias 证书 -keystore "c:\BKS/keystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "c: \BKS/prov-jdk15on-146.jar" -storetype BKS -storepass mysecret

让我们看看这一行是什么(这部分我真的很困惑): -"c:\BKS/mycrtfile.crt" :这是您的证书的路径。-"c:\BKS/keystore.bks" 这是我们将存储密钥库的路径,您可以更改我使用密钥库的输出名称,只需确保扩展文件为 .bks -"c:\BKS /prov-jdk15on-146.jar":这是我们文件的路径,它将完成所有工作。-mysecret:这是使用密钥库的密码,您将需要此密码,所以不要忘记这一点。

已编辑:
4.1-还使用此命令行来验证证书是否已正确导入密钥库:

keytool -list -keystore "res/raw/Keystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "c:\BKS/prov-jdk15on-146.jar" -storetype BKS -storepass mysecret

4.2-在此之后你应该看到这样的输出:

RootCA,22.10.2010,trustedCertEntry,指纹(MD5):24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93 IntermediateCA, 22.10.2010, trustCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
这意味着它已正确导入。

5.- 在此之后,如果您转到您的 BKS 文件夹,您将看到一个 Keystore.bks 文件,这意味着我们正在路上。

6.- 现在让我们进入 ANDROID 部分。在您的项目中检查您是否有“原始”文件夹,如果没有在 res 下创建此文件夹,则它必须位于 Yourproject/res/raw 中。

7.-将您的 Keystore.bks 文件复制到原始文件夹中。现在一切就绪,让我们进入代码。

8.--- 现在我们将创建一个类来读取和信任我们的 Keystore:

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 org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import com.futureconcepts.anonymous.R;
import android.content.Context;


public class Client extends  DefaultHttpClient   {
final Context context;
  public Client(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));

    HttpParams httpParams = new BasicHttpParams();
     HttpConnectionParams.setConnectionTimeout(httpParams,9000);
     HttpConnectionParams.setSoTimeout(httpParams, 9000);

      return new SingleClientConnManager(httpParams, registry);
  }


  private SSLSocketFactory newSslSocketFactory() {
      try {

          // Get an instance of the Bouncy Castle KeyStore format
            KeyStore trusted = KeyStore.getInstance("BKS");//put BKS literal  
            // Get the raw resource, which contains the keystore with
            // your trusted certificates (root and any intermediate certs)
            InputStream in =context.getResources().openRawResource(R.raw.keystore);
            try {
                // Initialize the keystore with the provided trusted certificates
                // Also provide the password of the keystore
                trusted.load(in, "mysecret".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

           sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
          return sf;
      } catch (Exception e) {
          throw new AssertionError(e);
      }
  }

}

9.我们现在做了一个请求,只需这样做: HttpClient client= new Client(this); ///设置你的Httpclient。

现在就是这样,您将只信任您的证书。我希望这个解释能帮助你或任何有同样问题的人。

于 2013-08-20T23:10:21.123 回答
0

Keystore(这是一篇关于 Keystore 和相关问题的精彩文章)和KeyChain可以解决问题,但您可能需要检查您所针对的 API 级别。此外,由于您提到了企业应用程序,您可能需要考虑证书固定。有助于您进行证书固定。

于 2013-08-21T11:01:56.897 回答
0

1) 在 app/src/main/ 中创建目录“assets”

2)将您的证书放在此目录中。

3)现在你可以得到 InputStream :

InputStream is = this.getAssets().open("mycrtfile.crt");

要使用 this.getAssets(),您必须在 Activity 中,因为在 Activity 中“this”对应于“Context”。如果您不在 Activity 中,则必须将 Context (this) 作为参数传递。

于 2015-08-21T12:42:27.437 回答