简体   繁体   English

OkHttp 客户端身份验证无法验证服务器并在同一请求中发送客户端证书

[英]OkHttp client authentication failing to validate server and send client certificate in the same request

I keep editing this question as I dig further into it.当我进一步深入研究这个问题时,我一直在编辑这个问题。

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.

相关问题 请求客户端证书认证的URL - Request a URL that client certificate authentication 向 OkHttp 客户端添加自定义证书 - Adding a custom certificate to an OkHttp Client 如何请求需要客户端证书进行身份验证的 URL - How to request a URL that requires a client certificate for authentication 具有客户端证书身份验证的HttpClient后请求 - HttpClient post-request with Client Certificate Authentication 带有客户端证书返回访问的 https 请求在 android 中被拒绝,但它在 post man 中运行良好,改造和 okhttp3 返回相同的错误 - https request with client certificate return access denied in android but it works good in post man , retrofit and okhttp3 return the same error 无法通过带有客户端证书的SSL发出SOAP请求 - Failing to make a SOAP request via SSL with client certificate 带有客户端证书的 TLS 握手失败 - TLS with client certificate failing handshake java http客户端如何验证服务器的CA证书? - How does java http client validate Server's CA Certificate? SSL:客户端身份验证,同一存储区中的多个证书版本 - SSL: Client Authentication, multiple certificate version in same store Android HTTPS Server-客户端身份验证自我认证 - Android HTTPS Server - Client Authentication self-certificate
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM