Open vixrt opened 3 years ago
The final error here is a little unhelpful, sorry, and I think we can improve that in a future release and there's possibly a bug.
The problem here boils down to the custom Provider
you are using to build the trust store for the connection, so you should be able to reproduce the same error without okhttp and Retrofit - just open a TLS socket to your web server using the same SslContext
.
What's looks to be going on is a little convoluted.
Conscrypt's TLS code is unable to directly use the certificate you load for crypto operations (I'll come back to why), so it wraps it to create a delegated key, which is intended to find a security Provider
which can use the key and delegate all operations to that Provider
.
The algorithm for finding a suitable provider goes like this:
RSA/ECB/
, e.g. RSA/ECB/PKCS1Padding
Providers
which are not Conscrypt which support this algorithmCipher
instance from each matchingProvider
with the delegated keyProvider
is found, throw the exception you are seeing.So, your custom Provider
doesn't claim to support RSA/ECB/PKCS1Padding
. There are a couple of possible reasons why this might not be a bug:
RSA/None
but historically a lot of code used ECB
in the resource string as JCA expects some kind of mode name. Conscrypt should maybe try both.So, tl;dr Conscrypt doesn't think it can handle the key and it doesn't think any other Provider
can handle this key format.
The simple "fix" is to make Conscrypt think your custom Provider
can handle the key, which means your provider should advertise support for RSA/ECB/PKCS1Padding
, then Conscrypt will find it and delegate crypto operations for this key to it.
Why doesn't Conscrypt think it can handle the key? The key was created by your custom Provider
so it's not a subclass of OpenSSLKey
which is what Conscrypt uses. If it's a subclass of RsaPrivateKey
and key.getFormat()
returns PKCS#8
then Conscrypt will generate an OpenSSLKey
from the output of key.getEncoded()
.
However if your custom provider is some kind of hardware keystore then obviously that won't work as the private values won't be accessible, which means the only way to get it to work is as a delegating key, which means Conscrypt needs to be able to find the correct Provider
to delegate to, as above.
Also, unless you have compelling reasons to do otherwise, it's better to accept the default TLS config, e.g.
val sslContext = SSLContext.getInstance("TLS")
and then don't customise the list of supported versions or cipher suites.
Please close this if that answers your question, or assign back to me if I've missed something.
Hi @prbprbprb , thanks for the reply Now my code is
val trustManager = trustManagers[0] as X509TrustManager
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(keyManagers, null, null)
return builder.sslSocketFactory(sslContext.socketFactory, trustManager).build()
At the end of creating the okhttpclient
I tried removing the cipher specifications and to getInstance of "TLS" only but it doesn't work
I have an hardware keystore, it's the official italian identification card.
I simplified the real code, which is from here https://github.com/italia/cieid-android-sdk the official italian repository You can find more here https://github.com/italia/cieid-android-sdk/tree/master/cieidsdk/src/main/java/it/ipzs/cieidsdk/ciekeystore
I still open the issue here and not there for 2 reasons
1) The dev won't release the full code of the app (no one knows why, it goes even against italian laws) 2) I think the issue is within this library, not in the project in general, because that code is used in the official app and the official app works
Thanks again
I got hit with this same exact issue to get mutual authentication TLS working with a custom keystore. I had to make some major changes to the client side of security provider to get it to work. I copied a bunch of code from the AndroidKeyStore, specifically search for adjustConfigForEncryptingWithPrivateKey
in the keystore provider code: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/android10-release/keystore/java/android/security
Also see the code in the provider class that advertises support for a nonsense Cipher with RSA private key (and sensible Cipher with RSA public key):
putAsymmetricCipherImpl("RSA/ECB/NoPadding",
PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$NoPadding");
put("Alg.Alias.Cipher.RSA/None/NoPadding", "RSA/ECB/NoPadding");
putAsymmetricCipherImpl("RSA/ECB/PKCS1Padding",
PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$PKCS1Padding");
put("Alg.Alias.Cipher.RSA/None/PKCS1Padding", "RSA/ECB/PKCS1Padding");
private void putAsymmetricCipherImpl(String transformation, String implClass) {
put("Cipher." + transformation, implClass);
put("Cipher." + transformation + " SupportedKeyClasses",
KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
}
The actual implementation of our crypto operations didn't need to change since the client side of the provider switches from encryption to signing before actually performing the operation. It's definitely weird stuff.
Our provider was working fine on Android 8.1, not sure if it was Android 9 or 10 that broke it, we jumped straight from 8.1 to 10.
Bug appears to be on this line:
Suggested fix for conscrypt; why not just perform the intended operation: a Signature
with an RSA private key instead of trying to do a Cipher operation? Or try both operations to work with providers that can do only one or the other, then fail if neither Cipher nor Signature with a private RSA key works.
I'm developing a kotlin android app, but I get this
I am using android 11
Here is some code that maybe can help better understanding my problem
Create OkHttpClient
Create Retrofit
And then I do an http post
And this is the postInterface
Thanks in advance