summaryrefslogtreecommitdiffstats
path: root/keystore
diff options
context:
space:
mode:
authorAlex Klyubin <klyubin@google.com>2015-06-25 09:04:37 -0700
committerAlex Klyubin <klyubin@google.com>2015-06-25 09:09:04 -0700
commit25d2270704e246d897596c991a36233cdc620790 (patch)
tree70f1800de6e8474bbd3140a8a079eae29c3a7b48 /keystore
parentc781405f43ca06041777f2e382c0d5b7bdeac43a (diff)
downloadframeworks_base-25d2270704e246d897596c991a36233cdc620790.zip
frameworks_base-25d2270704e246d897596c991a36233cdc620790.tar.gz
frameworks_base-25d2270704e246d897596c991a36233cdc620790.tar.bz2
Support RSA encrypt using private key and PKCS#1 paddding.
Some apps such as OpenVPN Connect for some reason generate PKCS#1-padded RSA signatures using Cipher (initialized in Cipher.ENCRYPT_MODE with private key!) instead of using Signature. Unfortunately, RI supports this strange behavior and previous releases of Android Keystore did the same. So, we have to continue supporting this craziness. Bug: 22083023 Change-Id: Ife3950d0d4ceb4e44e08014635312c1252878b69
Diffstat (limited to 'keystore')
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java15
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java69
2 files changed, 66 insertions, 18 deletions
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
index 50f3ed4..38cacd0 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
@@ -731,6 +731,21 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor
return mMainDataStreamer.getProducedOutputSizeBytes();
}
+ static String opmodeToString(int opmode) {
+ switch (opmode) {
+ case Cipher.ENCRYPT_MODE:
+ return "ENCRYPT_MODE";
+ case Cipher.DECRYPT_MODE:
+ return "DECRYPT_MODE";
+ case Cipher.WRAP_MODE:
+ return "WRAP_MODE";
+ case Cipher.UNWRAP_MODE:
+ return "UNWRAP_MODE";
+ default:
+ return String.valueOf(opmode);
+ }
+ }
+
// The methods below need to be implemented by subclasses.
/**
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
index 8e58195..94ed8b4 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
@@ -60,9 +60,10 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
}
@Override
- protected boolean isEncryptingUsingPrivateKeyPermitted() {
- // RSA encryption with no padding using private key is is a way to implement raw RSA
- // signatures. We have to support this.
+ protected boolean adjustConfigForEncryptingWithPrivateKey() {
+ // RSA encryption with no padding using private key is a way to implement raw RSA
+ // signatures which JCA does not expose via Signature. We thus have to support this.
+ setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
return true;
}
@@ -198,6 +199,15 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
}
@Override
+ protected boolean adjustConfigForEncryptingWithPrivateKey() {
+ // RSA encryption with PCKS#1 padding using private key is a way to implement RSA
+ // signatures with PKCS#1 padding. We have to support this for legacy reasons.
+ setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
+ setKeymasterPaddingOverride(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
+ return true;
+ }
+
+ @Override
protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
@Override
@@ -425,6 +435,7 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
}
private final int mKeymasterPadding;
+ private int mKeymasterPaddingOverride;
private int mModulusSizeBytes = -1;
@@ -458,20 +469,15 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
// Permitted
break;
case Cipher.ENCRYPT_MODE:
- if (!isEncryptingUsingPrivateKeyPermitted()) {
+ case Cipher.WRAP_MODE:
+ if (!adjustConfigForEncryptingWithPrivateKey()) {
throw new InvalidKeyException(
- "RSA private keys cannot be used with Cipher.ENCRYPT_MODE"
+ "RSA private keys cannot be used with " + opmodeToString(opmode)
+ + " and padding "
+ + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
+ ". Only RSA public keys supported for this mode");
}
- // JCA doesn't provide a way to generate raw RSA signatures (with arbitrary
- // padding). Thus, encrypting with private key is used instead.
- setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
break;
- case Cipher.WRAP_MODE:
- throw new InvalidKeyException(
- "RSA private keys cannot be used with Cipher.WRAP_MODE"
- + ". Only RSA public keys supported for this mode");
- // break;
default:
throw new InvalidKeyException(
"RSA private keys cannot be used with opmode: " + opmode);
@@ -485,12 +491,15 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
break;
case Cipher.DECRYPT_MODE:
case Cipher.UNWRAP_MODE:
- throw new InvalidKeyException("RSA public keys cannot be used with opmode: "
- + opmode + ". Only RSA private keys supported for this opmode.");
+ throw new InvalidKeyException(
+ "RSA public keys cannot be used with " + opmodeToString(opmode)
+ + " and padding "
+ + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
+ + ". Only RSA private keys supported for this opmode.");
// break;
default:
throw new InvalidKeyException(
- "RSA public keys cannot be used with opmode: " + opmode);
+ "RSA public keys cannot be used with " + opmodeToString(opmode));
}
}
@@ -511,13 +520,22 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
setKey(keystoreKey);
}
- protected boolean isEncryptingUsingPrivateKeyPermitted() {
+ /**
+ * Adjusts the configuration of this cipher for encrypting using the private key.
+ *
+ * <p>The default implementation does nothing and refuses to adjust the configuration.
+ *
+ * @return {@code true} if the configuration has been adjusted, {@code false} if encrypting
+ * using private key is not permitted for this cipher.
+ */
+ protected boolean adjustConfigForEncryptingWithPrivateKey() {
return false;
}
@Override
protected final void resetAll() {
mModulusSizeBytes = -1;
+ mKeymasterPaddingOverride = -1;
super.resetAll();
}
@@ -530,7 +548,11 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
protected void addAlgorithmSpecificParametersToBegin(
@NonNull KeymasterArguments keymasterArgs) {
keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
+ int keymasterPadding = getKeymasterPaddingOverride();
+ if (keymasterPadding == -1) {
+ keymasterPadding = mKeymasterPadding;
+ }
+ keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
int purposeOverride = getKeymasterPurposeOverride();
if ((purposeOverride != -1)
&& ((purposeOverride == KeymasterDefs.KM_PURPOSE_SIGN)
@@ -568,4 +590,15 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase
}
return mModulusSizeBytes;
}
+
+ /**
+ * Overrides the default padding of the crypto operation.
+ */
+ protected final void setKeymasterPaddingOverride(int keymasterPadding) {
+ mKeymasterPaddingOverride = keymasterPadding;
+ }
+
+ protected final int getKeymasterPaddingOverride() {
+ return mKeymasterPaddingOverride;
+ }
}