All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ramalingam C <ramalingam.c@intel.com>
To: igt-dev@lists.freedesktop.org, daniel.vetter@ffwll.ch
Subject: [igt-dev] [PATCH i-g-t 3/4] kms_content_protection: srm and downstream_info test
Date: Tue, 26 Feb 2019 12:53:24 +0530	[thread overview]
Message-ID: <1551165805-19130-4-git-send-email-ramalingam.c@intel.com> (raw)
In-Reply-To: <1551165805-19130-1-git-send-email-ramalingam.c@intel.com>

Retrieve the downstream info and use that to stitch a srm and
verify the revocation process.

Adds two more connector properties called CP_SRM and CP_Downstream_Info

SRM stitched here is polluted. Kernel trusts the userspace to validate
the SRM integrity through DCP signature. Actually this test exploits
that trust to test SRM and downstream_info features.

HDCP1.4 BKSV and HDCP2.2 receiver id of a HDCP sink is different. So we
need to force the KMD to use a single HDCP version across
downstream_info gathering and SRM setting and verifying teh revocation
process. So Type 1 is used.

Signed-off-by: Ramalingam C <ramalingam.c@intel.com>
---
 lib/igt_kms.c                  |   2 +
 lib/igt_kms.h                  |   2 +
 tests/kms_content_protection.c | 201 ++++++++++++++++++++++++++++++++++++++---
 3 files changed, 191 insertions(+), 14 deletions(-)

diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index b3d1c3456157..528cfe454816 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -200,6 +200,8 @@ const char * const igt_connector_prop_names[IGT_NUM_CONNECTOR_PROPS] = {
 	[IGT_CONNECTOR_CONTENT_PROTECTION] = "Content Protection",
 	[IGT_CONNECTOR_VRR_CAPABLE] = "vrr_capable",
 	[IGT_CONNECTOR_CP_CONTENT_TYPE] = "CP_Content_Type",
+	[IGT_CONNECTOR_CP_SRM] = "CP_SRM",
+	[IGT_CONNECTOR_CP_DOWNSTREAM_INFO] = "CP_Downstream_Info",
 };
 
 /*
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
index e152b6a2ed55..f7fb88d7e5e6 100644
--- a/lib/igt_kms.h
+++ b/lib/igt_kms.h
@@ -124,6 +124,8 @@ enum igt_atomic_connector_properties {
        IGT_CONNECTOR_CONTENT_PROTECTION,
        IGT_CONNECTOR_VRR_CAPABLE,
        IGT_CONNECTOR_CP_CONTENT_TYPE,
+       IGT_CONNECTOR_CP_SRM,
+       IGT_CONNECTOR_CP_DOWNSTREAM_INFO,
        IGT_NUM_CONNECTOR_PROPS
 };
 
diff --git a/tests/kms_content_protection.c b/tests/kms_content_protection.c
index 4563a6067a32..c41e9684deb6 100644
--- a/tests/kms_content_protection.c
+++ b/tests/kms_content_protection.c
@@ -55,6 +55,109 @@ struct data {
 #define FLIP_EVENT_POLLING_TIMEOUT_MSEC		1000
 
 
+#define DRM_MODE_HDCP_KSV_LEN			5
+#define DRM_MODE_HDCP_MAX_DEVICE_CNT		127
+
+#define DRM_MODE_HDCP14_IN_FORCE		(1 << 0)
+#define DRM_MODE_HDCP22_IN_FORCE		(1 << 1)
+
+struct cp_downstream_info {
+	/* HDCP ver in force */
+	__u32 ver_in_force;
+	__u8 content_type;
+
+	/* KSV of immediate HDCP Sink. In Little-Endian Format. */
+	char bksv[DRM_MODE_HDCP_KSV_LEN];
+
+	/* Whether Immediate HDCP sink is a repeater? */
+	bool is_repeater;
+
+	/* Depth received from immediate downstream repeater */
+	__u8 depth;
+
+	/* Device count received from immediate downstream repeater */
+	__u32 device_count;
+
+	/*
+	 * Max buffer required to hold ksv list received from immediate
+	 * repeater. In this array first device_count * DRM_MODE_HDCP_KSV_LEN
+	 * will hold the valid ksv bytes.
+	 * If authentication specification is
+	 *      HDCP1.4 - each KSV's Bytes will be in Little-Endian format.
+	 *      HDCP2.2 - each KSV's Bytes will be in Big-Endian format.
+	 */
+	char ksv_list[DRM_MODE_HDCP_KSV_LEN * DRM_MODE_HDCP_MAX_DEVICE_CNT];
+};
+
+__u8 facsimile_srm[] = {
+	0x80, 0x0, 0x0, 0x05, 0x01, 0x0, 0x0, 0x36, 0x02, 0x51, 0x1E, 0xF2,
+	0x1A, 0xCD, 0xE7, 0x26, 0x97, 0xF4, 0x01, 0x97, 0x10, 0x19, 0x92, 0x53,
+	0xE9, 0xF0, 0x59, 0x95, 0xA3, 0x7A, 0x3B, 0xFE, 0xE0, 0x9C, 0x76, 0xDD,
+	0x83, 0xAA, 0xC2, 0x5B, 0x24, 0xB3, 0x36, 0x84, 0x94, 0x75, 0x34, 0xDB,
+	0x10, 0x9E, 0x3B, 0x23, 0x13, 0xD8, 0x7A, 0xC2, 0x30, 0x79, 0x84};
+
+static void parse_downstream_info(struct cp_downstream_info *ds_info)
+{
+	char *ksvs;
+	int i;
+
+	if (ds_info->ver_in_force & DRM_MODE_HDCP14_IN_FORCE)
+		igt_debug("HDCP1.4 is Enabled\n");
+	else if (ds_info->ver_in_force & DRM_MODE_HDCP22_IN_FORCE)
+		igt_debug("HDCP2.2 is Enabled. Type%d\n",
+			  ds_info->content_type & CP_TYPE_1 ? 1 : 0);
+	else
+		return;
+
+	igt_debug("\tReceiver ID: %#04x %#04x %#04x %#04x %#04x\n",
+		  ds_info->bksv[0] & 0xFF, ds_info->bksv[1] & 0xFF,
+		  ds_info->bksv[2] & 0xFF, ds_info->bksv[3] & 0xFF,
+		  ds_info->bksv[4] & 0xFF);
+
+	if (ds_info->is_repeater) {
+		igt_debug("\tHDCP sink is a Repeater\n");
+
+		igt_debug("\tDepth: %d, Device count: %d\n", ds_info->depth,
+			  ds_info->device_count);
+		ksvs = ds_info->ksv_list;
+
+		for (i = 0; i < ds_info->device_count; i++) {
+			igt_debug("\tksv-%d: %#04x %#04x %#04x %#04x %#04x\n", i,
+				  ksvs[0] & 0xFF, ksvs[1] & 0xFF,
+				  ksvs[2] & 0xFF, ksvs[3] & 0xFF,
+				  ksvs[4] & 0xFF);
+			ksvs += DRM_MODE_HDCP_KSV_LEN;
+		}
+	} else {
+		igt_debug("\tHDCP sink is a Receiver\n");
+	}
+}
+
+static void retrieve_downstream_info_prepare_srm(igt_output_t *output)
+{
+	drmModePropertyBlobRes *ds_info_prop = NULL;
+	uint64_t downstream_blob_id;
+	struct cp_downstream_info *ds_info;
+	int i;
+
+	igt_debug("CP_downstream_info property is attached\n");
+
+	downstream_blob_id =
+		igt_output_get_prop(output, IGT_CONNECTOR_CP_DOWNSTREAM_INFO);
+
+	igt_assert_f(downstream_blob_id, "Invalid downstream blob id\n");
+	ds_info_prop = drmModeGetPropertyBlob(data.drm_fd, downstream_blob_id);
+
+	igt_assert(ds_info_prop);
+	igt_assert_eq(ds_info_prop->length, sizeof(struct cp_downstream_info));
+	ds_info = ds_info_prop->data;
+
+	parse_downstream_info(ds_info);
+
+	for (i = 0; i < 5; i++)
+		facsimile_srm[i + 9] = ds_info->bksv[i];
+}
+
 static void flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
 			 unsigned int tv_usec, void *_data)
 {
@@ -164,7 +267,7 @@ static void modeset_with_fb(const enum pipe pipe, igt_output_t *output,
 }
 
 static bool test_cp_enable(igt_output_t *output, enum igt_commit_style s,
-			   int content_type)
+			   int content_type, bool test_srm)
 {
 	igt_display_t *display = &data.display;
 	igt_plane_t *primary;
@@ -172,6 +275,25 @@ static bool test_cp_enable(igt_output_t *output, enum igt_commit_style s,
 
 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
 
+	if (output->props[IGT_CONNECTOR_CP_SRM]) {
+		if (test_srm) {
+			igt_debug("CP_SRM property is updated with SRM\n");
+
+			/* Set SRM Blob to CR_SRM property */
+			igt_output_replace_prop_blob(output,
+						     IGT_CONNECTOR_CP_SRM,
+						     facsimile_srm,
+						     sizeof(facsimile_srm));
+		} else if (output->values[IGT_CONNECTOR_CP_SRM]) {
+			igt_debug("CP_SRM property is cleared\n");
+
+			/* Set SRM Blob to CR_SRM property */
+			igt_output_replace_prop_blob(output,
+						     IGT_CONNECTOR_CP_SRM,
+						     NULL, 0);
+		}
+	}
+
 	igt_output_set_prop_value(output,
 				  IGT_CONNECTOR_CONTENT_PROTECTION, CP_DESIRED);
 	if (output->props[IGT_CONNECTOR_CP_CONTENT_TYPE])
@@ -214,13 +336,14 @@ static void test_cp_disable(igt_output_t *output, enum igt_commit_style s)
 
 static void test_cp_enable_with_retry(igt_output_t *output,
 				      enum igt_commit_style s, int retry,
-				      int content_type, bool expect_failure)
+				      int content_type, bool expect_failure,
+				      bool test_srm)
 {
 	bool ret;
 
 	do {
 		test_cp_disable(output, s);
-		ret = test_cp_enable(output, s, content_type);
+		ret = test_cp_enable(output, s, content_type, test_srm);
 
 		if (!ret && --retry)
 			igt_debug("Retry (%d/2) ...\n", 3 - retry);
@@ -229,6 +352,9 @@ static void test_cp_enable_with_retry(igt_output_t *output,
 	if (expect_failure)
 		igt_assert_f(!ret,
 			     "CP Enabled. Though it is expected to fail\n");
+	else if (test_srm)
+		igt_assert_f(!ret,
+			     "CP Enabled. Though ID is revoked through SRM\n");
 	else
 		igt_assert_f(ret, "Content Protection not enabled\n");
 }
@@ -256,12 +382,12 @@ static void test_cp_lic(igt_output_t *output)
 static void
 test_content_protection_on_output(igt_output_t *output, enum igt_commit_style s,
 				  bool dpms_test, int content_type,
-				  bool mei_reload_test)
+				  bool mei_reload_test, bool test_srm)
 {
 	igt_display_t *display = &data.display;
 	igt_plane_t *primary;
 	enum pipe pipe;
-	bool ret;
+	bool ret, srm_modified = false;
 
 	for_each_pipe(display, pipe) {
 		if (!igt_pipe_connector_valid(pipe, output))
@@ -276,8 +402,10 @@ test_content_protection_on_output(igt_output_t *output, enum igt_commit_style s,
 		if (!igt_pipe_is_free(display, pipe))
 			continue;
 
+		srm_modified = false;
 		modeset_with_fb(pipe, output, s);
-		test_cp_enable_with_retry(output, s, 3, content_type, false);
+		test_cp_enable_with_retry(output, s, 3, content_type, false,
+					  false);
 
 		if (mei_reload_test) {
 			igt_assert_f(!igt_kmod_unload("mei_hdcp", 0),
@@ -297,6 +425,23 @@ test_content_protection_on_output(igt_output_t *output, enum igt_commit_style s,
 
 		test_cp_lic(output);
 
+		if (output->props[IGT_CONNECTOR_CP_DOWNSTREAM_INFO] &&
+		    output->props[IGT_CONNECTOR_CP_SRM] &&
+		    test_srm) {
+			retrieve_downstream_info_prepare_srm(output);
+			srm_modified = true;
+		}
+
+		if (test_srm && srm_modified) {
+			test_cp_disable(output, s);
+			test_cp_enable_with_retry(output, s, 3, content_type,
+						  false, test_srm);
+
+			/* Destroy the SRM Blob */
+			test_cp_enable_with_retry(output, s, 1, content_type,
+						  false, false);
+		}
+
 		if (dpms_test) {
 			igt_pipe_set_prop_value(display, pipe,
 						IGT_CRTC_ACTIVE, 0);
@@ -310,7 +455,8 @@ test_content_protection_on_output(igt_output_t *output, enum igt_commit_style s,
 						  KERNEL_AUTH_TIME_ALLOWED_MSEC);
 			if (!ret)
 				test_cp_enable_with_retry(output, s, 2,
-							  content_type, false);
+							  content_type, false,
+							  false);
 		}
 
 		test_cp_disable(output, s);
@@ -375,7 +521,8 @@ static bool sink_hdcp2_capable(igt_output_t *output)
 
 static void
 test_content_protection(enum igt_commit_style s, bool dpms_test,
-			int content_type, bool mei_reload_test)
+			int content_type, bool mei_reload_test,
+			bool test_srm)
 {
 	igt_display_t *display = &data.display;
 	igt_output_t *output;
@@ -407,7 +554,7 @@ test_content_protection(enum igt_commit_style s, bool dpms_test,
 
 		test_content_protection_on_output(output, s, dpms_test,
 						  content_type,
-						  mei_reload_test);
+						  mei_reload_test, test_srm);
 		valid_tests++;
 	}
 
@@ -426,30 +573,56 @@ igt_main
 
 	igt_subtest("legacy")
 		test_content_protection(COMMIT_LEGACY, false, CP_TYPE_0,
-					false);
+					false, false);
 
 	igt_subtest("atomic") {
 		igt_require(data.display.is_atomic);
 		test_content_protection(COMMIT_ATOMIC, false, CP_TYPE_0,
-					false);
+					false, false);
 	}
 
 	igt_subtest("atomic-dpms") {
 		igt_require(data.display.is_atomic);
 		test_content_protection(COMMIT_ATOMIC, true, CP_TYPE_0,
-					false);
+					false, false);
 	}
 
 	igt_subtest("Type1") {
 		igt_require(data.display.is_atomic);
 		test_content_protection(COMMIT_ATOMIC, false, CP_TYPE_1,
-					false);
+					false, false);
 	}
 
 	igt_subtest("type1_mei_interface") {
 		igt_require(data.display.is_atomic);
 		test_content_protection(COMMIT_ATOMIC, false, CP_TYPE_1,
-					true);
+					true, false);
+	}
+
+	/*
+	 * SRM subtest perform the HDCP authentication, and then retrieve the
+	 * receiver id through downstream info.
+	 *
+	 * Using the receiver ID, facsimile SRM table is modified with
+	 * receiver ID retrieved from the downstream info. After modification
+	 * SRM table is not intact as per DCP Signature.
+	 *
+	 * But Kernel believes userspace and doesn't verify the DCP signature.
+	 * So we can exploite that trust to test the SRM and downstream info
+	 * features.
+	 *
+	 * So when modified SRM is applied Authentication will fail due to
+	 * receiver ID revocation.
+	 *
+	 * And Kernel attempts HDCP2.2 always and on failure of it HDCP1.4
+	 * will be attempted. But their ID of the sink varies between 1.4 and
+	 * 2.2 versions. So we need to stick to one version. Hence HDCP2.2 is
+	 * chosen using Type 1.
+	 */
+	igt_subtest("srm") {
+		igt_require(data.display.is_atomic);
+		test_content_protection(COMMIT_ATOMIC, false, CP_TYPE_1,
+					false, true);
 	}
 
 	igt_fixture
-- 
2.7.4

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

  parent reply	other threads:[~2019-02-26  7:29 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-26  7:23 [igt-dev] [PATCH i-g-t 0/4] Coverage for HDCP2.2 Phase II Ramalingam C
2019-02-26  7:23 ` [igt-dev] [PATCH i-g-t 1/4] kms_content_protection: Content type support Ramalingam C
2019-02-26  7:23 ` [igt-dev] [PATCH i-g-t 2/4] kms_content_protection: test teardown and rebuild of I915-mei I/F Ramalingam C
2019-02-27 10:22   ` C, Ramalingam
2019-02-26  7:23 ` Ramalingam C [this message]
2019-02-26  7:23 ` [igt-dev] [PATCH i-g-t 4/4] DO NOT MERGE: CP in fast feedback list Ramalingam C
2019-02-26  8:15 ` [igt-dev] ✓ Fi.CI.BAT: success for Coverage for HDCP2.2 Phase II Patchwork
2019-02-26  9:49 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1551165805-19130-4-git-send-email-ramalingam.c@intel.com \
    --to=ramalingam.c@intel.com \
    --cc=daniel.vetter@ffwll.ch \
    --cc=igt-dev@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.