Merge "composer: vts: send refresh frame even composition changes" into rvc-dev
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index b8a606a..16c33b9 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -1039,6 +1039,22 @@
{
.config =
{
+ .prop = toInt(VehicleProperty::CREATE_USER),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ },
+ {
+ .config =
+ {
+ .prop = toInt(VehicleProperty::REMOVE_USER),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ },
+ },
+ {
+ .config =
+ {
.prop = toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
index d744a06..f712ea2 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
@@ -30,6 +30,8 @@
constexpr int INITIAL_USER_INFO = static_cast<int>(VehicleProperty::INITIAL_USER_INFO);
constexpr int SWITCH_USER = static_cast<int>(VehicleProperty::SWITCH_USER);
+constexpr int CREATE_USER = static_cast<int>(VehicleProperty::CREATE_USER);
+constexpr int REMOVE_USER = static_cast<int>(VehicleProperty::REMOVE_USER);
constexpr int USER_IDENTIFICATION_ASSOCIATION =
static_cast<int>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
@@ -37,6 +39,8 @@
switch (prop) {
case INITIAL_USER_INFO:
case SWITCH_USER:
+ case CREATE_USER:
+ case REMOVE_USER:
case USER_IDENTIFICATION_ASSOCIATION:
return true;
default:
@@ -53,6 +57,11 @@
return onSetInitialUserInfoResponse(value);
case SWITCH_USER:
return onSetSwitchUserResponse(value);
+ case CREATE_USER:
+ return onSetCreateUserResponse(value);
+ case REMOVE_USER:
+ ALOGI("REMOVE_USER is FYI only, nothing to do...");
+ return {};
case USER_IDENTIFICATION_ASSOCIATION:
return onSetUserIdentificationAssociation(value);
default:
@@ -67,6 +76,8 @@
switch (prop) {
case INITIAL_USER_INFO:
case SWITCH_USER:
+ case CREATE_USER:
+ case REMOVE_USER:
ALOGE("onGetProperty(): %d is only supported on SET", prop);
return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
<< "only supported on SET";
@@ -162,6 +173,41 @@
return updatedValue;
}
+android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetCreateUserResponse(
+ const VehiclePropValue& value) {
+ if (value.value.int32Values.size() == 0) {
+ ALOGE("set(CREATE_USER): no int32values, ignoring it: %s", toString(value).c_str());
+ return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+ << "no int32values on " << toString(value);
+ }
+
+ if (value.areaId != 0) {
+ ALOGD("set(CREATE_USER) called from lshal; storing it: %s", toString(value).c_str());
+ mCreateUserResponseFromCmd.reset(new VehiclePropValue(value));
+ return {};
+ }
+ ALOGD("set(CREATE_USER) called from Android: %s", toString(value).c_str());
+
+ int32_t requestId = value.value.int32Values[0];
+ if (mCreateUserResponseFromCmd != nullptr) {
+ ALOGI("replying CREATE_USER with lshal value: %s",
+ toString(*mCreateUserResponseFromCmd).c_str());
+ return sendUserHalResponse(std::move(mCreateUserResponseFromCmd), requestId);
+ }
+
+ // Returns default response
+ auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
+ updatedValue->prop = CREATE_USER;
+ updatedValue->timestamp = elapsedRealtimeNano();
+ updatedValue->value.int32Values.resize(2);
+ updatedValue->value.int32Values[0] = requestId;
+ updatedValue->value.int32Values[1] = (int32_t)CreateUserStatus::SUCCESS;
+
+ ALOGI("no lshal response; replying with SUCCESS: %s", toString(*updatedValue).c_str());
+
+ return updatedValue;
+}
+
android::base::Result<std::unique_ptr<VehiclePropValue>>
EmulatedUserHal::onSetUserIdentificationAssociation(const VehiclePropValue& value) {
if (value.value.int32Values.size() == 0) {
@@ -247,6 +293,12 @@
} else {
dprintf(fd, "%sNo SwitchUser response\n", indent.c_str());
}
+ if (mCreateUserResponseFromCmd != nullptr) {
+ dprintf(fd, "%sCreateUser response: %s\n", indent.c_str(),
+ toString(*mCreateUserResponseFromCmd).c_str());
+ } else {
+ dprintf(fd, "%sNo CreateUser response\n", indent.c_str());
+ }
if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
dprintf(fd, "%sSetUserIdentificationAssociation response: %s\n", indent.c_str(),
toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h
index 3168d75..5243b96 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h
@@ -105,6 +105,12 @@
const VehiclePropValue& value);
/**
+ * Used to emulate CREATE_USER - see onSetInitialUserInfoResponse() for usage.
+ */
+ android::base::Result<std::unique_ptr<VehiclePropValue>> onSetCreateUserResponse(
+ const VehiclePropValue& value);
+
+ /**
* Used to emulate USER_IDENTIFICATION_ASSOCIATION - see onSetInitialUserInfoResponse() for
* usage.
*/
@@ -116,6 +122,7 @@
std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
std::unique_ptr<VehiclePropValue> mSwitchUserResponseFromCmd;
+ std::unique_ptr<VehiclePropValue> mCreateUserResponseFromCmd;
std::unique_ptr<VehiclePropValue> mSetUserIdentificationAssociationResponseFromCmd;
};
diff --git a/bluetooth/1.0/vts/functional/Android.bp b/bluetooth/1.0/vts/functional/Android.bp
index 463ed84..e9f867f 100644
--- a/bluetooth/1.0/vts/functional/Android.bp
+++ b/bluetooth/1.0/vts/functional/Android.bp
@@ -26,4 +26,5 @@
"general-tests",
"vts",
],
+ disable_framework: true,
}
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 550a2e0..f6860cf 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -575,7 +575,10 @@
}
virtual void TearDown() override {}
- hidl_vec<hidl_string> getCameraDeviceNames(sp<ICameraProvider> provider);
+ hidl_vec<hidl_string> getCameraDeviceNames(sp<ICameraProvider> provider,
+ bool addSecureOnly = false);
+
+ bool isSecureOnly(sp<ICameraProvider> provider, const hidl_string& name);
std::map<hidl_string, hidl_string> getCameraDeviceIdToNameMap(sp<ICameraProvider> provider);
@@ -799,6 +802,16 @@
bool *useHalBufManager /*out*/,
sp<DeviceCb> *cb /*out*/,
uint32_t streamConfigCounter = 0);
+ void configureSingleStream(const std::string& name, int32_t deviceVersion,
+ sp<ICameraProvider> provider,
+ const AvailableStream* previewThreshold, uint64_t bufferUsage,
+ RequestTemplate reqTemplate,
+ sp<ICameraDeviceSession>* session /*out*/,
+ V3_2::Stream* previewStream /*out*/,
+ HalStreamConfiguration* halStreamConfig /*out*/,
+ bool* supportsPartialResults /*out*/,
+ uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
+ sp<DeviceCb>* cb /*out*/, uint32_t streamConfigCounter = 0);
void verifyLogicalCameraMetadata(const std::string& cameraName,
const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device,
@@ -875,6 +888,9 @@
static Status getSystemCameraKind(const camera_metadata_t* staticMeta,
SystemCameraKind* systemCameraKind);
+ void processCaptureRequestInternal(uint64_t bufferusage, RequestTemplate reqTemplate,
+ bool useSecureOnlyCameras);
+
// Used by switchToOffline where a new result queue is created for offline reqs
void updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue);
@@ -1585,7 +1601,8 @@
return idToNameMap;
}
-hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames(sp<ICameraProvider> provider) {
+hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames(sp<ICameraProvider> provider,
+ bool addSecureOnly) {
std::vector<std::string> cameraDeviceNames;
Return<void> ret;
ret = provider->getCameraIdList(
@@ -1634,11 +1651,51 @@
}
}
- hidl_vec<hidl_string> retList(cameraDeviceNames.size());
+ std::vector<hidl_string> retList;
for (size_t i = 0; i < cameraDeviceNames.size(); i++) {
- retList[i] = cameraDeviceNames[i];
+ bool isSecureOnlyCamera = isSecureOnly(mProvider, cameraDeviceNames[i]);
+ if (addSecureOnly) {
+ if (isSecureOnlyCamera) {
+ retList.emplace_back(cameraDeviceNames[i]);
+ }
+ } else if (!isSecureOnlyCamera) {
+ retList.emplace_back(cameraDeviceNames[i]);
+ }
}
- return retList;
+ hidl_vec<hidl_string> finalRetList = std::move(retList);
+ return finalRetList;
+}
+
+bool CameraHidlTest::isSecureOnly(sp<ICameraProvider> provider, const hidl_string& name) {
+ Return<void> ret;
+ ::android::sp<ICameraDevice> device3_x;
+ bool retVal = false;
+ if (getCameraDeviceVersion(mProviderType, name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ return false;
+ }
+ ret = provider->getCameraDeviceInterface_V3_x(name, [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_x = device;
+ });
+ if (!ret.isOk()) {
+ ADD_FAILURE() << "Failed to get camera device interface for " << name;
+ }
+ ret = device3_x->getCameraCharacteristics([&](Status s, CameraMetadata metadata) {
+ ASSERT_EQ(Status::OK, s);
+ camera_metadata_t* chars = (camera_metadata_t*)metadata.data();
+ SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+ Status status = getSystemCameraKind(chars, &systemCameraKind);
+ ASSERT_EQ(status, Status::OK);
+ if (systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA) {
+ retVal = true;
+ }
+ });
+ if (!ret.isOk()) {
+ ADD_FAILURE() << "Failed to get camera characteristics for device " << name;
+ }
+ return retVal;
}
hidl_vec<hidl_vec<hidl_string>> CameraHidlTest::getConcurrentDeviceCombinations(
@@ -4316,8 +4373,21 @@
// Generate and verify a camera capture request
TEST_P(CameraHidlTest, processCaptureRequestPreview) {
- hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
- AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ processCaptureRequestInternal(GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, RequestTemplate::PREVIEW,
+ false /*secureOnlyCameras*/);
+}
+
+// Generate and verify a secure camera capture request
+TEST_P(CameraHidlTest, processSecureCaptureRequest) {
+ processCaptureRequestInternal(GRALLOC1_PRODUCER_USAGE_PROTECTED, RequestTemplate::STILL_CAPTURE,
+ true /*secureOnlyCameras*/);
+}
+
+void CameraHidlTest::processCaptureRequestInternal(uint64_t bufferUsage,
+ RequestTemplate reqTemplate,
+ bool useSecureOnlyCameras) {
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider, useSecureOnlyCameras);
+ AvailableStream streamThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
uint64_t bufferId = 1;
uint32_t frameNumber = 1;
@@ -4333,17 +4403,17 @@
return;
}
- V3_2::Stream previewStream;
+ V3_2::Stream testStream;
HalStreamConfiguration halStreamConfig;
sp<ICameraDeviceSession> session;
sp<DeviceCb> cb;
bool supportsPartialResults = false;
bool useHalBufManager = false;
uint32_t partialResultCount = 0;
- configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
- &previewStream /*out*/, &halStreamConfig /*out*/,
- &supportsPartialResults /*out*/,
- &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/);
+ configureSingleStream(name, deviceVersion, mProvider, &streamThreshold, bufferUsage,
+ reqTemplate, &session /*out*/, &testStream /*out*/,
+ &halStreamConfig /*out*/, &supportsPartialResults /*out*/,
+ &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/);
std::shared_ptr<ResultMetadataQueue> resultQueue;
auto resultQueueRet =
@@ -4364,7 +4434,6 @@
InFlightRequest inflightReq = {1, false, supportsPartialResults,
partialResultCount, resultQueue};
- RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
Return<void> ret;
ret = session->constructDefaultRequestSettings(reqTemplate,
[&](auto status, const auto& req) {
@@ -4383,7 +4452,7 @@
nullptr,
nullptr};
} else {
- allocateGraphicBuffer(previewStream.width, previewStream.height,
+ allocateGraphicBuffer(testStream.width, testStream.height,
android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
halStreamConfig.streams[0].consumerUsage),
halStreamConfig.streams[0].overrideFormat, &buffer_handle);
@@ -4432,7 +4501,7 @@
ASSERT_FALSE(inflightReq.errorCodeValid);
ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
- ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+ ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].streamId);
request.frameNumber++;
// Empty settings should be supported after the first call
@@ -4470,11 +4539,11 @@
ASSERT_FALSE(inflightReq.errorCodeValid);
ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
- ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+ ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].streamId);
}
if (useHalBufManager) {
- verifyBuffersReturned(session, deviceVersion, previewStream.id, cb);
+ verifyBuffersReturned(session, deviceVersion, testStream.id, cb);
}
ret = session->close();
@@ -6278,6 +6347,19 @@
bool *useHalBufManager /*out*/,
sp<DeviceCb> *outCb /*out*/,
uint32_t streamConfigCounter) {
+ configureSingleStream(name, deviceVersion, provider, previewThreshold,
+ GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, RequestTemplate::PREVIEW, session,
+ previewStream, halStreamConfig, supportsPartialResults,
+ partialResultCount, useHalBufManager, outCb, streamConfigCounter);
+}
+// Open a device session and configure a preview stream.
+void CameraHidlTest::configureSingleStream(
+ const std::string& name, int32_t deviceVersion, sp<ICameraProvider> provider,
+ const AvailableStream* previewThreshold, uint64_t bufferUsage, RequestTemplate reqTemplate,
+ sp<ICameraDeviceSession>* session /*out*/, V3_2::Stream* previewStream /*out*/,
+ HalStreamConfiguration* halStreamConfig /*out*/, bool* supportsPartialResults /*out*/,
+ uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
+ sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter) {
ASSERT_NE(nullptr, session);
ASSERT_NE(nullptr, previewStream);
ASSERT_NE(nullptr, halStreamConfig);
@@ -6366,11 +6448,14 @@
dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::UNKNOWN);
}
- V3_2::Stream stream3_2 = {0, StreamType::OUTPUT,
- static_cast<uint32_t> (outputPreviewStreams[0].width),
- static_cast<uint32_t> (outputPreviewStreams[0].height),
- static_cast<PixelFormat> (outputPreviewStreams[0].format),
- GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, dataspaceFlag, StreamRotation::ROTATION_0};
+ V3_2::Stream stream3_2 = {0,
+ StreamType::OUTPUT,
+ static_cast<uint32_t>(outputPreviewStreams[0].width),
+ static_cast<uint32_t>(outputPreviewStreams[0].height),
+ static_cast<PixelFormat>(outputPreviewStreams[0].format),
+ bufferUsage,
+ dataspaceFlag,
+ StreamRotation::ROTATION_0};
::android::hardware::hidl_vec<V3_2::Stream> streams3_2 = {stream3_2};
::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
@@ -6378,7 +6463,6 @@
createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
&config3_2, &config3_4, &config3_5, jpegBufferSize);
if (session3_5 != nullptr) {
- RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
ret = session3_5->constructDefaultRequestSettings(reqTemplate,
[&config3_5](auto status, const auto& req) {
ASSERT_EQ(Status::OK, status);
@@ -6401,7 +6485,6 @@
}
});
} else if (session3_4 != nullptr) {
- RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
ret = session3_4->constructDefaultRequestSettings(reqTemplate,
[&config3_4](auto status, const auto& req) {
ASSERT_EQ(Status::OK, status);
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index 7298c7d..14aef8e 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -18,5 +18,8 @@
},
},
},
- versions: ["1"],
+ versions: [
+ "1",
+ "2",
+ ],
}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/.hash b/identity/aidl/aidl_api/android.hardware.identity/2/.hash
new file mode 100644
index 0000000..036ce84
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/.hash
@@ -0,0 +1 @@
+194e04be642728623d65ec8321a3764fdea52ae0
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/Certificate.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/Certificate.aidl
new file mode 100644
index 0000000..7e3002d
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/Certificate.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+parcelable Certificate {
+ byte[] encodedCertificate;
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/CipherSuite.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/CipherSuite.aidl
new file mode 100644
index 0000000..447203f
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/CipherSuite.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@Backing(type="int") @VintfStability
+enum CipherSuite {
+ CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1,
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/HardwareInformation.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/HardwareInformation.aidl
new file mode 100644
index 0000000..e1296e0
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/HardwareInformation.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+parcelable HardwareInformation {
+ @utf8InCpp String credentialStoreName;
+ @utf8InCpp String credentialStoreAuthorName;
+ int dataChunkSize;
+ boolean isDirectAccess;
+ @utf8InCpp String[] supportedDocTypes;
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl
new file mode 100644
index 0000000..88104d9
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredential.aidl
@@ -0,0 +1,32 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+interface IIdentityCredential {
+ byte[] deleteCredential();
+ byte[] createEphemeralKeyPair();
+ void setReaderEphemeralPublicKey(in byte[] publicKey);
+ long createAuthChallenge();
+ void startRetrieval(in android.hardware.identity.SecureAccessControlProfile[] accessControlProfiles, in android.hardware.keymaster.HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob, in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
+ void startRetrieveEntryValue(in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize, in int[] accessControlProfileIds);
+ byte[] retrieveEntryValue(in byte[] encryptedContent);
+ void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
+ android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
+ void setRequestedNamespaces(in android.hardware.identity.RequestNamespace[] requestNamespaces);
+ void setVerificationToken(in android.hardware.keymaster.VerificationToken verificationToken);
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredentialStore.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredentialStore.aidl
new file mode 100644
index 0000000..5dafb76
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IIdentityCredentialStore.aidl
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+interface IIdentityCredentialStore {
+ android.hardware.identity.HardwareInformation getHardwareInformation();
+ android.hardware.identity.IWritableIdentityCredential createCredential(in @utf8InCpp String docType, in boolean testCredential);
+ android.hardware.identity.IIdentityCredential getCredential(in android.hardware.identity.CipherSuite cipherSuite, in byte[] credentialData);
+ const int STATUS_OK = 0;
+ const int STATUS_FAILED = 1;
+ const int STATUS_CIPHER_SUITE_NOT_SUPPORTED = 2;
+ const int STATUS_INVALID_DATA = 3;
+ const int STATUS_INVALID_AUTH_TOKEN = 4;
+ const int STATUS_INVALID_ITEMS_REQUEST_MESSAGE = 5;
+ const int STATUS_READER_SIGNATURE_CHECK_FAILED = 6;
+ const int STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND = 7;
+ const int STATUS_USER_AUTHENTICATION_FAILED = 8;
+ const int STATUS_READER_AUTHENTICATION_FAILED = 9;
+ const int STATUS_NO_ACCESS_CONTROL_PROFILES = 10;
+ const int STATUS_NOT_IN_REQUEST_MESSAGE = 11;
+ const int STATUS_SESSION_TRANSCRIPT_MISMATCH = 12;
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IWritableIdentityCredential.aidl
new file mode 100644
index 0000000..c5ac9d6
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+interface IWritableIdentityCredential {
+ android.hardware.identity.Certificate[] getAttestationCertificate(in byte[] attestationApplicationId, in byte[] attestationChallenge);
+ void startPersonalization(in int accessControlProfileCount, in int[] entryCounts);
+ android.hardware.identity.SecureAccessControlProfile addAccessControlProfile(in int id, in android.hardware.identity.Certificate readerCertificate, in boolean userAuthenticationRequired, in long timeoutMillis, in long secureUserId);
+ void beginAddEntry(in int[] accessControlProfileIds, in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize);
+ byte[] addEntryValue(in byte[] content);
+ void finishAddingEntries(out byte[] credentialData, out byte[] proofOfProvisioningSignature);
+ void setExpectedProofOfProvisioningSize(in int expectedProofOfProvisioningSize);
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestDataItem.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestDataItem.aidl
new file mode 100644
index 0000000..24ec26a
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestDataItem.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+parcelable RequestDataItem {
+ @utf8InCpp String name;
+ long size;
+ int[] accessControlProfileIds;
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestNamespace.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestNamespace.aidl
new file mode 100644
index 0000000..af00f3b
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/RequestNamespace.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+parcelable RequestNamespace {
+ @utf8InCpp String namespaceName;
+ android.hardware.identity.RequestDataItem[] items;
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/SecureAccessControlProfile.aidl b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/SecureAccessControlProfile.aidl
new file mode 100644
index 0000000..dfc1ad0
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/2/android/hardware/identity/SecureAccessControlProfile.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+parcelable SecureAccessControlProfile {
+ int id;
+ android.hardware.identity.Certificate readerCertificate;
+ boolean userAuthenticationRequired;
+ long timeoutMillis;
+ long secureUserId;
+ byte[] mac;
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
index 58b90b5..88104d9 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
@@ -27,4 +27,6 @@
byte[] retrieveEntryValue(in byte[] encryptedContent);
void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
android.hardware.identity.Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
+ void setRequestedNamespaces(in android.hardware.identity.RequestNamespace[] requestNamespaces);
+ void setVerificationToken(in android.hardware.keymaster.VerificationToken verificationToken);
}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
index 32f283c..c5ac9d6 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -24,4 +24,5 @@
void beginAddEntry(in int[] accessControlProfileIds, in @utf8InCpp String nameSpace, in @utf8InCpp String name, in int entrySize);
byte[] addEntryValue(in byte[] content);
void finishAddingEntries(out byte[] credentialData, out byte[] proofOfProvisioningSignature);
+ void setExpectedProofOfProvisioningSize(in int expectedProofOfProvisioningSize);
}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestDataItem.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestDataItem.aidl
new file mode 100644
index 0000000..24ec26a
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestDataItem.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+parcelable RequestDataItem {
+ @utf8InCpp String name;
+ long size;
+ int[] accessControlProfileIds;
+}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestNamespace.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestNamespace.aidl
new file mode 100644
index 0000000..af00f3b
--- /dev/null
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/RequestNamespace.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.identity;
+@VintfStability
+parcelable RequestNamespace {
+ @utf8InCpp String namespaceName;
+ android.hardware.identity.RequestDataItem[] items;
+}
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 7d14f03..d7f47e8 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -17,8 +17,10 @@
package android.hardware.identity;
import android.hardware.identity.Certificate;
+import android.hardware.identity.RequestNamespace;
import android.hardware.identity.SecureAccessControlProfile;
import android.hardware.keymaster.HardwareAuthToken;
+import android.hardware.keymaster.VerificationToken;
@VintfStability
interface IIdentityCredential {
@@ -70,10 +72,11 @@
/**
* Creates a challenge value to be used for proving successful user authentication. This
- * is included in the authToken passed to the startRetrieval() method.
+ * is included in the authToken passed to the startRetrieval() method and the
+ * verificationToken passed to the setVerificationToken() method.
*
* This method may only be called once per instance. If called more than once, STATUS_FAILED
- * will be returned.
+ * will be returned. If user authentication is not needed, this method may not be called.
*
* @return challenge, a non-zero number.
*/
@@ -82,6 +85,9 @@
/**
* Start an entry retrieval process.
*
+ * The setRequestedNamespaces() and setVerificationToken() methods will be called before
+ * this method is called.
+ *
* This method be called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(),
* createAuthChallenge() and before startRetrieveEntry(). This method call is followed by
* multiple calls of startRetrieveEntryValue(), retrieveEntryValue(), and finally
@@ -93,7 +99,19 @@
* must be identical for each startRetrieval() invocation. If this is not the case, this call
* fails with the STATUS_SESSION_TRANSCRIPT_MISMATCH error.
*
- * If the provided authToken is not valid this method fails with STATUS_INVALID_AUTH_TOKEN.
+ * If either authToken or verificationToken (as passed with setVerificationToken())
+ * is not valid this method fails with STATUS_INVALID_AUTH_TOKEN. Note that valid tokens
+ * are only passed if they are actually needed and available (this can be detected by
+ * the timestamp being set to zero). For example, if no data items with access control
+ * profiles using user authentication are requested, the tokens are not filled in.
+ * It's also possible that no usable auth token is actually available (it could be the user
+ * never unlocked the device within the timeouts in the access control profiles) and
+ * in this case the tokens aren't filled in either.
+ *
+ * For test credentials (identified by the testCredential boolean in the CredentialData
+ * CBOR created at provisioning time), the |mac| field in both the authToken and
+ * verificationToken should not be checked against the shared HMAC key (see IKeyMasterDevice
+ * for details). This is to enable VTS tests to check for correct behavior.
*
* Each of the provided accessControlProfiles is checked in this call. If they are not
* all valid, the call fails with STATUS_INVALID_DATA.
@@ -176,7 +194,8 @@
*
* @param authToken
* The authentication token that proves the user was authenticated, as required
- * by one or more of the provided accessControlProfiles. See above.
+ * by one or more of the provided accessControlProfiles. This token is only valid
+ * if the timestamp field is non-zero. See above.
*
* @param itemsRequest
* If non-empty, contains request data that is signed by the reader. See above.
@@ -274,7 +293,7 @@
* "DeviceAuthentication",
* SessionTranscript,
* DocType,
- * DeviceNameSpaceBytes,
+ * DeviceNameSpacesBytes,
* ]
*
* DocType = tstr
@@ -343,4 +362,25 @@
* @return an X.509 certificate for the new signing key, signed by the credential key.
*/
Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
+
+ /**
+ * Sets the namespaces and data items (including their size and access control profiles)
+ * which will be requested. This method must be called before startRetrieval() is called.
+ *
+ * This information is provided to make it possible for a HAL implementation to
+ * incrementally build up cryptographically authenticated data which includes the
+ * DeviceNameSpaces CBOR.
+ *
+ * @param requestNamespaces Namespaces and data items which will be requested.
+ */
+ void setRequestedNamespaces(in RequestNamespace[] requestNamespaces);
+
+ /**
+ * Sets the VerificationToken. This method must be called before startRetrieval() is
+ * called. This token uses the same challenge as returned by createAuthChallenge().
+ *
+ * @param verificationToken
+ * The verification token. This token is only valid if the timestamp field is non-zero.
+ */
+ void setVerificationToken(in VerificationToken verificationToken);
}
diff --git a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
index 07486e6..b7ad283 100644
--- a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -120,6 +120,8 @@
*
* startPersonalization must not be called more than once.
*
+ * The setExpectedProofOfProvisioningSize() method will be called before this method.
+ *
* @param accessControlProfileCount specifies the number of access control profiles that will
* be provisioned with addAccessControlProfile().
*
@@ -288,4 +290,16 @@
*/
void finishAddingEntries(out byte[] credentialData,
out byte[] proofOfProvisioningSignature);
+
+ /**
+ * Sets the expected size of the ProofOfProvisioning returned by finishAddingEntries(). This
+ * method must be called before startPersonalization() is called.
+ *
+ * This information is provided to make it possible for a HAL implementation to
+ * incrementally build up cryptographically authenticated data which includes the
+ * ProofOfProvisioning CBOR.
+ *
+ * @param expectedProofOfProvisioningSize the expected size of ProofOfProvisioning.
+ */
+ void setExpectedProofOfProvisioningSize(in int expectedProofOfProvisioningSize);
}
diff --git a/identity/aidl/android/hardware/identity/RequestDataItem.aidl b/identity/aidl/android/hardware/identity/RequestDataItem.aidl
new file mode 100644
index 0000000..05bc762
--- /dev/null
+++ b/identity/aidl/android/hardware/identity/RequestDataItem.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 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.
+ */
+
+package android.hardware.identity;
+
+@VintfStability
+parcelable RequestDataItem {
+ /**
+ * The data item name being requested, for example "driving_privileges".
+ */
+ @utf8InCpp String name;
+
+ /**
+ * The size of the data item value.
+ *
+ * Data item values are always encoded as CBOR so this is the length of
+ * the CBOR encoding of the value.
+ */
+ long size;
+
+ /**
+ * The access control profile ids this data item is configured with.
+ */
+ int[] accessControlProfileIds;
+}
diff --git a/identity/aidl/android/hardware/identity/RequestNamespace.aidl b/identity/aidl/android/hardware/identity/RequestNamespace.aidl
new file mode 100644
index 0000000..4d61506
--- /dev/null
+++ b/identity/aidl/android/hardware/identity/RequestNamespace.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020 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.
+ */
+
+package android.hardware.identity;
+
+import android.hardware.identity.RequestDataItem;
+
+@VintfStability
+parcelable RequestNamespace {
+ /**
+ * The name of the namespace that items are being requested from, for
+ * example "org.iso.18013.5.1".
+ */
+ @utf8InCpp String namespaceName;
+
+ /**
+ * The data items requested.
+ */
+ RequestDataItem[] items;
+}
diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp
index 341fae6..8a00d22 100644
--- a/identity/aidl/default/IdentityCredential.cpp
+++ b/identity/aidl/default/IdentityCredential.cpp
@@ -25,6 +25,7 @@
#include <string.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <cppbor.h>
#include <cppbor_parse.h>
@@ -32,6 +33,7 @@
namespace aidl::android::hardware::identity {
using ::aidl::android::hardware::keymaster::Timestamp;
+using ::android::base::StringPrintf;
using ::std::optional;
using namespace ::android::hardware::identity;
@@ -196,15 +198,8 @@
return false;
}
-Timestamp clockGetTime() {
- struct timespec time;
- clock_gettime(CLOCK_MONOTONIC, &time);
- Timestamp ts;
- ts.milliSeconds = time.tv_sec * 1000 + time.tv_nsec / 1000000;
- return ts;
-}
-
bool checkUserAuthentication(const SecureAccessControlProfile& profile,
+ const VerificationToken& verificationToken,
const HardwareAuthToken& authToken, uint64_t authChallenge) {
if (profile.secureUserId != authToken.userId) {
LOG(ERROR) << "secureUserId in profile (" << profile.secureUserId
@@ -212,6 +207,15 @@
return false;
}
+ if (verificationToken.timestamp.milliSeconds == 0) {
+ LOG(ERROR) << "VerificationToken is not set";
+ return false;
+ }
+ if (authToken.timestamp.milliSeconds == 0) {
+ LOG(ERROR) << "AuthToken is not set";
+ return false;
+ }
+
if (profile.timeoutMillis == 0) {
if (authToken.challenge == 0) {
LOG(ERROR) << "No challenge in authToken";
@@ -225,19 +229,11 @@
return true;
}
- // Note that the Epoch for timestamps in HardwareAuthToken is at the
- // discretion of the vendor:
+ // Timeout-based user auth follows. The verification token conveys what the
+ // time is right now in the environment which generated the auth token. This
+ // is what makes it possible to do timeout-based checks.
//
- // "[...] since some starting point (generally the most recent device
- // boot) which all of the applications within one secure environment
- // must agree upon."
- //
- // Therefore, if this software implementation is used on a device which isn't
- // the emulator then the assumption that the epoch is the same as used in
- // clockGetTime above will not hold. This is OK as this software
- // implementation should never be used on a real device.
- //
- Timestamp now = clockGetTime();
+ const Timestamp now = verificationToken.timestamp;
if (authToken.timestamp.milliSeconds > now.milliSeconds) {
LOG(ERROR) << "Timestamp in authToken (" << authToken.timestamp.milliSeconds
<< ") is in the future (now: " << now.milliSeconds << ")";
@@ -253,6 +249,18 @@
return true;
}
+ndk::ScopedAStatus IdentityCredential::setRequestedNamespaces(
+ const vector<RequestNamespace>& requestNamespaces) {
+ requestNamespaces_ = requestNamespaces;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus IdentityCredential::setVerificationToken(
+ const VerificationToken& verificationToken) {
+ verificationToken_ = verificationToken;
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus IdentityCredential::startRetrieval(
const vector<SecureAccessControlProfile>& accessControlProfiles,
const HardwareAuthToken& authToken, const vector<int8_t>& itemsRequestS,
@@ -451,7 +459,7 @@
"Type mismatch in nameSpaces map"));
}
string requestedNamespace = nsKey->value();
- vector<string> requestedKeys;
+ set<string> requestedKeys;
for (size_t m = 0; m < nsInnerMap->size(); m++) {
const auto& [innerMapKeyItem, innerMapValueItem] = (*nsInnerMap)[m];
const cppbor::Tstr* nameItem = innerMapKeyItem->asTstr();
@@ -463,13 +471,13 @@
IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE,
"Type mismatch in value in nameSpaces map"));
}
- requestedKeys.push_back(nameItem->value());
+ requestedKeys.insert(nameItem->value());
}
requestedNameSpacesAndNames_[requestedNamespace] = requestedKeys;
}
}
- // Finally, validate all the access control profiles in the requestData.
+ // Validate all the access control profiles in the requestData.
bool haveAuthToken = (authToken.mac.size() > 0);
for (const auto& profile : accessControlProfiles) {
if (!secureAccessControlProfileCheckMac(profile, storageKey_)) {
@@ -479,7 +487,8 @@
}
int accessControlCheck = IIdentityCredentialStore::STATUS_OK;
if (profile.userAuthenticationRequired) {
- if (!haveAuthToken || !checkUserAuthentication(profile, authToken, authChallenge_)) {
+ if (!haveAuthToken ||
+ !checkUserAuthentication(profile, verificationToken_, authToken, authChallenge_)) {
accessControlCheck = IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED;
}
} else if (profile.readerCertificate.encodedCertificate.size() > 0) {
@@ -500,10 +509,118 @@
itemsRequest_ = itemsRequest;
signingKeyBlob_ = byteStringToUnsigned(signingKeyBlobS);
+ // Finally, calculate the size of DeviceNameSpaces. We need to know it ahead of time.
+ expectedDeviceNameSpacesSize_ = calcDeviceNameSpacesSize();
+
numStartRetrievalCalls_ += 1;
return ndk::ScopedAStatus::ok();
}
+size_t cborNumBytesForLength(size_t length) {
+ if (length < 24) {
+ return 0;
+ } else if (length <= 0xff) {
+ return 1;
+ } else if (length <= 0xffff) {
+ return 2;
+ } else if (length <= 0xffffffff) {
+ return 4;
+ }
+ return 8;
+}
+
+size_t cborNumBytesForTstr(const string& value) {
+ return 1 + cborNumBytesForLength(value.size()) + value.size();
+}
+
+size_t IdentityCredential::calcDeviceNameSpacesSize() {
+ /*
+ * This is how DeviceNameSpaces is defined:
+ *
+ * DeviceNameSpaces = {
+ * * NameSpace => DeviceSignedItems
+ * }
+ * DeviceSignedItems = {
+ * + DataItemName => DataItemValue
+ * }
+ *
+ * Namespace = tstr
+ * DataItemName = tstr
+ * DataItemValue = any
+ *
+ * This function will calculate its length using knowledge of how CBOR is
+ * encoded.
+ */
+ size_t ret = 0;
+ size_t numNamespacesWithValues = 0;
+ for (const RequestNamespace& rns : requestNamespaces_) {
+ vector<RequestDataItem> itemsToInclude;
+
+ for (const RequestDataItem& rdi : rns.items) {
+ // If we have a CBOR request message, skip if item isn't in it
+ if (itemsRequest_.size() > 0) {
+ const auto& it = requestedNameSpacesAndNames_.find(rns.namespaceName);
+ if (it == requestedNameSpacesAndNames_.end()) {
+ continue;
+ }
+ const set<string>& dataItemNames = it->second;
+ if (dataItemNames.find(rdi.name) == dataItemNames.end()) {
+ continue;
+ }
+ }
+
+ // Access is granted if at least one of the profiles grants access.
+ //
+ // If an item is configured without any profiles, access is denied.
+ //
+ bool authorized = false;
+ for (auto id : rdi.accessControlProfileIds) {
+ auto it = profileIdToAccessCheckResult_.find(id);
+ if (it != profileIdToAccessCheckResult_.end()) {
+ int accessControlForProfile = it->second;
+ if (accessControlForProfile == IIdentityCredentialStore::STATUS_OK) {
+ authorized = true;
+ break;
+ }
+ }
+ }
+ if (!authorized) {
+ continue;
+ }
+
+ itemsToInclude.push_back(rdi);
+ }
+
+ // If no entries are to be in the namespace, we don't include it...
+ if (itemsToInclude.size() == 0) {
+ continue;
+ }
+
+ // Key: NameSpace
+ ret += cborNumBytesForTstr(rns.namespaceName);
+
+ // Value: Open the DeviceSignedItems map
+ ret += 1 + cborNumBytesForLength(itemsToInclude.size());
+
+ for (const RequestDataItem& item : itemsToInclude) {
+ // Key: DataItemName
+ ret += cborNumBytesForTstr(item.name);
+
+ // Value: DataItemValue - entryData.size is the length of serialized CBOR so we use
+ // that.
+ ret += item.size;
+ }
+
+ numNamespacesWithValues++;
+ }
+
+ // Now that we now the nunber of namespaces with values, we know how many
+ // bytes the DeviceNamespaces map in the beginning is going to take up.
+ ret += 1 + cborNumBytesForLength(numNamespacesWithValues);
+
+ return ret;
+}
+
ndk::ScopedAStatus IdentityCredential::startRetrieveEntryValue(
const string& nameSpace, const string& name, int32_t entrySize,
const vector<int32_t>& accessControlProfileIds) {
@@ -562,8 +679,8 @@
IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE,
"Name space was not requested in startRetrieval"));
}
- const auto& dataItemNames = it->second;
- if (std::find(dataItemNames.begin(), dataItemNames.end(), name) == dataItemNames.end()) {
+ const set<string>& dataItemNames = it->second;
+ if (dataItemNames.find(name) == dataItemNames.end()) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE,
"Data item name in name space was not requested in startRetrieval"));
@@ -608,7 +725,6 @@
ndk::ScopedAStatus IdentityCredential::retrieveEntryValue(const vector<int8_t>& encryptedContentS,
vector<int8_t>* outContent) {
auto encryptedContent = byteStringToUnsigned(encryptedContentS);
-
optional<vector<uint8_t>> content =
support::decryptAes128Gcm(storageKey_, encryptedContent, entryAdditionalData_);
if (!content) {
@@ -659,6 +775,17 @@
}
vector<uint8_t> encodedDeviceNameSpaces = deviceNameSpacesMap_.encode();
+ if (encodedDeviceNameSpaces.size() != expectedDeviceNameSpacesSize_) {
+ LOG(ERROR) << "encodedDeviceNameSpaces is " << encodedDeviceNameSpaces.size() << " bytes, "
+ << "was expecting " << expectedDeviceNameSpacesSize_;
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_INVALID_DATA,
+ StringPrintf(
+ "Unexpected CBOR size %zd for encodedDeviceNameSpaces, was expecting %zd",
+ encodedDeviceNameSpaces.size(), expectedDeviceNameSpacesSize_)
+ .c_str()));
+ }
+
// If there's no signing key or no sessionTranscript or no reader ephemeral
// public key, we return the empty MAC.
optional<vector<uint8_t>> mac;
diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h
index fc29254..40070c0 100644
--- a/identity/aidl/default/IdentityCredential.h
+++ b/identity/aidl/default/IdentityCredential.h
@@ -19,6 +19,7 @@
#include <aidl/android/hardware/identity/BnIdentityCredential.h>
#include <aidl/android/hardware/keymaster/HardwareAuthToken.h>
+#include <aidl/android/hardware/keymaster/VerificationToken.h>
#include <android/hardware/identity/support/IdentityCredentialSupport.h>
#include <map>
@@ -31,16 +32,19 @@
namespace aidl::android::hardware::identity {
using ::aidl::android::hardware::keymaster::HardwareAuthToken;
+using ::aidl::android::hardware::keymaster::VerificationToken;
using ::std::map;
+using ::std::set;
using ::std::string;
using ::std::vector;
-using MapStringToVectorOfStrings = map<string, vector<string>>;
-
class IdentityCredential : public BnIdentityCredential {
public:
IdentityCredential(const vector<uint8_t>& credentialData)
- : credentialData_(credentialData), numStartRetrievalCalls_(0), authChallenge_(0) {}
+ : credentialData_(credentialData),
+ numStartRetrievalCalls_(0),
+ authChallenge_(0),
+ expectedDeviceNameSpacesSize_(0) {}
// Parses and decrypts credentialData_, return a status code from
// IIdentityCredentialStore. Must be called right after construction.
@@ -51,6 +55,9 @@
ndk::ScopedAStatus createEphemeralKeyPair(vector<int8_t>* outKeyPair) override;
ndk::ScopedAStatus setReaderEphemeralPublicKey(const vector<int8_t>& publicKey) override;
ndk::ScopedAStatus createAuthChallenge(int64_t* outChallenge) override;
+ ndk::ScopedAStatus setRequestedNamespaces(
+ const vector<RequestNamespace>& requestNamespaces) override;
+ ndk::ScopedAStatus setVerificationToken(const VerificationToken& verificationToken) override;
ndk::ScopedAStatus startRetrieval(
const vector<SecureAccessControlProfile>& accessControlProfiles,
const HardwareAuthToken& authToken, const vector<int8_t>& itemsRequest,
@@ -86,6 +93,12 @@
// Set by createAuthChallenge()
uint64_t authChallenge_;
+ // Set by setRequestedNamespaces()
+ vector<RequestNamespace> requestNamespaces_;
+
+ // Set by setVerificationToken().
+ VerificationToken verificationToken_;
+
// Set at startRetrieval() time.
map<int32_t, int> profileIdToAccessCheckResult_;
vector<uint8_t> signingKeyBlob_;
@@ -93,16 +106,21 @@
std::unique_ptr<cppbor::Item> sessionTranscriptItem_;
vector<uint8_t> itemsRequest_;
vector<int32_t> requestCountsRemaining_;
- MapStringToVectorOfStrings requestedNameSpacesAndNames_;
+ map<string, set<string>> requestedNameSpacesAndNames_;
cppbor::Map deviceNameSpacesMap_;
cppbor::Map currentNameSpaceDeviceNameSpacesMap_;
+ // Calculated at startRetrieval() time.
+ size_t expectedDeviceNameSpacesSize_;
+
// Set at startRetrieveEntryValue() time.
string currentNameSpace_;
string currentName_;
size_t entryRemainingBytes_;
vector<uint8_t> entryValue_;
vector<uint8_t> entryAdditionalData_;
+
+ size_t calcDeviceNameSpacesSize();
};
} // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp
index 52cd496..7732c33 100644
--- a/identity/aidl/default/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/WritableIdentityCredential.cpp
@@ -22,6 +22,7 @@
#include <android/hardware/identity/support/IdentityCredentialSupport.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <cppbor/cppbor.h>
#include <cppbor/cppbor_parse.h>
@@ -34,6 +35,7 @@
namespace aidl::android::hardware::identity {
+using ::android::base::StringPrintf;
using ::std::optional;
using namespace ::android::hardware::identity;
@@ -105,6 +107,12 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus WritableIdentityCredential::setExpectedProofOfProvisioningSize(
+ int32_t expectedProofOfProvisioningSize) {
+ expectedProofOfProvisioningSize_ = expectedProofOfProvisioningSize;
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus WritableIdentityCredential::startPersonalization(
int32_t accessControlProfileCount, const vector<int32_t>& entryCounts) {
if (startPersonalizationCalled_) {
@@ -255,7 +263,7 @@
}
ndk::ScopedAStatus WritableIdentityCredential::addEntryValue(const vector<int8_t>& contentS,
- vector<int8_t>* outEncryptedContent) {
+ vector<int8_t>* outEncryptedContentS) {
auto content = byteStringToUnsigned(contentS);
size_t contentSize = content.size();
@@ -311,7 +319,7 @@
signedDataCurrentNamespace_.add(std::move(entryMap));
}
- *outEncryptedContent = byteStringToSigned(encryptedContent.value());
+ *outEncryptedContentS = byteStringToSigned(encryptedContent.value());
return ndk::ScopedAStatus::ok();
}
@@ -384,6 +392,16 @@
.add(testCredential_);
vector<uint8_t> encodedCbor = popArray.encode();
+ if (encodedCbor.size() != expectedProofOfProvisioningSize_) {
+ LOG(ERROR) << "CBOR for proofOfProvisioning is " << encodedCbor.size() << " bytes, "
+ << "was expecting " << expectedProofOfProvisioningSize_;
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_INVALID_DATA,
+ StringPrintf("Unexpected CBOR size %zd for proofOfProvisioning, was expecting %zd",
+ encodedCbor.size(), expectedProofOfProvisioningSize_)
+ .c_str()));
+ }
+
optional<vector<uint8_t>> signature = support::coseSignEcDsa(credentialPrivKey_,
encodedCbor, // payload
{}, // additionalData
diff --git a/identity/aidl/default/WritableIdentityCredential.h b/identity/aidl/default/WritableIdentityCredential.h
index cb91f7b..05104d7 100644
--- a/identity/aidl/default/WritableIdentityCredential.h
+++ b/identity/aidl/default/WritableIdentityCredential.h
@@ -43,6 +43,9 @@
const vector<int8_t>& attestationChallenge,
vector<Certificate>* outCertificateChain) override;
+ ndk::ScopedAStatus setExpectedProofOfProvisioningSize(
+ int32_t expectedProofOfProvisioningSize) override;
+
ndk::ScopedAStatus startPersonalization(int32_t accessControlProfileCount,
const vector<int32_t>& entryCounts) override;
@@ -62,7 +65,7 @@
vector<int8_t>* outCredentialData,
vector<int8_t>* outProofOfProvisioningSignature) override;
- // private:
+ private:
string docType_;
bool testCredential_;
@@ -82,6 +85,7 @@
cppbor::Array signedDataAccessControlProfiles_;
cppbor::Map signedDataNamespaces_;
cppbor::Array signedDataCurrentNamespace_;
+ size_t expectedProofOfProvisioningSize_;
// This field is initialized in addAccessControlProfile
set<int32_t> accessControlProfileIds_;
diff --git a/identity/aidl/default/service.cpp b/identity/aidl/default/service.cpp
index f05c615..bf95df5 100644
--- a/identity/aidl/default/service.cpp
+++ b/identity/aidl/default/service.cpp
@@ -22,9 +22,14 @@
#include "IdentityCredentialStore.h"
+using ::android::base::InitLogging;
+using ::android::base::StderrLogger;
+
using aidl::android::hardware::identity::IdentityCredentialStore;
-int main() {
+int main(int /*argc*/, char* argv[]) {
+ InitLogging(argv, StderrLogger);
+
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<IdentityCredentialStore> store =
ndk::SharedRefBase::make<IdentityCredentialStore>();
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index e4780bf..5b075c6 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -8,10 +8,16 @@
"VtsHalIdentityEndToEndTest.cpp",
"VtsIWritableIdentityCredentialTests.cpp",
"VtsIdentityTestUtils.cpp",
+ "VtsAttestationTests.cpp",
+ "VtsAttestationParserSupport.cpp",
],
shared_libs: [
+ "android.hardware.keymaster@4.0",
"libbinder",
"libcrypto",
+ "libkeymaster_portable",
+ "libsoft_attestation_cert",
+ "libpuresoftkeymasterdevice",
],
static_libs: [
"libcppbor",
diff --git a/identity/aidl/vts/VtsAttestationParserSupport.cpp b/identity/aidl/vts/VtsAttestationParserSupport.cpp
new file mode 100644
index 0000000..71fe733
--- /dev/null
+++ b/identity/aidl/vts/VtsAttestationParserSupport.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2019, 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.
+ */
+
+#include "VtsAttestationParserSupport.h"
+
+#include <aidl/Gtest.h>
+#include <map>
+
+namespace android::hardware::identity::test_utils {
+
+using std::endl;
+using std::map;
+using std::optional;
+using std::string;
+using std::vector;
+
+using ::android::sp;
+using ::android::String16;
+using ::android::binder::Status;
+
+using ::keymaster::ASN1_OBJECT_Ptr;
+using ::keymaster::AuthorizationSet;
+using ::keymaster::EVP_PKEY_Ptr;
+using ::keymaster::kAttestionRecordOid;
+using ::keymaster::TAG_ATTESTATION_APPLICATION_ID;
+using ::keymaster::TAG_IDENTITY_CREDENTIAL_KEY;
+using ::keymaster::TAG_INCLUDE_UNIQUE_ID;
+using ::keymaster::TypedTag;
+using ::keymaster::X509_Ptr;
+
+using support::certificateChainSplit;
+
+optional<keymaster_cert_chain_t> AttestationCertificateParser::certificateChainToKeymasterChain(
+ const vector<Certificate>& certificates) {
+ if (certificates.size() <= 0) {
+ return {};
+ }
+
+ keymaster_cert_chain_t kCert;
+ kCert.entry_count = certificates.size();
+ kCert.entries = (keymaster_blob_t*)malloc(sizeof(keymaster_blob_t) * kCert.entry_count);
+
+ int index = 0;
+ for (const auto& c : certificates) {
+ kCert.entries[index].data_length = c.encodedCertificate.size();
+ uint8_t* data = (uint8_t*)malloc(c.encodedCertificate.size());
+
+ memcpy(data, c.encodedCertificate.data(), c.encodedCertificate.size());
+ kCert.entries[index].data = (const uint8_t*)data;
+ index++;
+ }
+
+ return kCert;
+}
+
+bool AttestationCertificateParser::parse() {
+ optional<keymaster_cert_chain_t> cert_chain = certificateChainToKeymasterChain(origCertChain_);
+ if (!cert_chain) {
+ return false;
+ }
+
+ if (cert_chain.value().entry_count < 3) {
+ return false;
+ }
+
+ if (!verifyChain(cert_chain.value())) {
+ return false;
+ }
+
+ if (!verifyAttestationRecord(cert_chain.value().entries[0])) {
+ return false;
+ }
+
+ keymaster_free_cert_chain(&cert_chain.value());
+ return true;
+}
+
+ASN1_OCTET_STRING* AttestationCertificateParser::getAttestationRecord(X509* certificate) {
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1));
+ if (!oid.get()) return nullptr;
+
+ int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1);
+ if (location == -1) return nullptr;
+
+ X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+ if (!attest_rec_ext) return nullptr;
+
+ ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+ return attest_rec;
+}
+
+X509* AttestationCertificateParser::parseCertBlob(const keymaster_blob_t& blob) {
+ const uint8_t* p = blob.data;
+ return d2i_X509(nullptr, &p, blob.data_length);
+}
+
+bool AttestationCertificateParser::verifyAttestationRecord(
+ const keymaster_blob_t& attestation_cert) {
+ X509_Ptr cert(parseCertBlob(attestation_cert));
+ if (!cert.get()) {
+ return false;
+ }
+
+ ASN1_OCTET_STRING* attest_rec = getAttestationRecord(cert.get());
+ if (!attest_rec) {
+ return false;
+ }
+
+ keymaster_blob_t att_unique_id = {};
+ keymaster_blob_t att_challenge;
+ keymaster_error_t ret = parse_attestation_record(
+ attest_rec->data, attest_rec->length, &att_attestation_version_,
+ &att_attestation_security_level_, &att_keymaster_version_,
+ &att_keymaster_security_level_, &att_challenge, &att_sw_enforced_, &att_hw_enforced_,
+ &att_unique_id);
+ if (ret) {
+ return false;
+ }
+
+ att_challenge_.assign(att_challenge.data, att_challenge.data + att_challenge.data_length);
+ return true;
+}
+
+uint32_t AttestationCertificateParser::getKeymasterVersion() {
+ return att_keymaster_version_;
+}
+
+uint32_t AttestationCertificateParser::getAttestationVersion() {
+ return att_attestation_version_;
+}
+
+vector<uint8_t> AttestationCertificateParser::getAttestationChallenge() {
+ return att_challenge_;
+}
+
+keymaster_security_level_t AttestationCertificateParser::getKeymasterSecurityLevel() {
+ return att_keymaster_security_level_;
+}
+
+keymaster_security_level_t AttestationCertificateParser::getAttestationSecurityLevel() {
+ return att_attestation_security_level_;
+}
+
+// Verify the Attestation certificates are correctly chained.
+bool AttestationCertificateParser::verifyChain(const keymaster_cert_chain_t& chain) {
+ for (size_t i = 0; i < chain.entry_count - 1; ++i) {
+ keymaster_blob_t& key_cert_blob = chain.entries[i];
+ keymaster_blob_t& signing_cert_blob = chain.entries[i + 1];
+
+ X509_Ptr key_cert(parseCertBlob(key_cert_blob));
+ X509_Ptr signing_cert(parseCertBlob(signing_cert_blob));
+ if (!key_cert.get() || !signing_cert.get()) {
+ return false;
+ }
+
+ EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+ if (!signing_pubkey.get()) return false;
+
+ if (X509_verify(key_cert.get(), signing_pubkey.get()) != 1) {
+ return false;
+ }
+
+ if (i + 1 == chain.entry_count - 1) {
+ // Last entry is self-signed.
+ if (X509_verify(signing_cert.get(), signing_pubkey.get()) != 1) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace android::hardware::identity::test_utils
diff --git a/identity/aidl/vts/VtsAttestationParserSupport.h b/identity/aidl/vts/VtsAttestationParserSupport.h
new file mode 100644
index 0000000..7c7e1b6
--- /dev/null
+++ b/identity/aidl/vts/VtsAttestationParserSupport.h
@@ -0,0 +1,122 @@
+
+/*
+ * Copyright 2019, 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.
+ */
+
+#ifndef VTS_ATTESTATION_PARSER_SUPPORT_H
+#define VTS_ATTESTATION_PARSER_SUPPORT_H
+
+//#include <aidl/Gtest.h>
+#include <android/hardware/identity/IIdentityCredentialStore.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <keymaster/contexts/soft_attestation_cert.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/km_openssl/attestation_utils.h>
+#include <vector>
+
+namespace android::hardware::identity::test_utils {
+
+using ::std::optional;
+using ::std::string;
+using ::std::vector;
+
+using ::keymaster::AuthorizationSet;
+using ::keymaster::TypedTag;
+
+class AttestationCertificateParser {
+ public:
+ AttestationCertificateParser(const vector<Certificate>& certChain)
+ : origCertChain_(certChain) {}
+
+ bool parse();
+
+ uint32_t getKeymasterVersion();
+ uint32_t getAttestationVersion();
+ vector<uint8_t> getAttestationChallenge();
+ keymaster_security_level_t getKeymasterSecurityLevel();
+ keymaster_security_level_t getAttestationSecurityLevel();
+
+ template <keymaster_tag_t Tag>
+ bool getSwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
+ if (att_sw_enforced_.GetTagValue(tag)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ template <keymaster_tag_t Tag>
+ bool getHwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
+ if (att_hw_enforced_.GetTagValue(tag)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ template <keymaster_tag_t Tag>
+ optional<vector<uint8_t>> getHwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
+ keymaster_blob_t blob;
+ if (att_hw_enforced_.GetTagValue(tag, &blob)) {
+ return {};
+ }
+
+ vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
+ return ret;
+ }
+
+ template <keymaster_tag_t Tag>
+ optional<vector<uint8_t>> getSwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
+ keymaster_blob_t blob;
+ if (!att_sw_enforced_.GetTagValue(tag, &blob)) {
+ return {};
+ }
+
+ vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
+ return ret;
+ }
+
+ private:
+ // Helper functions.
+ bool verifyChain(const keymaster_cert_chain_t& chain);
+
+ ASN1_OCTET_STRING* getAttestationRecord(X509* certificate);
+
+ X509* parseCertBlob(const keymaster_blob_t& blob);
+
+ bool verifyAttestationRecord(const keymaster_blob_t& attestation_cert);
+
+ optional<keymaster_cert_chain_t> certificateChainToKeymasterChain(
+ const vector<Certificate>& certificates);
+
+ // Private variables.
+ vector<Certificate> origCertChain_;
+ AuthorizationSet att_sw_enforced_;
+ AuthorizationSet att_hw_enforced_;
+ uint32_t att_attestation_version_;
+ uint32_t att_keymaster_version_;
+ keymaster_security_level_t att_attestation_security_level_;
+ keymaster_security_level_t att_keymaster_security_level_;
+ vector<uint8_t> att_challenge_;
+};
+
+} // namespace android::hardware::identity::test_utils
+
+#endif // VTS_ATTESTATION_PARSER_SUPPORT_H
diff --git a/identity/aidl/vts/VtsAttestationTests.cpp b/identity/aidl/vts/VtsAttestationTests.cpp
new file mode 100644
index 0000000..00b5893
--- /dev/null
+++ b/identity/aidl/vts/VtsAttestationTests.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#define LOG_TAG "VtsAttestationTests"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android/hardware/identity/IIdentityCredentialStore.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cppbor.h>
+#include <cppbor_parse.h>
+#include <gtest/gtest.h>
+#include <future>
+#include <map>
+
+#include "VtsAttestationParserSupport.h"
+#include "VtsIdentityTestUtils.h"
+
+namespace android::hardware::identity {
+
+using std::endl;
+using std::map;
+using std::optional;
+using std::string;
+using std::vector;
+
+using ::android::sp;
+using ::android::String16;
+using ::android::binder::Status;
+
+using test_utils::AttestationCertificateParser;
+using test_utils::setupWritableCredential;
+using test_utils::validateAttestationCertificate;
+
+// This file verifies the Identity Credential VTS Attestation Certificate
+// generated.
+class VtsAttestationTests : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
+ String16(GetParam().c_str()));
+ ASSERT_NE(credentialStore_, nullptr);
+ }
+
+ sp<IIdentityCredentialStore> credentialStore_;
+};
+
+TEST_P(VtsAttestationTests, verifyAttestationWithEmptyChallengeEmptyId) {
+ Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+
+ vector<uint8_t> attestationChallenge;
+ vector<Certificate> attestationCertificate;
+ vector<uint8_t> attestationApplicationId = {};
+ result = writableCredential->getAttestationCertificate(
+ attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+
+ EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, hwInfo));
+}
+
+TEST_P(VtsAttestationTests, verifyAttestationWithEmptyChallengeNonemptyId) {
+ Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+
+ vector<uint8_t> attestationChallenge;
+ vector<Certificate> attestationCertificate;
+ string applicationId = "Attestation Verification";
+ vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()};
+
+ result = writableCredential->getAttestationCertificate(
+ attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+ EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, hwInfo));
+}
+
+TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeEmptyId) {
+ Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+
+ string challenge = "NotSoRandomChallenge";
+ vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
+ vector<Certificate> attestationCertificate;
+ vector<uint8_t> attestationApplicationId = {};
+
+ result = writableCredential->getAttestationCertificate(
+ attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+
+ EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, hwInfo));
+}
+
+TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeNonemptyId) {
+ Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+
+ string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
+ vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
+ vector<Certificate> attestationCertificate;
+ string applicationId = "Attestation Verification";
+ vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()};
+
+ result = writableCredential->getAttestationCertificate(
+ attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+
+ EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, hwInfo));
+}
+
+TEST_P(VtsAttestationTests, verifyAttestationWithVeryShortChallengeAndId) {
+ Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+
+ string challenge = "c";
+ vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
+ vector<Certificate> attestationCertificate;
+ string applicationId = "i";
+ vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()};
+
+ result = writableCredential->getAttestationCertificate(
+ attestationApplicationId, attestationChallenge, &attestationCertificate);
+
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+
+ EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
+ attestationApplicationId, hwInfo));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ Identity, VtsAttestationTests,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
+ android::PrintInstanceNameToString);
+
+} // namespace android::hardware::identity
diff --git a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
index 8a4e8a7..464ab0c 100644
--- a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
+++ b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "VtsHalIdentityTargetTest"
+#define LOG_TAG "VtsHalIdentityEndToEndTest"
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
@@ -43,6 +43,9 @@
using ::android::binder::Status;
using ::android::hardware::keymaster::HardwareAuthToken;
+using ::android::hardware::keymaster::VerificationToken;
+
+using test_utils::validateAttestationCertificate;
class IdentityAidl : public testing::TestWithParam<std::string> {
public:
@@ -68,13 +71,13 @@
// part of the request data.
vector<uint8_t> readerKey;
optional<vector<uint8_t>> readerCertificate =
- test_utils::GenerateReaderCertificate("1234", readerKey);
+ test_utils::generateReaderCertificate("1234", &readerKey);
ASSERT_TRUE(readerCertificate);
// Make the portrait image really big (just shy of 256 KiB) to ensure that
// the chunking code gets exercised.
vector<uint8_t> portraitImage;
- test_utils::SetImageData(portraitImage);
+ test_utils::setImageData(portraitImage);
// Access control profiles:
const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (reader authentication)
@@ -82,7 +85,20 @@
// Profile 1 (no authentication)
{1, {}, false, 0}};
+ // It doesn't matter since no user auth is needed in this particular test,
+ // but for good measure, clear out the tokens we pass to the HAL.
HardwareAuthToken authToken;
+ VerificationToken verificationToken;
+ authToken.challenge = 0;
+ authToken.userId = 0;
+ authToken.authenticatorId = 0;
+ authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
+ authToken.timestamp.milliSeconds = 0;
+ authToken.mac.clear();
+ verificationToken.challenge = 0;
+ verificationToken.timestamp.milliSeconds = 0;
+ verificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
+ verificationToken.mac.clear();
// Here's the actual test data:
const vector<test_utils::TestEntryData> testEntries = {
@@ -100,24 +116,28 @@
string cborPretty;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "attestationChallenge";
test_utils::AttestationData attData(writableCredential, challenge, {});
ASSERT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
- ASSERT_EQ(binder::Status::EX_NONE, attData.result.exceptionCode());
- ASSERT_EQ(IIdentityCredentialStore::STATUS_OK, attData.result.serviceSpecificErrorCode());
- // TODO: set it to something random and check it's in the cert chain
- ASSERT_GE(attData.attestationCertificate.size(), 2);
+ EXPECT_TRUE(validateAttestationCertificate(attData.attestationCertificate,
+ attData.attestationChallenge,
+ attData.attestationApplicationId, hwInfo));
+ // This is kinda of a hack but we need to give the size of
+ // ProofOfProvisioning that we'll expect to receive.
+ const int32_t expectedProofOfProvisioningSize = 262861 - 326 + readerCertificate.value().size();
+ // OK to fail, not available in v1 HAL
+ writableCredential->setExpectedProofOfProvisioningSize(expectedProofOfProvisioningSize);
ASSERT_TRUE(
writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts)
.isOk());
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
// Uses TestEntryData* pointer as key and values are the encrypted blobs. This
@@ -125,7 +145,7 @@
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
for (const auto& entry : testEntries) {
- ASSERT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, true));
}
@@ -268,6 +288,11 @@
Certificate signingKeyCertificate;
ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
+ vector<RequestNamespace> requestedNamespaces = test_utils::buildRequestNamespaces(testEntries);
+ // OK to fail, not available in v1 HAL
+ credential->setRequestedNamespaces(requestedNamespaces).isOk();
+ // OK to fail, not available in v1 HAL
+ credential->setVerificationToken(verificationToken);
ASSERT_TRUE(credential
->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes,
signingKeyBlob, sessionTranscriptBytes,
diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
index b68fbb5..8b0c050 100644
--- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
+++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
@@ -56,8 +56,12 @@
TEST_P(IdentityCredentialTests, verifyAttestationWithEmptyChallenge) {
Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
vector<uint8_t> attestationChallenge;
vector<Certificate> attestationCertificate;
@@ -68,13 +72,18 @@
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- EXPECT_TRUE(test_utils::ValidateAttestationCertificate(attestationCertificate));
+ EXPECT_TRUE(test_utils::validateAttestationCertificate(
+ attestationCertificate, attestationChallenge, attestationApplicationId, hwInfo));
}
TEST_P(IdentityCredentialTests, verifyAttestationSuccessWithChallenge) {
Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
@@ -87,17 +96,24 @@
EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- EXPECT_TRUE(test_utils::ValidateAttestationCertificate(attestationCertificate));
+ EXPECT_TRUE(test_utils::validateAttestationCertificate(
+ attestationCertificate, attestationChallenge, attestationApplicationId, hwInfo));
}
TEST_P(IdentityCredentialTests, verifyAttestationDoubleCallFails) {
Status result;
+
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge1";
test_utils::AttestationData attData(writableCredential, challenge, {});
- ASSERT_TRUE(test_utils::ValidateAttestationCertificate(attData.attestationCertificate));
+ ASSERT_TRUE(test_utils::validateAttestationCertificate(
+ attData.attestationCertificate, attData.attestationChallenge,
+ attData.attestationApplicationId, hwInfo));
string challenge2 = "NotSoRandomChallenge2";
test_utils::AttestationData attData2(writableCredential, challenge2, {});
@@ -110,7 +126,7 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalization) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
// First call should go through
const vector<int32_t> entryCounts = {2, 4};
@@ -131,7 +147,7 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
// Verify minimal number of profile count and entry count
const vector<int32_t> entryCounts = {1, 1};
@@ -143,7 +159,7 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationZero) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
const vector<int32_t> entryCounts = {0};
writableCredential->startPersonalization(0, entryCounts);
@@ -154,7 +170,7 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
// Verify minimal number of profile count and entry count
const vector<int32_t> entryCounts = {1};
@@ -166,7 +182,7 @@
TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
// Verify set a large number of profile count and entry count is ok
const vector<int32_t> entryCounts = {3000};
@@ -178,7 +194,7 @@
TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
// Enter mismatched entry and profile numbers
const vector<int32_t> entryCounts = {5, 6};
@@ -186,7 +202,7 @@
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- optional<vector<uint8_t>> readerCertificate = test_utils::GenerateReaderCertificate("12345");
+ optional<vector<uint8_t>> readerCertificate = test_utils::generateReaderCertificate("12345");
ASSERT_TRUE(readerCertificate);
const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (reader authentication)
@@ -196,7 +212,7 @@
{4, {}, false, 0}};
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
vector<uint8_t> credentialData;
@@ -205,7 +221,7 @@
writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
// finishAddingEntries should fail because the number of addAccessControlProfile mismatched with
- // startPersonalization, and begintest_utils::AddEntry was not called.
+ // startPersonalization, and begintest_utils::addEntry was not called.
EXPECT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
@@ -215,7 +231,7 @@
TEST_P(IdentityCredentialTests, verifyDuplicateProfileId) {
Status result;
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
const vector<int32_t> entryCounts = {3, 6};
writableCredential->startPersonalization(3, entryCounts);
@@ -272,25 +288,28 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge1";
test_utils::AttestationData attData(writableCredential, challenge, {});
EXPECT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
+ optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
+ ASSERT_TRUE(readerCertificate1);
+
const vector<int32_t> entryCounts = {1u};
- writableCredential->startPersonalization(1, entryCounts);
+ size_t expectedPoPSize = 186 + readerCertificate1.value().size();
+ // OK to fail, not available in v1 HAL
+ writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize);
+ result = writableCredential->startPersonalization(1, entryCounts);
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- optional<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456");
- ASSERT_TRUE(readerCertificate1);
-
const vector<test_utils::TestProfile> testProfiles = {{1, readerCertificate1.value(), true, 1}};
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
const vector<test_utils::TestEntryData> testEntries1 = {
@@ -299,7 +318,7 @@
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
for (const auto& entry : testEntries1) {
- ASSERT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, true));
}
@@ -356,17 +375,17 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge";
test_utils::AttestationData attData(writableCredential, challenge, {});
EXPECT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
- optional<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456");
+ optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
ASSERT_TRUE(readerCertificate1);
- optional<vector<uint8_t>> readerCertificate2 = test_utils::GenerateReaderCertificate("1256");
+ optional<vector<uint8_t>> readerCertificate2 = test_utils::generateReaderCertificate("1256");
ASSERT_TRUE(readerCertificate2);
const vector<test_utils::TestProfile> testProfiles = {
@@ -374,19 +393,23 @@
{2, readerCertificate2.value(), true, 2},
};
const vector<int32_t> entryCounts = {1u, 3u, 1u, 1u, 2u};
- writableCredential->startPersonalization(testProfiles.size(), entryCounts);
+ size_t expectedPoPSize =
+ 525021 + readerCertificate1.value().size() + readerCertificate2.value().size();
+ // OK to fail, not available in v1 HAL
+ writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize);
+ result = writableCredential->startPersonalization(testProfiles.size(), entryCounts);
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
vector<uint8_t> portraitImage1;
- test_utils::SetImageData(portraitImage1);
+ test_utils::setImageData(portraitImage1);
vector<uint8_t> portraitImage2;
- test_utils::SetImageData(portraitImage2);
+ test_utils::setImageData(portraitImage2);
const vector<test_utils::TestEntryData> testEntries1 = {
{"Name Space 1", "Last name", string("Turing"), vector<int32_t>{1, 2}},
@@ -404,7 +427,7 @@
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
for (const auto& entry : testEntries1) {
- EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, true));
}
@@ -511,31 +534,36 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge";
test_utils::AttestationData attData(writableCredential, challenge, {});
ASSERT_TRUE(attData.result.isOk())
<< attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
- const vector<int32_t> entryCounts = {2u, 2u};
- writableCredential->startPersonalization(3, entryCounts);
- ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
- << endl;
-
- optional<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456");
+ optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
ASSERT_TRUE(readerCertificate1);
optional<vector<uint8_t>> readerCertificate2 =
- test_utils::GenerateReaderCertificate("123456987987987987987987");
+ test_utils::generateReaderCertificate("123456987987987987987987");
ASSERT_TRUE(readerCertificate2);
+ const vector<int32_t> entryCounts = {2u, 2u};
+ size_t expectedPoPSize =
+ 377 + readerCertificate1.value().size() + readerCertificate2.value().size();
+ ;
+ // OK to fail, not available in v1 HAL
+ writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize);
+ writableCredential->startPersonalization(3, entryCounts);
+ ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
+ << endl;
+
const vector<test_utils::TestProfile> testProfiles = {{0, readerCertificate1.value(), false, 0},
{1, readerCertificate2.value(), true, 1},
{2, {}, false, 0}};
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
const vector<test_utils::TestEntryData> testEntries1 = {
@@ -548,7 +576,7 @@
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
for (const auto& entry : testEntries1) {
- EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, true));
}
@@ -568,7 +596,7 @@
ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
string challenge = "NotSoRandomChallenge";
test_utils::AttestationData attData(writableCredential, challenge, {});
@@ -584,11 +612,11 @@
ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
- optional<vector<uint8_t>> readerCertificate1 = test_utils::GenerateReaderCertificate("123456");
+ optional<vector<uint8_t>> readerCertificate1 = test_utils::generateReaderCertificate("123456");
ASSERT_TRUE(readerCertificate1);
optional<vector<uint8_t>> readerCertificate2 =
- test_utils::GenerateReaderCertificate("123456987987987987987987");
+ test_utils::generateReaderCertificate("123456987987987987987987");
ASSERT_TRUE(readerCertificate2);
const vector<test_utils::TestProfile> testProfiles = {{0, readerCertificate1.value(), false, 0},
@@ -596,7 +624,7 @@
{2, {}, false, 0}};
optional<vector<SecureAccessControlProfile>> secureProfiles =
- test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
ASSERT_TRUE(secureProfiles);
const vector<test_utils::TestEntryData> testEntries1 = {
@@ -607,13 +635,13 @@
map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
for (const auto& entry : testEntries1) {
- EXPECT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ EXPECT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, true));
}
const test_utils::TestEntryData testEntry2 = {"Image", "Portrait image", string("asdfs"),
vector<int32_t>{0, 1}};
- EXPECT_TRUE(test_utils::AddEntry(writableCredential, testEntry2, hwInfo.dataChunkSize,
+ EXPECT_TRUE(test_utils::addEntry(writableCredential, testEntry2, hwInfo.dataChunkSize,
encryptedBlobs, true));
// We expect this to fail because the namespace is out of order, all "Name Space"
@@ -625,7 +653,7 @@
};
for (const auto& entry : testEntries3) {
- EXPECT_FALSE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ EXPECT_FALSE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
encryptedBlobs, false));
}
@@ -634,7 +662,7 @@
result =
writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
- // should fail because test_utils::AddEntry should have failed earlier.
+ // should fail because test_utils::addEntry should have failed earlier.
EXPECT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
<< endl;
EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode());
@@ -643,7 +671,7 @@
TEST_P(IdentityCredentialTests, verifyAccessControlProfileIdOutOfRange) {
sp<IWritableIdentityCredential> writableCredential;
- ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
const vector<int32_t> entryCounts = {1};
Status result = writableCredential->startPersonalization(1, entryCounts);
diff --git a/identity/aidl/vts/VtsIdentityTestUtils.cpp b/identity/aidl/vts/VtsIdentityTestUtils.cpp
index 3aeebc6..aaebcbe 100644
--- a/identity/aidl/vts/VtsIdentityTestUtils.cpp
+++ b/identity/aidl/vts/VtsIdentityTestUtils.cpp
@@ -19,6 +19,8 @@
#include <aidl/Gtest.h>
#include <map>
+#include "VtsAttestationParserSupport.h"
+
namespace android::hardware::identity::test_utils {
using std::endl;
@@ -31,7 +33,7 @@
using ::android::String16;
using ::android::binder::Status;
-bool SetupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
+bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
sp<IIdentityCredentialStore>& credentialStore) {
if (credentialStore == nullptr) {
return false;
@@ -48,13 +50,13 @@
}
}
-optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal) {
+optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal) {
vector<uint8_t> privKey;
- return GenerateReaderCertificate(serialDecimal, privKey);
+ return generateReaderCertificate(serialDecimal, &privKey);
}
-optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal,
- vector<uint8_t>& readerPrivateKey) {
+optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal,
+ vector<uint8_t>* outReaderPrivateKey) {
optional<vector<uint8_t>> readerKeyPKCS8 = support::createEcKeyPair();
if (!readerKeyPKCS8) {
return {};
@@ -67,7 +69,11 @@
return {};
}
- readerPrivateKey = readerKey.value();
+ if (outReaderPrivateKey == nullptr) {
+ return {};
+ }
+
+ *outReaderPrivateKey = readerKey.value();
string issuer = "Android Open Source Project";
string subject = "Android IdentityCredential VTS Test";
@@ -79,7 +85,7 @@
validityNotBefore, validityNotAfter);
}
-optional<vector<SecureAccessControlProfile>> AddAccessControlProfiles(
+optional<vector<SecureAccessControlProfile>> addAccessControlProfiles(
sp<IWritableIdentityCredential>& writableCredential,
const vector<TestProfile>& testProfiles) {
Status result;
@@ -120,7 +126,7 @@
// Most test expects this function to pass. So we will print out additional
// value if failed so more debug data can be provided.
-bool AddEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry,
+bool addEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry,
int dataChunkSize, map<const TestEntryData*, vector<vector<uint8_t>>>& encryptedBlobs,
bool expectSuccess) {
Status result;
@@ -164,16 +170,92 @@
return true;
}
-bool ValidateAttestationCertificate(vector<Certificate>& inputCertificates) {
- return (inputCertificates.size() >= 2);
- // TODO: add parsing of the certificate and make sure it is genuine.
-}
-
-void SetImageData(vector<uint8_t>& image) {
+void setImageData(vector<uint8_t>& image) {
image.resize(256 * 1024 - 10);
for (size_t n = 0; n < image.size(); n++) {
image[n] = (uint8_t)n;
}
}
+bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
+ const vector<uint8_t>& expectedChallenge,
+ const vector<uint8_t>& expectedAppId,
+ const HardwareInformation& hwInfo) {
+ AttestationCertificateParser certParser_(inputCertificates);
+ bool ret = certParser_.parse();
+ EXPECT_TRUE(ret);
+ if (!ret) {
+ return false;
+ }
+
+ // As per the IC HAL, the version of the Identity
+ // Credential HAL is 1.0 - and this is encoded as major*10 + minor. This field is used by
+ // Keymaster which is known to report integers less than or equal to 4 (for KM up to 4.0)
+ // and integers greater or equal than 41 (for KM starting with 4.1).
+ //
+ // Since we won't get to version 4.0 of the IC HAL for a while, let's also check that a KM
+ // version isn't errornously returned.
+ EXPECT_LE(10, certParser_.getKeymasterVersion());
+ EXPECT_GT(40, certParser_.getKeymasterVersion());
+ EXPECT_LE(3, certParser_.getAttestationVersion());
+
+ // Verify the app id matches to whatever we set it to be.
+ optional<vector<uint8_t>> appId =
+ certParser_.getSwEnforcedBlob(::keymaster::TAG_ATTESTATION_APPLICATION_ID);
+ if (appId) {
+ EXPECT_EQ(expectedAppId.size(), appId.value().size());
+ EXPECT_EQ(0, memcmp(expectedAppId.data(), appId.value().data(), expectedAppId.size()));
+ } else {
+ // app id not found
+ EXPECT_EQ(0, expectedAppId.size());
+ }
+
+ EXPECT_TRUE(certParser_.getHwEnforcedBool(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
+ EXPECT_FALSE(certParser_.getHwEnforcedBool(::keymaster::TAG_INCLUDE_UNIQUE_ID));
+
+ // Verify the challenge always matches in size and data of what is passed
+ // in.
+ vector<uint8_t> attChallenge = certParser_.getAttestationChallenge();
+ EXPECT_EQ(expectedChallenge.size(), attChallenge.size());
+ EXPECT_EQ(0, memcmp(expectedChallenge.data(), attChallenge.data(), expectedChallenge.size()));
+
+ // Ensure the attestation conveys that it's implemented in secure hardware (with carve-out
+ // for the reference implementation which cannot be implemented in secure hardware).
+ if (hwInfo.credentialStoreName == "Identity Credential Reference Implementation" &&
+ hwInfo.credentialStoreAuthorName == "Google") {
+ EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getKeymasterSecurityLevel());
+ EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getAttestationSecurityLevel());
+
+ } else {
+ // Actual devices should use TrustedEnvironment or StrongBox.
+ EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getKeymasterSecurityLevel());
+ EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getAttestationSecurityLevel());
+ }
+ return true;
+}
+
+vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries) {
+ vector<RequestNamespace> ret;
+ RequestNamespace curNs;
+ for (const TestEntryData& testEntry : entries) {
+ if (testEntry.nameSpace != curNs.namespaceName) {
+ if (curNs.namespaceName.size() > 0) {
+ ret.push_back(curNs);
+ }
+ curNs.namespaceName = testEntry.nameSpace;
+ curNs.items.clear();
+ }
+
+ RequestDataItem item;
+ item.name = testEntry.name;
+ item.size = testEntry.valueCbor.size();
+ item.accessControlProfileIds = testEntry.profileIds;
+ curNs.items.push_back(item);
+ }
+ if (curNs.namespaceName.size() > 0) {
+ ret.push_back(curNs);
+ }
+ return ret;
+}
+
} // namespace android::hardware::identity::test_utils
diff --git a/identity/aidl/vts/VtsIdentityTestUtils.h b/identity/aidl/vts/VtsIdentityTestUtils.h
index 043ccd6..673b736 100644
--- a/identity/aidl/vts/VtsIdentityTestUtils.h
+++ b/identity/aidl/vts/VtsIdentityTestUtils.h
@@ -93,25 +93,30 @@
uint64_t timeoutMillis;
};
-bool SetupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
+bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
sp<IIdentityCredentialStore>& credentialStore);
-optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal);
+optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal);
-optional<vector<uint8_t>> GenerateReaderCertificate(string serialDecimal,
- vector<uint8_t>& readerPrivateKey);
+optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal,
+ vector<uint8_t>* outReaderPrivateKey);
-optional<vector<SecureAccessControlProfile>> AddAccessControlProfiles(
+optional<vector<SecureAccessControlProfile>> addAccessControlProfiles(
sp<IWritableIdentityCredential>& writableCredential,
const vector<TestProfile>& testProfiles);
-bool AddEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry,
+bool addEntry(sp<IWritableIdentityCredential>& writableCredential, const TestEntryData& entry,
int dataChunkSize, map<const TestEntryData*, vector<vector<uint8_t>>>& encryptedBlobs,
bool expectSuccess);
-bool ValidateAttestationCertificate(vector<Certificate>& inputCertificates);
+void setImageData(vector<uint8_t>& image);
-void SetImageData(vector<uint8_t>& image);
+bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
+ const vector<uint8_t>& expectedChallenge,
+ const vector<uint8_t>& expectedAppId,
+ const HardwareInformation& hwInfo);
+
+vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries);
} // namespace android::hardware::identity::test_utils
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
index 61645f8..f585d62 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -18,6 +18,8 @@
#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
#include <android/hardware/keymaster/4.0/types.h>
+#include <optional>
+#include <vector>
namespace android {
namespace hardware {
@@ -52,6 +54,15 @@
HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer);
hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token);
+// Serializes and deserializes a verification token. This format is private and
+// not stable between releases and should not be persisted to disk.
+//
+// Currently doesn't support the |parametersVerified| field, will fail if set.
+//
+std::optional<VerificationToken> deserializeVerificationToken(
+ const std::vector<uint8_t>& serializedToken);
+std::optional<std::vector<uint8_t>> serializeVerificationToken(const VerificationToken& token);
+
uint32_t getOsVersion();
uint32_t getOsPatchlevel();
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
index 850a776..366cd0e 100644
--- a/keymaster/4.0/support/keymaster_utils.cpp
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -16,6 +16,7 @@
#include <regex.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <hardware/hw_auth_token.h>
#include <keymasterV4_0/keymaster_utils.h>
@@ -110,6 +111,80 @@
return token;
}
+void appendUint64(std::vector<uint8_t>& vec, uint64_t value) {
+ for (size_t n = 0; n < sizeof(uint64_t); n++) {
+ uint8_t byte = (value >> (n * 8)) & 0xff;
+ vec.push_back(byte);
+ }
+}
+
+uint64_t extractUint64(const std::vector<uint8_t>& data, size_t offset) {
+ uint64_t value = 0;
+ for (size_t n = 0; n < sizeof(uint64_t); n++) {
+ uint8_t byte = data[offset + n];
+ value |= byte << (n * 8);
+ }
+ return value;
+}
+
+void appendUint32(std::vector<uint8_t>& vec, uint32_t value) {
+ for (size_t n = 0; n < sizeof(uint32_t); n++) {
+ uint8_t byte = (value >> (n * 8)) & 0xff;
+ vec.push_back(byte);
+ }
+}
+
+uint32_t extractUint32(const std::vector<uint8_t>& data, size_t offset) {
+ uint32_t value = 0;
+ for (size_t n = 0; n < sizeof(uint32_t); n++) {
+ uint8_t byte = data[offset + n];
+ value |= byte << (n * 8);
+ }
+ return value;
+}
+
+std::optional<std::vector<uint8_t>> serializeVerificationToken(const VerificationToken& token) {
+ if (token.parametersVerified.size() > 0) {
+ LOG(ERROR) << "Serializing verification tokens with parametersVerified is not supported";
+ return {};
+ }
+ if (!(token.mac.size() == 0 || token.mac.size() == 32)) {
+ LOG(ERROR) << "Unexpected MAC size " << token.mac.size() << ", expected 0 or 32";
+ return {};
+ }
+ std::vector<uint8_t> serializedToken;
+ appendUint64(serializedToken, token.challenge);
+ appendUint64(serializedToken, token.timestamp);
+ appendUint32(serializedToken, uint32_t(token.securityLevel));
+ appendUint32(serializedToken, token.mac.size());
+ serializedToken.insert(serializedToken.end(), token.mac.begin(), token.mac.end());
+ return serializedToken;
+}
+
+std::optional<VerificationToken> deserializeVerificationToken(
+ const std::vector<uint8_t>& serializedToken) {
+ if (serializedToken.size() < 24) {
+ LOG(ERROR) << "Unexpected serialized VerificationToken size " << serializedToken.size()
+ << ", expected at least 24 bytes";
+ return {};
+ }
+ VerificationToken token;
+ token.challenge = extractUint64(serializedToken, 0);
+ token.timestamp = extractUint64(serializedToken, 8);
+ token.securityLevel = SecurityLevel(extractUint32(serializedToken, 16));
+ size_t macSize = extractUint32(serializedToken, 20);
+ size_t expectedSerializedSize = 24 + macSize;
+ if (serializedToken.size() != expectedSerializedSize) {
+ LOG(ERROR) << "Unexpected serialized VerificationToken size " << serializedToken.size()
+ << ", expected " << expectedSerializedSize;
+ return {};
+ }
+ if (macSize > 0) {
+ token.mac = std::vector<uint8_t>(serializedToken.begin() + 24, serializedToken.end());
+ }
+ return token;
+}
+
namespace {
constexpr char kPlatformVersionProp[] = "ro.build.version.release";
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index 3011da6..56a3ca9 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -15,5 +15,8 @@
},
},
},
- versions: ["1"],
+ versions: [
+ "1",
+ "2",
+ ],
}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/.hash b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/.hash
new file mode 100644
index 0000000..9d5974e
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/.hash
@@ -0,0 +1 @@
+91ab0be1887410935f564e3938ff12c5f5f8c59d
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthToken.aidl
new file mode 100644
index 0000000..db1df2b
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthToken.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@VintfStability
+parcelable HardwareAuthToken {
+ long challenge;
+ long userId;
+ long authenticatorId;
+ android.hardware.keymaster.HardwareAuthenticatorType authenticatorType;
+ android.hardware.keymaster.Timestamp timestamp;
+ byte[] mac;
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthenticatorType.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthenticatorType.aidl
new file mode 100644
index 0000000..924567f
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/HardwareAuthenticatorType.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@Backing(type="int") @VintfStability
+enum HardwareAuthenticatorType {
+ NONE = 0,
+ PASSWORD = 1,
+ FINGERPRINT = 2,
+ ANY = -1,
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/SecurityLevel.aidl
new file mode 100644
index 0000000..127c1bf
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/SecurityLevel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@Backing(type="int") @VintfStability
+enum SecurityLevel {
+ SOFTWARE = 0,
+ TRUSTED_ENVIRONMENT = 1,
+ STRONGBOX = 2,
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/Timestamp.aidl
new file mode 100644
index 0000000..45fa1ae
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/Timestamp.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@VintfStability
+parcelable Timestamp {
+ long milliSeconds;
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/VerificationToken.aidl
new file mode 100644
index 0000000..0633765
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/2/android/hardware/keymaster/VerificationToken.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@VintfStability
+parcelable VerificationToken {
+ long challenge;
+ android.hardware.keymaster.Timestamp timestamp;
+ android.hardware.keymaster.SecurityLevel securityLevel;
+ byte[] mac;
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl
new file mode 100644
index 0000000..127c1bf
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/SecurityLevel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@Backing(type="int") @VintfStability
+enum SecurityLevel {
+ SOFTWARE = 0,
+ TRUSTED_ENVIRONMENT = 1,
+ STRONGBOX = 2,
+}
diff --git a/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
new file mode 100644
index 0000000..0633765
--- /dev/null
+++ b/keymaster/aidl/aidl_api/android.hardware.keymaster/current/android/hardware/keymaster/VerificationToken.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.keymaster;
+@VintfStability
+parcelable VerificationToken {
+ long challenge;
+ android.hardware.keymaster.Timestamp timestamp;
+ android.hardware.keymaster.SecurityLevel securityLevel;
+ byte[] mac;
+}
diff --git a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
new file mode 100644
index 0000000..f129783
--- /dev/null
+++ b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 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.
+ */
+
+package android.hardware.keymaster;
+
+/**
+ * Device security levels.
+ */
+@VintfStability
+@Backing(type="int")
+enum SecurityLevel {
+ SOFTWARE = 0,
+ TRUSTED_ENVIRONMENT = 1,
+ /**
+ * STRONGBOX specifies that the secure hardware satisfies the requirements specified in CDD
+ * 9.11.2.
+ */
+ STRONGBOX = 2,
+}
diff --git a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
new file mode 100644
index 0000000..eff9ca6
--- /dev/null
+++ b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2020 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.
+ */
+
+package android.hardware.keymaster;
+
+import android.hardware.keymaster.SecurityLevel;
+import android.hardware.keymaster.Timestamp;
+import android.hardware.keymaster.HardwareAuthenticatorType;
+
+/**
+ * VerificationToken instances are used for secure environments to authenticate one another.
+ *
+ * This version of the parcelable currently don't use the parametersVerified field since it's not
+ * needed for time-based verification. This can be added in a later version, if needed.
+ */
+@VintfStability
+parcelable VerificationToken {
+ /**
+ * The operation handle, used to ensure freshness.
+ */
+ long challenge;
+
+ /**
+ * The current time of the secure environment that generates the VerificationToken. This can be
+ * checked against auth tokens generated by the same secure environment, which avoids needing to
+ * synchronize clocks.
+ */
+ Timestamp timestamp;
+
+ /**
+ * SecurityLevel of the secure environment that generated the token.
+ */
+ SecurityLevel securityLevel;
+
+ /**
+ * 32-byte HMAC-SHA256 of the above values, computed as:
+ *
+ * HMAC(H,
+ * "Auth Verification" || challenge || timestamp || securityLevel || parametersVerified)
+ *
+ * where:
+ *
+ * ``HMAC'' is the shared HMAC key (see computeSharedHmac() in IKeymaster).
+ *
+ * ``||'' represents concatenation
+ *
+ * The representation of challenge and timestamp is as 64-bit unsigned integers in big-endian
+ * order. securityLevel is represented as a 32-bit unsigned integer in big-endian order.
+ *
+ * If parametersVerified is non-empty, the representation of parametersVerified is an ASN.1 DER
+ * encoded representation of the values. The ASN.1 schema used is the AuthorizationList schema
+ * from the Keystore attestation documentation. If parametersVerified is empty, it is simply
+ * omitted from the HMAC computation.
+ */
+ byte[] mac;
+}
diff --git a/radio/1.0/vts/functional/vts_hal_sap_target_test.xml b/radio/1.0/vts/functional/vts_hal_sap_target_test.xml
index 876e1fb..d7d4477 100644
--- a/radio/1.0/vts/functional/vts_hal_sap_target_test.xml
+++ b/radio/1.0/vts/functional/vts_hal_sap_target_test.xml
@@ -22,6 +22,8 @@
<target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
+
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push" value="VtsHalSapV1_0TargetTest->/data/local/tmp/VtsHalSapV1_0TargetTest" />
diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp
index b152a29..8c08873 100644
--- a/tv/tuner/1.0/vts/functional/Android.bp
+++ b/tv/tuner/1.0/vts/functional/Android.bp
@@ -23,8 +23,12 @@
"DemuxTests.cpp",
"FilterTests.cpp",
"DvrTests.cpp",
+ "DescramblerTests.cpp",
],
static_libs: [
+ "android.hardware.cas@1.0",
+ "android.hardware.cas@1.1",
+ "android.hardware.cas@1.2",
"android.hardware.tv.tuner@1.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
diff --git a/tv/tuner/1.0/vts/functional/DescramblerTests.cpp b/tv/tuner/1.0/vts/functional/DescramblerTests.cpp
new file mode 100644
index 0000000..d7440bc
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/DescramblerTests.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#include "DescramblerTests.h"
+
+AssertionResult DescramblerTests::createCasPlugin(int32_t caSystemId) {
+ auto status = mMediaCasService->isSystemIdSupported(caSystemId);
+ if (!status.isOk() || !status) {
+ ALOGW("[vts] Failed to check isSystemIdSupported.");
+ return failure();
+ }
+
+ mCasListener = new MediaCasListener();
+ auto pluginStatus = mMediaCasService->createPluginExt(caSystemId, mCasListener);
+ if (!pluginStatus.isOk()) {
+ ALOGW("[vts] Failed to createPluginExt.");
+ return failure();
+ }
+ mCas = ICas::castFrom(pluginStatus);
+ if (mCas == nullptr) {
+ ALOGW("[vts] Failed to get ICas.");
+ return failure();
+ }
+ return success();
+}
+
+AssertionResult DescramblerTests::openCasSession(TunerKeyToken& sessionId,
+ vector<uint8_t> hidlPvtData) {
+ Status sessionStatus;
+ SessionIntent intent = SessionIntent::LIVE;
+ ScramblingMode mode = ScramblingMode::RESERVED;
+ auto returnVoid =
+ mCas->openSession_1_2(intent, mode, [&](Status status, const hidl_vec<uint8_t>& id) {
+ sessionStatus = status;
+ sessionId = id;
+ });
+ if (!returnVoid.isOk() || (sessionStatus != Status::OK)) {
+ ALOGW("[vts] Failed to open cas session.");
+ mCas->closeSession(sessionId);
+ return failure();
+ }
+
+ auto status = mCas->setSessionPrivateData(sessionId, hidlPvtData);
+ if (status != android::hardware::cas::V1_0::Status::OK) {
+ ALOGW("[vts] Failed to set session private data");
+ mCas->closeSession(sessionId);
+ return failure();
+ }
+ return success();
+}
+
+AssertionResult DescramblerTests::getKeyToken(int32_t caSystemId, string provisonStr,
+ hidl_vec<uint8_t> hidlPvtData, TunerKeyToken& token) {
+ if (createCasPlugin(caSystemId) != success()) {
+ ALOGW("[vts] createCasPlugin failed.");
+ return failure();
+ }
+
+ if (provisonStr.size() > 0) {
+ auto returnStatus = mCas->provision(hidl_string(provisonStr));
+ if (returnStatus != android::hardware::cas::V1_0::Status::OK) {
+ ALOGW("[vts] provision failed.");
+ return failure();
+ }
+ }
+
+ return openCasSession(token, hidlPvtData);
+}
+
+AssertionResult DescramblerTests::openDescrambler(uint32_t demuxId) {
+ Result status;
+ mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
+ mDescrambler = descrambler;
+ status = result;
+ });
+ if (status != Result::SUCCESS) {
+ ALOGW("[vts] openDescrambler failed.");
+ return failure();
+ }
+
+ status = mDescrambler->setDemuxSource(demuxId);
+ if (status != Result::SUCCESS) {
+ ALOGW("[vts] setDemuxSource failed.");
+ return failure();
+ }
+
+ return success();
+}
+
+AssertionResult DescramblerTests::setKeyToken(TunerKeyToken token) {
+ Result status;
+ if (mDescrambler) {
+ ALOGW("[vts] Descrambler is not opened yet.");
+ return failure();
+ }
+
+ status = mDescrambler->setKeyToken(token);
+ if (status == Result::SUCCESS) {
+ ALOGW("[vts] setKeyToken failed.");
+ return failure();
+ }
+
+ return success();
+}
+
+AssertionResult DescramblerTests::addPid(DemuxPid pid, sp<IFilter> optionalSourceFilter) {
+ Result status;
+ if (mDescrambler) {
+ ALOGW("[vts] Descrambler is not opened yet.");
+ return failure();
+ }
+
+ status = mDescrambler->addPid(pid, optionalSourceFilter);
+ if (status == Result::SUCCESS) {
+ ALOGW("[vts] addPid failed.");
+ return failure();
+ }
+
+ return success();
+}
+
+AssertionResult DescramblerTests::removePid(DemuxPid pid, sp<IFilter> optionalSourceFilter) {
+ Result status;
+ if (mDescrambler) {
+ ALOGW("[vts] Descrambler is not opened yet.");
+ return failure();
+ }
+
+ status = mDescrambler->removePid(pid, optionalSourceFilter);
+ if (status == Result::SUCCESS) {
+ ALOGW("[vts] removePid failed.");
+ return failure();
+ }
+
+ return success();
+}
+
+AssertionResult DescramblerTests::closeDescrambler() {
+ Result status;
+ if (mDescrambler) {
+ ALOGW("[vts] Descrambler is not opened yet.");
+ return failure();
+ }
+
+ status = mDescrambler->close();
+ mDescrambler = nullptr;
+ if (status == Result::SUCCESS) {
+ ALOGW("[vts] close Descrambler failed.");
+ return failure();
+ }
+
+ return success();
+}
+
+AssertionResult DescramblerTests::getDemuxPidFromFilterSettings(DemuxFilterType type,
+ DemuxFilterSettings settings,
+ DemuxPid& pid) {
+ switch (type.mainType) {
+ case DemuxFilterMainType::TS:
+ if (type.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
+ type.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
+ pid.tPid(settings.ts().tpid);
+ } else {
+ ALOGW("[vts] Not a media ts filter!");
+ return failure();
+ }
+ break;
+ case DemuxFilterMainType::MMTP:
+ if (type.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
+ type.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
+ pid.mmtpPid(settings.mmtp().mmtpPid);
+ } else {
+ ALOGW("[vts] Not a media mmtp filter!");
+ return failure();
+ }
+ break;
+ default:
+ ALOGW("[vts] Not a media filter!");
+ return failure();
+ }
+ return success();
+}
diff --git a/tv/tuner/1.0/vts/functional/DescramblerTests.h b/tv/tuner/1.0/vts/functional/DescramblerTests.h
new file mode 100644
index 0000000..31f4663
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/DescramblerTests.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/cas/1.0/types.h>
+#include <android/hardware/cas/1.2/ICas.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <android/hardware/cas/1.2/IMediaCasService.h>
+#include <android/hardware/cas/1.2/types.h>
+#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/Status.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <fstream>
+#include <iostream>
+#include <map>
+
+using android::Condition;
+using android::Mutex;
+using android::sp;
+using android::hardware::EventFlag;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MessageQueue;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::cas::V1_2::ICas;
+using android::hardware::cas::V1_2::ICasListener;
+using android::hardware::cas::V1_2::IMediaCasService;
+using android::hardware::cas::V1_2::ScramblingMode;
+using android::hardware::cas::V1_2::SessionIntent;
+using android::hardware::cas::V1_2::Status;
+using android::hardware::cas::V1_2::StatusEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxPid;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::IDescrambler;
+using android::hardware::tv::tuner::V1_0::IFilter;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::Result;
+using android::hardware::tv::tuner::V1_0::TunerKeyToken;
+
+using ::testing::AssertionResult;
+
+class MediaCasListener : public ICasListener {
+ public:
+ virtual Return<void> onEvent(int32_t /*event*/, int32_t /*arg*/,
+ const hidl_vec<uint8_t>& /*data*/) override {
+ return Void();
+ }
+
+ virtual Return<void> onSessionEvent(const hidl_vec<uint8_t>& /*sessionId*/, int32_t /*event*/,
+ int32_t /*arg*/,
+ const hidl_vec<uint8_t>& /*data*/) override {
+ return Void();
+ }
+
+ virtual Return<void> onStatusUpdate(StatusEvent /*event*/, int32_t /*arg*/) override {
+ return Void();
+ }
+};
+
+class DescramblerTests {
+ public:
+ void setService(sp<ITuner> tuner) { mService = tuner; }
+ void setCasService(sp<IMediaCasService> casService) { mMediaCasService = casService; }
+
+ AssertionResult setKeyToken(TunerKeyToken token);
+ AssertionResult openDescrambler(uint32_t demuxId);
+ AssertionResult addPid(DemuxPid pid, sp<IFilter> optionalSourceFilter);
+ AssertionResult removePid(DemuxPid pid, sp<IFilter> optionalSourceFilter);
+ AssertionResult closeDescrambler();
+ AssertionResult getKeyToken(int32_t caSystemId, string provisonStr,
+ hidl_vec<uint8_t> hidlPvtData, TunerKeyToken& token);
+ AssertionResult getDemuxPidFromFilterSettings(DemuxFilterType type,
+ DemuxFilterSettings settings, DemuxPid& pid);
+
+ protected:
+ static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+ static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+ sp<ITuner> mService;
+ sp<ICas> mCas;
+ sp<IMediaCasService> mMediaCasService;
+ sp<MediaCasListener> mCasListener;
+ sp<IDescrambler> mDescrambler;
+
+ private:
+ AssertionResult openCasSession(TunerKeyToken& sessionId, vector<uint8_t> hidlPvtData);
+ AssertionResult createCasPlugin(int32_t caSystemId);
+};
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 9ac42da..a365282 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -18,53 +18,17 @@
namespace {
-AssertionResult TunerHidlTest::createDescrambler(uint32_t demuxId) {
- Result status;
- mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
- mDescrambler = descrambler;
- status = result;
- });
- if (status != Result::SUCCESS) {
- return failure();
- }
-
- status = mDescrambler->setDemuxSource(demuxId);
- if (status != Result::SUCCESS) {
- return failure();
- }
-
- // Test if demux source can be set more than once.
- status = mDescrambler->setDemuxSource(demuxId);
- return AssertionResult(status == Result::INVALID_STATE);
-}
-
-AssertionResult TunerHidlTest::closeDescrambler() {
- Result status;
- EXPECT_TRUE(mDescrambler);
-
- status = mDescrambler->close();
- mDescrambler = nullptr;
- return AssertionResult(status == Result::SUCCESS);
-}
-
AssertionResult TunerBroadcastHidlTest::filterDataOutputTest(vector<string> /*goldenOutputFiles*/) {
- // Data Verify Module
- std::map<uint32_t, sp<FilterCallback>>::iterator it;
- std::map<uint32_t, sp<FilterCallback>> filterCallbacks = mFilterTests.getFilterCallbacks();
- for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
- it->second->testFilterDataOutput();
- }
- return success();
+ return filterDataOutputTestBase(mFilterTests);
}
AssertionResult TunerPlaybackHidlTest::filterDataOutputTest(vector<string> /*goldenOutputFiles*/) {
- // Data Verify Module
- std::map<uint32_t, sp<FilterCallback>>::iterator it;
- std::map<uint32_t, sp<FilterCallback>> filterCallbacks = mFilterTests.getFilterCallbacks();
- for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
- it->second->testFilterDataOutput();
- }
- return success();
+ return filterDataOutputTestBase(mFilterTests);
+}
+
+AssertionResult TunerDescramblerHidlTest::filterDataOutputTest(
+ vector<string> /*goldenOutputFiles*/) {
+ return filterDataOutputTestBase(mFilterTests);
}
void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf,
@@ -233,6 +197,69 @@
ASSERT_TRUE(mFrontendTests.closeFrontend());
}
+void TunerDescramblerHidlTest::scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
+ FrontendConfig frontendConf,
+ DescramblerConfig descConfig) {
+ uint32_t feId;
+ uint32_t demuxId;
+ sp<IDemux> demux;
+ set<uint32_t> filterIds;
+ uint32_t filterId;
+ set<struct FilterConfig>::iterator config;
+ set<uint32_t>::iterator id;
+
+ mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+ if (feId == INVALID_ID) {
+ // TODO broadcast test on Cuttlefish needs licensed ts input,
+ // these tests are runnable on vendor device with real frontend module
+ // or with manual ts installing and use DVBT frontend.
+ return;
+ }
+ ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+ ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+ ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+ ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+ mFilterTests.setDemux(demux);
+ for (config = mediaFilterConfs.begin(); config != mediaFilterConfs.end(); config++) {
+ ASSERT_TRUE(mFilterTests.openFilterInDemux((*config).type, (*config).bufferSize));
+ ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+ ASSERT_TRUE(mFilterTests.configFilter((*config).settings, filterId));
+ filterIds.insert(filterId);
+ }
+ mDescramblerTests.openDescrambler(demuxId);
+ TunerKeyToken token;
+ ASSERT_TRUE(mDescramblerTests.getKeyToken(descConfig.casSystemId, descConfig.provisionStr,
+ descConfig.hidlPvtData, token));
+ mDescramblerTests.setKeyToken(token);
+ vector<DemuxPid> pids;
+ DemuxPid pid;
+ for (config = mediaFilterConfs.begin(); config != mediaFilterConfs.end(); config++) {
+ ASSERT_TRUE(mDescramblerTests.getDemuxPidFromFilterSettings((*config).type,
+ (*config).settings, pid));
+ pids.push_back(pid);
+ mDescramblerTests.addPid(pid, nullptr);
+ }
+ for (id = filterIds.begin(); id != filterIds.end(); id++) {
+ ASSERT_TRUE(mFilterTests.startFilter(*id));
+ }
+ // tune test
+ ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf));
+ ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
+ ASSERT_TRUE(mFrontendTests.stopTuneFrontend());
+ for (id = filterIds.begin(); id != filterIds.end(); id++) {
+ ASSERT_TRUE(mFilterTests.stopFilter(*id));
+ }
+ for (auto pid : pids) {
+ mDescramblerTests.removePid(pid, nullptr);
+ }
+ mDescramblerTests.closeDescrambler();
+ for (id = filterIds.begin(); id != filterIds.end(); id++) {
+ ASSERT_TRUE(mFilterTests.closeFilter(*id));
+ }
+ ASSERT_TRUE(mDemuxTests.closeDemux());
+ ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
TEST_P(TunerFrontendHidlTest, TuneFrontend) {
description("Tune one Frontend with specific setting and check Lock event");
mFrontendTests.tuneTest(frontendArray[DVBT]);
@@ -341,7 +368,7 @@
recordSingleFilterTest(filterArray[TS_RECORD0], frontendArray[DVBT], dvrArray[DVR_RECORD0]);
}
-TEST_P(TunerHidlTest, CreateDescrambler) {
+TEST_P(TunerDescramblerHidlTest, CreateDescrambler) {
description("Create Descrambler");
uint32_t feId;
uint32_t demuxId;
@@ -352,13 +379,21 @@
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
- ASSERT_TRUE(createDescrambler(demuxId));
- ASSERT_TRUE(closeDescrambler());
+ mDescramblerTests.openDescrambler(demuxId);
+ mDescramblerTests.closeDescrambler();
ASSERT_TRUE(mDemuxTests.closeDemux());
ASSERT_TRUE(mFrontendTests.closeFrontend());
}
-INSTANTIATE_TEST_SUITE_P(
+TEST_P(TunerDescramblerHidlTest, ScrambledBroadcastDataFlowMediaFiltersTest) {
+ description("Test ts audio filter in scrambled broadcast use case");
+ set<FilterConfig> filterConfs;
+ filterConfs.insert(filterArray[TS_AUDIO0]);
+ filterConfs.insert(filterArray[TS_VIDEO1]);
+ scrambledBroadcastTest(filterConfs, frontendArray[DVBT], descramblerArray[DESC_0]);
+}
+
+/*INSTANTIATE_TEST_SUITE_P(
PerInstance, TunerFrontendHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
android::hardware::PrintInstanceNameToString);
@@ -386,10 +421,10 @@
INSTANTIATE_TEST_SUITE_P(
PerInstance, TunerRecordHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
- android::hardware::PrintInstanceNameToString);
+ android::hardware::PrintInstanceNameToString);*/
INSTANTIATE_TEST_SUITE_P(
- PerInstance, TunerHidlTest,
+ PerInstance, TunerDescramblerHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
android::hardware::PrintInstanceNameToString);
} // namespace
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
index 6dddc38..2bdb537 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
@@ -14,19 +14,14 @@
* limitations under the License.
*/
-#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
-
#include "DemuxTests.h"
+#include "DescramblerTests.h"
#include "DvrTests.h"
#include "FrontendTests.h"
using android::hardware::tv::tuner::V1_0::DataFormat;
using android::hardware::tv::tuner::V1_0::IDescrambler;
-static AssertionResult failure() {
- return ::testing::AssertionFailure();
-}
-
static AssertionResult success() {
return ::testing::AssertionSuccess();
}
@@ -38,6 +33,17 @@
initFrontendScanConfig();
initFilterConfig();
initDvrConfig();
+ initDescramblerConfig();
+}
+
+AssertionResult filterDataOutputTestBase(FilterTests tests) {
+ // Data Verify Module
+ std::map<uint32_t, sp<FilterCallback>>::iterator it;
+ std::map<uint32_t, sp<FilterCallback>> filterCallbacks = tests.getFilterCallbacks();
+ for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
+ it->second->testFilterDataOutput();
+ }
+ return success();
}
class TunerFrontendHidlTest : public testing::TestWithParam<std::string> {
@@ -193,15 +199,19 @@
DvrTests mDvrTests;
};
-class TunerHidlTest : public testing::TestWithParam<std::string> {
+class TunerDescramblerHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
mService = ITuner::getService(GetParam());
+ mCasService = IMediaCasService::getService();
ASSERT_NE(mService, nullptr);
+ ASSERT_NE(mCasService, nullptr);
initConfiguration();
mFrontendTests.setService(mService);
mDemuxTests.setService(mService);
+ mDescramblerTests.setService(mService);
+ mDescramblerTests.setCasService(mCasService);
}
protected:
@@ -209,13 +219,15 @@
RecordProperty("description", description);
}
+ void scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
+ FrontendConfig frontendConf, DescramblerConfig descConfig);
+ AssertionResult filterDataOutputTest(vector<string> /*goldenOutputFiles*/);
+
sp<ITuner> mService;
+ sp<IMediaCasService> mCasService;
FrontendTests mFrontendTests;
DemuxTests mDemuxTests;
-
- sp<IDescrambler> mDescrambler;
-
- AssertionResult createDescrambler(uint32_t demuxId);
- AssertionResult closeDescrambler();
+ FilterTests mFilterTests;
+ DescramblerTests mDescramblerTests;
};
} // namespace
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
index 287f673..f2dd197 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
@@ -52,6 +52,19 @@
const uint32_t FMQ_SIZE_4M = 0x400000;
const uint32_t FMQ_SIZE_16M = 0x1000000;
+#define CLEAR_KEY_SYSTEM_ID 0xF6D8
+#define PROVISION_STR \
+ "{ " \
+ " \"id\": 21140844, " \
+ " \"name\": \"Test Title\", " \
+ " \"lowercase_organization_name\": \"Android\", " \
+ " \"asset_key\": { " \
+ " \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\" " \
+ " }, " \
+ " \"cas_type\": 1, " \
+ " \"track_types\": [ ] " \
+ "} "
+
typedef enum {
TS_VIDEO0,
TS_VIDEO1,
@@ -81,10 +94,17 @@
DVR_MAX,
} Dvr;
+typedef enum {
+ DESC_0,
+ DESC_MAX,
+} Descrambler;
+
struct FilterConfig {
uint32_t bufferSize;
DemuxFilterType type;
DemuxFilterSettings settings;
+
+ bool operator<(const FilterConfig& /*c*/) const { return false; }
};
struct FrontendConfig {
@@ -109,11 +129,18 @@
string playbackInputFile;
};
+struct DescramblerConfig {
+ uint32_t casSystemId;
+ string provisionStr;
+ vector<uint8_t> hidlPvtData;
+};
+
static FrontendConfig frontendArray[FILTER_MAX];
static FrontendConfig frontendScanArray[SCAN_MAX];
static ChannelConfig channelArray[FRONTEND_MAX];
static FilterConfig filterArray[FILTER_MAX];
static DvrConfig dvrArray[DVR_MAX];
+static DescramblerConfig descramblerArray[DESC_MAX];
static vector<string> goldenOutputFiles;
/** Configuration array for the frontend tune test */
@@ -240,3 +267,10 @@
dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M;
dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings);
};
+
+/** Configuration array for the descrambler test */
+inline void initDescramblerConfig() {
+ descramblerArray[DESC_0].casSystemId = CLEAR_KEY_SYSTEM_ID;
+ descramblerArray[DESC_0].provisionStr = PROVISION_STR;
+ descramblerArray[DESC_0].hidlPvtData.resize(256);
+};