使用自签名证书在android中创建安全的客户端 - 服务器连接

时间:2013-08-20 22:55:31

标签: android security ssl

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

我需要信任服务器的自签名证书及其证书颁发机构,当然,它本身并不受Android操作系统的信任。我几乎逐字地关注google's suggestion for creating an HTTPS environment in this scenario

我目前面临的问题是,我无法通过Google的示例访问此行中的.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的证书文件,而不是存储在{{1}}目录中的原始资源?

3 个答案:

答案 0 :(得分: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,这个类将为我们完成所有工作,有不同的版本,但这个适用于我{{3}还将此文件存储到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 certificate -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,Thumbprint(MD5):24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93 IntermediateCA,22.10.2010,trustedCertEntry,Thumbprint(MD5):98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
这意味着它是正确导入的。

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

6.-现在让我们转到ANDROID部分。在你的项目中检查你是否有“raw”文件夹,如果没有在res下创建这个文件夹,它必须在你的项目/ 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。

现在你只相信你的证书了。我希望这个解释可以帮助你或任何有同样问题的人。

答案 1 :(得分:0)

Keystore(以下是关于密钥库和相关问题的article很棒)和KeyChain可以解决这个问题,但您可能需要检查您定位的API级别。此外,由于您提到了Enterprise Application,因此您可能需要考虑证书固定。 This可以帮助您获取证书固定。

答案 2 :(得分: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)作为参数传递。