Merge "Use latest KM AIDL API"
diff --git a/keystore2/src/crypto/crypto.cpp b/keystore2/src/crypto/crypto.cpp
index 6de3be7..7feeaff 100644
--- a/keystore2/src/crypto/crypto.cpp
+++ b/keystore2/src/crypto/crypto.cpp
@@ -18,6 +18,7 @@
 
 #include "crypto.hpp"
 
+#include <assert.h>
 #include <log/log.h>
 #include <openssl/aes.h>
 #include <openssl/ec.h>
diff --git a/keystore2/src/crypto/include/certificate_utils.h b/keystore2/src/crypto/include/certificate_utils.h
index cad82b6..13d3ef0 100644
--- a/keystore2/src/crypto/include/certificate_utils.h
+++ b/keystore2/src/crypto/include/certificate_utils.h
@@ -20,6 +20,7 @@
 #include <openssl/x509.h>
 #include <stdint.h>
 
+#include <functional>
 #include <memory>
 #include <optional>
 #include <variant>
diff --git a/keystore2/src/metrics_store.rs b/keystore2/src/metrics_store.rs
index 62a7d13..5e88052 100644
--- a/keystore2/src/metrics_store.rs
+++ b/keystore2/src/metrics_store.rs
@@ -600,8 +600,10 @@
 
 /// Log error events related to Remote Key Provisioning (RKP).
 pub fn log_rkp_error_stats(rkp_error: MetricsRkpError, sec_level: &SecurityLevel) {
-    let rkp_error_stats = KeystoreAtomPayload::RkpErrorStats(
-        RkpErrorStats { rkpError: rkp_error, security_level: process_security_level(*sec_level) });
+    let rkp_error_stats = KeystoreAtomPayload::RkpErrorStats(RkpErrorStats {
+        rkpError: rkp_error,
+        security_level: process_security_level(*sec_level),
+    });
     METRICS_STORE.insert_atom(AtomID::RKP_ERROR_STATS, rkp_error_stats);
 }
 
diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index ea2698f..8ed2be4 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -159,8 +159,10 @@
                     if self.is_rkp_only() {
                         return Err(e);
                     }
-                    log_rkp_error_stats(MetricsRkpError::FALL_BACK_DURING_HYBRID,
-                            &self.security_level);
+                    log_rkp_error_stats(
+                        MetricsRkpError::FALL_BACK_DURING_HYBRID,
+                        &self.security_level,
+                    );
                     Ok(None)
                 }
                 Ok(v) => match v {
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index c25d928..17d8914 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -297,3 +297,42 @@
     assert!(key_metadata.certificateChain.is_none());
     Ok(key_metadata)
 }
