aws-amplify / aws-sdk-android

AWS SDK for Android. For more information, see our web site:
https://docs.amplify.aws
Other
1.03k stars 548 forks source link

How can I use an AndroidKeyStore based keypair with AWSIotKeystoreHelper / AWSIotMqttManager #3197

Closed jprofit-kt closed 1 year ago

jprofit-kt commented 1 year ago

The APIs for AWSIotKeystoreHelper and AWSIotMqttManager appear to require direct export access to the private key information. As such they are incompatible with hardware based keystore implementations including Android's AndroidKeyStore. This seems like a huge limitation if true. I'm hoping there is some way to use hardware backed keys that I am just not seeing.

Which AWS Services are you utilizing? AWSIotMqttManager via AWSIotKeystoreHelper

Provide code snippets (if applicable) The SDK documentation states that I should use AWSIotKeystoreHelper to create a keystore that can be used by AWSIotMqttManager. Here are the two api calls for creating such a keystore:

static java.security.KeyStore getIotKeystore(java.lang.String certId, java.io.InputStream keyStoreInputStream, java.lang.String keyStorePassword) Get certificate and private key from stream.
-- | --
static java.security.KeyStore | getIotKeystore(java.lang.String certId, java.lang.String keystorePath, java.lang.String keystoreName, java.lang.String keyStorePassword) Get certificate and private key from keystore on the file system.

In both cases, if an AndroidKeystore is passed in, exceptions are thrown when getIotKeystore attempts to directly import a private key via it's call to setKeyEntry on line 307:

tempKeystore.setKeyEntry("key-alias", key, AWS_IOT_INTERNAL_KEYSTORE_PASSWORD.toCharArray(), xcerts);

This exception occurs because the 'key' argument coming from the passed in keystore does not allow direct access to the actual private key information (as designed). key.getEncoded() for example, returns null which is also correct for hardware based keys.

I have also tried passing a AndroidKeystore directly into AWSIosMqttManager.connect(). This also fails because the AWS code appears to assume that it's keystore's private keys are fully decryptable with a well known password which is never the case for hardware backed keystores.

Environment(please complete the following information):

Device Information (please complete the following information):

jprofit-kt commented 1 year ago

This issue got tagged as a "feature request". Does this mean that the AWS Client Library for Android does not currently support hardware based key stores (Trusted Execution Engine, etc)?

tylerjroach commented 1 year ago

Hi @jprofit-kt,

KeyStore ultimately gets passed here: https://github.com/aws-amplify/aws-sdk-android/blob/main/aws-android-sdk-iot/src/main/java/com/amazonaws/mobileconnectors/iot/AWSIotSslUtility.java#L77 to init the KeyManagerFactory, and ultimately to create an SSLSocketFactory.

While I don't see any explicit references to AndroidKeyStore in our codebase, I believe it may still be supported. We have a previous issue mentioning the use of AndroidKeyStore: https://github.com/aws-amplify/aws-sdk-android/issues/1008.

Could you share how you are creating your AndroidKeyStore. I found a few similar questions on SO that reference using AndroidKeyStore for KeyManagerFactory and it appears that it should be possible, but may require creating the key differently (ex: sign vs encrypt as referenced in the links below).

https://stackoverflow.com/questions/55692965/use-hardware-backed-keys-in-sslcontext https://stackoverflow.com/questions/71324358/getting-error-creating-sslcontext-keymanagerfactory-using-androidkeystore-in-api

Let me know if either of these posts help in any way, and if not, please post how you are using AndroidKeyStore.

mattcreaser commented 1 year ago

Closing due to inactivity. Please open another issue if you need anything else.