>-----Original Message----- >From: C, Ramalingam >Sent: Thursday, January 31, 2019 12:29 PM >To: intel-gfx@xxxxxxxxxxxxxxxxxxxxx; dri-devel@xxxxxxxxxxxxxxxxxxxxx; >daniel.vetter@xxxxxxxx; Winkler, Tomas <tomas.winkler@xxxxxxxxx>; Shankar, >Uma <uma.shankar@xxxxxxxxx> >Cc: C, Ramalingam <ramalingam.c@xxxxxxxxx> >Subject: [PATCH v10 09/40] drm/i915: Implement HDCP2.2 receiver >authentication > >Implements HDCP2.2 authentication for hdcp2.2 receivers, with following steps: > Authentication and Key exchange (AKE). > Locality Check (LC). > Session Key Exchange(SKE). > DP Errata for stream type configuration for receivers. > >At AKE, the HDCP Receiver’s public key certificate is verified by the HDCP >Transmitter. A Master Key k m is exchanged. > >At LC, the HDCP Transmitter enforces locality on the content by requiring that the >Round Trip Time (RTT) between a pair of messages is not more than 20 ms. > >At SKE, The HDCP Transmitter exchanges Session Key ks with the HDCP Receiver. > >In DP HDCP2.2 encryption and decryption logics use the stream type as one of the >parameter. So Before enabling the Encryption DP HDCP2.2 receiver needs to be >communicated with stream type. This is added to spec as ERRATA. > >This generic implementation is complete only with the hdcp2 specific functions >defined at hdcp_shim. > >v2: Rebased. >v3: > %s/PARING/PAIRING > Coding style fixing [Uma] >v4: > Rebased as part of patch reordering. > Defined the functions for mei services. [Daniel] >v5: > Redefined the mei service functions as per comp redesign. > Required intel_hdcp members are defined [Sean Paul] >v6: > Typo of cipher is Fixed [Uma] > %s/uintxx_t/uxx > Check for comp_master is removed. >v7: > Adjust to the new interface. > Avoid using bool structure members. [Tomas] >v8: Rebased. >v9: > bool is used in struct intel_hdcp [Daniel] > config_stream_type is redesigned [Daniel] > >Signed-off-by: Ramalingam C <ramalingam.c@xxxxxxxxx> >Reviewed-by: Daniel Vetter <daniel.vetter@xxxxxxxx> Looks ok to me. Reviewed-by: Uma Shankar <uma.shankar@xxxxxxxxx> >--- > drivers/gpu/drm/i915/intel_drv.h | 34 +++++++ >drivers/gpu/drm/i915/intel_hdcp.c | 197 >+++++++++++++++++++++++++++++++++++--- > 2 files changed, 216 insertions(+), 15 deletions(-) > >diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h >index 31c7a4577ca9..e6792304520a 100644 >--- a/drivers/gpu/drm/i915/intel_drv.h >+++ b/drivers/gpu/drm/i915/intel_drv.h >@@ -393,6 +393,22 @@ struct intel_hdcp_shim { > /* Detects whether Panel is HDCP2.2 capable */ > int (*hdcp_2_2_capable)(struct intel_digital_port *intel_dig_port, > bool *capable); >+ >+ /* Write HDCP2.2 messages */ >+ int (*write_2_2_msg)(struct intel_digital_port *intel_dig_port, >+ void *buf, size_t size); >+ >+ /* Read HDCP2.2 messages */ >+ int (*read_2_2_msg)(struct intel_digital_port *intel_dig_port, >+ u8 msg_id, void *buf, size_t size); >+ >+ /* >+ * Implementation of DP HDCP2.2 Errata for the communication of >stream >+ * type to Receivers. In DP HDCP2.2 Stream type is one of the input to >+ * the HDCP2.2 Cipher for En/De-Cryption. Not applicable for HDMI. >+ */ >+ int (*config_stream_type)(struct intel_digital_port *intel_dig_port, >+ bool is_repeater, u8 type); > }; > > struct intel_hdcp { >@@ -420,6 +436,24 @@ struct intel_hdcp { > */ > u8 content_type; > struct hdcp_port_data port_data; >+ >+ bool is_paired; >+ bool is_repeater; >+ >+ /* >+ * Count of ReceiverID_List received. Initialized to 0 at AKE_INIT. >+ * Incremented after processing the RepeaterAuth_Send_ReceiverID_List. >+ * When it rolls over re-auth has to be triggered. >+ */ >+ u32 seq_num_v; >+ >+ /* >+ * Count of RepeaterAuth_Stream_Manage msg propagated. >+ * Initialized to 0 on AKE_INIT. Incremented after every successful >+ * transmission of RepeaterAuth_Stream_Manage message. When it rolls >+ * over re-Auth has to be triggered. >+ */ >+ u32 seq_num_m; > }; > > struct intel_connector { >diff --git a/drivers/gpu/drm/i915/intel_hdcp.c >b/drivers/gpu/drm/i915/intel_hdcp.c >index fbf8b7893bfa..1c81e17dc6c4 100644 >--- a/drivers/gpu/drm/i915/intel_hdcp.c >+++ b/drivers/gpu/drm/i915/intel_hdcp.c >@@ -17,6 +17,7 @@ > > #define KEY_LOAD_TRIES 5 > #define ENCRYPT_STATUS_CHANGE_TIMEOUT_MS 50 >+#define HDCP2_LC_RETRY_CNT 3 > > static > bool intel_hdcp_is_ksv_valid(u8 *ksv) >@@ -853,7 +854,7 @@ bool is_hdcp_supported(struct drm_i915_private >*dev_priv, enum port port) > return INTEL_GEN(dev_priv) >= 9 && port < PORT_E; } > >-static __attribute__((unused)) int >+static int > hdcp2_prepare_ake_init(struct intel_connector *connector, > struct hdcp2_ake_init *ake_data) { @@ -878,7 +879,7 @@ >hdcp2_prepare_ake_init(struct intel_connector *connector, > return ret; > } > >-static __attribute__((unused)) int >+static int > hdcp2_verify_rx_cert_prepare_km(struct intel_connector *connector, > struct hdcp2_ake_send_cert *rx_cert, > bool *paired, >@@ -908,9 +909,8 @@ hdcp2_verify_rx_cert_prepare_km(struct intel_connector >*connector, > return ret; > } > >-static __attribute__((unused)) int >-hdcp2_verify_hprime(struct intel_connector *connector, >- struct hdcp2_ake_send_hprime *rx_hprime) >+static int hdcp2_verify_hprime(struct intel_connector *connector, >+ struct hdcp2_ake_send_hprime *rx_hprime) > { > struct hdcp_port_data *data = &connector->hdcp.port_data; > struct drm_i915_private *dev_priv = to_i915(connector->base.dev); @@ >-933,7 +933,7 @@ hdcp2_verify_hprime(struct intel_connector *connector, > return ret; > } > >-static __attribute__((unused)) int >+static int > hdcp2_store_pairing_info(struct intel_connector *connector, > struct hdcp2_ake_send_pairing_info *pairing_info) { >@@ -958,7 +958,7 @@ hdcp2_store_pairing_info(struct intel_connector >*connector, > return ret; > } > >-static __attribute__((unused)) int >+static int > hdcp2_prepare_lc_init(struct intel_connector *connector, > struct hdcp2_lc_init *lc_init) > { >@@ -983,7 +983,7 @@ hdcp2_prepare_lc_init(struct intel_connector >*connector, > return ret; > } > >-static __attribute__((unused)) int >+static int > hdcp2_verify_lprime(struct intel_connector *connector, > struct hdcp2_lc_send_lprime *rx_lprime) { @@ -1008,9 >+1008,8 @@ hdcp2_verify_lprime(struct intel_connector *connector, > return ret; > } > >-static __attribute__((unused)) >-int hdcp2_prepare_skey(struct intel_connector *connector, >- struct hdcp2_ske_send_eks *ske_data) >+static int hdcp2_prepare_skey(struct intel_connector *connector, >+ struct hdcp2_ske_send_eks *ske_data) > { > struct hdcp_port_data *data = &connector->hdcp.port_data; > struct drm_i915_private *dev_priv = to_i915(connector->base.dev); @@ >-1087,8 +1086,7 @@ hdcp2_verify_mprime(struct intel_connector *connector, > return ret; > } > >-static __attribute__((unused)) >-int hdcp2_authenticate_port(struct intel_connector *connector) >+static int hdcp2_authenticate_port(struct intel_connector *connector) > { > struct hdcp_port_data *data = &connector->hdcp.port_data; > struct drm_i915_private *dev_priv = to_i915(connector->base.dev); @@ >-1137,11 +1135,180 @@ static int hdcp2_deauthenticate_port(struct >intel_connector *connector) > return hdcp2_close_mei_session(connector); > } > >+/* Authentication flow starts from here */ static int >+hdcp2_authentication_key_exchange(struct intel_connector *connector) { >+ struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); >+ struct intel_hdcp *hdcp = &connector->hdcp; >+ union { >+ struct hdcp2_ake_init ake_init; >+ struct hdcp2_ake_send_cert send_cert; >+ struct hdcp2_ake_no_stored_km no_stored_km; >+ struct hdcp2_ake_send_hprime send_hprime; >+ struct hdcp2_ake_send_pairing_info pairing_info; >+ } msgs; >+ const struct intel_hdcp_shim *shim = hdcp->shim; >+ size_t size; >+ int ret; >+ >+ /* Init for seq_num */ >+ hdcp->seq_num_v = 0; >+ hdcp->seq_num_m = 0; >+ >+ ret = hdcp2_prepare_ake_init(connector, &msgs.ake_init); >+ if (ret < 0) >+ return ret; >+ >+ ret = shim->write_2_2_msg(intel_dig_port, &msgs.ake_init, >+ sizeof(msgs.ake_init)); >+ if (ret < 0) >+ return ret; >+ >+ ret = shim->read_2_2_msg(intel_dig_port, HDCP_2_2_AKE_SEND_CERT, >+ &msgs.send_cert, sizeof(msgs.send_cert)); >+ if (ret < 0) >+ return ret; >+ >+ if (msgs.send_cert.rx_caps[0] != HDCP_2_2_RX_CAPS_VERSION_VAL) >+ return -EINVAL; >+ >+ hdcp->is_repeater = >HDCP_2_2_RX_REPEATER(msgs.send_cert.rx_caps[2]); >+ >+ /* >+ * Here msgs.no_stored_km will hold msgs corresponding to the km >+ * stored also. >+ */ >+ ret = hdcp2_verify_rx_cert_prepare_km(connector, &msgs.send_cert, >+ &hdcp->is_paired, >+ &msgs.no_stored_km, &size); >+ if (ret < 0) >+ return ret; >+ >+ ret = shim->write_2_2_msg(intel_dig_port, &msgs.no_stored_km, size); >+ if (ret < 0) >+ return ret; >+ >+ ret = shim->read_2_2_msg(intel_dig_port, >HDCP_2_2_AKE_SEND_HPRIME, >+ &msgs.send_hprime, >sizeof(msgs.send_hprime)); >+ if (ret < 0) >+ return ret; >+ >+ ret = hdcp2_verify_hprime(connector, &msgs.send_hprime); >+ if (ret < 0) >+ return ret; >+ >+ if (!hdcp->is_paired) { >+ /* Pairing is required */ >+ ret = shim->read_2_2_msg(intel_dig_port, >+ HDCP_2_2_AKE_SEND_PAIRING_INFO, >+ &msgs.pairing_info, >+ sizeof(msgs.pairing_info)); >+ if (ret < 0) >+ return ret; >+ >+ ret = hdcp2_store_pairing_info(connector, &msgs.pairing_info); >+ if (ret < 0) >+ return ret; >+ hdcp->is_paired = true; >+ } >+ >+ return 0; >+} >+ >+static int hdcp2_locality_check(struct intel_connector *connector) { >+ struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); >+ struct intel_hdcp *hdcp = &connector->hdcp; >+ union { >+ struct hdcp2_lc_init lc_init; >+ struct hdcp2_lc_send_lprime send_lprime; >+ } msgs; >+ const struct intel_hdcp_shim *shim = hdcp->shim; >+ int tries = HDCP2_LC_RETRY_CNT, ret, i; >+ >+ for (i = 0; i < tries; i++) { >+ ret = hdcp2_prepare_lc_init(connector, &msgs.lc_init); >+ if (ret < 0) >+ continue; >+ >+ ret = shim->write_2_2_msg(intel_dig_port, &msgs.lc_init, >+ sizeof(msgs.lc_init)); >+ if (ret < 0) >+ continue; >+ >+ ret = shim->read_2_2_msg(intel_dig_port, >+ HDCP_2_2_LC_SEND_LPRIME, >+ &msgs.send_lprime, >+ sizeof(msgs.send_lprime)); >+ if (ret < 0) >+ continue; >+ >+ ret = hdcp2_verify_lprime(connector, &msgs.send_lprime); >+ if (!ret) >+ break; >+ } >+ >+ return ret; >+} >+ >+static int hdcp2_session_key_exchange(struct intel_connector >+*connector) { >+ struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); >+ struct intel_hdcp *hdcp = &connector->hdcp; >+ struct hdcp2_ske_send_eks send_eks; >+ int ret; >+ >+ ret = hdcp2_prepare_skey(connector, &send_eks); >+ if (ret < 0) >+ return ret; >+ >+ ret = hdcp->shim->write_2_2_msg(intel_dig_port, &send_eks, >+ sizeof(send_eks)); >+ if (ret < 0) >+ return ret; >+ >+ return 0; >+} >+ > static int hdcp2_authenticate_sink(struct intel_connector *connector) { >- DRM_ERROR("Sink authentication is done in subsequent patches\n"); >+ struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); >+ struct intel_hdcp *hdcp = &connector->hdcp; >+ const struct intel_hdcp_shim *shim = hdcp->shim; >+ int ret; > >- return -EINVAL; >+ ret = hdcp2_authentication_key_exchange(connector); >+ if (ret < 0) { >+ DRM_DEBUG_KMS("AKE Failed. Err : %d\n", ret); >+ return ret; >+ } >+ >+ ret = hdcp2_locality_check(connector); >+ if (ret < 0) { >+ DRM_DEBUG_KMS("Locality Check failed. Err : %d\n", ret); >+ return ret; >+ } >+ >+ ret = hdcp2_session_key_exchange(connector); >+ if (ret < 0) { >+ DRM_DEBUG_KMS("SKE Failed. Err : %d\n", ret); >+ return ret; >+ } >+ >+ if (shim->config_stream_type) { >+ ret = shim->config_stream_type(intel_dig_port, >+ hdcp->is_repeater, >+ hdcp->content_type); >+ if (ret < 0) >+ return ret; >+ } >+ >+ hdcp->port_data.streams[0].stream_type = hdcp->content_type; >+ ret = hdcp2_authenticate_port(connector); >+ if (ret < 0) >+ return ret; >+ >+ return ret; > } > > static int hdcp2_enable_encryption(struct intel_connector *connector) >-- >2.7.4 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx