我正在尝试获取相互身份验证请求以在android上运行。我正在测试我自己的服务器,所以我有一个自签名的CA和客户端证书。
所以我必须允许不受信任的服务器证书。
这是我正在做的事情:
KeyStore clientCertificate = KeyStore.getInstance("PKCS12");
InputStream client_inputStream = getResources().openRawResource(R.raw.client);
clientCertificate.load(client_inputStream, "password".toCharArray());
new SSLRequest(clientCertificate).execute();
然后AsyncTask执行请求:
class SSLRequest extends AsyncTask<Void, Void, Void> {
private Exception exception;
private KeyStore clientCertificate;
public SSLRequest(KeyStore clientCertificate) {
this.clientCertificate = clientCertificate;
}
protected Void doInBackground(Void... params) {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactory(clientCertificate, null, trustStore);
HttpParams httpParameters = new BasicHttpParams();
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", sf, 443));
ClientConnectionManager cm = new SingleClientConnManager(httpParameters, schemeRegistry);
DefaultHttpClient httpClient = new DefaultHttpClient(cm, httpParameters);
HttpGet request = new HttpGet("https://myserver.com/some.json");
HttpResponse response = httpClient.execute(request);
response.getEntity().consumeContent();
} catch (Exception e) {
this.exception = e;
}
return null;
}
protected void onPostExecute(Void params) {
if (exception != null) {
status.setText("Error making SSL handshake");
} else {
status.setText("Successful SSL handshake");
}
}
}
我已经在浏览器和iOS客户端中测试了此请求,但我无法在Android中使用它。
我认为这是允许不受信任的服务器证书的正确方法:
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactory(clientCertificate, "password", trustStore);
不确定我为什么会这样:
javax.net.ssl.SSLPeerUnverifiedException
编辑:
我必须添加自己的SSLSocketFactory来信任自签名服务器证书:
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore keystore, String keystorePassword, KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(keystore, keystorePassword, truststore);
TrustManager trustManager = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] {trustManager}, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
一旦我使用它,我得到以下内容:
javax.net.ssl.SSLHandshakeException:握手失败
编辑2:
我在Lollipop上使用apache作为我的网络服务器。我的apache web服务器配置有:
# SSL Protocol support:
# List the enable protocol levels with which clients will be able to
# connect. Disable SSLv2 access by default:
SSLProtocol all -SSLv2 -SSLv3
# SSL Cipher Suite:
# List the ciphers that the client is permitted to negotiate.
# See the mod_ssl documentation for a complete list.
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
这可能是我的问题: HttpClient fails with Handshake Failed in Android 5.0 Lollipop
不确定我需要改变什么。我看了一遍,这似乎是推荐配置(现在)。
编辑3:
这是完整的堆栈跟踪:
06-01 13:23:14.369 24486-24571/mil.nga.giat.handshake W/System.err﹕ javax.net.ssl.SSLHandshakeException: Handshake failed
06-01 13:23:14.369 24486-24571/mil.nga.giat.handshake W/System.err﹕ at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:390)
06-01 13:23:14.369 24486-24571/mil.nga.giat.handshake W/System.err﹕ at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:623)
06-01 13:23:14.369 24486-24571/mil.nga.giat.handshake W/System.err﹕ at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:585)
06-01 13:23:14.369 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:75)
06-01 13:23:14.369 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:88)
06-01 13:23:14.369 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:175)
06-01 13:23:14.369 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:111)
06-01 13:23:14.371 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:134)
06-01 13:23:14.371 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:177)
06-01 13:23:14.371 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169)
06-01 13:23:14.371 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124)
06-01 13:23:14.372 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:365)
06-01 13:23:14.372 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:560)
06-01 13:23:14.372 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:492)
06-01 13:23:14.372 24486-24571/mil.nga.giat.handshake W/System.err﹕ at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:470)
06-01 13:23:14.372 24486-24571/mil.nga.giat.handshake W/System.err﹕ at mil.nga.giat.handshake.HandshakeActivity$SSLRequest.doInBackground(HandshakeActivity.java:115)
06-01 13:23:14.372 24486-24571/mil.nga.giat.handshake W/System.err﹕ at mil.nga.giat.handshake.HandshakeActivity$SSLRequest.doInBackground(HandshakeActivity.java:85)
06-01 13:23:14.372 24486-24571/mil.nga.giat.handshake W/System.err﹕ at android.os.AsyncTask$2.call(AsyncTask.java:292)
06-01 13:23:14.373 24486-24571/mil.nga.giat.handshake W/System.err﹕ at java.util.concurrent.FutureTask.run(FutureTask.java:237)
06-01 13:23:14.373 24486-24571/mil.nga.giat.handshake W/System.err﹕ at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
06-01 13:23:14.373 24486-24571/mil.nga.giat.handshake W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
06-01 13:23:14.373 24486-24571/mil.nga.giat.handshake W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
06-01 13:23:14.374 24486-24571/mil.nga.giat.handshake W/System.err﹕ at java.lang.Thread.run(Thread.java:818)
06-01 13:23:14.374 24486-24571/mil.nga.giat.handshake W/System.err﹕ Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0xa21b8800: Failure in SSL library, usually a protocol error
06-01 13:23:14.374 24486-24571/mil.nga.giat.handshake W/System.err﹕ error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure (external/openssl/ssl/s3_pkt.c:1303 0xb4b57be0:0x00000003)
06-01 13:23:14.375 24486-24571/mil.nga.giat.handshake W/System.err﹕ at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
06-01 13:23:14.375 24486-24571/mil.nga.giat.handshake W/System.err﹕ at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:318)
答案 0 :(得分:3)
我从未将客户端证书放在KeyManager中:
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keystore, "password".toCharArray());
sslContext.init(kmf.getKeyManagers(), new TrustManager[]{tm}, null);
答案 1 :(得分:2)
我正在尝试获取相互身份验证请求以在Android上运行...
(注释)设备上未安装服务器CA.它不是必须的。只需要客户端证书就可以完成握手。这就是我加载一个空信任库以允许不受信任的服务器证书的原因。
好的,所以最简单的解决方案是在设备上安装CA.我知道你不想这样做,我并不是真的责备你。它不是最好的解决方案,因为它会将您的CA与CA Zoo中的其他CA混合在一起。
由于您以编程方式执行 all ,因此我相信这是您的解决方案:Use PEM Encoded CA Cert on filesystem directly for HTTPS request?。客户端将使用您的CA验证服务器证书,然后继续使用客户端证书。 CA不需要安装在设备上。
另一种选择是自定义TrustManager
。但我更愿意让系统执行检查而不是覆盖行为和检查。您必须执行许多检查,并且它们容易出错。对于初学者,您必须知道要检查哪些检查结果的RFC。
我将使用自定义TrustManager
进行公钥固定。有很多例子;例如,请参阅OWASP网站上的Certificate and Public Key Pinning。您可以使用固定和放弃检查,因为您不需要授予信任。您要么与预期的服务器通信 - 使用公钥X;或者你没有 - 并且第三方所说的并不重要(如CA)。
另请注意,Java和Android的SSLFactory
存在一些问题,例如getInstance("TLS")
也会返回SSLv3;并且将禁用TLS 1.1和1.2。要解决此问题,请参阅Which Cipher Suites to enable for SSL Socket?。
与您的编辑相关:
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256
EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL
!LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
这通常可行:
HIGH:!aNULL:!kRSA:!MD5:!RC4:!SRP:!PSK
HIGH
会为您提供强大的功能(大约112位安全级别以上)。
!aNULL
删除匿名协议,!kRSA
删除密钥传输(但不删除RSA签名),因此您将使用Integer和Elliptic Curve Diffie-Hellman。您可以在下面使用Au=RSA
查看RSA签名示例。
HIGH
也会让你受到一些弱/受伤的伤害,比如MD5
和RC4
,所以你明确删除了它们。您还会删除不需要的密码套件,例如SRP
和PSK
。
您可以使用openssl ciphers -v 'HIGH:!aNULL:!kRSA:!MD5:!RC4:!SRP:!PSK'
$ openssl ciphers -v 'HIGH:!aNULL:!kRSA:!MD5:!RC4:!SRP:!PSK'
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
...
顺便说一句,这是你的字符串。总而言之,我觉得它看起来不错。 RC4会从某些浏览器中为您提供Obsolete Cryptography warnings。因为块密码中的填充oracles是固定的(再次......),所以就放弃它。
$ openssl ciphers -v 'EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384: \
EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS'
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-RC4-SHA SSLv3 Kx=ECDH Au=RSA Enc=RC4(128) Mac=SHA1
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1
ECDHE-ECDSA-RC4-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=RC4(128) Mac=SHA1
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(256) Mac=SHA256
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
DHE-RSA-CAMELLIA256-SHA SSLv3 Kx=DH Au=RSA Enc=Camellia(256) Mac=SHA1
DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(128) Mac=SHA256
DHE-RSA-AES128-SHA SSLv3 Kx=DH Au=RSA Enc=AES(128) Mac=SHA1
DHE-RSA-SEED-SHA SSLv3 Kx=DH Au=RSA Enc=SEED(128) Mac=SHA1
DHE-RSA-CAMELLIA128-SHA SSLv3 Kx=DH Au=RSA Enc=Camellia(128) Mac=SHA1
ECDH-RSA-RC4-SHA SSLv3 Kx=ECDH/RSA Au=ECDH Enc=RC4(128) Mac=SHA1
ECDH-ECDSA-RC4-SHA SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=RC4(128) Mac=SHA1
RC4-SHA SSLv3 Kx=RSA Au=RSA Enc=RC4(128) Mac=SHA1