Merge changes from topic "fix-aidl-mix-ports-and-bt" into main
* changes:
audio: Fix BT AIDL HAL module implementation
audio r_submix: Suggest configuration from the peer
audio: Refactor configuration population
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index 2d4d283..3c5f7f6 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -928,7 +928,10 @@
* using 'connectExternalDevice' method. 'disconnectExternalDevice' method will be called
* soon after this method with the same 'portId'.
*
- * @param portId The ID of the audio port that is about to disconnect
+ * Note: This method is called after the external device is disconnected. The system does
+ * not try to predict the disconnection event.
+ *
+ * @param portId The ID of the audio port corresponding to the disconnected device
* @throws EX_ILLEGAL_ARGUMENT In the following cases:
* - If the port can not be found by the ID.
* - If this is not a connected device port.
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 3d7ecb6..d210304 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -331,6 +331,7 @@
<version>1</version>
<interface>
<name>ISecretkeeper</name>
+ <instance>default</instance>
<instance>nonsecure</instance>
</interface>
</hal>
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 18d36e4..323e358 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -1554,6 +1554,7 @@
}
TEST_P(GraphicsComposerAidlCommandTest, SetDisplayBrightness) {
+ EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
const auto& [status, capabilities] =
mComposerClient->getDisplayCapabilities(getPrimaryDisplayId());
ASSERT_TRUE(status.isOk());
diff --git a/security/rkp/README.md b/security/rkp/README.md
index 2180d0f..2d00b83 100644
--- a/security/rkp/README.md
+++ b/security/rkp/README.md
@@ -210,10 +210,10 @@
describes an RKP VM. If there are further certificates without the RKP VM
marker, then the chain does not describe an RKP VM.
- Implementations must include the first RPK VM marker as early as possible
+ Implementations must include the first RKP VM marker as early as possible
after the point of divergence between TEE and non-TEE components in the DICE
chain, prior to loading the Android Bootloader (ABL).
2. "widevine" or "keymint": If there are no certificates with the RKP VM
marker then it describes a TEE component.
3. None: Any component described by a DICE chain that does not match the above
- two categories.
\ No newline at end of file
+ two categories.
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index a1de93e..68b966c 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -402,7 +402,7 @@
for (auto& key : keysToSign_) {
bytevec privateKeyBlob;
auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
vector<uint8_t> payload_value;
check_maced_pubkey(key, testMode, &payload_value);
@@ -447,7 +447,7 @@
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
auto result = verifyProductionProtectedData(
deviceInfo, cppbor::Array(), keysToSignMac, protectedData, testEekChain_, eekId_,
@@ -472,7 +472,7 @@
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
auto firstBcc = verifyProductionProtectedData(
deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
@@ -482,7 +482,7 @@
status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
auto secondBcc = verifyProductionProtectedData(
deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
@@ -532,7 +532,7 @@
auto status = provisionable_->generateCertificateRequest(
testMode, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
auto result = verifyProductionProtectedData(
deviceInfo, cborKeysToSign_, keysToSignMac, protectedData, testEekChain_, eekId_,
@@ -576,7 +576,7 @@
auto status = provisionable_->generateCertificateRequest(
testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
- ASSERT_FALSE(status.isOk()) << status.getMessage();
+ ASSERT_FALSE(status.isOk()) << status.getDescription();
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
@@ -596,7 +596,7 @@
auto status = provisionable_->generateCertificateRequest(
testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
challenge_, &deviceInfo, &protectedData, &keysToSignMac);
- ASSERT_FALSE(status.isOk()) << status.getMessage();
+ ASSERT_FALSE(status.isOk()) << status.getDescription();
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
@@ -722,7 +722,7 @@
auto challenge = randomBytes(size);
auto status =
provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge, &csr);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge);
ASSERT_TRUE(result) << result.message();
@@ -743,7 +743,7 @@
SCOPED_TRACE(testing::Message() << "challenge[" << size << "]");
auto challenge = randomBytes(size);
auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge, &csr);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge);
ASSERT_TRUE(result) << result.message();
@@ -758,7 +758,7 @@
auto status = provisionable_->generateCertificateRequestV2(
/* keysToSign */ {}, randomBytes(MAX_CHALLENGE_SIZE + 1), &csr);
- EXPECT_FALSE(status.isOk()) << status.getMessage();
+ EXPECT_FALSE(status.isOk()) << status.getDescription();
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_FAILED);
}
@@ -773,13 +773,13 @@
bytevec csr;
auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
ASSERT_TRUE(firstCsr) << firstCsr.message();
status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
ASSERT_TRUE(secondCsr) << secondCsr.message();
@@ -797,7 +797,7 @@
bytevec csr;
auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
- ASSERT_TRUE(status.isOk()) << status.getMessage();
+ ASSERT_TRUE(status.isOk()) << status.getDescription();
auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
ASSERT_TRUE(result) << result.message();
@@ -815,7 +815,7 @@
bytevec csr;
auto status =
provisionable_->generateCertificateRequestV2({keyWithCorruptMac}, challenge_, &csr);
- ASSERT_FALSE(status.isOk()) << status.getMessage();
+ ASSERT_FALSE(status.isOk()) << status.getDescription();
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
@@ -829,7 +829,7 @@
auto status = provisionable_->generateCertificateRequest(
false /* testMode */, {} /* keysToSign */, {} /* EEK chain */, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
- ASSERT_FALSE(status.isOk()) << status.getMessage();
+ ASSERT_FALSE(status.isOk()) << status.getDescription();
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_REMOVED);
}
@@ -843,7 +843,7 @@
auto status = provisionable_->generateCertificateRequest(
true /* testMode */, {} /* keysToSign */, {} /* EEK chain */, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
- ASSERT_FALSE(status.isOk()) << status.getMessage();
+ ASSERT_FALSE(status.isOk()) << status.getDescription();
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_REMOVED);
}
@@ -927,7 +927,7 @@
bytevec csr;
irpcStatus =
provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge_, &csr);
- ASSERT_TRUE(irpcStatus.isOk()) << irpcStatus.getMessage();
+ ASSERT_TRUE(irpcStatus.isOk()) << irpcStatus.getDescription();
auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge_);
ASSERT_TRUE(result) << result.message();
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl
index 87d0233..9887066 100644
--- a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/SecretId.aidl
@@ -35,5 +35,5 @@
/* @hide */
@VintfStability
parcelable SecretId {
- byte[] id;
+ byte[64] id;
}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
index 49c3446..b07dba8 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -39,9 +39,14 @@
/**
* Retrieve the instance of the `IAuthGraphKeyExchange` HAL that should be used for shared
- * session key establishment. These keys are used to perform encryption of messages as
+ * session key establishment. These keys are used to perform encryption of messages as
* described in SecretManagement.cddl, allowing the client and Secretkeeper to have a
- * cryptographically secure channel.
+ * cryptographically secure channel. In the key exchange protocol the client acts as P1
+ * (source) and Secretkeeper as P2 (sink). The interface returned here can be used to invoke
+ * methods on the sink.
+ *
+ * The client's identity is its DICE chain; Secretkeeper's identity is a
+ * per-boot key pair.
*/
IAuthGraphKeyExchange getAuthGraphKe();
@@ -56,8 +61,8 @@
* ProtectedRequestPacket & ProtectedResponsePacket using symmetric keys agreed between
* the client & service. This cryptographic protection is required because the messages are
* ferried via Android, which is allowed to be outside the TCB of clients (for example protected
- * Virtual Machines). For this, service (& client) must implement a key exchange protocol, which
- * is critical for establishing the secure channel.
+ * Virtual Machines). For this, service (& client) must implement the AuthGraph key exchange
+ * protocol to establish a secure channel between them.
*
* If an encrypted response cannot be generated, then a service-specific Binder error using one
* of the ERROR_ codes above will be returned.
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
index bd982e7..b17917f 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretId.aidl
@@ -25,5 +25,5 @@
/**
* 64-byte identifier for a secret.
*/
- byte[] id;
+ byte[64] id;
}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
index 3d08078..6a824c9 100644
--- a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
@@ -3,10 +3,11 @@
; The input parameter to the `processSecretManagementRequest` operation in
; `ISecretkeeper.aidl` is always an encrypted request message, CBOR-encoded as a
; COSE_Encrypt0 object. The encryption uses the first of the keys agreed using
-; the associated AuthGraph instance, referred to as `KeySourceToSink`.
-ProtectedRequestPacket = CryptoPayload<RequestPacket, KeySourceToSink>
+; the associated AuthGraph instance, referred to as `KeySourceToSink`. Additionally,
+; an external aad is used - RequestSeqNum.
+ProtectedRequestPacket = CryptoPayload<RequestPacket, KeySourceToSink, RequestSeqNum>
-CryptoPayload<Payload, Key> = [ ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
+CryptoPayload<Payload, Key, SeqNum> = [ ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
protected: bstr .cbor {
1 : 3, ; Algorithm: AES-GCM mode w/ 256-bit key, 128-bit tag
4 : bstr ; key identifier set to session ID produced
@@ -17,7 +18,7 @@
},
ciphertext : bstr ; AES-GCM-256(Key, bstr .cbor Payload)
; AAD for the encryption is CBOR-serialized
- ; Enc_structure (RFC 9052 s5.3) with empty external_aad.
+ ; Enc_structure (RFC 9052 s5.3) with SeqNum as the external_aad.
]
; Once decrypted, the request packet is an encoded CBOR array holding:
@@ -58,10 +59,18 @@
SecretId = bstr .size 64 ; Unique identifier of the secret.
Secret = bstr .size 32 ; The secret value.
+; A monotonically incrementing number is associated with each RequestPacket to prevent replay
+; of messages within a session. This starts with 0 and is incremented (by 1) for each request
+; in a session. Secretkeeper implementation must maintain an expected RequestSeqNum for each
+; session (increasing it by 1 for each SecretManagement request received). This will be used in
+; in decryption (external_aad).
+RequestSeqNum = bstr .cbor uint ; Encoded in accordance with Core Deterministic Encoding
+ ; Requirements [RFC 8949 s4.2.1]
+
; The return value from a successful `processSecretManagementRequest` operation is a
; response message encrypted with the second of the keys agreed using the associated
; AuthGraph instance, referred to as `KeySinkToSource`.
-ProtectedResponsePacket = CryptoPayload<ResponsePacket, KeySinkToSource>
+ProtectedResponsePacket = CryptoPayload<ResponsePacket, KeySinkToSource, ResponseSeqNum>
; Once decrypted, the inner response message is encoded as a CBOR array holding:
; - An initial integer return code value.
@@ -82,7 +91,7 @@
; Requested Entry not found.
ErrorCode_EntryNotFound: 3,
; Error happened while serialization or deserialization.
- SerializationError: 4,
+ ErrorCode_SerializationError: 4,
; Indicates that Dice Policy matching did not succeed & hence access not granted.
ErrorCode_DicePolicyError: 5,
)
@@ -95,8 +104,13 @@
GetSecretResult,
)
-GetVersionResult = (version : uint)
+GetVersionResult = (1)
StoreSecretResult = ()
GetSecretResult = (secret : Secret)
+
+; Analogous to RequestSeqNum, Secretkeeper must maintain ResponseSeqNum for each session.
+; This will be input to the encryption (ProtectedResponsePacket) as external_aad.
+ResponseSeqNum = bstr .cbor uint ; Encoded in accordance with Core Deterministic Encoding
+ ; Requirements [RFC 8949 s4.2.1]
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
index 7fc7a70..7de9d6a 100644
--- a/security/secretkeeper/aidl/vts/Android.bp
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -27,6 +27,7 @@
],
test_config: "AndroidTest.xml",
rustlibs: [
+ "libsecretkeeper_client",
"libsecretkeeper_comm_nostd",
"libsecretkeeper_core_nostd",
"android.hardware.security.secretkeeper-V1-rust",
diff --git a/security/secretkeeper/aidl/vts/rustfmt.toml b/security/secretkeeper/aidl/vts/rustfmt.toml
new file mode 120000
index 0000000..ed2086b
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/rustfmt.toml
@@ -0,0 +1 @@
+../../../../../../build/soong/scripts/rustfmt.toml
\ No newline at end of file
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
index 6a70d02..c457d24 100644
--- a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -24,18 +24,19 @@
use binder::StatusCode;
use coset::{CborSerializable, CoseEncrypt0};
use log::{info, warn};
+use secretkeeper_client::SkSession;
use secretkeeper_core::cipher;
use secretkeeper_comm::data_types::error::SecretkeeperError;
use secretkeeper_comm::data_types::request::Request;
use secretkeeper_comm::data_types::request_response_impl::{
GetVersionRequest, GetVersionResponse, GetSecretRequest, GetSecretResponse, StoreSecretRequest,
StoreSecretResponse };
-use secretkeeper_comm::data_types::{Id, Secret};
+use secretkeeper_comm::data_types::{Id, Secret, SeqNum};
use secretkeeper_comm::data_types::response::Response;
use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
const SECRETKEEPER_SERVICE: &str = "android.hardware.security.secretkeeper.ISecretkeeper";
-const SECRETKEEPER_INSTANCES: [&'static str; 2] = ["nonsecure", "default"];
+const SECRETKEEPER_INSTANCES: [&'static str; 2] = ["default", "nonsecure"];
const CURRENT_VERSION: u64 = 1;
// TODO(b/291238565): This will change once libdice_policy switches to Explicit-key DiceCertChain
@@ -75,9 +76,16 @@
// Initialize logging (which is OK to call multiple times).
logger::init(logger::Config::default().with_min_level(log::Level::Debug));
+ // Determine which instances are available.
+ let available = binder::get_declared_instances(SECRETKEEPER_SERVICE).unwrap_or_default();
+
// TODO: replace this with a parameterized set of tests that run for each available instance of
// ISecretkeeper (rather than having a fixed set of instance names to look for).
for instance in &SECRETKEEPER_INSTANCES {
+ if available.iter().find(|s| s == instance).is_none() {
+ // Skip undeclared instances.
+ continue;
+ }
let name = format!("{SECRETKEEPER_SERVICE}/{instance}");
match binder::get_interface(&name) {
Ok(sk) => {
@@ -88,10 +96,14 @@
info!("No /{instance} instance of ISecretkeeper present");
}
Err(e) => {
- panic!("unexpected error while fetching connection to Secretkeeper {:?}", e);
+ panic!(
+ "unexpected error while fetching connection to Secretkeeper {:?}",
+ e
+ );
}
}
}
+ info!("no Secretkeeper instances in {SECRETKEEPER_INSTANCES:?} are declared and present");
None
}
@@ -112,8 +124,7 @@
struct SkClient {
sk: binder::Strong<dyn ISecretkeeper>,
name: String,
- aes_keys: [key::AesKey; 2],
- session_id: Vec<u8>,
+ session: SkSession,
}
impl Drop for SkClient {
@@ -126,27 +137,58 @@
impl SkClient {
fn new() -> Option<Self> {
let (sk, name) = get_connection()?;
- let (aes_keys, session_id) = authgraph_key_exchange(sk.clone());
- Some(Self { sk, name, aes_keys, session_id })
+ Some(Self {
+ sk: sk.clone(),
+ name,
+ session: SkSession::new(sk).unwrap(),
+ })
}
- /// Wrapper around `ISecretkeeper::processSecretManagementRequest` that handles
+ /// This method is wrapper that use `SkSession::secret_management_request` which handles
/// encryption and decryption.
- fn secret_management_request(&self, req_data: &[u8]) -> Vec<u8> {
+ fn secret_management_request(&mut self, req_data: &[u8]) -> Vec<u8> {
+ self.session.secret_management_request(req_data).unwrap()
+ }
+
+ /// Unlike the method [`secret_management_request`], this method directly uses
+ /// `cipher::encrypt_message` & `cipher::decrypt_message`, allowing finer control of request
+ /// & response aad.
+ fn secret_management_request_custom_aad(
+ &self,
+ req_data: &[u8],
+ req_aad: &[u8],
+ expected_res_aad: &[u8],
+ ) -> Vec<u8> {
let aes_gcm = boring::BoringAes;
let rng = boring::BoringRng;
- let request_bytes =
- cipher::encrypt_message(&aes_gcm, &rng, &self.aes_keys[0], &self.session_id, &req_data)
- .unwrap();
+ let request_bytes = cipher::encrypt_message(
+ &aes_gcm,
+ &rng,
+ self.session.encryption_key(),
+ self.session.session_id(),
+ &req_data,
+ req_aad,
+ )
+ .unwrap();
- let response_bytes = self.sk.processSecretManagementRequest(&request_bytes).unwrap();
+ // Binder call!
+ let response_bytes = self
+ .sk
+ .processSecretManagementRequest(&request_bytes)
+ .unwrap();
let response_encrypt0 = CoseEncrypt0::from_slice(&response_bytes).unwrap();
- cipher::decrypt_message(&aes_gcm, &self.aes_keys[1], &response_encrypt0).unwrap()
+ cipher::decrypt_message(
+ &aes_gcm,
+ self.session.decryption_key(),
+ &response_encrypt0,
+ expected_res_aad,
+ )
+ .unwrap()
}
/// Helper method to store a secret.
- fn store(&self, id: &Id, secret: &Secret) {
+ fn store(&mut self, id: &Id, secret: &Secret) {
let store_request = StoreSecretRequest {
id: id.clone(),
secret: secret.clone(),
@@ -157,14 +199,20 @@
let store_response = self.secret_management_request(&store_request);
let store_response = ResponsePacket::from_slice(&store_response).unwrap();
- assert_eq!(store_response.response_type().unwrap(), ResponseType::Success);
+ assert_eq!(
+ store_response.response_type().unwrap(),
+ ResponseType::Success
+ );
// Really just checking that the response is indeed StoreSecretResponse
let _ = StoreSecretResponse::deserialize_from_packet(store_response).unwrap();
}
/// Helper method to get a secret.
- fn get(&self, id: &Id) -> Option<Secret> {
- let get_request = GetSecretRequest { id: id.clone(), updated_sealing_policy: None };
+ fn get(&mut self, id: &Id) -> Option<Secret> {
+ let get_request = GetSecretRequest {
+ id: id.clone(),
+ updated_sealing_policy: None,
+ };
let get_request = get_request.serialize_to_packet().to_vec().unwrap();
let get_response = self.secret_management_request(&get_request);
@@ -183,7 +231,10 @@
/// Helper method to delete secrets.
fn delete(&self, ids: &[&Id]) {
- let ids: Vec<SecretId> = ids.iter().map(|id| SecretId { id: id.0.to_vec() }).collect();
+ let ids: Vec<SecretId> = ids
+ .iter()
+ .map(|id| SecretId { id: id.0 })
+ .collect();
self.sk.deleteIds(&ids).unwrap();
}
@@ -251,7 +302,7 @@
#[test]
fn secret_management_get_version() {
- let sk_client = setup_client!();
+ let mut sk_client = setup_client!();
let request = GetVersionRequest {};
let request_packet = request.serialize_to_packet();
@@ -260,7 +311,10 @@
let response_bytes = sk_client.secret_management_request(&request_bytes);
let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
- assert_eq!(response_packet.response_type().unwrap(), ResponseType::Success);
+ assert_eq!(
+ response_packet.response_type().unwrap(),
+ ResponseType::Success
+ );
let get_version_response =
*GetVersionResponse::deserialize_from_packet(response_packet).unwrap();
assert_eq!(get_version_response.version, CURRENT_VERSION);
@@ -268,7 +322,7 @@
#[test]
fn secret_management_malformed_request() {
- let sk_client = setup_client!();
+ let mut sk_client = setup_client!();
let request = GetVersionRequest {};
let request_packet = request.serialize_to_packet();
@@ -280,14 +334,17 @@
let response_bytes = sk_client.secret_management_request(&request_bytes);
let response_packet = ResponsePacket::from_slice(&response_bytes).unwrap();
- assert_eq!(response_packet.response_type().unwrap(), ResponseType::Error);
+ assert_eq!(
+ response_packet.response_type().unwrap(),
+ ResponseType::Error
+ );
let err = *SecretkeeperError::deserialize_from_packet(response_packet).unwrap();
assert_eq!(err, SecretkeeperError::RequestMalformed);
}
#[test]
fn secret_management_store_get_secret_found() {
- let sk_client = setup_client!();
+ let mut sk_client = setup_client!();
sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
@@ -297,7 +354,7 @@
#[test]
fn secret_management_store_get_secret_not_found() {
- let sk_client = setup_client!();
+ let mut sk_client = setup_client!();
// Store a secret (corresponding to an id).
sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
@@ -308,7 +365,7 @@
#[test]
fn secretkeeper_store_delete_ids() {
- let sk_client = setup_client!();
+ let mut sk_client = setup_client!();
sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
@@ -325,7 +382,7 @@
#[test]
fn secretkeeper_store_delete_multiple_ids() {
- let sk_client = setup_client!();
+ let mut sk_client = setup_client!();
sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
@@ -337,7 +394,7 @@
#[test]
fn secretkeeper_store_delete_duplicate_ids() {
- let sk_client = setup_client!();
+ let mut sk_client = setup_client!();
sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
@@ -350,7 +407,7 @@
#[test]
fn secretkeeper_store_delete_nonexistent() {
- let sk_client = setup_client!();
+ let mut sk_client = setup_client!();
sk_client.store(&ID_EXAMPLE, &SECRET_EXAMPLE);
sk_client.store(&ID_EXAMPLE_2, &SECRET_EXAMPLE);
@@ -363,7 +420,7 @@
#[test]
fn secretkeeper_store_delete_all() {
- let sk_client = setup_client!();
+ let mut sk_client = setup_client!();
if sk_client.name != "nonsecure" {
// Don't run deleteAll() on a secure device, as it might affect
@@ -389,3 +446,107 @@
// (Try to) Get the secret that was never stored
assert_eq!(sk_client.get(&ID_NOT_STORED), None);
}
+
+// This test checks that Secretkeeper uses the expected [`RequestSeqNum`] as aad while
+// decrypting requests and the responses are encrypted with correct [`ResponseSeqNum`] for the
+// first few messages.
+#[test]
+fn secret_management_replay_protection_seq_num() {
+ let sk_client = setup_client!();
+ // Construct encoded request packets for the test
+ let (req_1, req_2, req_3) = construct_secret_management_requests();
+
+ // Lets now construct the seq_numbers(in request & expected in response)
+ let mut seq_a = SeqNum::new();
+ let [seq_0, seq_1, seq_2] = std::array::from_fn(|_| seq_a.get_then_increment().unwrap());
+
+ // Check first request/response is successful
+ let res = ResponsePacket::from_slice(
+ &sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0),
+ )
+ .unwrap();
+ assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+ // Check 2nd request/response is successful
+ let res = ResponsePacket::from_slice(
+ &sk_client.secret_management_request_custom_aad(&req_2, &seq_1, &seq_1),
+ )
+ .unwrap();
+ assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+ // Check 3rd request/response is successful
+ let res = ResponsePacket::from_slice(
+ &sk_client.secret_management_request_custom_aad(&req_3, &seq_2, &seq_2),
+ )
+ .unwrap();
+ assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+}
+
+// This test checks that Secretkeeper uses fresh [`RequestSeqNum`] & [`ResponseSeqNum`]
+// for new sessions.
+#[test]
+fn secret_management_replay_protection_seq_num_per_session() {
+ let sk_client = setup_client!();
+
+ // Construct encoded request packets for the test
+ let (req_1, _, _) = construct_secret_management_requests();
+
+ // Lets now construct the seq_number (in request & expected in response)
+ let mut seq_a = SeqNum::new();
+ let seq_0 = seq_a.get_then_increment().unwrap();
+ // Check first request/response is successful
+ let res = ResponsePacket::from_slice(
+ &sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0),
+ )
+ .unwrap();
+ assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+
+ // Start another session
+ let sk_client_diff = setup_client!();
+ // Check first request/response is with seq_0 is successful
+ let res = ResponsePacket::from_slice(
+ &sk_client_diff.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0),
+ )
+ .unwrap();
+ assert_eq!(res.response_type().unwrap(), ResponseType::Success);
+}
+
+// This test checks that Secretkeeper rejects requests with out of order [`RequestSeqNum`]
+#[test]
+// TODO(b/317416663): This test fails, when HAL is not present in the device. Refactor to fix this.
+#[ignore]
+#[should_panic]
+fn secret_management_replay_protection_out_of_seq_req_not_accepted() {
+ let sk_client = setup_client!();
+
+ // Construct encoded request packets for the test
+ let (req_1, req_2, _) = construct_secret_management_requests();
+
+ // Lets now construct the seq_numbers(in request & expected in response)
+ let mut seq_a = SeqNum::new();
+ let [seq_0, seq_1, seq_2] = std::array::from_fn(|_| seq_a.get_then_increment().unwrap());
+
+ // Assume First request/response is successful
+ sk_client.secret_management_request_custom_aad(&req_1, &seq_0, &seq_0);
+
+ // Check 2nd request/response with skipped seq_num in request is a binder error
+ // This should panic!
+ sk_client.secret_management_request_custom_aad(&req_2, /*Skipping seq_1*/ &seq_2, &seq_1);
+}
+
+fn construct_secret_management_requests() -> (Vec<u8>, Vec<u8>, Vec<u8>) {
+ let version_request = GetVersionRequest {};
+ let version_request = version_request.serialize_to_packet().to_vec().unwrap();
+ let store_request = StoreSecretRequest {
+ id: ID_EXAMPLE,
+ secret: SECRET_EXAMPLE,
+ sealing_policy: HYPOTHETICAL_DICE_POLICY.to_vec(),
+ };
+ let store_request = store_request.serialize_to_packet().to_vec().unwrap();
+ let get_request = GetSecretRequest {
+ id: ID_EXAMPLE,
+ updated_sealing_policy: None,
+ };
+ let get_request = get_request.serialize_to_packet().to_vec().unwrap();
+ (version_request, store_request, get_request)
+}
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
index fccd2ed..3d60e89 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
@@ -35,6 +35,7 @@
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+ mFrontendTests.setDemux(demux);
mFilterTests.setDemux(demux);
ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.config1_0.type,
filterConf.config1_0.bufferSize));
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index 3664b6c..766814f 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -48,6 +48,7 @@
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+ mFrontendTests.setDemux(demux);
mFilterTests.setDemux(demux);
ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
@@ -1197,6 +1198,10 @@
vector<ScanHardwareConnections> scan_configs = generateScanConfigurations();
for (auto& configuration : scan_configs) {
scan = configuration;
+ // Skip test if the frontend implementation doesn't support blind scan
+ if (!frontendMap[scan.frontendId].supportBlindScan) {
+ continue;
+ }
mFrontendTests.scanTest(frontendMap[scan.frontendId], FrontendScanType::SCAN_BLIND);
}
}
@@ -1221,6 +1226,10 @@
vector<ScanHardwareConnections> scan_configs = generateScanConfigurations();
for (auto& configuration : scan_configs) {
scan = configuration;
+ // Skip test if the frontend implementation doesn't support blind scan
+ if (!frontendMap[scan.frontendId].supportBlindScan) {
+ continue;
+ }
mFrontendTests.scanTest(frontendMap[scan.frontendId], FrontendScanType::SCAN_BLIND);
}
}
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
index 516cb62..5c13ed0 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
@@ -612,6 +612,7 @@
frontendMap[defaultFeId].isSoftwareFe = true;
frontendMap[defaultFeId].canConnectToCiCam = true;
frontendMap[defaultFeId].ciCamId = 0;
+ frontendMap[defaultFeId].supportBlindScan = true;
FrontendDvbtSettings dvbt;
dvbt.transmissionMode = FrontendDvbtTransmissionMode::MODE_8K_E;
frontendMap[defaultFeId].settings.set<FrontendSettings::Tag::dvbt>(dvbt);
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index 9517520..5ffb38f 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -114,6 +114,7 @@
FrontendSettings settings;
vector<FrontendStatusType> tuneStatusTypes;
vector<FrontendStatus> expectTuneStatuses;
+ bool supportBlindScan;
};
struct FilterConfig {
@@ -354,6 +355,11 @@
} else {
hasHwFe = true;
}
+ if (feConfig.hasSupportBlindScan()) {
+ frontendMap[id].supportBlindScan = feConfig.getSupportBlindScan();
+ } else {
+ frontendMap[id].supportBlindScan = true;
+ }
// TODO: b/182519645 complete the tune status config
frontendMap[id].tuneStatusTypes = types;
frontendMap[id].expectTuneStatuses = statuses;
diff --git a/tv/tuner/config/api/current.txt b/tv/tuner/config/api/current.txt
index dbd3486..ff2df90 100644
--- a/tv/tuner/config/api/current.txt
+++ b/tv/tuner/config/api/current.txt
@@ -369,6 +369,7 @@
method @Nullable public android.media.tuner.testing.configuration.V1_0.IsdbsFrontendSettings getIsdbsFrontendSettings_optional();
method @Nullable public android.media.tuner.testing.configuration.V1_0.IsdbtFrontendSettings getIsdbtFrontendSettings_optional();
method @Nullable public java.math.BigInteger getRemoveOutputPid();
+ method @Nullable public boolean getSupportBlindScan();
method @Nullable public android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum getType();
method public void setAtscFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.AtscFrontendSettings);
method public void setConnectToCicamId(@Nullable java.math.BigInteger);
@@ -381,6 +382,7 @@
method public void setIsdbsFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.IsdbsFrontendSettings);
method public void setIsdbtFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.IsdbtFrontendSettings);
method public void setRemoveOutputPid(@Nullable java.math.BigInteger);
+ method public void setSupportBlindScan(@Nullable boolean);
method public void setType(@Nullable android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum);
}
diff --git a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
index c51ac51..eafaca9 100644
--- a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
+++ b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
@@ -162,6 +162,7 @@
<xs:attribute name="connectToCicamId" type="xs:nonNegativeInteger" use="optional"/>
<xs:attribute name="removeOutputPid" type="xs:nonNegativeInteger" use="optional"/>
<xs:attribute name="endFrequency" type="xs:nonNegativeInteger" use="optional"/>
+ <xs:attribute name="supportBlindScan" type="xs:boolean" use="optional"/>
</xs:complexType>
<!-- FILTER SESSION -->
diff --git a/uwb/aidl/default/src/uwb_chip.rs b/uwb/aidl/default/src/uwb_chip.rs
index d749147..d1c3c67 100644
--- a/uwb/aidl/default/src/uwb_chip.rs
+++ b/uwb/aidl/default/src/uwb_chip.rs
@@ -61,6 +61,20 @@
callbacks.as_binder().unlink_to_death(death_recipient)?;
token.cancel();
handle.await.unwrap();
+ let packet: UciControlPacket = DeviceResetCmdBuilder {
+ reset_config: ResetConfig::UwbsReset,
+ }
+ .build()
+ .into();
+ // DeviceResetCmd need to be send to reset the device to stop all running
+ // activities on UWBS.
+ let packet_vec: Vec<UciControlPacketHal> = packet.into();
+ for hal_packet in packet_vec.into_iter() {
+ serial
+ .write(&hal_packet.to_vec())
+ .map(|written| written as i32)
+ .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
+ }
consume_device_reset_rsp_and_ntf(
&mut serial
.try_clone()
@@ -238,21 +252,7 @@
let mut state = self.state.lock().await;
- if let State::Opened { ref mut serial, .. } = *state {
- let packet: UciControlPacket = DeviceResetCmdBuilder {
- reset_config: ResetConfig::UwbsReset,
- }
- .build()
- .into();
- // DeviceResetCmd need to be send to reset the device to stop all running
- // activities on UWBS.
- let packet_vec: Vec<UciControlPacketHal> = packet.into();
- for hal_packet in packet_vec.into_iter() {
- serial
- .write(&hal_packet.to_vec())
- .map(|written| written as i32)
- .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
- }
+ if let State::Opened { .. } = *state {
state.close().await
} else {
Err(binder::ExceptionCode::ILLEGAL_STATE.into())