+
+/// Generate HMAC key.
+pub fn generate_hmac_key(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    alias: &str,
+    key_size: i32,
+    min_mac_len: i32,
+    digest: Digest,
+) -> binder::Result<KeyMetadata> {
+    let gen_params = AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::HMAC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .key_size(key_size)
+        .min_mac_length(min_mac_len)
+        .digest(digest);
+
+    let key_metadata = sec_level.generateKey(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(alias.to_string()),
+            blob: None,
+        },
+        None,
+        &gen_params,
+        0,
+        b"entropy",
+    )?;
+
+    // Should not have public certificate.
+    assert!(key_metadata.certificate.is_none());
+
+    // Should not have an attestation record.
+    assert!(key_metadata.certificateChain.is_none());
+
+    Ok(key_metadata)
+}
diff --git a/keystore2/tests/keystore2_client_hmac_key_tests.rs b/keystore2/tests/keystore2_client_hmac_key_tests.rs
new file mode 100644
index 0000000..6bb8001
--- /dev/null
+++ b/keystore2/tests/keystore2_client_hmac_key_tests.rs
@@ -0,0 +1,305 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+    Algorithm::Algorithm, Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose,
+    SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+    Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+};
+
+use keystore2_test_utils::{
+    authorizations, get_keystore_service, key_generations, key_generations::Error,
+};
+
+use crate::keystore2_client_test_utils::perform_sample_sign_operation;
+
+/// Generate HMAC key with given parameters and perform a sample operation using generated key.
+fn create_hmac_key_and_operation(
+    sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+    alias: &str,
+    key_size: i32,
+    mac_len: i32,
+    min_mac_len: i32,
+    digest: Digest,
+) -> Result<(), binder::Status> {
+    let key_metadata =
+        key_generations::generate_hmac_key(sec_level, alias, key_size, min_mac_len, digest)?;
+
+    let op_response = sec_level.createOperation(
+        &key_metadata.key,
+        &authorizations::AuthSetBuilder::new()
+            .purpose(KeyPurpose::SIGN)
+            .digest(digest)
+            .mac_length(mac_len),
+        false,
+    )?;
+
+    assert!(op_response.iOperation.is_some());
+    assert_eq!(
+        Ok(()),
+        key_generations::map_ks_error(perform_sample_sign_operation(
+            &op_response.iOperation.unwrap()
+        ))
+    );
+
+    Ok(())
+}
+
+/// Generate HMAC keys with various digest modes [SHA1, SHA_2_224, SHA_2_256, SHA_2_384,
+/// SHA_2_512]. Create an operation using generated keys. Test should create operations
+/// successfully.
+#[test]
+fn keystore2_hmac_key_op_success() {
+    let digests =
+        [Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512];
+    let min_mac_len = 128;
+    let mac_len = 128;
+    let key_size = 128;
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    for digest in digests {
+        let alias = format!("ks_hmac_test_key_{}", digest.0);
+
+        assert_eq!(
+            Ok(()),
+            create_hmac_key_and_operation(
+                &sec_level,
+                &alias,
+                key_size,
+                mac_len,
+                min_mac_len,
+                digest,
+            )
+        );
+    }
+}
+
+/// Generate HMAC keys with various key lengths. For invalid key sizes, key generation
+/// should fail with an error code `UNSUPPORTED_KEY_SIZE`.
+#[test]
+fn keystore2_hmac_gen_keys_fails_expect_unsupported_key_size() {
+    let min_mac_len = 256;
+    let digest = Digest::SHA_2_256;
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    for key_size in 0..513 {
+        let alias = format!("ks_hmac_test_key_{}", key_size);
+        let result = key_generations::map_ks_error(key_generations::generate_hmac_key(
+            &sec_level,
+            &alias,
+            key_size,
+            min_mac_len,
+            digest,
+        ));
+
+        match result {
+            Ok(_) => {
+                assert!((key_size >= 64 && key_size % 8 == 0));
+            }
+            Err(e) => {
+                assert_eq!(e, Error::Km(ErrorCode::UNSUPPORTED_KEY_SIZE));
+                assert!((key_size < 64 || key_size % 8 != 0), "Unsupported KeySize: {}", key_size);
+            }
+        }
+    }
+}
+
+/// Generate HMAC keys with various min-mac-lengths. For invalid min-mac-length, key generation
+/// should fail with an error code `UNSUPPORTED_MIN_MAC_LENGTH`.
+#[test]
+fn keystore2_hmac_gen_keys_fails_expect_unsupported_min_mac_length() {
+    let digest = Digest::SHA_2_256;
+    let key_size = 128;
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    for min_mac_len in 0..257 {
+        let alias = format!("ks_hmac_test_key_mml_{}", min_mac_len);
+        match key_generations::map_ks_error(key_generations::generate_hmac_key(
+            &sec_level,
+            &alias,
+            key_size,
+            min_mac_len,
+            digest,
+        )) {
+            Ok(_) => {
+                assert!((min_mac_len >= 64 && min_mac_len % 8 == 0));
+            }
+            Err(e) => {
+                assert_eq!(e, Error::Km(ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH));
+                assert!(
+                    (min_mac_len < 64 || min_mac_len % 8 != 0),
+                    "Unsupported MinMacLength: {}",
+                    min_mac_len
+                );
+            }
+        }
+    }
+}
+
+/// Try to generate HMAC key with multiple digests in key authorizations list.
+/// Test fails to generate a key with multiple digests with an error code `UNSUPPORTED_DIGEST`.
+#[test]
+fn keystore2_hmac_gen_key_multi_digests_fails_expect_unsupported_digest() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = "ks_hmac_test_key_multi_dig";
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::HMAC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .key_size(128)
+        .min_mac_length(128)
+        .digest(Digest::SHA1)
+        .digest(Digest::SHA_2_256);
+
+    let result = key_generations::map_ks_error(sec_level.generateKey(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(alias.to_string()),
+            blob: None,
+        },
+        None,
+        &gen_params,
+        0,
+        b"entropy",
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_DIGEST), result.unwrap_err());
+}
+
+/// Try to generate HMAC key without providing digest mode. HMAC key generation with
+/// no digest should fail with an error code `UNSUPPORTED_DIGEST`.
+#[test]
+fn keystore2_hmac_gen_key_no_digests_fails_expect_unsupported_digest() {
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = "ks_hmac_test_key_no_dig";
+    let gen_params = authorizations::AuthSetBuilder::new()
+        .no_auth_required()
+        .algorithm(Algorithm::HMAC)
+        .purpose(KeyPurpose::SIGN)
+        .purpose(KeyPurpose::VERIFY)
+        .key_size(128)
+        .min_mac_length(128);
+
+    let result = key_generations::map_ks_error(sec_level.generateKey(
+        &KeyDescriptor {
+            domain: Domain::APP,
+            nspace: -1,
+            alias: Some(alias.to_string()),
+            blob: None,
+        },
+        None,
+        &gen_params,
+        0,
+        b"entropy",
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_DIGEST), result.unwrap_err());
+}
+
+/// Try to generate a HMAC key with NONE digest mode, it should fail with `UNSUPPORTED_DIGEST`
+/// error code.
+#[test]
+fn keystore2_hmac_gen_key_with_none_digest_fails_expect_unsupported_digest() {
+    let min_mac_len = 128;
+    let key_size = 128;
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    let alias = "ks_hmac_test_key_fail";
+    let result = key_generations::map_ks_error(key_generations::generate_hmac_key(
+        &sec_level,
+        alias,
+        key_size,
+        min_mac_len,
+        Digest::NONE,
+    ));
+    assert!(result.is_err());
+    assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_DIGEST), result.unwrap_err());
+}
+
+/// Generate HMAC key with min-mac-len of 128 bits for the digest modes Digest::SHA1 and
+/// Digest::SHA_2_224. Try to create an operation with generated key and mac-length greater than
+/// digest length. Test should fail to create an operation with an error code
+/// `UNSUPPORTED_MAC_LENGTH`.
+#[test]
+fn keystore2_hmac_key_op_with_mac_len_greater_than_digest_len_fail() {
+    let digests = [Digest::SHA1, Digest::SHA_2_224];
+    let min_mac_len = 128;
+    let mac_len = 256;
+    let key_size = 128;
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    for digest in digests {
+        let alias = format!("ks_hmac_test_key_{}", digest.0);
+
+        let result = key_generations::map_ks_error(create_hmac_key_and_operation(
+            &sec_level,
+            &alias,
+            key_size,
+            mac_len,
+            min_mac_len,
+            digest,
+        ));
+
+        assert!(result.is_err());
+        assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_MAC_LENGTH), result.unwrap_err());
+    }
+}
+
+/// Generate HMAC key with min-mac-len of 128 bits for the digest modes Digest::SHA1 and
+/// Digest::SHA_2_224. Try to create an operation with generated key and mac-length less than
+/// min-mac-length. Test should fail to create an operation with an error code
+/// `INVALID_MAC_LENGTH`.
+#[test]
+fn keystore2_hmac_key_op_with_mac_len_less_than_min_mac_len_fail() {
+    let digests = [Digest::SHA1, Digest::SHA_2_224];
+    let min_mac_len = 128;
+    let mac_len = 64;
+    let key_size = 128;
+
+    let keystore2 = get_keystore_service();
+    let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+    for digest in digests {
+        let alias = format!("ks_hmac_test_key_{}", digest.0);
+
+        let result = key_generations::map_ks_error(create_hmac_key_and_operation(
+            &sec_level,
+            &alias,
+            key_size,
+            mac_len,
+            min_mac_len,
+            digest,
+        ));
+
+        assert!(result.is_err());
+        assert_eq!(Error::Km(ErrorCode::INVALID_MAC_LENGTH), result.unwrap_err());
+    }
+}
diff --git a/keystore2/tests/keystore2_client_list_entries_tests.rs b/keystore2/tests/keystore2_client_list_entries_tests.rs
index d50ef5c..def9d94 100644
--- a/keystore2/tests/keystore2_client_list_entries_tests.rs
+++ b/keystore2/tests/keystore2_client_list_entries_tests.rs
@@ -24,7 +24,7 @@
 use keystore2_test_utils::{get_keystore_service, key_generations, key_generations::Error, run_as};
 
 /// Try to find a key with given key parameters using `listEntries` API.
