[06/10] drm/i915: SRM parsing and revocation check for HDCP2

Submitted by Ramalingam C on Feb. 26, 2019, 7:36 a.m.

Details

Message ID 1551166569-19683-7-git-send-email-ramalingam.c@intel.com
State New
Headers show
Series "HDCP2.2 Phase II" ( rev: 1 ) in Intel GFX

Not browsing as part of any series.

Commit Message

Ramalingam C Feb. 26, 2019, 7:36 a.m.
SRM blob with hdcp2 id is parsed and parsed list of revoked ids is
used in the authentication process to identify the compromised HDCP
sinks.

Signed-off-by: Ramalingam C <ramalingam.c@intel.com>
---
 drivers/gpu/drm/i915/intel_hdcp.c | 86 +++++++++++++++++++++++++++++++++++++--
 include/drm/drm_hdcp.h            | 20 +++++++++
 2 files changed, 103 insertions(+), 3 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c
index 7d007de984d7..b92fc0383788 100644
--- a/drivers/gpu/drm/i915/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/intel_hdcp.c
@@ -1244,6 +1244,12 @@  static int hdcp2_authentication_key_exchange(struct intel_connector *connector)
 
 	hdcp->is_repeater = HDCP_2_2_RX_REPEATER(msgs.send_cert.rx_caps[2]);
 
