Keystore: Included KM_TAG_RSA_OAEP_MGF_DIGEST tag
Included KM_TAG_RSA_OAEP_MGF_DIGEST for RSA keys generation and import
if supported padding is defined as OAEP. All supported digest are added
as KM_TAG_RSA_OAEP_MGF_DIGEST and also default MGF1-SHA1 digest is added
because crypto operations could fail is MGF1ParameterSpec is not provided.
Note this includes additional Attestation parameter in returned
certificate and need to handle accordingly.
Bug: 203688354
Test: run cts -m CtsKeystoreTestCases -t android.keystore.cts.CipherTest#testKatBasicWithDifferentProviders
Change-Id: I2086f2520667ccac9116e04de39f6328a0d3fc5b
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index f900558..8efc5eb 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -68,6 +68,8 @@
public static final int KM_TAG_RSA_PUBLIC_EXPONENT = Tag.RSA_PUBLIC_EXPONENT; // KM_ULONG | 200;
public static final int KM_TAG_INCLUDE_UNIQUE_ID = Tag.INCLUDE_UNIQUE_ID; // KM_BOOL | 202;
+ public static final int KM_TAG_RSA_OAEP_MGF_DIGEST = Tag.RSA_OAEP_MGF_DIGEST;
+ // KM_ENUM_REP | 203;
public static final int KM_TAG_ACTIVE_DATETIME = Tag.ACTIVE_DATETIME; // KM_DATE | 400;
public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME =
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index d9a7994..dbd918e 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -29,6 +29,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
import java.util.Collection;
import java.util.Locale;
@@ -675,6 +677,26 @@
}
}
+ /**
+ * @hide
+ */
+ @NonNull public static @DigestEnum
+ AlgorithmParameterSpec fromKeymasterToMGF1ParameterSpec(int digest) {
+ switch (digest) {
+ default:
+ case KeymasterDefs.KM_DIGEST_SHA1:
+ return MGF1ParameterSpec.SHA1;
+ case KeymasterDefs.KM_DIGEST_SHA_2_224:
+ return MGF1ParameterSpec.SHA224;
+ case KeymasterDefs.KM_DIGEST_SHA_2_256:
+ return MGF1ParameterSpec.SHA256;
+ case KeymasterDefs.KM_DIGEST_SHA_2_384:
+ return MGF1ParameterSpec.SHA384;
+ case KeymasterDefs.KM_DIGEST_SHA_2_512:
+ return MGF1ParameterSpec.SHA512;
+ }
+ }
+
@NonNull
public static @DigestEnum String fromKeymasterToSignatureAlgorithmDigest(int digest) {
switch (digest) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
index e808c5c..7571e44 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
@@ -69,6 +69,7 @@
*/
abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStoreCryptoOperation {
private static final String TAG = "AndroidKeyStoreCipherSpiBase";
+ public static final String DEFAULT_MGF1_DIGEST = "SHA-1";
// Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after
// doFinal finishes.
@@ -133,24 +134,28 @@
if ("RSA/ECB/OAEPWithSHA-224AndMGF1Padding".equals(transform)) {
OAEPParameterSpec spec =
new OAEPParameterSpec("SHA-224", "MGF1",
- new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+ new MGF1ParameterSpec(DEFAULT_MGF1_DIGEST),
+ PSource.PSpecified.DEFAULT);
mCipher.init(opmode, key, spec, random);
} else if ("RSA/ECB/OAEPWithSHA-256AndMGF1Padding".equals(transform)) {
OAEPParameterSpec spec =
new OAEPParameterSpec("SHA-256", "MGF1",
- new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+ new MGF1ParameterSpec(DEFAULT_MGF1_DIGEST),
+ PSource.PSpecified.DEFAULT);
mCipher.init(opmode, key, spec, random);
} else if ("RSA/ECB/OAEPWithSHA-384AndMGF1Padding".equals(transform)) {
OAEPParameterSpec spec =
new OAEPParameterSpec("SHA-384", "MGF1",
- new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+ new MGF1ParameterSpec(DEFAULT_MGF1_DIGEST),
+ PSource.PSpecified.DEFAULT);
mCipher.init(opmode, key, spec, random);
} else if ("RSA/ECB/OAEPWithSHA-512AndMGF1Padding".equals(transform)) {
OAEPParameterSpec spec =
new OAEPParameterSpec("SHA-512", "MGF1",
- new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+ new MGF1ParameterSpec(DEFAULT_MGF1_DIGEST),
+ PSource.PSpecified.DEFAULT);
mCipher.init(opmode, key, spec, random);
} else {
mCipher.init(opmode, key, random);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index cdc1085..acc0005 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -16,6 +16,8 @@
package android.security.keystore2;
+import static android.security.keystore2.AndroidKeyStoreCipherSpiBase.DEFAULT_MGF1_DIGEST;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
@@ -908,6 +910,26 @@
params.add(KeyStore2ParameterUtils.makeEnum(
KeymasterDefs.KM_TAG_PADDING, padding
));
+ if (padding == KeymasterDefs.KM_PAD_RSA_OAEP) {
+ final boolean[] hasDefaultMgf1DigestBeenAdded = {false};
+ ArrayUtils.forEach(mKeymasterDigests, (digest) -> {
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, digest
+ ));
+ hasDefaultMgf1DigestBeenAdded[0] |=
+ digest.equals(KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST));
+ });
+ /* Because of default MGF1 digest is SHA-1. It has to be added in Key
+ * characteristics. Otherwise, crypto operations will fail with Incompatible
+ * MGF1 digest.
+ */
+ if (!hasDefaultMgf1DigestBeenAdded[0]) {
+ params.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST,
+ KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST)
+ ));
+ }
+ }
});
ArrayUtils.forEach(mKeymasterSignaturePaddings, (padding) -> {
params.add(KeyStore2ParameterUtils.makeEnum(
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
index 5848247..e9b66aa 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
@@ -161,10 +161,11 @@
*/
abstract static class OAEPWithMGF1Padding extends AndroidKeyStoreRSACipherSpi {
- private static final String MGF_ALGORITGM_MGF1 = "MGF1";
+ private static final String MGF_ALGORITHM_MGF1 = "MGF1";
private int mKeymasterDigest = -1;
private int mDigestOutputSizeBytes;
+ private int mKeymasterMgf1Digest = KeymasterDefs.KM_DIGEST_SHA1; // Default MGF1 digest
OAEPWithMGF1Padding(int keymasterDigest) {
super(KeymasterDefs.KM_PAD_RSA_OAEP);
@@ -189,10 +190,10 @@
+ ". Only OAEPParameterSpec supported");
}
OAEPParameterSpec spec = (OAEPParameterSpec) params;
- if (!MGF_ALGORITGM_MGF1.equalsIgnoreCase(spec.getMGFAlgorithm())) {
+ if (!MGF_ALGORITHM_MGF1.equalsIgnoreCase(spec.getMGFAlgorithm())) {
throw new InvalidAlgorithmParameterException(
"Unsupported MGF: " + spec.getMGFAlgorithm()
- + ". Only " + MGF_ALGORITGM_MGF1 + " supported");
+ + ". Only " + MGF_ALGORITHM_MGF1 + " supported");
}
String jcaDigest = spec.getDigestAlgorithm();
int keymasterDigest;
@@ -225,11 +226,6 @@
}
MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec) mgfParams;
String mgf1JcaDigest = mgfSpec.getDigestAlgorithm();
- if (!KeyProperties.DIGEST_SHA1.equalsIgnoreCase(mgf1JcaDigest)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported MGF1 digest: " + mgf1JcaDigest
- + ". Only " + KeyProperties.DIGEST_SHA1 + " supported");
- }
PSource pSource = spec.getPSource();
if (!(pSource instanceof PSource.PSpecified)) {
throw new InvalidAlgorithmParameterException(
@@ -244,6 +240,7 @@
+ ". Only pSpecifiedEmpty (PSource.PSpecified.DEFAULT) supported");
}
mKeymasterDigest = keymasterDigest;
+ mKeymasterMgf1Digest = KeyProperties.Digest.toKeymaster(mgf1JcaDigest);
mDigestOutputSizeBytes =
(KeymasterUtils.getDigestOutputSizeBits(keymasterDigest) + 7) / 8;
}
@@ -273,10 +270,10 @@
protected final AlgorithmParameters engineGetParameters() {
OAEPParameterSpec spec =
new OAEPParameterSpec(
- KeyProperties.Digest.fromKeymaster(mKeymasterDigest),
- MGF_ALGORITGM_MGF1,
- MGF1ParameterSpec.SHA1,
- PSource.PSpecified.DEFAULT);
+ KeyProperties.Digest.fromKeymaster(mKeymasterDigest),
+ MGF_ALGORITHM_MGF1,
+ KeyProperties.Digest.fromKeymasterToMGF1ParameterSpec(mKeymasterMgf1Digest),
+ PSource.PSpecified.DEFAULT);
try {
AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP");
params.init(spec);
@@ -298,6 +295,9 @@
parameters.add(KeyStore2ParameterUtils.makeEnum(
KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest
));
+ parameters.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, mKeymasterMgf1Digest
+ ));
}
@Override
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 33411e1..9d424e9 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -16,6 +16,8 @@
package android.security.keystore2;
+import static android.security.keystore2.AndroidKeyStoreCipherSpiBase.DEFAULT_MGF1_DIGEST;
+
import android.annotation.NonNull;
import android.hardware.biometrics.BiometricManager;
import android.hardware.security.keymint.HardwareAuthenticatorType;
@@ -511,6 +513,28 @@
KeymasterDefs.KM_TAG_PADDING,
padding
));
+ if (padding == KeymasterDefs.KM_PAD_RSA_OAEP) {
+ if (spec.isDigestsSpecified()) {
+ boolean hasDefaultMgf1DigestBeenAdded = false;
+ for (String digest : spec.getDigests()) {
+ importArgs.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST,
+ KeyProperties.Digest.toKeymaster(digest)
+ ));
+ hasDefaultMgf1DigestBeenAdded |= digest.equals(DEFAULT_MGF1_DIGEST);
+ }
+ /* Because of default MGF1 digest is SHA-1. It has to be added in Key
+ * characteristics. Otherwise, crypto operations will fail with Incompatible
+ * MGF1 digest.
+ */
+ if (!hasDefaultMgf1DigestBeenAdded) {
+ importArgs.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST,
+ KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST)
+ ));
+ }
+ }
+ }
}
for (String padding : spec.getSignaturePaddings()) {
importArgs.add(KeyStore2ParameterUtils.makeEnum(
diff --git a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
index dcdd7de..54955c6 100644
--- a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
@@ -78,6 +78,7 @@
kp.value = KeyParameterValue.blockMode(v);
break;
case Tag.DIGEST:
+ case Tag.RSA_OAEP_MGF_DIGEST:
kp.value = KeyParameterValue.digest(v);
break;
case Tag.EC_CURVE: