[英]OkHttp client authentication failing to validate server and send client certificate in the same request
EDIT I'm able to build my OkHttp client to where it includes both the client cert in the Client.SSLContext.KeyManager, and the trusted certs in the Client.SSLContext.TrustManager编辑我能够将我的 OkHttp 客户端构建到它包含 Client.SSLContext.KeyManager 中的客户端证书和 Client.SSLContext.TrustManager 中的受信任证书的位置
// Create keyManagerFactory with keystore.jks
KeyStore clientStore = KeyStore.getInstance(KeyStore.getDefaultType());
clientStore.load(new FileInputStream(new File("keystore.jks")), storePassword.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientStore, storePassword.toCharArray());
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
// Create trustManagerFactory with default cacerts truststore
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
trustManager = trustManagers[0];
// Create sslContext from keyManagers (from custom keystore with client key) and default trustManagers
sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
sslSocketFactory = sslContext.getSocketFactory();
defaultFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
okClient = new OkHttpClient
.Builder()
.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManager)
.build();
However, my client still isn't sending my client certificate (server cert is validated through the trust store successfully).但是,我的客户端仍然没有发送我的客户端证书(服务器证书已通过信任库成功验证)。 Getting this in the ssl debug logs
在 ssl 调试日志中获取此信息
No X.509 certificate for client authentication, use empty Certificate message instead
Here's what my SSLContext looks like on the HttpClient.这是我的 SSLContext 在 HttpClient 上的样子。
Seems like that should send the client cert named "cureskeystore" in the request?
似乎应该在请求中发送名为“cureskeystore”的客户端证书?
keystore.jks
is built with the following commands keystore.jks
使用以下命令构建
openssl pkcs12 -export \
-name curesKeyStore \
-in clientCert.crt \
-inkey privateKey.pem \
-certfile clientCert.crt \
-out chain.p12 \
-passout pass:${STORE_PASSWORD}
keytool -importkeystore \
-srckeystore chain.p12 \
-srcstoretype pkcs12 \
-destkeystore keystore.jks \
-deststoretype pkcs12 \
-storepass ${STORE_PASSWORD} \
-srcstorepass ${STORE_PASSWORD} > /dev/null 2>&1
I have also tried creating a store with the client cert + -CAfile
with the root and intermediate certs:我还尝试使用具有根证书和中间证书的客户端证书 +
-CAfile
创建商店:
# client cert with CAcerts included
openssl pkcs12 -export -chain \
-in clientCert.crt \
-inkey privateKey.pem \
-out keystore.p12 \
-name p12KeyStore \
-CAfile caCerts.crt \
-caname root \
-passout pass:${STORE_PASSWORD}
keytool -importkeystore \
-srcstoretype PKCS12 \
-destkeystore keystore.jks \
-srckeystore keystore.p12 \
-alias p12KeyStore \
-storepass ${STORE_PASSWORD} \
-srcstorepass ${STORE_PASSWORD}
Another possible issue is the CertificateRequest not matching my client certificate.另一个可能的问题是 CertificateRequest 与我的客户端证书不匹配。
javax.net.ssl|DEBUG|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|CertificateRequest.java:671|Consuming CertificateRequest handshake message (
"CertificateRequest": {
"certificate types": [ecdsa_sign, rsa_sign, dss_sign]
"supported signature algorithms": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp521r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, ecdsa_sha224, rsa_sha224, dsa_sha224, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1]
"certificate authorities": [redacted, but does not include Entrust]
}
)
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|X509Authentication.java:213|No X.509 cert selected for EC
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|CertificateRequest.java:764|Unavailable authentication scheme: ecdsa_secp256r1_sha256
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|X509Authentication.java:213|No X.509 cert selected for EC
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|CertificateRequest.java:764|Unavailable authentication scheme: ecdsa_secp384r1_sha384
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|X509Authentication.java:213|No X.509 cert selected for EC
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|CertificateRequest.java:764|Unavailable authentication scheme: ecdsa_secp521r1_sha512
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|X509Authentication.java:213|No X.509 cert selected for RSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_pss_rsae_sha256
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|X509Authentication.java:213|No X.509 cert selected for RSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_pss_rsae_sha384
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|X509Authentication.java:213|No X.509 cert selected for RSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_pss_rsae_sha512
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|X509Authentication.java:213|No X.509 cert selected for RSASSA-PSS
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_pss_pss_sha256
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|X509Authentication.java:213|No X.509 cert selected for RSASSA-PSS
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.619 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_pss_pss_sha384
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|X509Authentication.java:213|No X.509 cert selected for RSASSA-PSS
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_pss_pss_sha512
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|X509Authentication.java:213|No X.509 cert selected for RSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_pkcs1_sha256
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|X509Authentication.java:213|No X.509 cert selected for RSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_pkcs1_sha384
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|X509Authentication.java:213|No X.509 cert selected for RSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_pkcs1_sha512
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|X509Authentication.java:213|No X.509 cert selected for DSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|CertificateRequest.java:764|Unavailable authentication scheme: dsa_sha256
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|X509Authentication.java:213|No X.509 cert selected for EC
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|CertificateRequest.java:764|Unavailable authentication scheme: ecdsa_sha224
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|X509Authentication.java:213|No X.509 cert selected for RSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_sha224
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|X509Authentication.java:213|No X.509 cert selected for DSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|CertificateRequest.java:764|Unavailable authentication scheme: dsa_sha224
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|X509Authentication.java:213|No X.509 cert selected for EC
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.620 EDT|CertificateRequest.java:764|Unavailable authentication scheme: ecdsa_sha1
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.621 EDT|X509Authentication.java:213|No X.509 cert selected for RSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.621 EDT|CertificateRequest.java:764|Unavailable authentication scheme: rsa_pkcs1_sha1
javax.net.ssl|ALL|24|XNIO-1 task-1|2021-10-18 11:07:18.621 EDT|X509Authentication.java:213|No X.509 cert selected for DSA
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.621 EDT|CertificateRequest.java:764|Unavailable authentication scheme: dsa_sha1
javax.net.ssl|WARNING|24|XNIO-1 task-1|2021-10-18 11:07:18.621 EDT|CertificateRequest.java:774|No available authentication scheme
My certificate's signing algorithm is SHA256withRSA
.我的证书的签名算法是
SHA256withRSA
。 Is that not the same as rsa_pkcs1_sha256
?这与
rsa_pkcs1_sha256
不一样吗? Also, my client certificate is signed by Entrust, which is not listed in the certificate authorities for the server's CertificateRequest.此外,我的客户端证书是由 Entrust 签署的,该证书未在服务器的 CertificateRequest 的证书颁发机构中列出。
EDIT: I made some requests to a different HTTPS server that does not include certificate authorities
in its CertificateRequest to the client.编辑:我向不同的 HTTPS 服务器发出了一些请求,该服务器在对客户端的 CertificateRequest 中不包含
certificate authorities
。 I verified that SSL can find the expected client certificate and sends it back to the server as expected.我验证了 SSL 可以找到预期的客户端证书并按预期将其发送回服务器。 So it seems like this is an issue with the server request not including my CA in their list of accepted
certificate authorities
.因此,这似乎是服务器请求的问题,未将我的 CA 包含在他们接受的
certificate authorities
列表中。 Reaching out to the server to request an update.联系服务器以请求更新。
Okay;好的; it has developed your problem is that when the server requests your client-cert/auth, it specifies a CA list that doesn't include the CA(s?) used by your cert-and-chain, even though when presented with your cert-and-chain the server accepts it.
它已经开发出您的问题是,当服务器请求您的客户端证书/身份验证时,它指定了一个 CA 列表,该列表不包括您的证书和链使用的 CA(s?),即使在提供您的证书时-and-chain 服务器接受它。 After commenting about writing a wrapper KeyManager, I realized it would be easy enough to test, and the following example works for me to send a client cert different from what the server asked for.
在对编写包装器 KeyManager 发表评论后,我意识到测试很容易,下面的示例适用于我发送与服务器要求的客户端证书不同的客户端证书。 I used SSLSocket directly for simplicity, but anything (like OkHttp) using the same SSLContext or SSLSocketFactory should work.
为简单起见,我直接使用了 SSLSocket,但使用相同 SSLContext 或 SSLSocketFactory 的任何东西(如 OkHttp)都应该可以工作。 Tested in 8u301 (but I can check some others if you want) against OpenSSL commandline, which lets me request client cert for CA X but when I submit a cert from CA Y it only logs the verification error without aborting the connection.
针对 OpenSSL 命令行在 8u301 中进行了测试(但如果需要,我可以检查其他一些),这让我可以为 CA X 请求客户端证书,但是当我从 CA Y 提交证书时,它只记录验证错误而不会中止连接。
public class SO69577136KeyManagerIgnoreCAs {
public static void main (String[] args) throws Exception {
// keystore.p12 pw truststore.p12 pw host port [Y: wrap KM to ignore issuers]
KeyStore st = KeyStore.getInstance("PKCS12");
try( InputStream is = new FileInputStream(args[0]) ){ st.load(is,args[1].toCharArray()); }
KeyManagerFactory kf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kf.init(st, args[1].toCharArray());
KeyManager[] km = kf.getKeyManagers();
try( InputStream is = new FileInputStream(args[2]) ){ st.load(is,args[3].toCharArray()); }
TrustManagerFactory tf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tf.init(st);
TrustManager[] tm = tf.getTrustManagers();
if( args.length>6 && args[6].startsWith("Y") ){
X509ExtendedKeyManager orig = (X509ExtendedKeyManager)km[0]; // exception if wrong type
km[0] = new X509ExtendedKeyManager(){
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
return orig.chooseClientAlias(keyType, null, socket);
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
// not implemented
return null;
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return orig.getCertificateChain(alias);
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
// shouldn't actually be used AFAICT but just in case
return orig.getClientAliases(keyType, issuers);
}
@Override
public PrivateKey getPrivateKey(String alias) {
return orig.getPrivateKey(alias);
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
// not implemented
return null;
}
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
return orig.chooseEngineClientAlias(keyType, null, engine);
// could just forward to chooseClientAlias(socket=null), that's what underlying does
}
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {
// not implemented
return null;
}
};
}
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(km, tm, null /* default */);
SSLSocketFactory sf = ctx.getSocketFactory();
SSLSocket ss = (SSLSocket) sf.createSocket(args[4], Integer.parseInt(args[5]));
ss.startHandshake();
System.out.println ("successful");
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.