进球
我正在努力实现与Client-Certificate的通信。
步骤1:创建pkcs# 10请求(CSR)并将其交给我的服务器进行签名。服务器联系人将CSR传递给CA, CA对CSR进行签名,并返回pkcs# 7(带有签名的pkcs# 10和CA的证书)。
步骤2:创建pkcs# 12,将其安全地存储在Android设备上
步骤3:创建SSL连接,以便根据证书对客户端进行身份验证。
现在,第1步使用海绵城堡1.50.0.0完美工作,但我被困在其他步骤…我目前得到一个ssl握手异常,但我觉得我应该重新考虑我的实现。
有人知道如何实现流程吗?如何创建和存储任何需要的客户端证书与Android的SSLContext工作,以及如何创建这样的SSLContext?
我试过了
我的第一次尝试是使用KeyChain,但是我们想要避免上面描述的用户交互。我的第二次尝试是遵循Rich Freedman的步骤,但我不知道如何从pkcs# 7和私钥中创建pkcs# 12。对于持久性,我浏览了这篇文章,但是(a)它是c#, (b)它是未加密的,(C)我认为android平台有一个更好的密钥持久性机制,一个我还一无所知的机制。最后,这段代码(用于从PEM和pkcs# 7创建PKCS12)不能很好地工作,因为我不知道如何获得CER文件和它需要的其他东西。
谢谢!
可能不是最好的代码,但它可以工作,它并没有严格回答你所有的问题,但也许你会发现你可以使用的部分
你的心流很好,我也在做同样的事情。
我将密钥保存在动态创建的密钥库中。另外,我有一个用openssl工具创建的可信证书的密钥库。
对于通信,我使用okHttp + retrofit
https://github.com/square/okhttphttps://github.com/square/retrofit
生成KeyPair
:
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.genKeyPair();
return keyPair;
}
生成csr:
private static PKCS10CertificationRequest generateCSRFile(KeyPair keyPair) throws IOException, OperatorCreationException {
String principal = "CN=company1, OU=company1, O=company1, C=GB";
AsymmetricKeyParameter privateKey = PrivateKeyFactory.createKey(keyPair.getPrivate().getEncoded());
AlgorithmIdentifier signatureAlgorithm = new DefaultSignatureAlgorithmIdentifierFinder()
.find("SHA1WITHRSA");
AlgorithmIdentifier digestAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find("SHA-1");
ContentSigner signer = new BcRSAContentSignerBuilder(signatureAlgorithm, digestAlgorithm).build(privateKey);
PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name(
principal), keyPair.getPublic());
ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
extensionsGenerator.addExtension(X509Extension.basicConstraints, true, new BasicConstraints(true));
extensionsGenerator.addExtension(X509Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign
| KeyUsage.cRLSign));
csrBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extensionsGenerator.generate());
PKCS10CertificationRequest csr = csrBuilder.build(signer);
return csr;
}
发送csr(可能需要转换为pem格式),接收证书。
初始密钥存储库:
KeyStore store = KeyStore.getInstance("BKS");
InputStream in;
try {
in = App.getInstance().getApplicationContext().openFileInput(filename);
try {
store.load(in, password);
} finally {
in.close();
}
} catch (FileNotFoundException e) {
//create new keystore
store.load(null, password);
}
Init信任存储库:
KeyStore trustStore = KeyStore.getInstance("BKS");
InputStream in = App.getInstance().getApplicationContext().getResources().openRawResource(R.raw.truststore);
try {
trustStore.load(in, trustorePassword);
} finally {
in.close();
}
将密钥添加到密钥库(确保您的私钥和证书匹配,密钥库不会抛出异常,如果它们不匹配,并且使用okHttp这可能导致libssl崩溃(仅在api低于4.1的设备上):
keyStore.setKeyEntry(alias, privateKey, password, new X509Certificate[]{certificate});
使用自己的SSLContext
创建okHttpClient:
OkHttpClient client = new OkHttpClient();
KeyStore keyStore = App.getInstance().getKeyStoreUtil().getKeyStore();
KeyStore trustStore = App.getInstance().getKeyStoreUtil().getTrustStore();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyStorePassword);
SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
client.setSslSocketFactory(sslCtx.getSocketFactory());
client.setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
看看Nikolay Elenkov的博客,你可以找到很多有用的信息和源代码。
- http://nelenkov.blogspot.com/
- http://nelenkov.blogspot.com/2011/11/using-ics-keychain-api.html
- http://nelenkov.blogspot.in/2011/12/ics-trust-store-implementation.html
- http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html
- http://nelenkov.blogspot.com/2012/05/storing-application-secrets-in-androids.html
- http://nelenkov.blogspot.com/2013/08/credential -存储-改进- android - 43. - html
@edit
发布你的异常
@edit2
在您的情况下,您需要从webservice响应中提取X509Certificate
,将其存储在用于生成csr请求的私钥的密钥库中,并将CA证书存储在另一个将作为truststore工作的密钥库中。(可以是相同的密钥存储库,但不建议这样做)。