+	if (intel_hdcp_ksvs_revocated(hdcp,
+				      msgs.send_cert.cert_rx.receiver_id, 1)) {
+		DRM_ERROR("Receiver ID is revocated\n");
+		return -EPERM;
+	}
+
 	/*
 	 * Here msgs.no_stored_km will hold msgs corresponding to the km
 	 * stored also.
@@ -1402,7 +1408,7 @@  int hdcp2_authenticate_repeater_topology(struct intel_connector *connector)
 	} msgs;
 	const struct intel_hdcp_shim *shim = hdcp->shim;
 	u8 *rx_info;
-	u32 seq_num_v;
+	u32 seq_num_v, device_cnt;
 	int ret;
 
 	ret = shim->read_2_2_msg(intel_dig_port, HDCP_2_2_REP_SEND_RECVID_LIST,
@@ -1427,6 +1433,14 @@  int hdcp2_authenticate_repeater_topology(struct intel_connector *connector)
 		return -EINVAL;
 	}
 
+	device_cnt = HDCP_2_2_DEV_COUNT_HI(rx_info[0]) << 4 ||
+			HDCP_2_2_DEV_COUNT_LO(rx_info[1]);
+	if (intel_hdcp_ksvs_revocated(hdcp, msgs.recvid_list.receiver_ids,
+				      device_cnt)) {
+		DRM_ERROR("Revoked receiver ID(s) is in list\n");
+		return -EPERM;
+	}
+
 	ret = hdcp2_verify_rep_topology_prepare_ack(connector,
 						    &msgs.recvid_list,
 						    &msgs.rep_ack);
@@ -1982,12 +1996,72 @@  static int intel_hdcp_parse_srm(struct drm_connector *connector,
 	return 0;
 }
 
+static int intel_hdcp2_parse_srm(struct drm_connector *connector,
+				 struct drm_property_blob *blob)
+{
+	struct intel_hdcp *hdcp = &(to_intel_connector(connector)->hdcp);
+	struct hdcp2_srm_header *header;
+	u32 vrl_length, ksv_count, ksv_sz;
+	u8 *buf;
+
+	if (blob->length < (sizeof(struct hdcp2_srm_header) +
+	    DRM_HDCP_2_VRL_LENGTH_SIZE + DRM_HDCP_2_DCP_SIG_SIZE)) {
+		DRM_ERROR("Invalid blob length\n");
+		return -EINVAL;
+	}
+
+	header = (struct hdcp2_srm_header *)blob->data;
+	DRM_DEBUG_KMS("SRM ID: 0x%x, SRM Ver: 0x%x, SRM Gen No: 0x%x\n",
+		      header->spec_indicator.srm_id,
+		      __swab16(header->srm_version), header->srm_gen_no);
+	WARN_ON(header->spec_indicator.reserved);
+	buf = blob->data + sizeof(*header);
+
+	vrl_length = (*buf << 16 | *(buf + 1) << 8 | *(buf + 2));
+	if (blob->length < (sizeof(struct hdcp2_srm_header) + vrl_length) ||
+	    vrl_length < (DRM_HDCP_2_VRL_LENGTH_SIZE +
+			  DRM_HDCP_2_DCP_SIG_SIZE)) {
+		DRM_ERROR("Invalid blob length or vrl length\n");
+		return -EINVAL;
+	}
+
+	/* Length of the all vrls combined */
+	vrl_length -= (DRM_HDCP_2_VRL_LENGTH_SIZE + DRM_HDCP_2_DCP_SIG_SIZE);
+	if (!vrl_length) {
+		DRM_ERROR("No vrl found\n");
+		return -EINVAL;
+	}
+
+	buf += DRM_HDCP_2_VRL_LENGTH_SIZE;
+	ksv_count = (*buf << 2) | DRM_HDCP_2_KSV_COUNT_2_LSBITS(*(buf + 1));
+	if (!ksv_count)
+		return 0;
+
+	kfree(hdcp->revocated_ksv_list);
+	hdcp->revocated_ksv_list = kzalloc(ksv_count * DRM_HDCP_KSV_LEN,
+					   GFP_KERNEL);
+	if (!hdcp->revocated_ksv_list) {
+		DRM_ERROR("Out of Memory\n");
+		return -ENOMEM;
+	}
+
+	ksv_sz = ksv_count * DRM_HDCP_KSV_LEN;
+	buf += DRM_HDCP_2_NO_OF_DEV_PLUS_RESERVED_SZ;
+
+	DRM_DEBUG_KMS("Revoked KSVs: %d\n", ksv_count);
+	memcpy(hdcp->revocated_ksv_list, buf, ksv_sz);
+	hdcp->revocated_ksv_cnt = ksv_count;
+
+	return 0;
+}
+
 static void intel_hdcp_update_srm(struct intel_connector *intel_connector,
 				  u32 srm_blob_id)
 {
 	struct drm_connector *connector = &intel_connector->base;
 	struct intel_hdcp *hdcp = &intel_connector->hdcp;
 	struct drm_property_blob *blob;
+	u8 srm_id;
 
 	DRM_DEBUG_KMS("srm_blob_id %u\n", srm_blob_id);
 
@@ -2002,8 +2076,14 @@  static void intel_hdcp_update_srm(struct intel_connector *intel_connector,
 	if (!blob || !blob->data)
 		return;
 
-	if (!intel_hdcp_parse_srm(connector, blob))
-		hdcp->srm_blob_id = srm_blob_id;
+	srm_id = *((u8 *)blob->data);
+	if (srm_id == DRM_HDCP_SRM_ID) {
+		if (!intel_hdcp_parse_srm(connector, blob))
+			hdcp->srm_blob_id = srm_blob_id;
+	} else if (srm_id == DRM_HDCP2_SRM_ID) {
+		if (!intel_hdcp2_parse_srm(connector, blob))
+			hdcp->srm_blob_id = srm_blob_id;
+	}
 
 	drm_property_blob_put(blob);
 }
diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h
index 1ccae47fcff5..1e630a593b73 100644
--- a/include/drm/drm_hdcp.h
+++ b/include/drm/drm_hdcp.h
@@ -279,4 +279,24 @@  struct hdcp_srm_header {
 	u8 srm_gen_no;
 } __packed;
 
+#define DRM_HDCP_2_SRM_ID			0x9
+#define DRM_HDCP_2_INDICATOR			0x1
+#define DRM_HDCP_2_VRL_LENGTH_SIZE		3
+#define DRM_HDCP_2_DCP_SIG_SIZE			384
+#define DRM_HDCP_2_NO_OF_DEV_PLUS_RESERVED_SZ	4
+
+#define DRM_HDCP_2_KSV_COUNT_2_LSBITS(byte)	(((byte) & 0xC) >> 6)
+#define DRM_HDCP_SRM_ID				0x80
+#define DRM_HDCP2_SRM_ID			0x91
+
+struct hdcp2_srm_header {
+	struct {
+		u8 hdcp2_indicator:4;
+		u8 srm_id:4;
+		u8 reserved;
+	} spec_indicator;
+	u16 srm_version;
+	u8 srm_gen_no;
+} __packed;
+
 #endif