-fn is_key_alias_exist(
+fn key_alias_exists(
     keystore2: &binder::Strong<dyn IKeystoreService>,
     domain: Domain,
     nspace: i64,
@@ -66,7 +66,7 @@
 
             // Make sure there is no key exist with this `alias` in `SELINUX` domain and
             // `SELINUX_SHELL_NAMESPACE` namespace.
-            if is_key_alias_exist(
+            if key_alias_exists(
                 &keystore2,
                 Domain::SELINUX,
                 key_generations::SELINUX_SHELL_NAMESPACE,
@@ -95,7 +95,7 @@
 
             // Verify that above generated key entry is listed with domain SELINUX and
             // namespace SELINUX_SHELL_NAMESPACE
-            assert!(is_key_alias_exist(
+            assert!(key_alias_exists(
                 &keystore2,
                 Domain::SELINUX,
                 key_generations::SELINUX_SHELL_NAMESPACE,
diff --git a/keystore2/tests/keystore2_client_operation_tests.rs b/keystore2/tests/keystore2_client_operation_tests.rs
index d8b85f6..e1102dd 100644
--- a/keystore2/tests/keystore2_client_operation_tests.rs
+++ b/keystore2/tests/keystore2_client_operation_tests.rs
@@ -14,12 +14,15 @@
 
 use nix::unistd::{getuid, Gid, Uid};
 use rustutils::users::AID_USER_OFFSET;
+use std::thread;
+use std::thread::JoinHandle;
 
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
 };
 use android_system_keystore2::aidl::android::system::keystore2::{
-    CreateOperationResponse::CreateOperationResponse, Domain::Domain, ResponseCode::ResponseCode,
+    CreateOperationResponse::CreateOperationResponse, Domain::Domain,
+    IKeystoreOperation::IKeystoreOperation, ResponseCode::ResponseCode,
 };
 
 use keystore2_test_utils::{
@@ -57,6 +60,25 @@
         .collect()
 }
 
+/// Executes an operation in a thread. Expect an `OPERATION_BUSY` error in case of operation
+/// failure. Returns True if `OPERATION_BUSY` error is encountered otherwise returns false.
+fn perform_op_busy_in_thread(op: binder::Strong<dyn IKeystoreOperation>) -> JoinHandle<bool> {
+    thread::spawn(move || {
+        for _n in 1..1000 {
+            match key_generations::map_ks_error(op.update(b"my message")) {
+                Ok(_) => continue,
+                Err(e) => {
+                    assert_eq!(Error::Rc(ResponseCode::OPERATION_BUSY), e);
+                    return true;
+                }
+            }
+        }
+        let sig = op.finish(None, None).unwrap();
+        assert!(sig.is_some());
+        false
+    })
+}
+
 /// This test verifies that backend service throws BACKEND_BUSY error when all
 /// operations slots are full. This test creates operations in child processes and
 /// collects the status of operations performed in each child proc and determines
@@ -402,3 +424,29 @@
         });
     }
 }
+
+/// Create an operation and try to use this operation handle in multiple threads to perform
+/// operations. Test should fail to perform an operation with an error response `OPERATION_BUSY`
+/// when multiple threads try to access the operation handle at same time.
+#[test]
+fn keystore2_op_fails_operation_busy() {
+    let op_response = create_signing_operation(
+        ForcedOp(false),
+        KeyPurpose::SIGN,
+        Digest::SHA_2_256,
+        Domain::APP,
+        -1,
+        Some("op_busy_alias_test_key".to_string()),
+    )
+    .unwrap();
+
+    let op: binder::Strong<dyn IKeystoreOperation> = op_response.iOperation.unwrap();
+
+    let th_handle_1 = perform_op_busy_in_thread(op.clone());
+    let th_handle_2 = perform_op_busy_in_thread(op);
+
+    let result1 = th_handle_1.join().unwrap();
+    let result2 = th_handle_2.join().unwrap();
+
+    assert!(result1 || result2);
+}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index 734faf6..b2257ed 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -16,6 +16,7 @@
 pub mod keystore2_client_aes_key_tests;
 pub mod keystore2_client_ec_key_tests;
 pub mod keystore2_client_grant_key_tests;
+pub mod keystore2_client_hmac_key_tests;
 pub mod keystore2_client_key_id_domain_tests;
 pub mod keystore2_client_list_entries_tests;
 pub mod keystore2_client_operation_tests;