diff --git a/aosp_integration_patches_aosp_12_r15/device_google_cuttlefish.patch b/aosp_integration_patches_aosp_12_r15/device_google_cuttlefish.patch
new file mode 100644
index 00000000..b0fca48f
--- /dev/null
+++ b/aosp_integration_patches_aosp_12_r15/device_google_cuttlefish.patch
@@ -0,0 +1,62 @@
+diff --git a/shared/device.mk b/shared/device.mk
+index 8647d0175..d1955772f 100644
+--- a/shared/device.mk
++++ b/shared/device.mk
+@@ -538,6 +538,10 @@ endif
+ PRODUCT_PACKAGES += \
+ $(LOCAL_KEYMINT_PRODUCT_PACKAGE)
+
++PRODUCT_PACKAGES += \
++ android.hardware.security.keymint-service.strongbox
++
++
+ # Keymint configuration
+ PRODUCT_COPY_FILES += \
+ frameworks/native/data/etc/android.software.device_id_attestation.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.device_id_attestation.xml
+diff --git a/shared/sepolicy/vendor/file_contexts b/shared/sepolicy/vendor/file_contexts
+index 20538a50f..2b74242f7 100644
+--- a/shared/sepolicy/vendor/file_contexts
++++ b/shared/sepolicy/vendor/file_contexts
+@@ -87,6 +87,7 @@
+ /vendor/bin/hw/android\.hardware\.input\.classifier@1\.0-service.default u:object_r:hal_input_classifier_default_exec:s0
+ /vendor/bin/hw/android\.hardware\.thermal@2\.0-service\.mock u:object_r:hal_thermal_default_exec:s0
+ /vendor/bin/hw/android\.hardware\.security\.keymint-service\.remote u:object_r:hal_keymint_remote_exec:s0
++/vendor/bin/hw/android\.hardware\.security\.keymint-service\.strongbox u:object_r:hal_keymint_strongbox_exec:s0
+ /vendor/bin/hw/android\.hardware\.keymaster@4\.1-service.remote u:object_r:hal_keymaster_remote_exec:s0
+ /vendor/bin/hw/android\.hardware\.gatekeeper@1\.0-service.remote u:object_r:hal_gatekeeper_remote_exec:s0
+ /vendor/bin/hw/android\.hardware\.oemlock-service.example u:object_r:hal_oemlock_default_exec:s0
+diff --git a/shared/sepolicy/vendor/hal_keymint_strongbox.te b/shared/sepolicy/vendor/hal_keymint_strongbox.te
+new file mode 100644
+index 000000000..09d0da267
+--- /dev/null
++++ b/shared/sepolicy/vendor/hal_keymint_strongbox.te
+@@ -0,0 +1,15 @@
++type hal_keymint_strongbox, domain;
++hal_server_domain(hal_keymint_strongbox, hal_keymint)
++
++type hal_keymint_strongbox_exec, exec_type, vendor_file_type, file_type;
++init_daemon_domain(hal_keymint_strongbox)
++
++vndbinder_use(hal_keymint_strongbox)
++get_prop(hal_keymint_strongbox, vendor_security_patch_level_prop);
++
++# Allow access to sockets
++allow hal_keymint_strongbox self:tcp_socket { connect create write read getattr getopt setopt };
++allow hal_keymint_strongbox port_type:tcp_socket name_connect;
++allow hal_keymint_strongbox port:tcp_socket { name_connect };
++allow hal_keymint_strongbox vendor_data_file:file { open read getattr };
++
+diff --git a/shared/sepolicy/vendor/service_contexts b/shared/sepolicy/vendor/service_contexts
+index d20d026cf..b8f0155ab 100644
+--- a/shared/sepolicy/vendor/service_contexts
++++ b/shared/sepolicy/vendor/service_contexts
+@@ -4,6 +4,9 @@ android.hardware.neuralnetworks.IDevice/nnapi-sample_float_slow u:object_r:hal_n
+ android.hardware.neuralnetworks.IDevice/nnapi-sample_minimal u:object_r:hal_neuralnetworks_service:s0
+ android.hardware.neuralnetworks.IDevice/nnapi-sample_quant u:object_r:hal_neuralnetworks_service:s0
+ android.hardware.neuralnetworks.IDevice/nnapi-sample_sl_shim u:object_r:hal_neuralnetworks_service:s0
++android.hardware.security.keymint.IKeyMintDevice/strongbox u:object_r:hal_keymint_service:s0
++android.hardware.security.sharedsecret.ISharedSecret/strongbox u:object_r:hal_sharedsecret_service:s0
++android.hardware.security.keymint.IRemotelyProvisionedComponent/strongbox u:object_r:hal_keymint_service:s0
+
+ # Binder service mappings
+ gce u:object_r:gce_service:s0
diff --git a/aosp_integration_patches_aosp_12_r15/hardware_interfaces.patch b/aosp_integration_patches_aosp_12_r15/hardware_interfaces.patch
new file mode 100644
index 00000000..bf456260
--- /dev/null
+++ b/aosp_integration_patches_aosp_12_r15/hardware_interfaces.patch
@@ -0,0 +1,1213 @@
+diff --git a/compatibility_matrices/compatibility_matrix.6.xml b/compatibility_matrices/compatibility_matrix.6.xml
+index aee2c5164..1391bbf54 100644
+--- a/compatibility_matrices/compatibility_matrix.6.xml
++++ b/compatibility_matrices/compatibility_matrix.6.xml
+@@ -349,6 +349,13 @@
+ default
+
+
++
++ android.hardware.security.keymint
++
++ IRemotelyProvisionedComponent
++ strongbox
++
++
+
+ android.hardware.light
+ 1
+diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
+index 8b6e8414d..4955db7d7 100644
+--- a/compatibility_matrices/compatibility_matrix.current.xml
++++ b/compatibility_matrices/compatibility_matrix.current.xml
+@@ -66,7 +66,7 @@
+
+ IEvsEnumerator
+ default
+- [a-z]+/[0-9]+
++ [a-z]/[0-9]
+
+
+
+@@ -168,7 +168,7 @@
+ 2.4-7
+
+ ICameraProvider
+- [^/]+/[0-9]+
++ [^/]/[0-9]
+
+
+
+@@ -349,6 +349,13 @@
+ default
+
+
++
++ android.hardware.security.keymint
++
++ IRemotelyProvisionedComponent
++ strongbox
++
++
+
+ android.hardware.light
+ 1
+@@ -511,6 +518,15 @@
+ strongbox
+
+
++
++ android.hardware.security.sharedsecret
++ 1
++
++ ISharedSecret
++ strongbox
++
++
++
+
+ android.hardware.sensors
+ 1.0
+diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+index 26ed34427..2d5bc9575 100644
+--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
++++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+@@ -198,7 +198,7 @@ TEST_P(AttestKeyTest, RsaAttestedAttestKeys) {
+ AttestationKey attest_key;
+ vector attest_key_characteristics;
+ vector attest_key_cert_chain;
+- ASSERT_EQ(ErrorCode::OK,
++ auto result =
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .AttestKey()
+@@ -209,7 +209,13 @@ TEST_P(AttestKeyTest, RsaAttestedAttestKeys) {
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+- &attest_key_characteristics, &attest_key_cert_chain));
++ &attest_key_characteristics, &attest_key_cert_chain);
++ //Strongbox does not support Factory provisioned attestation key.
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::OK, result);
+
+ EXPECT_GT(attest_key_cert_chain.size(), 1);
+ verify_subject_and_serial(attest_key_cert_chain[0], serial_int, subject, false);
+@@ -297,7 +303,7 @@ TEST_P(AttestKeyTest, RsaAttestKeyChaining) {
+ attest_key_opt = attest_key;
+ }
+
+- EXPECT_EQ(ErrorCode::OK,
++ auto result =
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .AttestKey()
+@@ -308,8 +314,13 @@ TEST_P(AttestKeyTest, RsaAttestKeyChaining) {
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+- &cert_chain_list[i]));
+-
++ &cert_chain_list[i]);
++ // Strongbox does not support Factory provisioned attestation key.
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::OK, result);
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ ASSERT_GT(cert_chain_list[i].size(), 0);
+@@ -369,7 +380,7 @@ TEST_P(AttestKeyTest, EcAttestKeyChaining) {
+ attest_key_opt = attest_key;
+ }
+
+- EXPECT_EQ(ErrorCode::OK,
++ auto result =
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .AttestKey()
+@@ -380,8 +391,13 @@ TEST_P(AttestKeyTest, EcAttestKeyChaining) {
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+- &cert_chain_list[i]));
+-
++ &cert_chain_list[i]);
++ // Strongbox does not support Factory provisioned attestation key.
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::OK, result);
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ ASSERT_GT(cert_chain_list[i].size(), 0);
+@@ -442,35 +458,40 @@ TEST_P(AttestKeyTest, AlternateAttestKeyChaining) {
+ attest_key.keyBlob = key_blob_list[i - 1];
+ attest_key_opt = attest_key;
+ }
+-
++ ErrorCode result;
+ if ((i & 0x1) == 1) {
+- EXPECT_EQ(ErrorCode::OK,
+- GenerateKey(AuthorizationSetBuilder()
+- .EcdsaSigningKey(EcCurve::P_256)
+- .AttestKey()
+- .AttestationChallenge("foo")
+- .AttestationApplicationId("bar")
+- .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+- .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+- .Authorization(TAG_NO_AUTH_REQUIRED)
+- .SetDefaultValidity(),
+- attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+- &cert_chain_list[i]));
++ result =
++ GenerateKey(AuthorizationSetBuilder()
++ .EcdsaSigningKey(EcCurve::P_256)
++ .AttestKey()
++ .AttestationChallenge("foo")
++ .AttestationApplicationId("bar")
++ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
++ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
++ .Authorization(TAG_NO_AUTH_REQUIRED)
++ .SetDefaultValidity(),
++ attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
++ &cert_chain_list[i]);
+ } else {
+- EXPECT_EQ(ErrorCode::OK,
+- GenerateKey(AuthorizationSetBuilder()
+- .RsaSigningKey(2048, 65537)
+- .AttestKey()
+- .AttestationChallenge("foo")
+- .AttestationApplicationId("bar")
+- .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+- .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+- .Authorization(TAG_NO_AUTH_REQUIRED)
+- .SetDefaultValidity(),
+- attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+- &cert_chain_list[i]));
++ result =
++ GenerateKey(AuthorizationSetBuilder()
++ .RsaSigningKey(2048, 65537)
++ .AttestKey()
++ .AttestationChallenge("foo")
++ .AttestationApplicationId("bar")
++ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
++ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
++ .Authorization(TAG_NO_AUTH_REQUIRED)
++ .SetDefaultValidity(),
++ attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
++ &cert_chain_list[i]);
+ }
+-
++ // Strongbox does not support Factory provisioned attestation key.
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::OK, result);
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ ASSERT_GT(cert_chain_list[i].size(), 0);
+diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+index 20324117b..741bcf8f6 100644
+--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
++++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+@@ -1145,6 +1145,15 @@ vector KeyMintAidlTestBase::InvalidCurves() {
+ }
+ }
+
++vector KeyMintAidlTestBase::ValidExponents() {
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ return {65537};
++ } else {
++ return {3, 65537};
++ }
++}
++
++
+ vector KeyMintAidlTestBase::ValidDigests(bool withNone, bool withMD5) {
+ switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
+diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+index ec3fcf6a3..0561a9b94 100644
+--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
++++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+@@ -250,7 +250,9 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam {
+ .SetDefaultValidity();
+ tagModifier(&rsaBuilder);
+ errorCode = GenerateKey(rsaBuilder, &rsaKeyData.blob, &rsaKeyData.characteristics);
+- EXPECT_EQ(expectedReturn, errorCode);
++ if (!(SecLevel() == SecurityLevel::STRONGBOX && ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED == errorCode)) {
++ EXPECT_EQ(expectedReturn, errorCode);
++ }
+
+ /* ECDSA */
+ KeyData ecdsaKeyData;
+@@ -262,7 +264,10 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam {
+ .SetDefaultValidity();
+ tagModifier(&ecdsaBuilder);
+ errorCode = GenerateKey(ecdsaBuilder, &ecdsaKeyData.blob, &ecdsaKeyData.characteristics);
+- EXPECT_EQ(expectedReturn, errorCode);
++ if (!(SecLevel() == SecurityLevel::STRONGBOX && ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED == errorCode)) {
++ EXPECT_EQ(expectedReturn, errorCode);
++ }
++
+ return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData};
+ }
+ bool IsSecure() const { return securityLevel_ != SecurityLevel::SOFTWARE; }
+@@ -279,6 +284,7 @@ class KeyMintAidlTestBase : public ::testing::TestWithParam {
+ vector InvalidCurves();
+
+ vector ValidDigests(bool withNone, bool withMD5);
++ vector ValidExponents();
+
+ static vector build_params() {
+ auto params = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
+diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+index 5a87b8385..d30f9dae9 100644
+--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
++++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+@@ -902,8 +902,8 @@ TEST_P(NewKeyGenerationTest, RsaWithAttestation) {
+ for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ vector key_blob;
+ vector key_characteristics;
+- ASSERT_EQ(ErrorCode::OK,
+- GenerateKey(AuthorizationSetBuilder()
++
++ auto result = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+@@ -913,8 +913,14 @@ TEST_P(NewKeyGenerationTest, RsaWithAttestation) {
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+- &key_blob, &key_characteristics));
++ &key_blob, &key_characteristics);
+
++ // Strongbox does not support Factory provisioned attestation key
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::OK, result);
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
+@@ -1031,8 +1037,7 @@ TEST_P(NewKeyGenerationTest, RsaEncryptionWithAttestation) {
+
+ vector key_blob;
+ vector key_characteristics;
+- ASSERT_EQ(ErrorCode::OK,
+- GenerateKey(AuthorizationSetBuilder()
++ auto result = GenerateKey(AuthorizationSetBuilder()
+ .RsaEncryptionKey(key_size, 65537)
+ .Padding(PaddingMode::NONE)
+ .AttestationChallenge(challenge)
+@@ -1041,8 +1046,14 @@ TEST_P(NewKeyGenerationTest, RsaEncryptionWithAttestation) {
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+- &key_blob, &key_characteristics));
++ &key_blob, &key_characteristics);
+
++ // Strongbox does not support Factory provisioned attestation key
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::OK, result);
+ ASSERT_GT(key_blob.size(), 0U);
+ AuthorizationSet auths;
+ for (auto& entry : key_characteristics) {
+@@ -1143,15 +1154,21 @@ TEST_P(NewKeyGenerationTest, RsaWithAttestationMissAppId) {
+ vector key_blob;
+ vector key_characteristics;
+
+- ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+- GenerateKey(AuthorizationSetBuilder()
++ auto result = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .AttestationChallenge(challenge)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+- &key_blob, &key_characteristics));
++ &key_blob, &key_characteristics);
++
++ // Strongbox does not support Factory provisioned attestation key
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, result);
+ }
+
+ /*
+@@ -1261,8 +1278,8 @@ TEST_P(NewKeyGenerationTest, LimitedUsageRsaWithAttestation) {
+ for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ vector key_blob;
+ vector key_characteristics;
+- ASSERT_EQ(ErrorCode::OK,
+- GenerateKey(AuthorizationSetBuilder()
++
++ auto result = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+@@ -1273,7 +1290,14 @@ TEST_P(NewKeyGenerationTest, LimitedUsageRsaWithAttestation) {
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+- &key_blob, &key_characteristics));
++ &key_blob, &key_characteristics);
++
++ //Strongbox does not support Factory provisioned attestation key
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::OK, result);
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+@@ -1404,8 +1428,8 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestation) {
+ for (auto curve : ValidCurves()) {
+ vector key_blob;
+ vector key_characteristics;
+- ASSERT_EQ(ErrorCode::OK,
+- GenerateKey(AuthorizationSetBuilder()
++
++ auto result = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::NONE)
+@@ -1414,7 +1438,15 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestation) {
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+- &key_blob, &key_characteristics));
++ &key_blob, &key_characteristics);
++
++ //Strongbox does not support Factory provisioned attestation key
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::OK, result);
++
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
+@@ -1491,6 +1523,12 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationTags) {
+ // Tag not required to be supported by all KeyMint implementations.
+ continue;
+ }
++
++ //Strongbox does not support Factory provisioned attestation key
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ continue;
++ }
+ ASSERT_EQ(result, ErrorCode::OK);
+ ASSERT_GT(key_blob.size(), 0U);
+
+@@ -1540,8 +1578,14 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationTags) {
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity();
+ builder.push_back(tag);
+- ASSERT_EQ(ErrorCode::CANNOT_ATTEST_IDS,
+- GenerateKey(builder, &key_blob, &key_characteristics));
++
++ auto result = GenerateKey(builder, &key_blob, &key_characteristics);
++ //Strongbox does not support Factory provisioned attestation key
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ continue;
++ }
++ ASSERT_EQ(ErrorCode::CANNOT_ATTEST_IDS, result);
+ }
+ }
+
+@@ -1577,6 +1621,13 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationTagNoApplicationId) {
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity(),
+ &key_blob, &key_characteristics);
++
++ // Strongbox does not support Factory provisioned attestation key
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++
+ ASSERT_EQ(result, ErrorCode::OK);
+ ASSERT_GT(key_blob.size(), 0U);
+
+@@ -1655,13 +1706,19 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationRequireAppId) {
+ vector key_blob;
+ vector key_characteristics;
+
+- ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+- GenerateKey(AuthorizationSetBuilder()
++ auto result = GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .SetDefaultValidity(),
+- &key_blob, &key_characteristics));
++ &key_blob, &key_characteristics);
++
++ // Strongbox does not support Factory provisioned attestation key
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, result);
+ }
+
+ /*
+@@ -1718,14 +1775,21 @@ TEST_P(NewKeyGenerationTest, AttestationApplicationIDLengthProperlyEncoded) {
+ const string app_id(length, 'a');
+ vector key_blob;
+ vector key_characteristics;
+- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
++ auto result = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .SetDefaultValidity(),
+- &key_blob, &key_characteristics));
++ &key_blob, &key_characteristics);
++ //Strongbox does not support Factory provisioned attestation key
++ if (SecLevel() == SecurityLevel::STRONGBOX) {
++ ASSERT_EQ(ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED, result);
++ return;
++ }
++ ASSERT_EQ(ErrorCode::OK, result);
++
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
+@@ -3755,25 +3819,27 @@ typedef KeyMintAidlTestBase EncryptionOperationsTest;
+ * Verifies that raw RSA decryption works.
+ */
+ TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+- for (uint64_t exponent : {3, 65537}) {
+- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+- .Authorization(TAG_NO_AUTH_REQUIRED)
+- .RsaEncryptionKey(2048, exponent)
+- .Padding(PaddingMode::NONE)
+- .SetDefaultValidity()));
+
+- string message = string(2048 / 8, 'a');
+- auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+- string ciphertext1 = LocalRsaEncryptMessage(message, params);
+- EXPECT_EQ(2048U / 8, ciphertext1.size());
++ for (uint64_t exponent : ValidExponents())
++ {
++ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
++ .Authorization(TAG_NO_AUTH_REQUIRED)
++ .RsaEncryptionKey(2048, exponent)
++ .Padding(PaddingMode::NONE)
++ .SetDefaultValidity()));
+
+- string ciphertext2 = LocalRsaEncryptMessage(message, params);
+- EXPECT_EQ(2048U / 8, ciphertext2.size());
++ string message = string(2048 / 8, 'a');
++ auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
++ string ciphertext1 = LocalRsaEncryptMessage(message, params);
++ EXPECT_EQ(2048U / 8, ciphertext1.size());
+
+- // Unpadded RSA is deterministic
+- EXPECT_EQ(ciphertext1, ciphertext2);
++ string ciphertext2 = LocalRsaEncryptMessage(message, params);
++ EXPECT_EQ(2048U / 8, ciphertext2.size());
+
+- CheckedDeleteKey();
++ // Unpadded RSA is deterministic
++ EXPECT_EQ(ciphertext1, ciphertext2);
++
++ CheckedDeleteKey();
+ }
+ }
+
+@@ -6255,7 +6321,7 @@ TEST_P(ClearOperationsTest, TooManyOperations) {
+ size_t i;
+
+ for (i = 0; i < max_operations; i++) {
+- result = Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, op_handles[i]);
++ result = Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params, op_handles[i]);
+ if (ErrorCode::OK != result) {
+ break;
+ }
+@@ -6263,12 +6329,12 @@ TEST_P(ClearOperationsTest, TooManyOperations) {
+ EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS, result);
+ // Try again just in case there's a weird overflow bug
+ EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
+- Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params));
++ Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params));
+ for (size_t j = 0; j < i; j++) {
+ EXPECT_EQ(ErrorCode::OK, Abort(op_handles[j]))
+ << "Aboort failed for i = " << j << std::endl;
+ }
+- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params));
++ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params));
+ AbortIfNeeded();
+ }
+
+@@ -6367,7 +6433,6 @@ TEST_P(KeyAgreementTest, Ecdh) {
+ OPENSSL_free(p);
+
+ // Generate EC key in KeyMint (only access to public key material)
+- vector challenge = {0x41, 0x42};
+ EXPECT_EQ(
+ ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+@@ -6376,7 +6441,6 @@ TEST_P(KeyAgreementTest, Ecdh) {
+ .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+ .Authorization(TAG_ALGORITHM, Algorithm::EC)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, {0x61, 0x62})
+- .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .SetDefaultValidity()))
+ << "Failed to generate key";
+ ASSERT_GT(cert_chain_.size(), 0);
+@@ -6456,14 +6520,24 @@ TEST_P(EarlyBootKeyTest, CreateEarlyBootKeys) {
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
+
+ for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) {
++
++ if (SecLevel() == SecurityLevel::STRONGBOX && keyData.blob.size() == 0U) {
++ continue;
++ }
+ ASSERT_GT(keyData.blob.size(), 0U);
+ AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics);
+ EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params;
+ }
+ CheckedDeleteKey(&aesKeyData.blob);
+ CheckedDeleteKey(&hmacKeyData.blob);
+- CheckedDeleteKey(&rsaKeyData.blob);
+- CheckedDeleteKey(&ecdsaKeyData.blob);
++
++ if (rsaKeyData.blob.size() != 0U) {
++ CheckedDeleteKey(&rsaKeyData.blob);
++ }
++ if (ecdsaKeyData.blob.size() != 0U) {
++ CheckedDeleteKey(&ecdsaKeyData.blob);
++ }
++
+ }
+
+ /*
+@@ -6479,14 +6553,21 @@ TEST_P(EarlyBootKeyTest, CreateAttestedEarlyBootKey) {
+ });
+
+ for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) {
++ if (SecLevel() == SecurityLevel::STRONGBOX && keyData.blob.size() == 0U) {
++ continue;
++ }
+ ASSERT_GT(keyData.blob.size(), 0U);
+ AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics);
+ EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params;
+ }
+ CheckedDeleteKey(&aesKeyData.blob);
+ CheckedDeleteKey(&hmacKeyData.blob);
+- CheckedDeleteKey(&rsaKeyData.blob);
+- CheckedDeleteKey(&ecdsaKeyData.blob);
++ if (rsaKeyData.blob.size() != 0U) {
++ CheckedDeleteKey(&rsaKeyData.blob);
++ }
++ if (ecdsaKeyData.blob.size() != 0U) {
++ CheckedDeleteKey(&ecdsaKeyData.blob);
++ }
+ }
+
+ /*
+diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+index 38f358686..74e44c7b4 100644
+--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
++++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+@@ -164,6 +164,7 @@ class VtsRemotelyProvisionedComponentTests : public testing::TestWithParamgetHardwareInfo(&rpcHardwareInfo).isOk());
+ }
+
+ static vector build_params() {
+@@ -173,6 +174,7 @@ class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam provisionable_;
++ RpcHardwareInfo rpcHardwareInfo;
+ };
+
+ using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
+@@ -273,11 +275,10 @@ TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
+ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
+ protected:
+ CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
+- generateTestEekChain(3);
+ }
+
+ void generateTestEekChain(size_t eekLength) {
+- auto chain = generateEekChain(eekLength, eekId_);
++ auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
+ EXPECT_TRUE(chain) << chain.message();
+ if (chain) testEekChain_ = chain.moveValue();
+ testEekLength_ = eekLength;
+@@ -298,6 +299,17 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
+ }
+ }
+
++ ErrMsgOr getSessionKey(ErrMsgOr>& senderPubkey) {
++ if (rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
++ rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
++ return x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
++ senderPubkey->first, false /* senderIsA */);
++ } else {
++ return ECDH_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
++ senderPubkey->first, false /* senderIsA */);
++ }
++ }
++
+ void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+ const bytevec& keysToSignMac, const ProtectedData& protectedData,
+ std::vector* bccOutput = nullptr) {
+@@ -310,9 +322,7 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
+ ASSERT_TRUE(senderPubkey) << senderPubkey.message();
+ EXPECT_EQ(senderPubkey->second, eekId_);
+
+- auto sessionKey =
+- x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
+- senderPubkey->first, false /* senderIsA */);
++ auto sessionKey = getSessionKey(senderPubkey);
+ ASSERT_TRUE(sessionKey) << sessionKey.message();
+
+ auto protectedDataPayload =
+@@ -322,7 +332,7 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
+ auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
+ ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
+ ASSERT_TRUE(parsedPayload->asArray());
+- EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
++ EXPECT_LE(parsedPayload->asArray()->size(), 3U);
+
+ auto& signedMac = parsedPayload->asArray()->get(0);
+ auto& bcc = parsedPayload->asArray()->get(1);
+@@ -406,6 +416,7 @@ TEST_P(CertificateRequestTest, NewKeyPerCallInTestMode) {
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
++ generateTestEekChain(3);
+ auto status = provisionable_->generateCertificateRequest(
+ testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
+@@ -445,7 +456,7 @@ TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(
+- testMode, {} /* keysToSign */, getProdEekChain(), challenge_, &deviceInfo,
++ testMode, {} /* keysToSign */, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
+ EXPECT_TRUE(status.isOk());
+ }
+@@ -486,7 +497,7 @@ TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(
+- testMode, keysToSign_, getProdEekChain(), challenge_, &deviceInfo, &protectedData,
++ testMode, keysToSign_, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_, &deviceInfo, &protectedData,
+ &keysToSignMac);
+ EXPECT_TRUE(status.isOk());
+ }
+@@ -502,6 +513,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
++ generateTestEekChain(3);
+ auto status = provisionable_->generateCertificateRequest(
+ testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
+@@ -521,7 +533,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(
+- testMode, {keyWithCorruptMac}, getProdEekChain(), challenge_, &deviceInfo,
++ testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
+ ASSERT_FALSE(status.isOk()) << status.getMessage();
+ EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
+@@ -535,7 +547,7 @@ TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
+ bool testMode = false;
+ generateKeys(testMode, 4 /* numKeys */);
+
+- auto prodEekChain = getProdEekChain();
++ auto prodEekChain = getProdEekChain(rpcHardwareInfo.supportedEekCurve);
+ auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
+ ASSERT_NE(parsedChain, nullptr) << parseErr;
+ ASSERT_NE(parsedChain->asArray(), nullptr);
+@@ -566,7 +578,7 @@ TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
+
+ // Build an EEK chain that omits the first self-signed cert.
+ auto truncatedChain = cppbor::Array();
+- auto [chain, _, parseErr] = cppbor::parse(getProdEekChain());
++ auto [chain, _, parseErr] = cppbor::parse(getProdEekChain(rpcHardwareInfo.supportedEekCurve));
+ ASSERT_TRUE(chain);
+ auto eekChain = chain->asArray();
+ ASSERT_NE(eekChain, nullptr);
+@@ -594,6 +606,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
++ generateTestEekChain(3);
+ auto status = provisionable_->generateCertificateRequest(
+ true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
+@@ -612,6 +625,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
++ generateTestEekChain(3);
+ auto status = provisionable_->generateCertificateRequest(
+ false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
+ &protectedData, &keysToSignMac);
+diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
+index 9e218b6a3..73fb8c277 100644
+--- a/security/keymint/support/Android.bp
++++ b/security/keymint/support/Android.bp
+@@ -62,6 +62,7 @@ cc_library {
+ "libcppcose_rkp",
+ "libcrypto",
+ "libjsoncpp",
++ "android.hardware.security.keymint-V1-ndk_platform",
+ ],
+ }
+
+diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
+index 406b7a9b7..4d9ed2b0c 100644
+--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
++++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
+@@ -52,6 +52,20 @@ inline constexpr uint8_t kCoseEncodedGeekCert[] = {
+ 0x31, 0xbf, 0x6b, 0xe8, 0x1e, 0x35, 0xe2, 0xf0, 0x2d, 0xce, 0x6c, 0x2f, 0x4f, 0xf2,
+ 0xf5, 0x4f, 0xa5, 0xd4, 0x83, 0xad, 0x96, 0xa2, 0xf1, 0x87, 0x58, 0x04};
+
++// The Google ECDSA root key for the Endpoint Encryption Key chain, encoded as COSE_Sign1
++inline constexpr uint8_t kCoseEncodedEcdsaRootCert[] = {
++ 0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01,
++ 0x21, 0x58, 0x20, 0xf7, 0x14, 0x8a, 0xdb, 0x97, 0xf4, 0xcc, 0x53, 0xef, 0xd2, 0x64, 0x11,
++ 0xc4, 0xe3, 0x75, 0x1f, 0x66, 0x1f, 0xa4, 0x71, 0x0c, 0x6c, 0xcf, 0xfa, 0x09, 0x46, 0x80,
++ 0x74, 0x87, 0x54, 0xf2, 0xad, 0x22, 0x58, 0x20, 0x5e, 0x7f, 0x5b, 0xf6, 0xec, 0xe4, 0xf6,
++ 0x19, 0xcc, 0xff, 0x13, 0x37, 0xfd, 0x0f, 0xa1, 0xc8, 0x93, 0xdb, 0x18, 0x06, 0x76, 0xc4,
++ 0x5d, 0xe6, 0xd7, 0x6a, 0x77, 0x86, 0xc3, 0x2d, 0xaf, 0x8f, 0x58, 0x47, 0x30, 0x45, 0x02,
++ 0x20, 0x2f, 0x97, 0x8e, 0x42, 0xfb, 0xbe, 0x07, 0x2d, 0x95, 0x47, 0x85, 0x47, 0x93, 0x40,
++ 0xb0, 0x1f, 0xd4, 0x9b, 0x47, 0xa4, 0xc4, 0x44, 0xa9, 0xf2, 0xa1, 0x07, 0x87, 0x10, 0xc7,
++ 0x9f, 0xcb, 0x11, 0x02, 0x21, 0x00, 0xf4, 0xbf, 0x9f, 0xe8, 0x3b, 0xe0, 0xe7, 0x34, 0x4c,
++ 0x15, 0xfc, 0x7b, 0xc3, 0x7e, 0x33, 0x05, 0xf4, 0xd1, 0x34, 0x3c, 0xed, 0x02, 0x04, 0x60,
++ 0x7a, 0x15, 0xe0, 0x79, 0xd3, 0x8a, 0xff, 0x24};
++
+ /**
+ * Generates random bytes.
+ */
+@@ -67,12 +81,12 @@ struct EekChain {
+ * Generates an X25518 EEK with the specified eekId and an Ed25519 chain of the
+ * specified length. All keys are generated randomly.
+ */
+-ErrMsgOr generateEekChain(size_t length, const bytevec& eekId);
++ErrMsgOr generateEekChain(int32_t supportedEekCurve, size_t length, const bytevec& eekId);
+
+ /**
+ * Returns the CBOR-encoded, production Google Endpoint Encryption Key chain.
+ */
+-bytevec getProdEekChain();
++bytevec getProdEekChain(int32_t supportedEekCurve);
+
+ struct BccEntryData {
+ bytevec pubKey;
+diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
+index 0cbee5104..ae5120f8b 100644
+--- a/security/keymint/support/remote_prov_utils.cpp
++++ b/security/keymint/support/remote_prov_utils.cpp
+@@ -17,15 +17,195 @@
+ #include
+ #include
+
++#include
+ #include
+ #include
+ #include
++#include
++#include
++#include
++#include
+ #include
++#include
+ #include
+ #include
+
+ namespace aidl::android::hardware::security::keymint::remote_prov {
+
++constexpr int kP256AffinePointSize = 32;
++
++using EC_KEY_Ptr = bssl::UniquePtr;
++using EVP_PKEY_Ptr = bssl::UniquePtr;
++using EVP_PKEY_CTX_Ptr = bssl::UniquePtr;
++
++ErrMsgOr ecKeyGetPrivateKey(const EC_KEY* ecKey) {
++ // Extract private key.
++ const BIGNUM* bignum = EC_KEY_get0_private_key(ecKey);
++ if (bignum == nullptr) {
++ return "Error getting bignum from private key";
++ }
++ int size = BN_num_bytes(bignum);
++ // Pad with zeros incase the length is lesser than 32.
++ bytevec privKey(32, 0);
++ BN_bn2bin(bignum, privKey.data() + 32 - size);
++ return privKey;
++}
++
++ErrMsgOr ecKeyGetPublicKey(const EC_KEY* ecKey) {
++ // Extract public key.
++ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
++ if (group.get() == nullptr) {
++ return "Error creating EC group by curve name";
++ }
++ const EC_POINT* point = EC_KEY_get0_public_key(ecKey);
++ if (point == nullptr) return "Error getting ecpoint from public key";
++
++ int size = EC_POINT_point2oct(group.get(), point,
++ POINT_CONVERSION_UNCOMPRESSED, nullptr, 0,
++ nullptr);
++ if (size == 0) {
++ return "Error generating public key encoding";
++ }
++
++ bytevec publicKey;
++ publicKey.resize(size);
++ EC_POINT_point2oct(group.get(), point,
++ POINT_CONVERSION_UNCOMPRESSED, publicKey.data(),
++ publicKey.size(), nullptr);
++ return publicKey;
++}
++
++ErrMsgOr> getAffineCoordinates(
++ const bytevec& pubKey) {
++ auto group = EC_GROUP_Ptr(
++ EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
++ if (group.get() == nullptr) {
++ return "Error creating EC group by curve name";
++ }
++ auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
++ if (EC_POINT_oct2point(group.get(), point.get(), pubKey.data(),
++ pubKey.size(), nullptr) != 1) {
++ return "Error decoding publicKey";
++ }
++ BIGNUM_Ptr x(BN_new());
++ BIGNUM_Ptr y(BN_new());
++ BN_CTX_Ptr ctx(BN_CTX_new());
++ if (!ctx.get()) return "Failed to create BN_CTX instance";
++
++ if (!EC_POINT_get_affine_coordinates_GFp(group.get(), point.get(),
++ x.get(), y.get(),
++ ctx.get())) {
++ return "Failed to get affine coordinates from ECPoint";
++ }
++ bytevec pubX(kP256AffinePointSize);
++ bytevec pubY(kP256AffinePointSize);
++ if (BN_bn2binpad(x.get(), pubX.data(), kP256AffinePointSize) !=
++ kP256AffinePointSize) {
++ return "Error in converting absolute value of x cordinate to big-endian";
++ }
++ if (BN_bn2binpad(y.get(), pubY.data(), kP256AffinePointSize) !=
++ kP256AffinePointSize) {
++ return "Error in converting absolute value of y cordinate to big-endian";
++ }
++ return std::make_tuple(std::move(pubX), std::move(pubY));
++}
++
++ErrMsgOr> generateEc256KeyPair() {
++ auto ec_key = EC_KEY_Ptr(EC_KEY_new());
++ if (ec_key.get() == nullptr) {
++ return "Failed to allocate ec key";
++ }
++
++ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
++ if (group.get() == nullptr) {
++ return "Error creating EC group by curve name";
++ }
++
++ if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
++ EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
++ return "Error generating key";
++ }
++
++ auto privKey = ecKeyGetPrivateKey(ec_key.get());
++ if (!privKey) return privKey.moveMessage();
++
++ auto pubKey = ecKeyGetPublicKey(ec_key.get());
++ if (!pubKey) return pubKey.moveMessage();
++
++ return std::make_tuple(pubKey.moveValue(), privKey.moveValue());
++}
++
++ErrMsgOr> generateX25519KeyPair() {
++ /* Generate X25519 key pair */
++ bytevec pubKey(X25519_PUBLIC_VALUE_LEN);
++ bytevec privKey(X25519_PRIVATE_KEY_LEN);
++ X25519_keypair(pubKey.data(), privKey.data());
++ return std::make_tuple(std::move(pubKey), std::move(privKey));
++}
++
++ErrMsgOr> generateED25519KeyPair() {
++ /* Generate ED25519 key pair */
++ bytevec pubKey(ED25519_PUBLIC_KEY_LEN);
++ bytevec privKey(ED25519_PRIVATE_KEY_LEN);
++ ED25519_keypair(pubKey.data(), privKey.data());
++ return std::make_tuple(std::move(pubKey), std::move(privKey));
++}
++
++ErrMsgOr> generateKeyPair(
++ int32_t supportedEekCurve, bool isEek) {
++
++ switch (supportedEekCurve) {
++ case RpcHardwareInfo::CURVE_NONE:
++ case RpcHardwareInfo::CURVE_25519:
++ if (isEek) {
++ return generateX25519KeyPair();
++ }
++ return generateED25519KeyPair();
++ case RpcHardwareInfo::CURVE_P256:
++ return generateEc256KeyPair();
++ default:
++ return "Unknown EEK Curve.";
++ }
++}
++
++ErrMsgOr constructCoseKey(int32_t supportedEekCurve, const bytevec& eekId,
++ const bytevec& pubKey) {
++ CoseKeyType keyType;
++ CoseKeyAlgorithm algorithm;
++ CoseKeyCurve curve;
++ bytevec pubX;
++ bytevec pubY;
++ switch (supportedEekCurve) {
++ case RpcHardwareInfo::CURVE_NONE:
++ case RpcHardwareInfo::CURVE_25519:
++ keyType = OCTET_KEY_PAIR;
++ algorithm = (eekId.empty()) ? EDDSA : ECDH_ES_HKDF_256;
++ curve = (eekId.empty()) ? ED25519 : cppcose::X25519;
++ pubX = pubKey;
++ break;
++ case RpcHardwareInfo::CURVE_P256: {
++ keyType = EC2;
++ algorithm = (eekId.empty()) ? ES256 : ECDH_ES_HKDF_256;
++ curve = P256;
++ auto affineCoordinates = getAffineCoordinates(pubKey);
++ if (!affineCoordinates) return affineCoordinates.moveMessage();
++ std::tie(pubX, pubY) = affineCoordinates.moveValue();
++ } break;
++ default:
++ return "Unknown EEK Curve.";
++ }
++ cppbor::Map coseKey = cppbor::Map()
++ .add(CoseKey::KEY_TYPE, keyType)
++ .add(CoseKey::ALGORITHM, algorithm)
++ .add(CoseKey::CURVE, curve)
++ .add(CoseKey::PUBKEY_X, pubX);
++
++ if (!pubY.empty()) coseKey.add(CoseKey::PUBKEY_Y, pubY);
++ if (!eekId.empty()) coseKey.add(CoseKey::KEY_ID, eekId);
++
++ return coseKey.canonicalize().encode();
++}
++
+ bytevec kTestMacKey(32 /* count */, 0 /* byte value */);
+
+ bytevec randomBytes(size_t numBytes) {
+@@ -34,7 +214,17 @@ bytevec randomBytes(size_t numBytes) {
+ return retval;
+ }
+
+-ErrMsgOr generateEekChain(size_t length, const bytevec& eekId) {
++ErrMsgOr constructCoseSign1(int32_t supportedEekCurve, const bytevec& key,
++ const bytevec& payload, const bytevec& aad) {
++ if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
++ return constructECDSACoseSign1(key, {} /* protectedParams */, payload, aad);
++ } else {
++ return cppcose::constructCoseSign1(key, payload, aad);
++ }
++}
++
++ErrMsgOr generateEekChain(int32_t supportedEekCurve, size_t length,
++ const bytevec& eekId) {
+ if (length < 2) {
+ return "EEK chain must contain at least 2 certs.";
+ }
+@@ -43,42 +233,31 @@ ErrMsgOr generateEekChain(size_t length, const bytevec& eekId) {
+
+ bytevec prev_priv_key;
+ for (size_t i = 0; i < length - 1; ++i) {
+- bytevec pub_key(ED25519_PUBLIC_KEY_LEN);
+- bytevec priv_key(ED25519_PRIVATE_KEY_LEN);
+-
+- ED25519_keypair(pub_key.data(), priv_key.data());
++ auto keyPair = generateKeyPair(supportedEekCurve, false);
++ if (!keyPair) keyPair.moveMessage();
++ auto [pub_key, priv_key] = keyPair.moveValue();
+
+ // The first signing key is self-signed.
+ if (prev_priv_key.empty()) prev_priv_key = priv_key;
+
+- auto coseSign1 = constructCoseSign1(prev_priv_key,
+- cppbor::Map() /* payload CoseKey */
+- .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+- .add(CoseKey::ALGORITHM, EDDSA)
+- .add(CoseKey::CURVE, ED25519)
+- .add(CoseKey::PUBKEY_X, pub_key)
+- .canonicalize()
+- .encode(),
++ auto coseKey = constructCoseKey(supportedEekCurve, {}, pub_key);
++ if (!coseKey) return coseKey.moveMessage();
++
++ auto coseSign1 = constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(),
+ {} /* AAD */);
+ if (!coseSign1) return coseSign1.moveMessage();
+ eekChain.add(coseSign1.moveValue());
+
+ prev_priv_key = priv_key;
+ }
++ auto keyPair = generateKeyPair(supportedEekCurve, true);
++ if (!keyPair) keyPair.moveMessage();
++ auto [pub_key, priv_key] = keyPair.moveValue();
+
+- bytevec pub_key(X25519_PUBLIC_VALUE_LEN);
+- bytevec priv_key(X25519_PRIVATE_KEY_LEN);
+- X25519_keypair(pub_key.data(), priv_key.data());
++ auto coseKey = constructCoseKey(supportedEekCurve, eekId, pub_key);
++ if (!coseKey) return coseKey.moveMessage();
+
+- auto coseSign1 = constructCoseSign1(prev_priv_key,
+- cppbor::Map() /* payload CoseKey */
+- .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+- .add(CoseKey::KEY_ID, eekId)
+- .add(CoseKey::ALGORITHM, ECDH_ES_HKDF_256)
+- .add(CoseKey::CURVE, cppcose::X25519)
+- .add(CoseKey::PUBKEY_X, pub_key)
+- .canonicalize()
+- .encode(),
++ auto coseSign1 = constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(),
+ {} /* AAD */);
+ if (!coseSign1) return coseSign1.moveMessage();
+ eekChain.add(coseSign1.moveValue());
+@@ -86,16 +265,15 @@ ErrMsgOr generateEekChain(size_t length, const bytevec& eekId) {
+ return EekChain{eekChain.encode(), pub_key, priv_key};
+ }
+
+-bytevec getProdEekChain() {
+- bytevec prodEek;
+- prodEek.reserve(1 + sizeof(kCoseEncodedRootCert) + sizeof(kCoseEncodedGeekCert));
+-
+- // In CBOR encoding, 0x82 indicates an array of two items
+- prodEek.push_back(0x82);
+- prodEek.insert(prodEek.end(), std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert));
+- prodEek.insert(prodEek.end(), std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert));
+-
+- return prodEek;
++bytevec getProdEekChain(int32_t supportedEekCurve) {
++ cppbor::Array chain;
++ if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
++ chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsaRootCert), std::end(kCoseEncodedEcdsaRootCert))));
++ } else {
++ chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert))));
++ chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert))));
++ }
++ return chain.encode();
+ }
+
+ ErrMsgOr verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
+@@ -122,7 +300,8 @@ ErrMsgOr verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
+ }
+
+ auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+- if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
++ if (!algorithm || !algorithm->asInt() || (algorithm->asInt()->value() != EDDSA &&
++ algorithm->asInt()->value() != ES256)) {
+ return "Unsupported signature algorithm";
+ }
+
+@@ -136,16 +315,35 @@ ErrMsgOr verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
+ if (!serializedKey || !serializedKey->asBstr()) return "Could not find key entry";
+
+ bool selfSigned = signingCoseKey.empty();
+- auto key =
++ bytevec key;
++ if (algorithm->asInt()->value() == EDDSA) {
++ auto key =
+ CoseKey::parseEd25519(selfSigned ? serializedKey->asBstr()->value() : signingCoseKey);
+- if (!key) return "Bad signing key: " + key.moveMessage();
++ if (!key) return "Bad signing key: " + key.moveMessage();
+
+- bytevec signatureInput =
++ bytevec signatureInput =
+ cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
+
+- if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
+- key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
+- return "Signature verification failed";
++ if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
++ key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
++ return "Signature verification failed";
++ }
++ } else { // P256
++ auto key =
++ CoseKey::parseP256(selfSigned ? serializedKey->asBstr()->value() : signingCoseKey);
++ if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() ||
++ key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) {
++ return "Bad signing key: " + key.moveMessage();
++ }
++ auto publicKey = key->getEcPublicKey();
++ if (!publicKey) return publicKey.moveMessage();
++
++ bytevec signatureInput =
++ cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
++
++ if (!verifyEcdsaDigest(publicKey.moveValue(), sha256(signatureInput), signature->value())) {
++ return "Signature verification failed";
++ }
+ }
+
+ return serializedKey->asBstr()->value();
+diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
+index 8697c5190..0009bf713 100644
+--- a/security/keymint/support/remote_prov_utils_test.cpp
++++ b/security/keymint/support/remote_prov_utils_test.cpp
+@@ -14,6 +14,7 @@
+ * limitations under the License.
+ */
+
++#include
+ #include
+ #include
+ #include
+@@ -35,13 +36,13 @@ using ::keymaster::validateAndExtractEekPubAndId;
+ using ::testing::ElementsAreArray;
+
+ TEST(RemoteProvUtilsTest, GenerateEekChainInvalidLength) {
+- ASSERT_FALSE(generateEekChain(1, /*eekId=*/{}));
++ ASSERT_FALSE(generateEekChain(CURVE_25519, 1, /*eekId=*/{}));
+ }
+
+ TEST(RemoteProvUtilsTest, GenerateEekChain) {
+ bytevec kTestEekId = {'t', 'e', 's', 't', 'I', 'd', 0};
+ for (size_t length : {2, 3, 31}) {
+- auto get_eek_result = generateEekChain(length, kTestEekId);
++ auto get_eek_result = generateEekChain(CURVE_25519, length, kTestEekId);
+ ASSERT_TRUE(get_eek_result) << get_eek_result.message();
+
+ auto& [chain, pubkey, privkey] = *get_eek_result;
diff --git a/aosp_integration_patches_aosp_12_r15/system_keymaster.patch b/aosp_integration_patches_aosp_12_r15/system_keymaster.patch
new file mode 100644
index 00000000..b994b768
--- /dev/null
+++ b/aosp_integration_patches_aosp_12_r15/system_keymaster.patch
@@ -0,0 +1,441 @@
+diff --git a/cppcose/cppcose.cpp b/cppcose/cppcose.cpp
+index bfe9928..5009bfe 100644
+--- a/cppcose/cppcose.cpp
++++ b/cppcose/cppcose.cpp
+@@ -21,10 +21,17 @@
+
+ #include
+ #include
++#include
+
+ #include
+
+ namespace cppcose {
++constexpr int kP256AffinePointSize = 32;
++
++using EVP_PKEY_Ptr = bssl::UniquePtr;
++using EVP_PKEY_CTX_Ptr = bssl::UniquePtr;
++using ECDSA_SIG_Ptr = bssl::UniquePtr;
++using EC_KEY_Ptr = bssl::UniquePtr;
+
+ namespace {
+
+@@ -51,6 +58,92 @@ ErrMsgOr> aesGcmInitAndProcessAad(const bytevec&
+ return std::move(ctx);
+ }
+
++
++ErrMsgOr signEcdsaDigest(const bytevec& key, const bytevec& data) {
++ auto bn = BIGNUM_Ptr(BN_bin2bn(key.data(), key.size(), nullptr));
++ if (bn.get() == nullptr) {
++ return "Error creating BIGNUM";
++ }
++
++ auto ec_key = EC_KEY_Ptr(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
++ if (EC_KEY_set_private_key(ec_key.get(), bn.get()) != 1) {
++ return "Error setting private key from BIGNUM";
++ }
++
++ ECDSA_SIG* sig = ECDSA_do_sign(data.data(), data.size(), ec_key.get());
++ if (sig == nullptr) {
++ return "Error signing digest";
++ }
++ size_t len = i2d_ECDSA_SIG(sig, nullptr);
++ bytevec signature(len);
++ unsigned char* p = (unsigned char*)signature.data();
++ i2d_ECDSA_SIG(sig, &p);
++ ECDSA_SIG_free(sig);
++ return signature;
++}
++
++ErrMsgOr ecdh(const bytevec& publicKey, const bytevec& privateKey) {
++ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
++ auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
++ if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) !=
++ 1) {
++ return "Error decoding publicKey";
++ }
++ auto ecKey = EC_KEY_Ptr(EC_KEY_new());
++ auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
++ if (ecKey.get() == nullptr || pkey.get() == nullptr) {
++ return "Memory allocation failed";
++ }
++ if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
++ return "Error setting group";
++ }
++ if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
++ return "Error setting point";
++ }
++ if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) {
++ return "Error setting key";
++ }
++
++ auto bn = BIGNUM_Ptr(BN_bin2bn(privateKey.data(), privateKey.size(), nullptr));
++ if (bn.get() == nullptr) {
++ return "Error creating BIGNUM for private key";
++ }
++ auto privEcKey = EC_KEY_Ptr(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
++ if (EC_KEY_set_private_key(privEcKey.get(), bn.get()) != 1) {
++ return "Error setting private key from BIGNUM";
++ }
++ auto privPkey = EVP_PKEY_Ptr(EVP_PKEY_new());
++ if (EVP_PKEY_set1_EC_KEY(privPkey.get(), privEcKey.get()) != 1) {
++ return "Error setting private key";
++ }
++
++ auto ctx = EVP_PKEY_CTX_Ptr(EVP_PKEY_CTX_new(privPkey.get(), NULL));
++ if (ctx.get() == nullptr) {
++ return "Error creating context";
++ }
++
++ if (EVP_PKEY_derive_init(ctx.get()) != 1) {
++ return "Error initializing context";
++ }
++
++ if (EVP_PKEY_derive_set_peer(ctx.get(), pkey.get()) != 1) {
++ return "Error setting peer";
++ }
++
++ /* Determine buffer length for shared secret */
++ size_t secretLen = 0;
++ if (EVP_PKEY_derive(ctx.get(), NULL, &secretLen) != 1) {
++ return "Error determing length of shared secret";
++ }
++ bytevec sharedSecret;
++ sharedSecret.resize(secretLen);
++
++ if (EVP_PKEY_derive(ctx.get(), sharedSecret.data(), &secretLen) != 1) {
++ return "Error deriving shared secret";
++ }
++ return sharedSecret;
++}
++
+ } // namespace
+
+ ErrMsgOr generateHmacSha256(const bytevec& key, const bytevec& data) {
+@@ -134,6 +227,17 @@ ErrMsgOr verifyAndParseCoseMac0(const cppbor::Item* macIt
+ return payload->value();
+ }
+
++ErrMsgOr createECDSACoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
++ const bytevec& payload, const bytevec& aad) {
++ bytevec signatureInput = cppbor::Array()
++ .add("Signature1") //
++ .add(protectedParams)
++ .add(aad)
++ .add(payload)
++ .encode();
++ return signEcdsaDigest(key, sha256(signatureInput));
++}
++
+ ErrMsgOr createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
+ const bytevec& payload, const bytevec& aad) {
+ bytevec signatureInput = cppbor::Array()
+@@ -152,6 +256,19 @@ ErrMsgOr createCoseSign1Signature(const bytevec& key, const bytevec& pr
+ return signature;
+ }
+
++ErrMsgOr constructECDSACoseSign1(const bytevec& key, cppbor::Map protectedParams,
++ const bytevec& payload, const bytevec& aad) {
++ bytevec protParms = protectedParams.add(ALGORITHM, ES256).canonicalize().encode();
++ auto signature = createECDSACoseSign1Signature(key, protParms, payload, aad);
++ if (!signature) return signature.moveMessage();
++
++ return cppbor::Array()
++ .add(std::move(protParms))
++ .add(cppbor::Map() /* unprotected parameters */)
++ .add(std::move(payload))
++ .add(std::move(*signature));
++}
++
+ ErrMsgOr constructCoseSign1(const bytevec& key, cppbor::Map protectedParams,
+ const bytevec& payload, const bytevec& aad) {
+ bytevec protParms = protectedParams.add(ALGORITHM, EDDSA).canonicalize().encode();
+@@ -193,7 +310,8 @@ ErrMsgOr verifyAndParseCoseSign1(const cppbor::Array* coseSign1,
+ }
+
+ auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+- if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
++ if (!algorithm || !algorithm->asInt() ||
++ !(algorithm->asInt()->value() == EDDSA || algorithm->asInt()->value() == ES256)) {
+ return "Unsupported signature algorithm";
+ }
+
+@@ -203,17 +321,30 @@ ErrMsgOr verifyAndParseCoseSign1(const cppbor::Array* coseSign1,
+ }
+
+ bool selfSigned = signingCoseKey.empty();
+- auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey);
+- if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty()) {
+- return "Bad signing key: " + key.moveMessage();
+- }
+-
+ bytevec signatureInput =
+ cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
+-
+- if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
+- key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
+- return "Signature verification failed";
++ if (algorithm->asInt()->value() == EDDSA) {
++ auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey);
++ if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty()) {
++ return "Bad signing key: " + key.moveMessage();
++ }
++
++ if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
++ key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
++ return "Signature verification failed";
++ }
++ } else { // P256
++ auto key = CoseKey::parseP256(selfSigned ? payload->value() : signingCoseKey);
++ if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() ||
++ key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) {
++ return "Bad signing key: " + key.moveMessage();
++ }
++ auto publicKey = key->getEcPublicKey();
++ if (!publicKey) return publicKey.moveMessage();
++
++ if (!verifyEcdsaDigest(publicKey.moveValue(), sha256(signatureInput), signature->value())) {
++ return "Signature verification failed";
++ }
+ }
+
+ return payload->value();
+@@ -294,28 +425,47 @@ getSenderPubKeyFromCoseEncrypt(const cppbor::Item* coseEncrypt) {
+ if (!senderCoseKey || !senderCoseKey->asMap()) return "Invalid sender COSE_Key";
+
+ auto& keyType = senderCoseKey->asMap()->get(CoseKey::KEY_TYPE);
+- if (!keyType || !keyType->asInt() || keyType->asInt()->value() != OCTET_KEY_PAIR) {
++ if (!keyType || !keyType->asInt() || (keyType->asInt()->value() != OCTET_KEY_PAIR &&
++ keyType->asInt()->value() != EC2)) {
+ return "Invalid key type";
+ }
+
+ auto& curve = senderCoseKey->asMap()->get(CoseKey::CURVE);
+- if (!curve || !curve->asInt() || curve->asInt()->value() != X25519) {
++ if (!curve || !curve->asInt() ||
++ (keyType->asInt()->value() == OCTET_KEY_PAIR && curve->asInt()->value() != X25519) ||
++ (keyType->asInt()->value() == EC2 && curve->asInt()->value() != P256)) {
+ return "Unsupported curve";
+ }
+
+- auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
+- if (!pubkey || !pubkey->asBstr() ||
+- pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
+- return "Invalid X25519 public key";
++ bytevec publicKey;
++ if (keyType->asInt()->value() == EC2) {
++ auto& pubX = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
++ if (!pubX || !pubX->asBstr() || pubX->asBstr()->value().size() != kP256AffinePointSize) {
++ return "Invalid EC public key";
++ }
++ auto& pubY = senderCoseKey->asMap()->get(CoseKey::PUBKEY_Y);
++ if (!pubY || !pubY->asBstr() || pubY->asBstr()->value().size() != kP256AffinePointSize) {
++ return "Invalid EC public key";
++ }
++ auto key = CoseKey::getEcPublicKey(pubX->asBstr()->value(), pubY->asBstr()->value());
++ if (!key) return key.moveMessage();
++ publicKey = key.moveValue();
++ } else {
++ auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
++ if (!pubkey || !pubkey->asBstr() ||
++ pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
++ return "Invalid X25519 public key";
++ }
++ publicKey = pubkey->asBstr()->value();
+ }
+
+ auto& key_id = unprotParms->asMap()->get(KEY_ID);
+ if (key_id && key_id->asBstr()) {
+- return std::make_pair(pubkey->asBstr()->value(), key_id->asBstr()->value());
++ return std::make_pair(publicKey, key_id->asBstr()->value());
+ }
+
+ // If no key ID, just return an empty vector.
+- return std::make_pair(pubkey->asBstr()->value(), bytevec{});
++ return std::make_pair(publicKey, bytevec{});
+ }
+
+ ErrMsgOr decryptCoseEncrypt(const bytevec& key, const cppbor::Item* coseEncrypt,
+@@ -367,6 +517,43 @@ ErrMsgOr decryptCoseEncrypt(const bytevec& key, const cppbor::Item* cos
+ return aesGcmDecrypt(key, nonce->asBstr()->value(), aad, ciphertext->asBstr()->value());
+ }
+
++ErrMsgOr ECDH_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
++ const bytevec& pubKeyB, bool senderIsA) {
++ if (privKeyA.empty() || pubKeyA.empty() || pubKeyB.empty()) {
++ return "Missing input key parameters";
++ }
++
++ auto rawSharedKey = ecdh(pubKeyB, privKeyA);
++ if (!rawSharedKey) return rawSharedKey.moveMessage();
++
++ bytevec kdfContext = cppbor::Array()
++ .add(AES_GCM_256)
++ .add(cppbor::Array() // Sender Info
++ .add(cppbor::Bstr("client"))
++ .add(bytevec{} /* nonce */)
++ .add(senderIsA ? pubKeyA : pubKeyB))
++ .add(cppbor::Array() // Recipient Info
++ .add(cppbor::Bstr("server"))
++ .add(bytevec{} /* nonce */)
++ .add(senderIsA ? pubKeyB : pubKeyA))
++ .add(cppbor::Array() // SuppPubInfo
++ .add(kAesGcmKeySizeBits) // output key length
++ .add(bytevec{})) // protected
++ .encode();
++
++ bytevec retval(SHA256_DIGEST_LENGTH);
++ bytevec salt{};
++ if (!HKDF(retval.data(), retval.size(), //
++ EVP_sha256(), //
++ rawSharedKey->data(), rawSharedKey->size(), //
++ salt.data(), salt.size(), //
++ kdfContext.data(), kdfContext.size())) {
++ return "ECDH HKDF failed";
++ }
++
++ return retval;
++}
++
+ ErrMsgOr x25519_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
+ const bytevec& pubKeyB, bool senderIsA) {
+ if (privKeyA.empty() || pubKeyA.empty() || pubKeyB.empty()) {
+@@ -460,4 +647,43 @@ ErrMsgOr aesGcmDecrypt(const bytevec& key, const bytevec& nonce, const
+ return plaintext;
+ }
+
++bytevec sha256(const bytevec& data) {
++ bytevec ret(SHA256_DIGEST_LENGTH);
++ SHA256_CTX ctx;
++ SHA256_Init(&ctx);
++ SHA256_Update(&ctx, data.data(), data.size());
++ SHA256_Final((unsigned char*)ret.data(), &ctx);
++ return ret;
++}
++
++bool verifyEcdsaDigest(const bytevec& key, const bytevec& digest, const bytevec& signature) {
++ const unsigned char* p = (unsigned char*)signature.data();
++ auto sig = ECDSA_SIG_Ptr(d2i_ECDSA_SIG(nullptr, &p, signature.size()));
++ if (sig.get() == nullptr) {
++ return false;
++ }
++
++ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
++ auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
++ if (EC_POINT_oct2point(group.get(), point.get(), key.data(), key.size(), nullptr) != 1) {
++ return false;
++ }
++ auto ecKey = EC_KEY_Ptr(EC_KEY_new());
++ if (ecKey.get() == nullptr) {
++ return false;
++ }
++ if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
++ return false;
++ }
++ if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
++ return false;
++ }
++
++ int rc = ECDSA_do_verify(digest.data(), digest.size(), sig.get(), ecKey.get());
++ if (rc != 1) {
++ return false;
++ }
++ return true;
++}
++
+ } // namespace cppcose
+diff --git a/include/keymaster/cppcose/cppcose.h b/include/keymaster/cppcose/cppcose.h
+index 0f97388..03251f1 100644
+--- a/include/keymaster/cppcose/cppcose.h
++++ b/include/keymaster/cppcose/cppcose.h
+@@ -24,17 +24,25 @@
+
+ #include
+ #include
+-
++#include
++#include
++#include
+ #include
+ #include
+ #include
+ #include
++#include
+ #include
+ #include
+ #include
+
+ namespace cppcose {
+
++using BIGNUM_Ptr = bssl::UniquePtr;
++using EC_GROUP_Ptr = bssl::UniquePtr;
++using EC_POINT_Ptr = bssl::UniquePtr;
++using BN_CTX_Ptr = bssl::UniquePtr;
++
+ template class ErrMsgOr;
+ using bytevec = std::vector;
+ using HmacSha256 = std::array;
+@@ -203,6 +211,41 @@ class CoseKey {
+ return key;
+ }
+
++ static ErrMsgOr getEcPublicKey(const bytevec& pubX, const bytevec& pubY) {
++ auto bnX = BIGNUM_Ptr(BN_bin2bn(pubX.data(), pubX.size(), nullptr));
++ if (bnX.get() == nullptr) {
++ return "Error creating BIGNUM X Coordinate";
++ }
++ auto bnY = BIGNUM_Ptr(BN_bin2bn(pubY.data(), pubY.size(), nullptr));
++ if (bnY.get() == nullptr) {
++ return "Error creating BIGNUM Y Coordinate";
++ }
++ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
++ auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
++ if (!point) return "Failed to create EC_POINT instance";
++ BN_CTX_Ptr ctx(BN_CTX_new());
++ if (!ctx.get()) return "Failed to create BN_CTX instance";
++ if (!EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(), bnX.get(), bnY.get(),
++ ctx.get())) {
++ return "Failed to set affine coordinates.";
++ }
++ int size = EC_POINT_point2oct(group.get(), point.get(), POINT_CONVERSION_UNCOMPRESSED,
++ nullptr, 0, nullptr);
++ if (size == 0) {
++ return "Error generating public key encoding";
++ }
++ bytevec publicKey(size);
++ EC_POINT_point2oct(group.get(), point.get(), POINT_CONVERSION_UNCOMPRESSED,
++ publicKey.data(), publicKey.size(), nullptr);
++ return publicKey;
++ }
++
++ ErrMsgOr getEcPublicKey() {
++ auto pubX = getBstrValue(PUBKEY_X).value();
++ auto pubY = getBstrValue(PUBKEY_Y).value();
++ return getEcPublicKey(pubX, pubY);
++ }
++
+ std::optional getIntValue(Label label) {
+ const auto& value = key_->get(label);
+ if (!value || !value->asInt()) return {};
+@@ -252,6 +295,8 @@ ErrMsgOr constructCoseSign1(const bytevec& key, const bytevec& pa
+ const bytevec& aad);
+ ErrMsgOr constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields,
+ const bytevec& payload, const bytevec& aad);
++ErrMsgOr constructECDSACoseSign1(const bytevec& key, cppbor::Map extraProtectedFields,
++ const bytevec& payload, const bytevec& aad);
+ /**
+ * Verify and parse a COSE_Sign1 message, returning the payload.
+ *
+@@ -282,7 +327,10 @@ decryptCoseEncrypt(const bytevec& key, const cppbor::Item* encryptItem, const by
+
+ ErrMsgOr x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey,
+ const bytevec& recipientPubKey, bool senderIsA);
+-
++ErrMsgOr ECDH_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
++ const bytevec& pubKeyB, bool senderIsA);
++bool verifyEcdsaDigest(const bytevec& key, const bytevec& digest, const bytevec& signature);
++bytevec sha256(const bytevec& data);
+ ErrMsgOr aesGcmEncrypt(const bytevec& key, const bytevec& nonce,
+ const bytevec& aad,
+ const bytevec& plaintext);
diff --git a/aosp_integration_patches_aosp_12_r15/system_security.patch b/aosp_integration_patches_aosp_12_r15/system_security.patch
new file mode 100644
index 00000000..22956d5e
--- /dev/null
+++ b/aosp_integration_patches_aosp_12_r15/system_security.patch
@@ -0,0 +1,13 @@
+diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
+index 64849c1..40ca554 100644
+--- a/keystore2/src/km_compat/km_compat.cpp
++++ b/keystore2/src/km_compat/km_compat.cpp
+@@ -1314,7 +1314,7 @@ KeymasterDevices initializeKeymasters() {
+ CHECK(serviceManager.get()) << "Failed to get ServiceManager";
+ auto result = enumerateKeymasterDevices(serviceManager.get());
+ auto softKeymaster = result[SecurityLevel::SOFTWARE];
+- if (!result[SecurityLevel::TRUSTED_ENVIRONMENT]) {
++ if ((!result[SecurityLevel::TRUSTED_ENVIRONMENT]) && (!result[SecurityLevel::STRONGBOX])) {
+ result = enumerateKeymasterDevices(serviceManager.get());
+ }
+ if (softKeymaster) result[SecurityLevel::SOFTWARE] = softKeymaster;
diff --git a/aosp_integration_patches_aosp_12_r15/system_sepolicy.patch b/aosp_integration_patches_aosp_12_r15/system_sepolicy.patch
new file mode 100644
index 00000000..f533e8c7
--- /dev/null
+++ b/aosp_integration_patches_aosp_12_r15/system_sepolicy.patch
@@ -0,0 +1,40 @@
+diff --git a/prebuilts/api/31.0/public/hal_neverallows.te b/prebuilts/api/31.0/public/hal_neverallows.te
+index 105689b8a..275f9a5c2 100644
+--- a/prebuilts/api/31.0/public/hal_neverallows.te
++++ b/prebuilts/api/31.0/public/hal_neverallows.te
+@@ -9,6 +9,7 @@ neverallow {
+ -hal_wifi_supplicant_server
+ -hal_telephony_server
+ -hal_uwb_server
++ -hal_keymint_server
+ } self:global_capability_class_set { net_admin net_raw };
+
+ # Unless a HAL's job is to communicate over the network, or control network
+@@ -27,6 +28,7 @@ neverallow {
+ -hal_wifi_supplicant_server
+ -hal_telephony_server
+ -hal_uwb_server
++ -hal_keymint_server
+ } domain:{ tcp_socket udp_socket rawip_socket } *;
+
+ # The UWB HAL is not actually a networking HAL but may need to bring up and down
+diff --git a/public/hal_neverallows.te b/public/hal_neverallows.te
+index 105689b8a..275f9a5c2 100644
+--- a/public/hal_neverallows.te
++++ b/public/hal_neverallows.te
+@@ -9,6 +9,7 @@ neverallow {
+ -hal_wifi_supplicant_server
+ -hal_telephony_server
+ -hal_uwb_server
++ -hal_keymint_server
+ } self:global_capability_class_set { net_admin net_raw };
+
+ # Unless a HAL's job is to communicate over the network, or control network
+@@ -27,6 +28,7 @@ neverallow {
+ -hal_wifi_supplicant_server
+ -hal_telephony_server
+ -hal_uwb_server
++ -hal_keymint_server
+ } domain:{ tcp_socket udp_socket rawip_socket } *;
+
+ # The UWB HAL is not actually a networking HAL but may need to bring up and down