Key's password should not have to be the same as the keystore's password
Describe the bug This SDK contains a few pieces of code that assume the key's password and the keystore's password are exactly the same.
For example, both overloads of AWSIotKeystoreHelper.getIotKeystore accept a keyStorePassword parameter that is used for two different purposes:
- Passed to
KeyStore.load - Passed to
getTempKeystoremethod ascustomerKeystorePasswordparameter that is later used forKeyStore.getKey
The KeyStore.load usage is correct. According to load's Javadoc: "A password may be given to unlock the keystore (...) or to check the integrity of the keystore data". However, the Keystore.getKey usage is wrong because the password must match the key's password, not the keystore's password. It looks like the key's password and the keystore's passwords are confused and treated as if they were the same thing, which is a wrong assumption. As a result, to make the SDK work, one must use a keystore whose password is exactly the same as the key's password.
Another example is AWSIotKeystoreHelper.saveCertificateAndPrivateKey method that uses keystorePassword parameter for both KeyStore.setKeyEntry and for KeyStore.store.
To Reproduce
val keystore = KeyStore.getInstance(KeyStore.getDefaultType()).apply { load(null) }
val certFactory = CertificateFactory.getInstance("X.509")
val certs = listOf("removed to make this code shorter", "let me know if you need real examples").map {
certFactory.generateCertificate(ByteArrayInputStream(Base64.Default.decode(it)))
}
val kpg = KeyPairGenerator.getInstance("RSA").apply { initialize(2048) }
val key = kpg.generateKeyPair().private
keystore.setKeyEntry("alias", key, "KeyPassword".toCharArray(), certs.toTypedArray())
val keystoreOutputStream = ByteArrayOutputStream()
keystore.store(keystoreOutputStream, "KeystorePassword".toCharArray())
val keystoreBytes = keystoreOutputStream.toByteArray()
keystoreOutputStream.close()
val keystoreInputStream = ByteArrayInputStream(keystoreBytes)
// Proper usage example:
val awsKeystore = KeyStore.getInstance(KeyStore.getDefaultType())
awsKeystore.load(keystoreInputStream, "KeystorePassword".toCharArray())
val recoveredKey = awsKeystore.getKey("alias", "KeyPassword".toCharArray())
println(recoveredKey.encoded.contentEquals(key.encoded))
// No way to pass both passwords:
AWSIotKeystoreHelper.getIotKeystore(
"alias",
keystoreInputStream,
"KeystorePassword"
)
Which AWS service(s) are affected? AWS SDK IoT
Expected behavior AWS SDK should accept both the keystore's password and the key's password separately and not assume they are the same.
Screenshots n/a
Environment Information (please complete the following information):
- AWS Android SDK Version: 2.73.0
- Device: all
- Android Version: all
- Specific to simulators: no
Additional context n/a
@azabost I've taken a look at the information you provided and agree with your assessment. I will mark this as feature-request so we can add overloaded methods to allow separate passwords for key and keystore. Thank you.