[PATCH 12/43] misc/mei/hdcp: Verify Receiver Cert and prepare km

Ramalingam C
2018-02-14T14:20:19Z

Requests for verification for receiver certification and also the
preparation for next AKE auth message with km.

On Success ME FW validate the HDCP2.2 receivers certificate and do the
revocation check on the receiver ID. AKE_Stored_Km will be prepared if
the receiver is already paired, else AKE_No_Stored_Km will be prepared.

Here AKE_Stored_Km and AKE_No_Stored_Km are HDCP2.2 protocol msgs.

Signed-off-by: Ramalingam C <ramalingam.c@intel.com>
---
drivers/misc/mei/mei_hdcp.c | 89 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/mei_hdcp.h | 15 ++++++++
2 files changed, 104 insertions(+)

diff --git a/drivers/misc/mei/mei_hdcp.c b/drivers/misc/mei/mei_hdcp.c
index 0b09f069f6d6..536c27701fe8 100644
--- a/drivers/misc/mei/mei_hdcp.c
+++ b/drivers/misc/mei/mei_hdcp.c
@@ -119,6 +119,95 @@ int mei_initiate_hdcp2_session(struct mei_hdcp_data *data,
}
EXPORT_SYMBOL(mei_initiate_hdcp2_session);

+/**
+ * mei_verify_receiver_cert_prepare_km:
+ * Function to verify the Receiver Certificate AKE_Send_Cert
+ * and prepare AKE_Stored_Km or AKE_No_Stored_Km
+ *
+ * @data : Intel HW specific Data
+ * @rx_cert : Pointer for AKE_Send_Cert
+ * @km_stored : Pointer for pairing status flag
+ * @ek_pub_km : Pointer for output msg
+ * @msg_sz : Pointer for size of AKE_XXXXX_Km
+ *
+ * Returns 0 on Success, <0 on Failure
+ */
+int
+mei_verify_receiver_cert_prepare_km(struct mei_hdcp_data *data,
+ struct hdcp2_ake_send_cert *rx_cert,
+ bool *km_stored,
+ struct hdcp2_ake_no_stored_km *ek_pub_km,
+ size_t *msg_sz)
+{
+ struct wired_cmd_verify_receiver_cert_in verify_rxcert_in = { { 0 } };
+ struct wired_cmd_verify_receiver_cert_out verify_rxcert_out = { { 0 } };
+ enum me_status status;
+ struct device *dev;
+ ssize_t byte;
+
+ if (!data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz)
+ return -EINVAL;
+
+ /* check for the mei_device enabled or not */
+ if (!mei_cldev_active_and_enabled(data->cldev))
+ return -ENODEV;
+
+ dev = &data->cldev->dev;
+
+ /* Fill header details */
+ verify_rxcert_in.header.api_version = HDCP_API_VERSION;
+ verify_rxcert_in.header.command_id = WIRED_VERIFY_RECEIVER_CERT;
+ verify_rxcert_in.header.status = ME_HDCP_STATUS_SUCCESS;
+ verify_rxcert_in.header.buffer_len =
+ WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN;
+
+ /* Fill the data */
+ verify_rxcert_in.port.integrated_port_type = data->port_type;
+ verify_rxcert_in.port.physical_port = data->port;
+
+ memcpy(&verify_rxcert_in.cert_rx, &rx_cert->cert_rx,
+ sizeof(rx_cert->cert_rx));
+ memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, sizeof(rx_cert->r_rx));
+ verify_rxcert_in.rx_caps = rx_cert->rx_caps;
+
+ /* Request to ME */
+ byte = mei_cldev_send(data->cldev, (u8 *)&verify_rxcert_in,
+ sizeof(verify_rxcert_in));
+ if (byte < 0) {
+ dev_err(dev, "mei_cldev_send failed: %d\n", (int)byte);
+ return byte;
+ }
+
+ /* Response from ME */
+ byte = mei_cldev_recv(data->cldev, (u8 *)&verify_rxcert_out,
+ sizeof(verify_rxcert_out));
+ if (byte < 0) {
+ dev_err(dev, "mei_cldev_recv failed: %d\n", (int)byte);
+ return byte;
+ }
+
+ status = (enum me_status)verify_rxcert_out.header.status;
+ if (status != ME_HDCP_STATUS_SUCCESS) {
+ dev_err(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n",
+ WIRED_VERIFY_RECEIVER_CERT, status);
+ return -1;
+ }
+
+ *km_stored = verify_rxcert_out.km_stored;
+ if (verify_rxcert_out.km_stored) {
+ ek_pub_km->msg_id = AKE_STORED_KM;
+ *msg_sz = sizeof(struct hdcp2_ake_stored_km);
+ } else {
+ ek_pub_km->msg_id = AKE_NO_STORED_KM;
+ *msg_sz = sizeof(struct hdcp2_ake_no_stored_km);
+ }
+
+ memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff,
+ sizeof(verify_rxcert_out.ekm_buff));
+ return 0;
+}
+EXPORT_SYMBOL(mei_verify_receiver_cert_prepare_km);
+
static int mei_hdcp_probe(struct mei_cl_device *cldev,
const struct mei_cl_device_id *id)
{
diff --git a/include/linux/mei_hdcp.h b/include/linux/mei_hdcp.h
index c333528b9c1e..510a5c1ff1ff 100644
--- a/include/linux/mei_hdcp.h
+++ b/include/linux/mei_hdcp.h
@@ -105,6 +105,12 @@ void mei_hdcp_cldev_put_reference(struct mei_cl_device *cldev);

int mei_initiate_hdcp2_session(struct mei_hdcp_data *data,
struct hdcp2_ake_init *ake_data);
+int
+mei_verify_receiver_cert_prepare_km(struct mei_hdcp_data *data,
+ struct hdcp2_ake_send_cert *rx_cert,
+ bool *km_stored,
+ struct hdcp2_ake_no_stored_km *ek_pub_km,
+ size_t *msg_sz);
#else
static inline
int mei_hdcp_cldev_get_reference(void *client_data,
@@ -125,5 +131,14 @@ int mei_initiate_hdcp2_session(struct mei_hdcp_data *data,
{
return -ENODEV;
}
+static inline int
+mei_verify_receiver_cert_prepare_km(struct mei_hdcp_data *data,
+ struct hdcp2_ake_send_cert *rx_cert,
+ bool *km_stored,
+ struct hdcp2_ake_no_stored_km *ek_pub_km,
+ size_t *msg_sz)
+{
+ return -ENODEV;
+}
#endif /* defined (CONFIG_INTEL_MEI_HDCP) */
#endif /* defined (_LINUX_MEI_HDCP_H) */