我正在开发一个企业安卓应用程序,因此有必要在我的测试阶段在客户端(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
。
是否有更好的方法来存储和访问我需要加载为FileInputStream
或res
的证书文件,而不是存储在{{1}}目录中的原始资源?
答案 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)作为参数传递。