From 47fc031576ffd1211fa893caaba42394e0714ff2 Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Wed, 27 Jan 2021 13:30:12 -0800 Subject: [PATCH 1/5] Include DRM key type to SessionMetrics. [ Merge of http://go/wvgerrit/111903 ] CDM metrics has been updated to include the DRM key type. The CDM session records the key type when the wrapped DRM key is successfully loaded into an OEMCrypto session. Now that the API refers to a general DRM key rather than an RSA key, the timer metric for loading the DRM key has been renamed on the client to reflect this. Test: Metric unit tests Bug: 140813486 Change-Id: I9069f13ac7c979cc8556e08591e1cf8f623d0a84 --- libwvdrmengine/cdm/core/src/cdm_session.cpp | 19 +++++++++++++++++-- .../cdm/core/src/crypto_session.cpp | 2 +- .../cdm/metrics/include/metrics_collections.h | 3 ++- .../cdm/metrics/src/metrics_collections.cpp | 6 ++++-- .../cdm/metrics/src/wv_metrics.proto | 8 ++++---- .../test/metrics_collections_unittest.cpp | 8 +++++--- .../src_hidl/hidl_metrics_adapter.cpp | 4 ++-- .../test/hidl_metrics_adapter_unittest.cpp | 2 +- libwvdrmengine/src_hidl/wv_metrics.cpp | 2 +- .../tools/metrics_dump/src/wv_metrics.cpp | 2 +- 10 files changed, 38 insertions(+), 18 deletions(-) diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index f993f5de..3091a723 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -38,6 +38,7 @@ return false; \ } +namespace wvcdm { namespace { const size_t kKeySetIdLength = 14; @@ -49,10 +50,22 @@ void SetErrorDetail(int* error_detail, T error_code) { } } +int DrmKeyTypeToMetricValue(CryptoWrappedKey::Type type) { + constexpr int kUnknownMetricType = -1; + constexpr int kRsaMetricType = 0; + constexpr int kEccMetricType = 1; + switch (type) { + case CryptoWrappedKey::kRsa: + return kRsaMetricType; + case CryptoWrappedKey::kEcc: + return kEccMetricType; + default: + LOGE("Unexpected DRM key type: %d", static_cast(type)); + return kUnknownMetricType; + } +} } // namespace -namespace wvcdm { - CdmSession::CdmSession(FileSystem* file_system, std::shared_ptr metrics) : metrics_(metrics), @@ -187,6 +200,8 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, load_cert_sts); switch (load_cert_sts) { case NO_ERROR: + metrics_->drm_certificate_key_type_.Record( + DrmKeyTypeToMetricValue(private_key.type())); break; case SESSION_LOST_STATE_ERROR: case SYSTEM_INVALIDATED_ERROR: diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 45a9baed..45a9f9ee 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -1300,7 +1300,7 @@ CdmResponseType CryptoSession::LoadCertificatePrivateKey( oec_session_id_, key_type, reinterpret_cast(wrapped_key.data()), wrapped_key.size()), - metrics_, oemcrypto_load_device_rsa_key_, sts); + metrics_, oemcrypto_load_device_drm_key_, sts); }); return MapOEMCryptoResult(sts, LOAD_DEVICE_RSA_KEY_ERROR, diff --git a/libwvdrmengine/cdm/metrics/include/metrics_collections.h b/libwvdrmengine/cdm/metrics/include/metrics_collections.h index ffa8a591..1f556d89 100644 --- a/libwvdrmengine/cdm/metrics/include/metrics_collections.h +++ b/libwvdrmengine/cdm/metrics/include/metrics_collections.h @@ -234,7 +234,7 @@ class CryptoMetrics { ValueMetric oemcrypto_is_anti_rollback_hw_present_; ValueMetric oemcrypto_is_keybox_valid_; EventMetric - oemcrypto_load_device_rsa_key_; + oemcrypto_load_device_drm_key_; EventMetric oemcrypto_load_entitled_keys_; EventMetric @@ -338,6 +338,7 @@ class SessionMetrics { ValueMetric license_sdk_version_; ValueMetric license_service_version_; ValueMetric playback_id_; + ValueMetric drm_certificate_key_type_; // Serialize the session metrics to the provided |metric_group|. // |metric_group| is owned by the caller and must not be null. diff --git a/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp b/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp index c2152052..8bc7fb63 100644 --- a/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp +++ b/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp @@ -140,8 +140,8 @@ void CryptoMetrics::Serialize(WvCdmMetrics::CryptoMetrics *crypto_metrics) oemcrypto_is_anti_rollback_hw_present_.ToProto()); crypto_metrics->set_allocated_oemcrypto_is_keybox_valid( oemcrypto_is_keybox_valid_.ToProto()); - oemcrypto_load_device_rsa_key_.ToProto( - crypto_metrics->mutable_oemcrypto_load_device_rsa_key_time_us()); + oemcrypto_load_device_drm_key_.ToProto( + crypto_metrics->mutable_oemcrypto_load_device_drm_key_time_us()); oemcrypto_load_entitled_keys_.ToProto( crypto_metrics->mutable_oemcrypto_load_entitled_keys_time_us()); oemcrypto_load_keys_.ToProto( @@ -247,6 +247,8 @@ void SessionMetrics::SerializeSessionMetrics( session_metrics->set_allocated_license_service_version( license_service_version_.ToProto()); session_metrics->set_allocated_playback_id(playback_id_.ToProto()); + session_metrics->set_allocated_drm_certificate_key_type( + drm_certificate_key_type_.ToProto()); } OemCryptoDynamicAdapterMetrics::OemCryptoDynamicAdapterMetrics() diff --git a/libwvdrmengine/cdm/metrics/src/wv_metrics.proto b/libwvdrmengine/cdm/metrics/src/wv_metrics.proto index ea97fdcc..5fc59717 100644 --- a/libwvdrmengine/cdm/metrics/src/wv_metrics.proto +++ b/libwvdrmengine/cdm/metrics/src/wv_metrics.proto @@ -155,7 +155,7 @@ message WvCdmMetrics { repeated DistributionMetric oemcrypto_initialize_time_us = 38; optional ValueMetric oemcrypto_is_anti_rollback_hw_present = 39; optional ValueMetric oemcrypto_is_keybox_valid = 40; - repeated DistributionMetric oemcrypto_load_device_rsa_key_time_us = 41; + repeated DistributionMetric oemcrypto_load_device_drm_key_time_us = 41; repeated DistributionMetric oemcrypto_load_entitled_keys_time_us = 42; repeated DistributionMetric oemcrypto_load_keys_time_us = 43; optional ValueMetric oemcrypto_max_hdcp_capability = 44; @@ -182,8 +182,6 @@ message WvCdmMetrics { optional ValueMetric oemcrypto_set_sandbox = 70; repeated CounterMetric oemcrypto_set_decrypt_hash = 71; optional ValueMetric oemcrypto_resource_rating_tier = 72; - // TODO(b/142684157): Remove this comment before closing bug. - // OemCrypto V16 metrics start at 77 (4 new metrics pending review). repeated DistributionMetric oemcrypto_prep_and_sign_license_request_time_us = 77; repeated DistributionMetric @@ -199,7 +197,7 @@ message WvCdmMetrics { // This contains metrics that were captured within a CdmSession. This contains // nested CryptoMetrics that were captured in the context of the session. - // next id: 9 + // next id: 13 message SessionMetrics { optional ValueMetric session_id = 1; optional CryptoMetrics crypto_metrics = 2; @@ -212,6 +210,8 @@ message WvCdmMetrics { optional ValueMetric license_sdk_version = 9; optional ValueMetric license_service_version = 10; optional ValueMetric playback_id = 11; + // Value is enumerated based on the OEMCrypto document: RSA = 0, ECC = 1 + optional ValueMetric drm_certificate_key_type = 12; } // These are metrics recorded at the Engine level. This includes CryptoSession diff --git a/libwvdrmengine/cdm/metrics/test/metrics_collections_unittest.cpp b/libwvdrmengine/cdm/metrics/test/metrics_collections_unittest.cpp index 156af527..069c2109 100644 --- a/libwvdrmengine/cdm/metrics/test/metrics_collections_unittest.cpp +++ b/libwvdrmengine/cdm/metrics/test/metrics_collections_unittest.cpp @@ -276,6 +276,7 @@ TEST_F(SessionMetricsTest, AllSessionMetrics) { session_metrics.oemcrypto_build_info_.Record("test build info"); session_metrics.license_sdk_version_.Record("test license sdk version"); session_metrics.license_service_version_.Record("test license service version"); + session_metrics.drm_certificate_key_type_.Record(1); // Record a CryptoMetrics metric in the session. session_metrics.GetCryptoMetrics()->crypto_session_generic_decrypt_ @@ -297,6 +298,7 @@ TEST_F(SessionMetricsTest, AllSessionMetrics) { actual.license_service_version().string_value().c_str()); EXPECT_GT( actual.crypto_metrics().crypto_session_generic_decrypt_time_us_size(), 0); + EXPECT_EQ(1, actual.drm_certificate_key_type().int_value()); } TEST_F(SessionMetricsTest, EmptySessionMetrics) { @@ -404,8 +406,8 @@ TEST_F(CryptoMetricsTest, AllCryptoMetrics) { .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); crypto_metrics.oemcrypto_is_anti_rollback_hw_present_.Record(true); crypto_metrics.oemcrypto_is_keybox_valid_.Record(true); - crypto_metrics.oemcrypto_load_device_rsa_key_ - .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); + crypto_metrics.oemcrypto_load_device_drm_key_.Record( + 1.0, OEMCrypto_ERROR_INIT_FAILED); crypto_metrics.oemcrypto_load_keys_.Record(1.0, OEMCrypto_ERROR_INIT_FAILED); crypto_metrics.oemcrypto_refresh_keys_ .Record(1.0, OEMCrypto_ERROR_INIT_FAILED); @@ -509,7 +511,7 @@ TEST_F(CryptoMetricsTest, AllCryptoMetrics) { EXPECT_GT(actual.oemcrypto_initialize_time_us_size(), 0); EXPECT_EQ(true, actual.oemcrypto_is_anti_rollback_hw_present().int_value()); EXPECT_EQ(true, actual.oemcrypto_is_keybox_valid().int_value()); - EXPECT_GT(actual.oemcrypto_load_device_rsa_key_time_us_size(), 0); + EXPECT_GT(actual.oemcrypto_load_device_drm_key_time_us_size(), 0); EXPECT_GT(actual.oemcrypto_load_keys_time_us_size(), 0); EXPECT_GT(actual.oemcrypto_refresh_keys_time_us_size(), 0); EXPECT_GT(actual.oemcrypto_report_usage_size(), 0); diff --git a/libwvdrmengine/mediadrm/src_hidl/hidl_metrics_adapter.cpp b/libwvdrmengine/mediadrm/src_hidl/hidl_metrics_adapter.cpp index 2e7dbe47..c770a669 100644 --- a/libwvdrmengine/mediadrm/src_hidl/hidl_metrics_adapter.cpp +++ b/libwvdrmengine/mediadrm/src_hidl/hidl_metrics_adapter.cpp @@ -570,8 +570,8 @@ void HidlMetricsAdapter::AddCryptoMetrics( proto_metrics.oemcrypto_is_keybox_valid()); } group_builder->AddDistributions( - "oemcrypto_load_device_rsa_key_time_us", - proto_metrics.oemcrypto_load_device_rsa_key_time_us()); + "oemcrypto_load_device_drm_key_time_us", + proto_metrics.oemcrypto_load_device_drm_key_time_us()); group_builder->AddDistributions( "oemcrypto_load_entitled_keys_time_us", proto_metrics.oemcrypto_load_entitled_keys_time_us()); diff --git a/libwvdrmengine/mediadrm/test/hidl_metrics_adapter_unittest.cpp b/libwvdrmengine/mediadrm/test/hidl_metrics_adapter_unittest.cpp index 525c0f8c..ef43174c 100644 --- a/libwvdrmengine/mediadrm/test/hidl_metrics_adapter_unittest.cpp +++ b/libwvdrmengine/mediadrm/test/hidl_metrics_adapter_unittest.cpp @@ -378,7 +378,7 @@ TEST(HidlMetricsAdapterTest, EngineAndSessionAllMetrics) { crypto_metrics.mutable_oemcrypto_is_anti_rollback_hw_present ()->set_int_value(1); crypto_metrics.mutable_oemcrypto_is_keybox_valid()->set_int_value(1); - crypto_metrics.add_oemcrypto_load_device_rsa_key_time_us()->set_min(1.0f); + crypto_metrics.add_oemcrypto_load_device_drm_key_time_us()->set_min(1.0f); crypto_metrics.add_oemcrypto_load_entitled_keys_time_us()->set_min(1.0f); crypto_metrics.add_oemcrypto_load_keys_time_us()->set_min(1.0f); crypto_metrics.mutable_oemcrypto_max_hdcp_capability()->set_int_value(1); diff --git a/libwvdrmengine/src_hidl/wv_metrics.cpp b/libwvdrmengine/src_hidl/wv_metrics.cpp index 8cdf171b..23a2f2ac 100644 --- a/libwvdrmengine/src_hidl/wv_metrics.cpp +++ b/libwvdrmengine/src_hidl/wv_metrics.cpp @@ -333,7 +333,7 @@ void FormatCryptoMetrics(const WvCdmMetrics_CryptoMetrics metrics, FORMAT_REPEATED_DISTRIBUTION(oemcrypto_initialize_time_us, indent); FORMAT_OPTIONAL_VALUE(oemcrypto_is_anti_rollback_hw_present, indent); FORMAT_OPTIONAL_VALUE(oemcrypto_is_keybox_valid, indent); - FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_device_rsa_key_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_device_drm_key_time_us, indent); FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_entitled_keys_time_us, indent); FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_keys_time_us, indent); FORMAT_OPTIONAL_HDCP_CAPABILITY(oemcrypto_max_hdcp_capability, indent); diff --git a/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp b/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp index aa494619..78d4980f 100644 --- a/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp +++ b/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp @@ -330,7 +330,7 @@ void FormatCryptoMetrics(const drm_metrics::WvCdmMetrics_CryptoMetrics metrics, FORMAT_REPEATED_DISTRIBUTION(oemcrypto_initialize_time_us, indent); FORMAT_OPTIONAL_VALUE(oemcrypto_is_anti_rollback_hw_present, indent); FORMAT_OPTIONAL_VALUE(oemcrypto_is_keybox_valid, indent); - FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_device_rsa_key_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_device_drm_key_time_us, indent); FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_entitled_keys_time_us, indent); FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_keys_time_us, indent); FORMAT_OPTIONAL_HDCP_CAPABILITY(oemcrypto_max_hdcp_capability, indent); From 5e982e8fff2b9e3a08d1b7ff89d1e2b653e699ff Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Wed, 27 Jan 2021 11:32:30 -0800 Subject: [PATCH 2/5] Updated DrmDeviceCertificate for signature algo. [ Merge of http://go/wvgerrit/110823 ] DrmDeviceCertificate is the CDM's reduced version of DrmCertificate used in the backend. With the introduction of ECC, the CDM needs to extract the signature algorithm to determine how to handle the wrapped private key used by OEMCrypto post-provisioning. This change brings the DrmDeviceCertificate in line with the provisioning service's DrmCertificate message as the new source of truth. Bug: 140813486 Test: Compiled proto Change-Id: I164a1c9266fb74b6cdd0ff35f1986ca032033bba (cherry picked from commit 667c672c8032926d663dfda93026f64c7f8dab84) Merged-In: I164a1c9266fb74b6cdd0ff35f1986ca032033bba --- .../cdm/core/src/license_protocol.proto | 78 ++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/libwvdrmengine/cdm/core/src/license_protocol.proto b/libwvdrmengine/cdm/core/src/license_protocol.proto index d2164e22..b5d0b3cc 100644 --- a/libwvdrmengine/cdm/core/src/license_protocol.proto +++ b/libwvdrmengine/cdm/core/src/license_protocol.proto @@ -758,13 +758,44 @@ message EncryptedClientIdentification { } // ---------------------------------------------------------------------------- -// device_certificate.proto +// Source of truth: drm_certificate.proto +// Formally: device_certificate.proto (of wv_drm_sdk) // ---------------------------------------------------------------------------- // Description of section: // Device certificate and certificate status list format definitions. +message RootOfTrustId { + // The version specifies the EC algorithm that was used to generate the + // root of trust id. + enum RootOfTrustIdVersion { + // Should not be used. + ROOT_OF_TRUST_ID_VERSION_UNSPECIFIED = 0; + // Version 1 of the ID uses EC-IES with SECP256R1 curve. + ROOT_OF_TRUST_ID_VERSION_1 = 1; + } + optional RootOfTrustIdVersion version = 1; + // The key_id is used for key rotation. It indicates which key was used to + // generate the root of trust id. + optional uint32 key_id = 2; + + // The EC-IES encrypted message containing the unique_id. The bytes are + // a concatenation of + // 1) The ephemeral public key. Uncompressed keypoint format per X9.62. + // 2) The plaintext encrypted with the derived AES key using AES CBC, + // PKCS7 padding and a zerio iv. + // 3) The HMAC SHA256 of the cipher text. + optional bytes encrypted_unique_id = 3; + + // The hash of encrypted unique id and other values. + // unique_id_hash = SHA256( + // encrypted_unique_id || system_id || SHA256(unique_id || secret_sauce)). + optional bytes unique_id_hash = 4; +} + // DRM certificate definition for user devices, intermediate, service, and root // certificates. +// DrmDeviceCertificate tracks the provisioning service's DrmCertificate, +// only including fields that are required by CDM devices. message DrmDeviceCertificate { enum CertificateType { ROOT = 0; @@ -773,6 +804,31 @@ message DrmDeviceCertificate { SERVICE = 3; PROVISIONER = 4; } + enum ServiceType { + UNKNOWN_SERVICE_TYPE = 0; + LICENSE_SERVER_SDK = 1; + LICENSE_SERVER_PROXY_SDK = 2; + PROVISIONING_SDK = 3; + CAS_PROXY_SDK = 4; + } + enum Algorithm { + UNKNOWN_ALGORITHM = 0; + RSA = 1; + ECC_SECP256R1 = 2; + ECC_SECP384R1 = 3; + ECC_SECP521R1 = 4; + } + + message EncryptionKey { + // Device public key. PKCS#1 ASN.1 DER-encoded. Required. + optional bytes public_key = 1; + // Required. The algorithm field contains the curve used to create the + // |public_key| if algorithm is one of the ECC types. + // The |algorithm| is used for both to determine the if the certificate is + // ECC or RSA. The |algorithm| also specifies the parameters that were used + // to create |public_key| and are used to create an ephemeral session key. + optional Algorithm algorithm = 2 [default = RSA]; + } // Type of certificate. Required. optional CertificateType type = 1; @@ -793,6 +849,26 @@ message DrmDeviceCertificate { // Service identifier (web origin) for the provider which owns the // certificate. Required for service and provisioner certificates. optional string provider_id = 7; + // This field is used only when type = SERVICE to specify which SDK uses + // service certificate. This repeated field is treated as a set. A certificate + // may be used for the specified service SDK if the appropriate ServiceType + // is specified in this field. + repeated ServiceType service_types = 8; + // Required. The algorithm field contains the curve used to create the + // |public_key| if algorithm is one of the ECC types. + // The |algorithm| is used for both to determine the if the certificate is ECC + // or RSA. The |algorithm| also specifies the parameters that were used to + // create |public_key| and are used to create an ephemeral session key. + optional Algorithm algorithm = 9 [default = RSA]; + // Optional. May be present in DEVICE certificate types. This is the root + // of trust identifier that holds an encrypted value that identifies the + // keybox or other root of trust that was used to provision a DEVICE drm + // certificate. + optional RootOfTrustId rot_id = 10; + // Optional. May be present in devices that explicitly support dual keys. When + // present the |public_key| is used for verification of received license + // request messages. + optional EncryptionKey encryption_key = 11; } // DeviceCertificate signed with intermediate or root certificate private key. From e70c7a116eaa1922de45b4ee0047eb0859f88b9a Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Wed, 27 Jan 2021 11:37:21 -0800 Subject: [PATCH 3/5] Report OEMCrypto's ECC capabilities. [ Merge of http://go/wvgerrit/110824 ] When generating a provisioning request, the CDM includes the different certificate key types that are supported. This change will enable the reporting of ECC certificate types if OEMCrypto supports them. Test: Linux unit tests and Android integration test Bug: 140813486 Change-Id: I713ff1c469dff5c8a41461727ce63486d962575e (cherry picked from commit 547d2f8775b04984a1826438933cee713b892b4c) Merged-In: I713ff1c469dff5c8a41461727ce63486d962575e --- .../cdm/core/include/crypto_session.h | 3 + .../cdm/core/src/client_identification.cpp | 69 +++++++++---------- .../cdm/core/src/crypto_session.cpp | 12 ++-- .../cdm/core/test/license_unittest.cpp | 67 +++++++++--------- 4 files changed, 78 insertions(+), 73 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index b9a56391..d5907dcc 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -54,6 +54,9 @@ class CryptoSession { bool rsa_2048_bit; bool rsa_3072_bit; bool rsa_cast; + bool ecc_secp256r1; + bool ecc_secp384r1; + bool ecc_secp521r1; }; // Creates an instance of CryptoSession with the given |crypto_metrics|. diff --git a/libwvdrmengine/cdm/core/src/client_identification.cpp b/libwvdrmengine/cdm/core/src/client_identification.cpp index a3404297..519fdf39 100644 --- a/libwvdrmengine/cdm/core/src/client_identification.cpp +++ b/libwvdrmengine/cdm/core/src/client_identification.cpp @@ -56,7 +56,9 @@ bool IsPropertyKeyReserved(const std::string& prop_name) { } // namespace // Protobuf generated classes. -using video_widevine::ClientIdentification_ClientCapabilities; +using ClientCapabilities = + video_widevine::ClientIdentification::ClientCapabilities; +using AnalogOutputCapabilities = ClientCapabilities::AnalogOutputCapabilities; using video_widevine::ClientIdentification_NameValue; using video_widevine::EncryptedClientIdentification; using video_widevine::ProvisioningOptions; @@ -187,7 +189,7 @@ CdmResponseType ClientIdentification::Prepare( client_id->set_provider_client_token(provider_client_token); } - ClientIdentification_ClientCapabilities* client_capabilities = + ClientCapabilities* client_capabilities = client_id->mutable_client_capabilities(); client_capabilities->set_client_token(true); @@ -214,38 +216,31 @@ CdmResponseType ClientIdentification::Prepare( switch (max_version) { case HDCP_NONE: client_capabilities->set_max_hdcp_version( - video_widevine:: - ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_NONE); + ClientCapabilities::HDCP_NONE); break; case HDCP_V1: client_capabilities->set_max_hdcp_version( - video_widevine:: - ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V1); + ClientCapabilities::HDCP_V1); break; case HDCP_V2: client_capabilities->set_max_hdcp_version( - video_widevine:: - ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2); + ClientCapabilities::HDCP_V2); break; case HDCP_V2_1: client_capabilities->set_max_hdcp_version( - video_widevine:: - ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_1); + ClientCapabilities::HDCP_V2_1); break; case HDCP_V2_2: client_capabilities->set_max_hdcp_version( - video_widevine:: - ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_2); + ClientCapabilities::HDCP_V2_2); break; case HDCP_V2_3: client_capabilities->set_max_hdcp_version( - video_widevine:: - ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_3); + ClientCapabilities::HDCP_V2_3); break; case HDCP_NO_DIGITAL_OUTPUT: client_capabilities->set_max_hdcp_version( - video_widevine:: - ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_NO_DIGITAL_OUTPUT); + ClientCapabilities::HDCP_NO_DIGITAL_OUTPUT); break; default: LOGW("Unexpected HDCP max capability version: max_version = %d", @@ -258,13 +253,23 @@ CdmResponseType ClientIdentification::Prepare( if (crypto_session_->GetSupportedCertificateTypes(&supported_certs)) { if (supported_certs.rsa_2048_bit) { client_capabilities->add_supported_certificate_key_type( - video_widevine:: - ClientIdentification_ClientCapabilities_CertificateKeyType_RSA_2048); + ClientCapabilities::RSA_2048); } if (supported_certs.rsa_3072_bit) { client_capabilities->add_supported_certificate_key_type( - video_widevine:: - ClientIdentification_ClientCapabilities_CertificateKeyType_RSA_3072); + ClientCapabilities::RSA_3072); + } + if (supported_certs.ecc_secp256r1) { + client_capabilities->add_supported_certificate_key_type( + ClientCapabilities::ECC_SECP256R1); + } + if (supported_certs.ecc_secp384r1) { + client_capabilities->add_supported_certificate_key_type( + ClientCapabilities::ECC_SECP384R1); + } + if (supported_certs.ecc_secp521r1) { + client_capabilities->add_supported_certificate_key_type( + ClientCapabilities::ECC_SECP521R1); } } @@ -280,33 +285,27 @@ CdmResponseType ClientIdentification::Prepare( bool can_support_cgms_a; if (crypto_session_->GetAnalogOutputCapabilities( &can_support_output, &can_disable_output, &can_support_cgms_a)) { - video_widevine::ClientIdentification_ClientCapabilities_AnalogOutputCapabilities - capabilities = video_widevine:: - ClientIdentification_ClientCapabilities_AnalogOutputCapabilities_ANALOG_OUTPUT_NONE; + AnalogOutputCapabilities capabilities = + ClientCapabilities::ANALOG_OUTPUT_NONE; if (can_support_output) { if (can_support_cgms_a) { - capabilities = video_widevine:: - ClientIdentification_ClientCapabilities_AnalogOutputCapabilities_ANALOG_OUTPUT_SUPPORTS_CGMS_A; + capabilities = ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A; } else { - capabilities = video_widevine:: - ClientIdentification_ClientCapabilities_AnalogOutputCapabilities_ANALOG_OUTPUT_SUPPORTED; + capabilities = ClientCapabilities::ANALOG_OUTPUT_SUPPORTED; } } client_capabilities->set_analog_output_capabilities(capabilities); client_capabilities->set_can_disable_analog_output(can_disable_output); } else { client_capabilities->set_analog_output_capabilities( - video_widevine:: - ClientIdentification_ClientCapabilities_AnalogOutputCapabilities_ANALOG_OUTPUT_UNKNOWN); + ClientCapabilities::ANALOG_OUTPUT_UNKNOWN); } - uint32_t version, tier; - if (crypto_session_->GetApiVersion(&version)) { - if (version >= OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER) { - if (crypto_session_->GetResourceRatingTier(&tier)) { - client_capabilities->set_resource_rating_tier(tier); - } + if (api_version >= OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER) { + uint32_t tier; + if (crypto_session_->GetResourceRatingTier(&tier)) { + client_capabilities->set_resource_rating_tier(tier); } } diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 43509f23..97e9a144 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -1888,14 +1888,16 @@ bool CryptoSession::GetSupportedCertificateTypes( LOGV("Getting supported certificate types: id = %u", oec_session_id_); RETURN_IF_UNINITIALIZED(false); RETURN_IF_NULL(support, false); - - uint32_t oec_support; - WithOecReadLock("GetSupportedCertificateTypes", [&] { - oec_support = OEMCrypto_SupportedCertificates(requested_security_level_); - }); + const uint32_t oec_support = + WithOecReadLock("GetSupportedCertificateTypes", [&] { + return OEMCrypto_SupportedCertificates(requested_security_level_); + }); support->rsa_2048_bit = oec_support & OEMCrypto_Supports_RSA_2048bit; support->rsa_3072_bit = oec_support & OEMCrypto_Supports_RSA_3072bit; support->rsa_cast = oec_support & OEMCrypto_Supports_RSA_CAST; + support->ecc_secp256r1 = oec_support & OEMCrypto_Supports_ECC_secp256r1; + support->ecc_secp384r1 = oec_support & OEMCrypto_Supports_ECC_secp384r1; + support->ecc_secp521r1 = oec_support & OEMCrypto_Supports_ECC_secp521r1; return true; } diff --git a/libwvdrmengine/cdm/core/test/license_unittest.cpp b/libwvdrmengine/cdm/core/test/license_unittest.cpp index 84e39dff..cf22f709 100644 --- a/libwvdrmengine/cdm/core/test/license_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/license_unittest.cpp @@ -116,7 +116,10 @@ const std::string kLicenseRequestSignature = a2bs_hex( const std::string kFakeCoreMessage = a2bs_hex("DEADBEEF"); const CryptoSession::SupportedCertificateTypes kDefaultSupportedCertTypes = { - true, true, true}; + /* RSA 2048 */ true, /* RSA 3072 */ true, + /* RSA CAST */ false, + /* ECC 256 */ true, /* ECC 384 */ true, + /* ECC 521 */ true}; const std::string kFakeEntitlementKeyId = a2bs_hex("2a538231c616c67143032a645f9c545d"); @@ -171,6 +174,8 @@ class MockInitializationData : public InitializationData { } // namespace // Protobuf generated classes +using ClientCapabilities = + video_widevine::ClientIdentification::ClientCapabilities; using video_widevine::ClientIdentification; using video_widevine::License; using video_widevine::License_KeyContainer; @@ -304,7 +309,7 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { bool usage_information_support = true; CryptoSession::HdcpCapability current_hdcp_version = HDCP_NO_DIGITAL_OUTPUT; CryptoSession::HdcpCapability max_hdcp_version = HDCP_V2_1; - uint32_t crypto_session_api_version = 9; + const uint32_t crypto_session_api_version = 16; EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true)); EXPECT_CALL(*crypto_session_, request_id()) @@ -315,10 +320,10 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { EXPECT_CALL(*crypto_session_, GetHdcpCapabilities(NotNull(), NotNull())) .WillOnce(DoAll(SetArgPointee<0>(current_hdcp_version), SetArgPointee<1>(max_hdcp_version), Return(NO_ERROR))); + // Supported certificates set by SetUp(). EXPECT_CALL(*crypto_session_, GetSupportedCertificateTypes(NotNull())); EXPECT_CALL(*crypto_session_, GetApiVersion(NotNull())) - .Times(2) - .WillRepeatedly( + .WillOnce( DoAll(SetArgPointee<0>(crypto_session_api_version), Return(true))); EXPECT_CALL(*clock_, GetCurrentTime()).WillOnce(Return(kLicenseStartTime)); EXPECT_CALL(*crypto_session_, GenerateNonce(NotNull())) @@ -379,24 +384,22 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { EXPECT_FALSE(client_id.has_provider_client_token()); EXPECT_FALSE(client_id.has_license_counter()); - const ::video_widevine::ClientIdentification_ClientCapabilities& - client_capabilities = client_id.client_capabilities(); + const ClientCapabilities& client_capabilities = + client_id.client_capabilities(); EXPECT_TRUE(client_capabilities.has_client_token()); EXPECT_TRUE(client_capabilities.has_session_token()); EXPECT_FALSE(client_capabilities.video_resolution_constraints()); - EXPECT_EQ(video_widevine:: - ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_1, + EXPECT_EQ(ClientCapabilities::HDCP_V2_1, client_capabilities.max_hdcp_version()); EXPECT_EQ(crypto_session_api_version, client_capabilities.oem_crypto_api_version()); - EXPECT_THAT( - client_capabilities.supported_certificate_key_type(), - UnorderedElementsAre( - video_widevine:: - ClientIdentification_ClientCapabilities_CertificateKeyType_RSA_2048, - video_widevine:: - ClientIdentification_ClientCapabilities_CertificateKeyType_RSA_3072)); + EXPECT_THAT(client_capabilities.supported_certificate_key_type(), + UnorderedElementsAre(ClientCapabilities::RSA_2048, + ClientCapabilities::RSA_3072, + ClientCapabilities::ECC_SECP256R1, + ClientCapabilities::ECC_SECP384R1, + ClientCapabilities::ECC_SECP521R1)); EXPECT_FALSE(client_capabilities.has_resource_rating_tier()); // Verify Content Identification @@ -425,11 +428,12 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { } TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) { - bool usage_information_support = true; - CryptoSession::HdcpCapability current_hdcp_version = HDCP_NO_DIGITAL_OUTPUT; - CryptoSession::HdcpCapability max_hdcp_version = HDCP_V2_1; - uint32_t crypto_session_api_version = 15; - uint32_t resource_rating_tier = RESOURCE_RATING_TIER_LOW; + const bool usage_information_support = true; + const CryptoSession::HdcpCapability current_hdcp_version = + HDCP_NO_DIGITAL_OUTPUT; + const CryptoSession::HdcpCapability max_hdcp_version = HDCP_V2_1; + const uint32_t crypto_session_api_version = 15; + const uint32_t resource_rating_tier = RESOURCE_RATING_TIER_LOW; EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true)); EXPECT_CALL(*crypto_session_, request_id()) @@ -442,8 +446,7 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) { SetArgPointee<1>(max_hdcp_version), Return(NO_ERROR))); EXPECT_CALL(*crypto_session_, GetSupportedCertificateTypes(NotNull())); EXPECT_CALL(*crypto_session_, GetApiVersion(NotNull())) - .Times(2) - .WillRepeatedly( + .WillOnce( DoAll(SetArgPointee<0>(crypto_session_api_version), Return(true))); EXPECT_CALL(*crypto_session_, GetResourceRatingTier(NotNull())) .WillOnce(DoAll(SetArgPointee<0>(resource_rating_tier), Return(true))); @@ -506,24 +509,22 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) { EXPECT_FALSE(client_id.has_provider_client_token()); EXPECT_FALSE(client_id.has_license_counter()); - const ::video_widevine::ClientIdentification_ClientCapabilities& - client_capabilities = client_id.client_capabilities(); + const ClientCapabilities& client_capabilities = + client_id.client_capabilities(); EXPECT_TRUE(client_capabilities.has_client_token()); EXPECT_TRUE(client_capabilities.has_session_token()); EXPECT_FALSE(client_capabilities.video_resolution_constraints()); - EXPECT_EQ(video_widevine:: - ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_1, + EXPECT_EQ(ClientCapabilities::HDCP_V2_1, client_capabilities.max_hdcp_version()); EXPECT_EQ(crypto_session_api_version, client_capabilities.oem_crypto_api_version()); - EXPECT_THAT( - client_capabilities.supported_certificate_key_type(), - UnorderedElementsAre( - video_widevine:: - ClientIdentification_ClientCapabilities_CertificateKeyType_RSA_2048, - video_widevine:: - ClientIdentification_ClientCapabilities_CertificateKeyType_RSA_3072)); + EXPECT_THAT(client_capabilities.supported_certificate_key_type(), + UnorderedElementsAre(ClientCapabilities::RSA_2048, + ClientCapabilities::RSA_3072, + ClientCapabilities::ECC_SECP256R1, + ClientCapabilities::ECC_SECP384R1, + ClientCapabilities::ECC_SECP521R1)); EXPECT_EQ(resource_rating_tier, client_capabilities.resource_rating_tier()); // Verify Content Identification From e15c0607c7be0d266792668a2669f3783b08a0b7 Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Wed, 27 Jan 2021 13:19:13 -0800 Subject: [PATCH 4/5] Enable the CDM to track the DRM private key type. [ Merge of http://go/wvgerrit/110923 ] The CDM is responsible for telling OEMCrypto the underlying DRM private key type when loading it into a session. To do this, the CDM must determine and store the key type of a successfully loaded provisioning response. The type of key is available from the DRM certificate proto that is provided in the reponse. This change introduces a class to contain the wrapped key and type together. To store the type, the CDM device files have been updated to include a key type with the DRM certificate and to store from and load to the new class. Unittests have been updated for using the new class where the wrapped key was used before. Test: Linux unit tests Bug: 140813486 Change-Id: I09249afe9c291632fb651ecd00eac697d6939ec7 (cherry picked from commit 6c457402e944079271cef488aa4699f986da6a2e) Merged-In: I09249afe9c291632fb651ecd00eac697d6939ec7 --- .../cdm/core/include/crypto_session.h | 3 +- .../cdm/core/include/crypto_wrapped_key.h | 52 +++ .../cdm/core/include/device_files.h | 6 +- .../cdm/core/include/wv_cdm_types.h | 1 + libwvdrmengine/cdm/core/src/cdm_session.cpp | 14 +- .../cdm/core/src/certificate_provisioning.cpp | 47 ++- .../cdm/core/src/crypto_session.cpp | 19 +- libwvdrmengine/cdm/core/src/device_files.cpp | 53 ++- .../cdm/core/src/device_files.proto | 5 + .../cdm/core/test/cdm_session_unittest.cpp | 19 +- .../cdm/core/test/device_files_unittest.cpp | 360 +++++++++++++----- .../cdm/core/test/test_printers.cpp | 3 + .../cdm/test/request_license_test.cpp | 3 +- libwvdrmengine/include/WVErrors.h | 3 +- libwvdrmengine/include/mapErrors-inl.h | 2 + libwvdrmengine/include_hidl/mapErrors-inl.h | 1 + 16 files changed, 451 insertions(+), 140 deletions(-) create mode 100644 libwvdrmengine/cdm/core/include/crypto_wrapped_key.h diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index d5907dcc..0401cbfc 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -13,6 +13,7 @@ #include #include "OEMCryptoCENC.h" +#include "crypto_wrapped_key.h" #include "disallow_copy_and_assign.h" #include "key_session.h" #include "metrics_collections.h" @@ -170,7 +171,7 @@ class CryptoSession { const std::string& signature, std::string* wrapped_private_key); virtual CdmResponseType LoadCertificatePrivateKey( - const std::string& wrapped_key); + const CryptoWrappedKey& private_key); // Media data path virtual CdmResponseType Decrypt(const CdmDecryptionParametersV16& params); diff --git a/libwvdrmengine/cdm/core/include/crypto_wrapped_key.h b/libwvdrmengine/cdm/core/include/crypto_wrapped_key.h new file mode 100644 index 00000000..bf947bb9 --- /dev/null +++ b/libwvdrmengine/cdm/core/include/crypto_wrapped_key.h @@ -0,0 +1,52 @@ +// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +#ifndef WVCDM_CORE_CRYPTO_WRAPPED_KEY_H_ +#define WVCDM_CORE_CRYPTO_WRAPPED_KEY_H_ + +#include + +namespace wvcdm { + +// Represents OEMCrypto's wrapped private DRM key. As of v16, it is +// possible for OEMCrypto to support ECC-based DRM certificates. The +// format of the wrapped key is vendor specific; however, the API +// requires that the CDM track whether the wrapped key is RSA or ECC. +class CryptoWrappedKey { + public: + enum Type : int32_t { kUninitialized = 0, kRsa = 1, kEcc = 2 }; + CryptoWrappedKey() {} + CryptoWrappedKey(Type type, const std::string& key) + : type_(type), key_(key) {} + + Type type() const { return type_; } + void set_type(Type type) { type_ = type; } + + const std::string& key() const { return key_; } + // Mutable reference getter for passing to OMECrypto. + std::string& key() { return key_; } + void set_key(const std::string& key) { key_ = key; } + + void Clear() { + type_ = kUninitialized; + key_.clear(); + } + // A valid key must have a known key type and have key data. + bool IsValid() const { return type_ != kUninitialized && !key_.empty(); } + // Equality operator is for testing only. Real keys may have + // different meta data but the same logical key. + bool operator==(const CryptoWrappedKey& other) const { + return type_ == other.type_ && key_ == other.key_; + } + + private: + // DRM key type of the wrapped key. For wrapped keys which the type + // of key is unknown, assume it to be RSA. + Type type_ = kUninitialized; + // Vendor-specific wrapped DRM key. + std::string key_; +}; // class CryptoWrappedKey + +} // namespace wvcdm + +#endif // WVCDM_CORE_CRYPTO_WRAPPED_KEY_H_ diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 6add2dd0..b760d453 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -9,6 +9,7 @@ #include #include +#include "crypto_wrapped_key.h" #include "device_files.pb.h" #include "disallow_copy_and_assign.h" #include "platform.h" @@ -98,10 +99,10 @@ class DeviceFiles { // ATSC certificates are installed by the ATSC service. They can be read // and used but not written or removed. virtual bool StoreCertificate(const std::string& certificate, - const std::string& wrapped_private_key); + const CryptoWrappedKey& private_key); virtual bool RetrieveCertificate(bool atsc_mode_enabled, std::string* certificate, - std::string* wrapped_private_key, + CryptoWrappedKey* private_key, std::string* serial_number, uint32_t* system_id); virtual bool HasCertificate(bool atsc_mode_enabled); @@ -269,6 +270,7 @@ class DeviceFiles { FRIEND_TEST(DeviceFilesSecurityLevelTest, SecurityLevel); FRIEND_TEST(DeviceCertificateTest, StoreCertificate); FRIEND_TEST(DeviceCertificateTest, ReadCertificate); + FRIEND_TEST(DeviceCertificateTest, ReadCertificateWithoutKeyType); FRIEND_TEST(DeviceCertificateTest, HasCertificate); FRIEND_TEST(DeviceFilesStoreTest, StoreLicense); FRIEND_TEST(DeviceFilesHlsAttributesTest, Delete); diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 7154ee7e..acad7d0f 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -417,6 +417,7 @@ enum CdmResponseType : int32_t { RESTORE_OFFLINE_LICENSE_ERROR_3 = 362, NO_SRM_VERSION = 363, SESSION_NOT_FOUND_23 = 364, + CERT_PROVISIONING_RESPONSE_ERROR_9 = 365, // Don't forget to add new values to // * core/test/test_printers.cpp. // * android/include/mapErrors-inl.h diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 6d6720e6..f993f5de 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -13,6 +13,7 @@ #include "cdm_engine.h" #include "clock.h" +#include "crypto_wrapped_key.h" #include "file_store.h" #include "log.h" #include "properties.h" @@ -170,18 +171,18 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, // License server client ID token is a stored certificate. Stage it or // indicate that provisioning is needed. Get token from stored certificate - std::string wrapped_key; + CryptoWrappedKey private_key; bool atsc_mode_enabled = false; if (cdm_client_property_set != nullptr) atsc_mode_enabled = cdm_client_property_set->use_atsc_mode(); if (!file_handle_->RetrieveCertificate(atsc_mode_enabled, &client_token, - &wrapped_key, &serial_number, + &private_key, &serial_number, nullptr)) { return NEED_PROVISIONING; } CdmResponseType load_cert_sts; M_TIME( - load_cert_sts = crypto_session_->LoadCertificatePrivateKey(wrapped_key), + load_cert_sts = crypto_session_->LoadCertificatePrivateKey(private_key), crypto_metrics_, crypto_session_load_certificate_private_key_, load_cert_sts); switch (load_cert_sts) { @@ -202,9 +203,12 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, if (forced_session_id) { key_set_id_ = *forced_session_id; } else { - bool ok = GenerateKeySetId(atsc_mode_enabled, &key_set_id_); - (void)ok; // ok is now used when assertions are turned off. + const bool ok = GenerateKeySetId(atsc_mode_enabled, &key_set_id_); assert(ok); + if (!ok) { + // Assertions may be disabled + LOGE("Could not generate keyset ID"); + } } session_id_ = diff --git a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp index 68a6ba02..84741bca 100644 --- a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp +++ b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp @@ -5,6 +5,7 @@ #include "certificate_provisioning.h" #include "client_identification.h" +#include "crypto_wrapped_key.h" #include "device_files.h" #include "file_store.h" #include "license_protocol.pb.h" @@ -333,7 +334,8 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse( } else { // The response is base64 encoded in a JSON wrapper. // Extract it and decode it. On error return an empty string. - bool result = ExtractAndDecodeSignedMessage(response_message, &response); + const bool result = + ExtractAndDecodeSignedMessage(response_message, &response); if (!result || response.empty()) { LOGE("Provisioning response message is an invalid JSON/base64 string"); return CERT_PROVISIONING_RESPONSE_ERROR_1; @@ -391,9 +393,9 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse( return CERT_PROVISIONING_RESPONSE_ERROR_4; } - std::string wrapped_private_key; + CryptoWrappedKey private_key; const CdmResponseType status = crypto_session_->LoadProvisioning( - signed_message, core_message, signature, &wrapped_private_key); + signed_message, core_message, signature, &private_key.key()); if (status != NO_ERROR) { LOGE("LoadProvisioning failed: status = %d", static_cast(status)); @@ -404,15 +406,46 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse( crypto_session_->Close(); // This is the entire certificate (SignedDrmDeviceCertificate). - const std::string& device_certificate = + const std::string& device_cert_data = provisioning_response.device_certificate(); if (cert_type_ == kCertificateX509) { - *cert = device_certificate; - *wrapped_key = wrapped_private_key; + *cert = device_cert_data; + *wrapped_key = private_key.key(); return NO_ERROR; } + // Need to parse cert for key type. + SignedDrmDeviceCertificate signed_device_cert; + if (!signed_device_cert.ParseFromString(device_cert_data)) { + LOGE("Failed to parse signed DRM certificate"); + return CERT_PROVISIONING_RESPONSE_ERROR_9; + } + DrmDeviceCertificate device_cert; + if (!device_cert.ParseFromString(signed_device_cert.drm_certificate())) { + LOGE("Failed to parse DRM certificate"); + return CERT_PROVISIONING_RESPONSE_ERROR_9; + } + if (!device_cert.has_algorithm()) { + LOGW("DRM certificate does not specify algorithm type, assuming RSA"); + private_key.set_type(CryptoWrappedKey::kRsa); + } else { + switch (device_cert.algorithm()) { + case DrmDeviceCertificate::RSA: + private_key.set_type(CryptoWrappedKey::kRsa); + break; + case DrmDeviceCertificate::ECC_SECP256R1: + case DrmDeviceCertificate::ECC_SECP384R1: + case DrmDeviceCertificate::ECC_SECP521R1: + private_key.set_type(CryptoWrappedKey::kEcc); + break; + default: + LOGE("Unknown DRM key type: algorithm = %d", + static_cast(device_cert.algorithm())); + return CERT_PROVISIONING_RESPONSE_ERROR_9; + } + } + // The certificate will be stored to the device as the final step in // the device provisioning process. @@ -421,7 +454,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse( LOGE("Failed to initialize DeviceFiles"); return CERT_PROVISIONING_RESPONSE_ERROR_7; } - if (!handle.StoreCertificate(device_certificate, wrapped_private_key)) { + if (!handle.StoreCertificate(device_cert_data, private_key)) { LOGE("Failed to store provisioning certificate"); return CERT_PROVISIONING_RESPONSE_ERROR_8; } diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 97e9a144..45a9baed 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -1271,28 +1271,33 @@ CdmResponseType CryptoSession::LoadEntitledContentKeys( } CdmResponseType CryptoSession::LoadCertificatePrivateKey( - const std::string& wrapped_key) { + const CryptoWrappedKey& private_key) { // TODO(b/141655126): Getting the OEM Cert no longer loads the private key. // Call OEMCrypto_GetOEMPublicCertificate before OEMCrypto_LoadDRMPrivateKey // so it caches the OEMCrypto Public Key and then throw away result std::string temp_buffer(CERTIFICATE_DATA_SIZE, '\0'); size_t buf_size = temp_buffer.size(); uint8_t* buf = reinterpret_cast(&temp_buffer[0]); - OEMCryptoResult sts; - WithOecSessionLock( + OEMCryptoResult sts = WithOecSessionLock( "LoadCertificatePrivateKey() calling OEMCrypto_GetOEMPublicCertificate", [&] { - sts = OEMCrypto_GetOEMPublicCertificate(buf, &buf_size, - requested_security_level_); + return OEMCrypto_GetOEMPublicCertificate(buf, &buf_size, + requested_security_level_); }); metrics_->oemcrypto_get_oem_public_certificate_.Increment(sts); - LOGV("Loading device RSA key: id = %u", oec_session_id_); + const OEMCrypto_PrivateKeyType key_type = + (private_key.type() == CryptoWrappedKey::kEcc) + ? OEMCrypto_ECC_Private_Key + : OEMCrypto_RSA_Private_Key; + const std::string& wrapped_key = private_key.key(); + + LOGV("Loading device DRM key: id = %u", oec_session_id_); // TODO(b/140813486): determine if cert is RSA or ECC. WithOecSessionLock( "LoadCertificatePrivateKey() calling OEMCrypto_LoadDRMPrivateKey()", [&] { M_TIME(sts = OEMCrypto_LoadDRMPrivateKey( - oec_session_id_, OEMCrypto_RSA_Private_Key, + oec_session_id_, key_type, reinterpret_cast(wrapped_key.data()), wrapped_key.size()), metrics_, oemcrypto_load_device_rsa_key_, sts); diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index 0385cdbd..7c21b8e4 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -112,8 +112,16 @@ bool DeviceFiles::Init(CdmSecurityLevel security_level) { } bool DeviceFiles::StoreCertificate(const std::string& certificate, - const std::string& wrapped_private_key) { + const CryptoWrappedKey& private_key) { RETURN_FALSE_IF_UNINITIALIZED(); + if (certificate.empty()) { + LOGE("Missing certificate information"); + return false; + } + if (!private_key.IsValid()) { + LOGE("Private key is invalid"); + return false; + } // Fill in file information video_widevine_client::sdk::File file; @@ -123,7 +131,19 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate, DeviceCertificate* device_certificate = file.mutable_device_certificate(); device_certificate->set_certificate(certificate); - device_certificate->set_wrapped_private_key(wrapped_private_key); + device_certificate->set_wrapped_private_key(private_key.key()); + switch (private_key.type()) { + case CryptoWrappedKey::kRsa: + device_certificate->set_key_type(DeviceCertificate::RSA); + break; + case CryptoWrappedKey::kEcc: + device_certificate->set_key_type(DeviceCertificate::ECC); + break; + case CryptoWrappedKey::kUninitialized: // Suppress compiler warnings. + default: + LOGE("Unexpected key type"); + return false; + } std::string serialized_file; file.SerializeToString(&serialized_file); @@ -134,10 +154,12 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate, bool DeviceFiles::RetrieveCertificate(bool atsc_mode_enabled, std::string* certificate, - std::string* wrapped_private_key, + CryptoWrappedKey* private_key, std::string* serial_number, uint32_t* system_id) { RETURN_FALSE_IF_UNINITIALIZED(); + RETURN_FALSE_IF_NULL(certificate); + RETURN_FALSE_IF_NULL(private_key); if (!HasCertificate(atsc_mode_enabled)) { return false; @@ -169,7 +191,30 @@ bool DeviceFiles::RetrieveCertificate(bool atsc_mode_enabled, DeviceCertificate device_certificate = file.device_certificate(); *certificate = device_certificate.certificate(); - *wrapped_private_key = device_certificate.wrapped_private_key(); + private_key->Clear(); + private_key->set_key(device_certificate.wrapped_private_key()); + if (device_certificate.has_key_type()) { + const DeviceCertificate::PrivateKeyType key_type = + device_certificate.key_type(); + switch (key_type) { + case DeviceCertificate::RSA: + private_key->set_type(CryptoWrappedKey::kRsa); + break; + case DeviceCertificate::ECC: + private_key->set_type(CryptoWrappedKey::kEcc); + break; + default: + LOGW("Unknown DRM key type, defaulting to RSA: type = %d", key_type); + private_key->set_type(CryptoWrappedKey::kRsa); + break; + } + } else { + // Possible that device certificate is from V15, in this case, the + // only supported key of at that time was RSA. + LOGD("No key type info, assuming RSA"); + private_key->set_type(CryptoWrappedKey::kRsa); + } + return CertificateProvisioning::ExtractDeviceInfo( device_certificate.certificate(), serial_number, system_id); } diff --git a/libwvdrmengine/cdm/core/src/device_files.proto b/libwvdrmengine/cdm/core/src/device_files.proto index 21eafe42..3d743525 100644 --- a/libwvdrmengine/cdm/core/src/device_files.proto +++ b/libwvdrmengine/cdm/core/src/device_files.proto @@ -21,8 +21,13 @@ message NameValue { } message DeviceCertificate { + enum PrivateKeyType { + RSA = 0; + ECC = 1; + } optional bytes certificate = 1; optional bytes wrapped_private_key = 2; + optional PrivateKeyType key_type = 3 [default = RSA]; } message License { diff --git a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp index d3c32dbc..1822faee 100644 --- a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp @@ -9,6 +9,7 @@ #include "cdm_session.h" #include "crypto_key.h" +#include "crypto_wrapped_key.h" #include "properties.h" #include "service_certificate.h" #include "string_conversions.h" @@ -71,7 +72,7 @@ const std::string kToken = a2bs_hex( "8CD5A9DF6E3D3A99B806F6D60991358C5BE77117D4F3168F3348E9A048539F892F4D783152" "C7A8095224AA56B78C5CF7BD1AB1B179C0C0D11E3C3BAC84C141A00191321E3ACC17242E68" "3C"); -const std::string kWrappedKey = a2bs_hex( +const std::string kWrappedKeyData = a2bs_hex( "3B84252DD84F1A710365014A114507FFFA3DD404625D61D1EEC7C3A39D72CB8D9318ADE9DA" "05D69F9776DAFDA49A97BC30E84CA275925DFD98CA04F7DB23465103A224852192DE232902" "99FF82024F5CCA7716ACA9BE0B56348BA16B9E3136D73789C842CB2ECA4820DDAAF59CCB9B" @@ -108,14 +109,15 @@ const std::string kWrappedKey = a2bs_hex( "33EF70621A98184DDAB5E14BC971CF98CF6C91A37FFA83B00AD3BCABBAAB2DEF1C52F43003" "E74C92B44F9205D22262FB47948654229DE1920F8EDF96A19A88A1CA1552F8856FB4CBF83B" "AA3348419159D207F65FCE9C1A500C6818"); +const CryptoWrappedKey kWrappedKey = {CryptoWrappedKey::kRsa, kWrappedKeyData}; class MockDeviceFiles : public DeviceFiles { public: MockDeviceFiles() : DeviceFiles(nullptr) {} MOCK_METHOD1(Init, bool(CdmSecurityLevel)); - MOCK_METHOD5(RetrieveCertificate, - bool(bool, std::string*, std::string*, std::string*, uint32_t*)); + MOCK_METHOD5(RetrieveCertificate, bool(bool, std::string*, CryptoWrappedKey*, + std::string*, uint32_t*)); }; class MockUsageTableHeader : public UsageTableHeader { @@ -142,7 +144,8 @@ class MockCryptoSession : public TestCryptoSession { MOCK_METHOD0(GetSecurityLevel, CdmSecurityLevel()); MOCK_METHOD0(Open, CdmResponseType()); MOCK_METHOD1(Open, CdmResponseType(SecurityLevel)); - MOCK_METHOD1(LoadCertificatePrivateKey, CdmResponseType(const std::string&)); + MOCK_METHOD1(LoadCertificatePrivateKey, + CdmResponseType(const CryptoWrappedKey&)); MOCK_METHOD0(DeleteAllUsageReports, CdmResponseType()); MOCK_METHOD1(GetUsageSupportType, CdmResponseType(CdmUsageSupportType* type)); MOCK_METHOD0(GetUsageTableHeader, UsageTableHeader*()); @@ -219,7 +222,7 @@ TEST_F(CdmSessionTest, InitWithBuiltInCertificate) { RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _)) .WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey), Return(true))); - EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey))) + EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey)) .InSequence(crypto_session_seq) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true)); @@ -247,7 +250,7 @@ TEST_F(CdmSessionTest, InitWithCertificate) { RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _)) .WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey), Return(true))); - EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey))) + EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey)) .InSequence(crypto_session_seq) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*license_parser_, @@ -274,7 +277,7 @@ TEST_F(CdmSessionTest, ReInitFail) { RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _)) .WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey), Return(true))); - EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey))) + EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey)) .InSequence(crypto_session_seq) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*license_parser_, @@ -329,7 +332,7 @@ TEST_F(CdmSessionTest, UpdateUsageEntry) { RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _)) .WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey), Return(true))); - EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey))) + EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey)) .InSequence(crypto_session_seq) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*crypto_session_, GetUsageTableHeader()) diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index 25cc5553..fc9b8016 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -13,6 +13,7 @@ #include "arraysize.h" #include "cdm_random.h" +#include "crypto_wrapped_key.h" #include "file_store.h" #include "properties.h" #include "string_conversions.h" @@ -28,100 +29,212 @@ const uint32_t kWrappedKeyLen = 500; const std::string kEmptyString; -// Structurally valid test certificate. -// The data elements in this module are used to test the storage and -// retrieval of certificates and licenses +// Structurally valid test certificate of provisioning 3.0. +// {'certificate': {'algorithm': 'RSA', +// 'creation_time': '2020-12-14T23:17:27', +// 'public_key': ... 270 bytes, +// 'serial_number': '7CB49F987A635E1E0A52184694582D6E', +// 'type': 'DRM_USER_DEVICE'}, +// 'signature': ... 256 byts, +// 'signer': { +// 'certificate': {'creation_time': '2017-11-17T13:21:39', +// 'public_key': ... 270 bytes, +// 'serial_number': '65802C9B625E5A319C33DC1CB7C3C6D4', +// 'type': 'DRM_INTERMEDIATE'}, +// 'signature': ... 384 bytes } +// } +// Value of |certificate| in DeviceCertFile proto messages +// kTestCertificateFileData and kTestCertificateFileWithoutKeyTypeData const std::string kTestCertificate = a2bs_hex( - "0A98030802120D73657269616C5F6E756D62657218B4B2CDE00422E8024D49494243674B43" - "415145412B78475A2F77637A39756746705030374E73706F365531376C3059684669467078" - "78553470546B334C69667A3952337A734973754552777461372B66574966784F6F32303865" - "74742F6A68736B69566F645345743351424768345842697079576F704B775A393348486144" - "565A41414C692F32412B785442745764456F37584755756A4B447643322F615A4B756B666A" - "704F6955493841684C41666A6D6C63442F555A31515068306D4873676C524E436D7043776D" - "7753584139564E6D687A2B5069422B446D6C3457576E4B572F56486F32756A54587871372B" - "65664D55344832666E79335365334B594F73465046475A31544E5153596C46755368577248" - "5074694C6D5564506F50364356326D4D4C31746B2B6C3744494971587251684C554B444143" - "654D35726F4D78306B4C6855574238502B30756A31434E6C4E4E344A525A6C433778466671" - "694D62465255395A344E3659774944415141422899203A11746573742E7769646576696E65" - "2E636F6D128202307836353063396632653637303165336665373364333035343930346139" - "61346262646239363733336631633463373433656635373361643661633134633561336266" - "38613437333166366536323736666165613532343733303336373766623864626466323466" - "66373865353363323530353263646361383765656366656538353437366263623861303563" - "62396131656665663763623837646436383232336531313763653830306163343631373731" - "37323534343735376134383762653332663561623866653038373966613861646437386265" - "34363565613866386435616366393737653966316165333664346434373831366561366564" - "343133373262"); + "0AEB03080212107CB49F987A635E1E0A52184694582D6E1887C6E1FE05228E023082010A" + "0282010100DB13F5089C061E8EB62562692B3A06A774A99129BD63445FEC24448D07C30D" + "7343553442A989AF000B7D962033C290D9A81DDCBCF3980512445EB7E6CF544FC1FB3FC7" + "58FB9E06B6C28562A841E4AE2D3368795C41A2D6043CA9830E0F36583C8FDB839C2752C1" + "3E184034EE412BA8A90271295B094255A16319706F4D6C9CF1EBB1B39BA2A7B9B2780344" + "DD5834BF71F4D5185508D2FDFB10419BD4F48E79DDFC78471C11B9E99DF98221D6FAB25A" + "EE24574FB02D614974942A36527C62B73A6FB7CA9EF828EB598DA59060D654851103F857" + "A041E66B2FFB99713D31A64605932833E8CCDA6CF0F888AE6E78EDC9DA0D88A185B97FEB" + "3EA74CF146BE7D9267020301000128E83D3A0C7769646576696E652E636F6D480152AA01" + "080110001A8101044F554B9400E10B17185036B6A1628EFC61B22166DE2235717A44F953" + "B7928F3415B9D113835B10106CB6C2187F34188723D82ECF95CF5ECAB58923F173186081" + "5999F08BF4BE4A44DB7B991B5F915F2ADCEE481E26096AAEC3AC761B624A92158AC91035" + "041173392B1E495428F0D17406B10889B6B701FAF08D2284F95DBBCA2220595267DCA89A" + "2E57E7D4CA3C62ED6D12742408A07C103DF860DC0520C3664EEB1280028CD44E12AA7C1A" + "8EBF88C81A2A54EFD29F8BC6C377B0C11C3404F84D8B9EAD52A0E18E929A4923A4172C2A" + "C1CDADD16E41A7833AA0DE9D09F685DAC9ACC702CB9061632C1C82333A6FB6BC9C4B2540" + "BE18CED4AB0AF1C3EFE521308F3D4CF513C20500064FE935FDDF7BBAC0BA99AA7FA66017" + "898DEE6F6F5EF90C875D5D8DA39E769E8D1485253EEE93A97B35A8EAE8D3213D392B552F" + "B4B4A37955EBE7362287502EB649D982F06D308178642C1F69B12383B050CF60CD292093" + "29C148FB4F422ED5ED139A25A89E13D4AB2E8DB940299D1414AF30DDF0D06AF55C1978F6" + "E71E4548F20FFAE953A99D492F3D2847783338D74F66D2DFEBB50896ACBC4795A81AB405" + "0AAE020801121065802C9B625E5A319C33DC1CB7C3C6D418E3A5BDD005228E023082010A" + "0282010100B80502043C2A8A0FD8D25C613E1E3E3B5E349F332F04516A7510D38021A562" + "9B9AA027AEAD3C759B7AFE70BED65F3DF6860FF5EB60B983A3FFA33FDE06F3B73014DFC8" + "45AB371C6600562E9D904F842B8BA4A5D9200FFA3ED45D705520A5C372A889F9E3143862" + "34C6897AE655851FCD9ADB4EF9126C78386EA93BCB25BA3EC475C55C608E771C763AB025" + "06F9B07252D6ABF7EA64B1EBDE7B95C6407690533BD6890B9274C16066F74FC401EA355F" + "0A02106814D49BF0C89E6E1F8DB2A47841CD0DAD793296A107C36223404F2BF1FCA16FD0" + "A4B982634DB62407F8F14ACAE3B05A038BD3E4BBBAE4391BBFA7A47FB9D01DE857EA88E5" + "E36EE36E245859FC0F020301000128E83D1280037E06581A019184AB572AFDCADDD03F16" + "1CE68200F8E6F8AD161947360BC8D49C0D68009B1C4644F9B3F3FB6DDFD92EF92DE62D41" + "D459D29D81BFAEF3970A3A39D25B2662ECB03B2DA7B68302FAA6DD98D95A143CC8C1CB6A" + "DDA76D2EE9C3723FAF95A29CDC3E968B6821A91C051CA280A86669710A1AD7A44BF92180" + "27460DF694E2E9270396DF221963F21EE6AA220A5EE4A4D0FEB3D53EB5732F8F91E9A96B" + "3B8BE284C51339EA284D4D0EDD55B6AD56F7416420E05E059F9734A96BE25AA44560DBA8" + "C38755A42A82BD7F88EDD19DF346A667B33B8114C76A8838C423D824A50B23251A088136" + "D6E8F475299D2AFD46CEA51B5CBDF789A572125CD24FBB813B387A10CD2A30E3447634AB" + "3408F96B9CF3D98896D405F3F540D9C57962760FCD177CDD101EB8A4148B9C29CED5EAD6" + "45A95B698F1CDC6E1DB6678B85074186080D68D13CD37E07B16DE370CD9AFB9B25564A73" + "A30E2AF8085EA37D310C474F0E67AC00CA992A5296FAEDAD7AA06ECD790F1E3D426558FA" + "98383E3CD2ED4830"); // A Wrapped Private Key -// The data elements in this module are used to test the storage and -// retrieval of certificates and licenses -const std::string kTestWrappedPrivateKey = - "4F724B065326371A2F5F6F51467C2E26555C453B5C7C1B4F2738454B782E3E7B5340435A" - "66374D0612052C521A233D7A67194871751C78575E5177070130264C4F037633320E667B" - "1A49192924491338693D106E6113014A733A241A1A033E28352178146B4F543D38104A59" - "19120325502C31365506096D59585E08774B5B567A7B5D03451E6B11633E52672C226103" - "104B3E4C031A6403050F3A574D2C501711773802741F7F3A0D364757101D02181C7D4D35" - "207167506A424C094E4A72316F791F162D76657D2B5D3C2D7B273A286927717561316518" - "7E55282430491467086425432347701C3116446D21645C756B2D3D0F797C3220322D622A" - "254D0B7D4F1D5D0C0A36755D1246741A34783C45157247091C78232B7D2E0E1F637A2A37" - "39085D76166747034350613969072F5B5C5B21657E470C7E513B3F091D74455A3A073705" - "7B7E3B5337191D4E7536087C334B6028530F3F5B23380B6A076031294501003D6D1F240F" - "63053D5D0B271B6A0F26185650731308660B0447566041684F584C22216E567D3B775569" - "5F7F3D6B64525E7227165948101540243C19495C4C702F37490F26613353797825624143" - "263043020E1E6760123D51056F2F1E482F2E3D021B27677D3E7E3C0C11757C3448275E08" - "382E111263644C6D224714706D760A054A586E17505C3429575A41043F184209"; +// Value of |wrapped_private_key| in DeviceCertFile proto messages +// kTestCertificateFileData and kTestCertificateFileWithoutKeyTypeData. +// Value is randomly generated value and is not compatible with a real +// OEMCrypto implementation. +const std::string kTestWrappedPrivateKeyData = a2bs_hex( + "B36550E6BEACCB34F6C3B2ABF86634EE5383829C844F9B0C14DCF9A22FE3543CCBA8FD61" + "E21CEE503E7A40B93B07A4186A362D9E6F88DD48D4516635C6D0C253C03F12EFA6095618" + "D647F5212C518C4A6AA7172BC691530703FEDDFDB25ECF885A53FF2B4B98773979D61AE6" + "59E340489811512A5C2FD445A4B0AE88A3A7F29ACE5B01ECF580D0993227BC408B602B0B" + "C099920C17044FE66242372C2B2E8CA5C1EEC0844BC19198ADADE47FB449DC9B30784952" + "B3A8131B912CE928070D665C0557EBE7484FDABFBCA0F2C2BFD4FBDDB6681C4689FD276C" + "231B72B15AC4E5C3C088449DE4785F1D4835AC44E39B119991EFF6E72C7D3B8C75CE588D" + "B0B3AD69EB79C19B22CB518EF964C9D985AFD3677F0D13015AD7BEA84CD01E335E68AF15" + "3B989FE8BEEC60A94753C638535FA3F215F750F6954AC395F8702941409E7276910CE118" + "19649641318B5BD1B78DECEADB2B562312CC286DB0BCC14A60C84CB21AB6E75E59DAFBE7" + "01D6405DD3F47D2F8A95422ED8EB5ECE330C9886406B3B69180B697521F3865B4A05DF2B" + "B51D16CAFEF05866E5D55C360C759F5B10E0D354D63D5A14E5BA19DBF9394E18E474E790" + "63B4E877C2FE6BCA732ED39B091B6D7A21DD9D6D6750C1CA2ABC5DEC2A81B5359771849E" + "7B4560EB6D329E59455A70F57F035DFB50EC4354D7E068ADFAFAD4081ACA67FD"); +const CryptoWrappedKey kTestWrappedKey = {CryptoWrappedKey::kRsa, + kTestWrappedPrivateKeyData}; -// The test certificate in file storage format. -// The data elements in this module are used to test the storage and -// retrieval of certificates and licenses +// Structurally valid test certificate device file, missing |key_type| field. +// {'certificate': kTestCertificate, +// 'wrapped_private_key': kTestWrappedPrivateKeyData +// } +const std::string kTestCertificateFileWithoutKeyTypeData = a2bs_hex( + "0AA90F080110011AA20F0AA80B0AEB03080212107CB49F987A635E1E0A52184694582D6E" + "1887C6E1FE05228E023082010A0282010100DB13F5089C061E8EB62562692B3A06A774A9" + "9129BD63445FEC24448D07C30D7343553442A989AF000B7D962033C290D9A81DDCBCF398" + "0512445EB7E6CF544FC1FB3FC758FB9E06B6C28562A841E4AE2D3368795C41A2D6043CA9" + "830E0F36583C8FDB839C2752C13E184034EE412BA8A90271295B094255A16319706F4D6C" + "9CF1EBB1B39BA2A7B9B2780344DD5834BF71F4D5185508D2FDFB10419BD4F48E79DDFC78" + "471C11B9E99DF98221D6FAB25AEE24574FB02D614974942A36527C62B73A6FB7CA9EF828" + "EB598DA59060D654851103F857A041E66B2FFB99713D31A64605932833E8CCDA6CF0F888" + "AE6E78EDC9DA0D88A185B97FEB3EA74CF146BE7D9267020301000128E83D3A0C77696465" + "76696E652E636F6D480152AA01080110001A8101044F554B9400E10B17185036B6A1628E" + "FC61B22166DE2235717A44F953B7928F3415B9D113835B10106CB6C2187F34188723D82E" + "CF95CF5ECAB58923F1731860815999F08BF4BE4A44DB7B991B5F915F2ADCEE481E26096A" + "AEC3AC761B624A92158AC91035041173392B1E495428F0D17406B10889B6B701FAF08D22" + "84F95DBBCA2220595267DCA89A2E57E7D4CA3C62ED6D12742408A07C103DF860DC0520C3" + "664EEB1280028CD44E12AA7C1A8EBF88C81A2A54EFD29F8BC6C377B0C11C3404F84D8B9E" + "AD52A0E18E929A4923A4172C2AC1CDADD16E41A7833AA0DE9D09F685DAC9ACC702CB9061" + "632C1C82333A6FB6BC9C4B2540BE18CED4AB0AF1C3EFE521308F3D4CF513C20500064FE9" + "35FDDF7BBAC0BA99AA7FA66017898DEE6F6F5EF90C875D5D8DA39E769E8D1485253EEE93" + "A97B35A8EAE8D3213D392B552FB4B4A37955EBE7362287502EB649D982F06D308178642C" + "1F69B12383B050CF60CD29209329C148FB4F422ED5ED139A25A89E13D4AB2E8DB940299D" + "1414AF30DDF0D06AF55C1978F6E71E4548F20FFAE953A99D492F3D2847783338D74F66D2" + "DFEBB50896ACBC4795A81AB4050AAE020801121065802C9B625E5A319C33DC1CB7C3C6D4" + "18E3A5BDD005228E023082010A0282010100B80502043C2A8A0FD8D25C613E1E3E3B5E34" + "9F332F04516A7510D38021A5629B9AA027AEAD3C759B7AFE70BED65F3DF6860FF5EB60B9" + "83A3FFA33FDE06F3B73014DFC845AB371C6600562E9D904F842B8BA4A5D9200FFA3ED45D" + "705520A5C372A889F9E314386234C6897AE655851FCD9ADB4EF9126C78386EA93BCB25BA" + "3EC475C55C608E771C763AB02506F9B07252D6ABF7EA64B1EBDE7B95C6407690533BD689" + "0B9274C16066F74FC401EA355F0A02106814D49BF0C89E6E1F8DB2A47841CD0DAD793296" + "A107C36223404F2BF1FCA16FD0A4B982634DB62407F8F14ACAE3B05A038BD3E4BBBAE439" + "1BBFA7A47FB9D01DE857EA88E5E36EE36E245859FC0F020301000128E83D1280037E0658" + "1A019184AB572AFDCADDD03F161CE68200F8E6F8AD161947360BC8D49C0D68009B1C4644" + "F9B3F3FB6DDFD92EF92DE62D41D459D29D81BFAEF3970A3A39D25B2662ECB03B2DA7B683" + "02FAA6DD98D95A143CC8C1CB6ADDA76D2EE9C3723FAF95A29CDC3E968B6821A91C051CA2" + "80A86669710A1AD7A44BF9218027460DF694E2E9270396DF221963F21EE6AA220A5EE4A4" + "D0FEB3D53EB5732F8F91E9A96B3B8BE284C51339EA284D4D0EDD55B6AD56F7416420E05E" + "059F9734A96BE25AA44560DBA8C38755A42A82BD7F88EDD19DF346A667B33B8114C76A88" + "38C423D824A50B23251A088136D6E8F475299D2AFD46CEA51B5CBDF789A572125CD24FBB" + "813B387A10CD2A30E3447634AB3408F96B9CF3D98896D405F3F540D9C57962760FCD177C" + "DD101EB8A4148B9C29CED5EAD645A95B698F1CDC6E1DB6678B85074186080D68D13CD37E" + "07B16DE370CD9AFB9B25564A73A30E2AF8085EA37D310C474F0E67AC00CA992A5296FAED" + "AD7AA06ECD790F1E3D426558FA98383E3CD2ED483012F403B36550E6BEACCB34F6C3B2AB" + "F86634EE5383829C844F9B0C14DCF9A22FE3543CCBA8FD61E21CEE503E7A40B93B07A418" + "6A362D9E6F88DD48D4516635C6D0C253C03F12EFA6095618D647F5212C518C4A6AA7172B" + "C691530703FEDDFDB25ECF885A53FF2B4B98773979D61AE659E340489811512A5C2FD445" + "A4B0AE88A3A7F29ACE5B01ECF580D0993227BC408B602B0BC099920C17044FE66242372C" + "2B2E8CA5C1EEC0844BC19198ADADE47FB449DC9B30784952B3A8131B912CE928070D665C" + "0557EBE7484FDABFBCA0F2C2BFD4FBDDB6681C4689FD276C231B72B15AC4E5C3C088449D" + "E4785F1D4835AC44E39B119991EFF6E72C7D3B8C75CE588DB0B3AD69EB79C19B22CB518E" + "F964C9D985AFD3677F0D13015AD7BEA84CD01E335E68AF153B989FE8BEEC60A94753C638" + "535FA3F215F750F6954AC395F8702941409E7276910CE11819649641318B5BD1B78DECEA" + "DB2B562312CC286DB0BCC14A60C84CB21AB6E75E59DAFBE701D6405DD3F47D2F8A95422E" + "D8EB5ECE330C9886406B3B69180B697521F3865B4A05DF2BB51D16CAFEF05866E5D55C36" + "0C759F5B10E0D354D63D5A14E5BA19DBF9394E18E474E79063B4E877C2FE6BCA732ED39B" + "091B6D7A21DD9D6D6750C1CA2ABC5DEC2A81B5359771849E7B4560EB6D329E59455A70F5" + "7F035DFB50EC4354D7E068ADFAFAD4081ACA67FD1220F07050C50264B496211432D47DAA" + "88EE59BAD141B8FD372BAE67A6FF05C74DAC"); + +// Structurally valid test certificate device file. +// {'certificate': kTestCertificate, +// 'key_type': 'RSA', +// 'wrapped_private_key': kTestWrappedPrivateKeyData +// } const std::string kTestCertificateFileData = a2bs_hex( - "0A950D080110011A8E0D0AA0050A98030802120D73657269616C5F6E756D62657218B4B2CD" - "E00422E8024D49494243674B43415145412B78475A2F77637A39756746705030374E73706F" - "365531376C305968466946707878553470546B334C69667A3952337A734973754552777461" - "372B66574966784F6F3230386574742F6A68736B69566F6453457433514247683458426970" - "79576F704B775A393348486144565A41414C692F32412B785442745764456F37584755756A" - "4B447643322F615A4B756B666A704F6955493841684C41666A6D6C63442F555A3151506830" - "6D4873676C524E436D7043776D7753584139564E6D687A2B5069422B446D6C3457576E4B57" - "2F56486F32756A54587871372B65664D55344832666E79335365334B594F73465046475A31" - "544E5153596C467553685772485074694C6D5564506F50364356326D4D4C31746B2B6C3744" - "494971587251684C554B444143654D35726F4D78306B4C6855574238502B30756A31434E6C" - "4E4E344A525A6C433778466671694D62465255395A344E3659774944415141422899203A11" - "746573742E7769646576696E652E636F6D1282023078363530633966326536373031653366" - "65373364333035343930346139613462626462393637333366316334633734336566353733" - "61643661633134633561336266386134373331663665363237366661656135323437333033" - "36373766623864626466323466663738653533633235303532636463613837656563666565" - "38353437366263623861303563623961316566656637636238376464363832323365313137" - "63653830306163343631373731373235343437353761343837626533326635616238666530" - "38373966613861646437386265343635656138663864356163663937376539663161653336" - "6434643437383136656136656434313337326212E807344637323442303635333236333731" - "41324635463646353134363743324532363535354334353342354337433142344632373338" - "34353442373832453345374235333430343335413636333734443036313230353243353231" - "41323333443741363731393438373137353143373835373545353137373037303133303236" - "34433446303337363333333230453636374231413439313932393234343931333338363933" - "44313036453631313330313441373333413234314131413033334532383335323137383134" - "36423446353433443338313034413539313931323033323535303243333133363535303630" - "39364435393538354530383737344235423536374137423544303334353145364231313633" - "33453532363732433232363130333130344233453443303331413634303330353046334135" - "37344432433530313731313737333830323734314637463341304433363437353731303144" - "30323138314337443444333532303731363735303641343234433039344534413732333136" - "46373931463136324437363635374432423544334332443742323733413238363932373731" - "37353631333136353138374535353238323433303439313436373038363432353433323334" - "37373031433331313634343644323136343543373536423244334430463739374333323230" - "33323244363232413235344430423744344631443544304330413336373535443132343637" - "34314133343738334334353135373234373039314337383233324237443245304531463633" - "37413241333733393038354437363136363734373033343335303631333936393037324635" - "42354335423231363537453437304337453531334233463039314437343435354133413037" - "33373035374237453342353333373139314434453735333630383743333334423630323835" - "33304633463542323333383042364130373630333132393435303130303344364431463234" - "30463633303533443544304232373142364130463236313835363530373331333038363630" - "42303434373536363034313638344635383443323232313645353637443342373735353639" - "35463746334436423634353235453732323731363539343831303135343032343343313934" - "39354334433730324633373439304632363631333335333739373832353632343134333236" - "33303433303230453145363736303132334435313035364632463145343832463245334430" - "32314232373637374433453745334330433131373537433334343832373545303833383245" - "31313132363336343443364432323437313437303644373630413035344135383645313735" - "303543333432393537354134313034334631383432303912205C6993E9656F73A41739773A" - "0FCBA8AE232CD8856ACE585FF6BFB2A09C20061E"); + "0AAB0F080110011AA40F0AA80B0AEB03080212107CB49F987A635E1E0A52184694582D6E" + "1887C6E1FE05228E023082010A0282010100DB13F5089C061E8EB62562692B3A06A774A9" + "9129BD63445FEC24448D07C30D7343553442A989AF000B7D962033C290D9A81DDCBCF398" + "0512445EB7E6CF544FC1FB3FC758FB9E06B6C28562A841E4AE2D3368795C41A2D6043CA9" + "830E0F36583C8FDB839C2752C13E184034EE412BA8A90271295B094255A16319706F4D6C" + "9CF1EBB1B39BA2A7B9B2780344DD5834BF71F4D5185508D2FDFB10419BD4F48E79DDFC78" + "471C11B9E99DF98221D6FAB25AEE24574FB02D614974942A36527C62B73A6FB7CA9EF828" + "EB598DA59060D654851103F857A041E66B2FFB99713D31A64605932833E8CCDA6CF0F888" + "AE6E78EDC9DA0D88A185B97FEB3EA74CF146BE7D9267020301000128E83D3A0C77696465" + "76696E652E636F6D480152AA01080110001A8101044F554B9400E10B17185036B6A1628E" + "FC61B22166DE2235717A44F953B7928F3415B9D113835B10106CB6C2187F34188723D82E" + "CF95CF5ECAB58923F1731860815999F08BF4BE4A44DB7B991B5F915F2ADCEE481E26096A" + "AEC3AC761B624A92158AC91035041173392B1E495428F0D17406B10889B6B701FAF08D22" + "84F95DBBCA2220595267DCA89A2E57E7D4CA3C62ED6D12742408A07C103DF860DC0520C3" + "664EEB1280028CD44E12AA7C1A8EBF88C81A2A54EFD29F8BC6C377B0C11C3404F84D8B9E" + "AD52A0E18E929A4923A4172C2AC1CDADD16E41A7833AA0DE9D09F685DAC9ACC702CB9061" + "632C1C82333A6FB6BC9C4B2540BE18CED4AB0AF1C3EFE521308F3D4CF513C20500064FE9" + "35FDDF7BBAC0BA99AA7FA66017898DEE6F6F5EF90C875D5D8DA39E769E8D1485253EEE93" + "A97B35A8EAE8D3213D392B552FB4B4A37955EBE7362287502EB649D982F06D308178642C" + "1F69B12383B050CF60CD29209329C148FB4F422ED5ED139A25A89E13D4AB2E8DB940299D" + "1414AF30DDF0D06AF55C1978F6E71E4548F20FFAE953A99D492F3D2847783338D74F66D2" + "DFEBB50896ACBC4795A81AB4050AAE020801121065802C9B625E5A319C33DC1CB7C3C6D4" + "18E3A5BDD005228E023082010A0282010100B80502043C2A8A0FD8D25C613E1E3E3B5E34" + "9F332F04516A7510D38021A5629B9AA027AEAD3C759B7AFE70BED65F3DF6860FF5EB60B9" + "83A3FFA33FDE06F3B73014DFC845AB371C6600562E9D904F842B8BA4A5D9200FFA3ED45D" + "705520A5C372A889F9E314386234C6897AE655851FCD9ADB4EF9126C78386EA93BCB25BA" + "3EC475C55C608E771C763AB02506F9B07252D6ABF7EA64B1EBDE7B95C6407690533BD689" + "0B9274C16066F74FC401EA355F0A02106814D49BF0C89E6E1F8DB2A47841CD0DAD793296" + "A107C36223404F2BF1FCA16FD0A4B982634DB62407F8F14ACAE3B05A038BD3E4BBBAE439" + "1BBFA7A47FB9D01DE857EA88E5E36EE36E245859FC0F020301000128E83D1280037E0658" + "1A019184AB572AFDCADDD03F161CE68200F8E6F8AD161947360BC8D49C0D68009B1C4644" + "F9B3F3FB6DDFD92EF92DE62D41D459D29D81BFAEF3970A3A39D25B2662ECB03B2DA7B683" + "02FAA6DD98D95A143CC8C1CB6ADDA76D2EE9C3723FAF95A29CDC3E968B6821A91C051CA2" + "80A86669710A1AD7A44BF9218027460DF694E2E9270396DF221963F21EE6AA220A5EE4A4" + "D0FEB3D53EB5732F8F91E9A96B3B8BE284C51339EA284D4D0EDD55B6AD56F7416420E05E" + "059F9734A96BE25AA44560DBA8C38755A42A82BD7F88EDD19DF346A667B33B8114C76A88" + "38C423D824A50B23251A088136D6E8F475299D2AFD46CEA51B5CBDF789A572125CD24FBB" + "813B387A10CD2A30E3447634AB3408F96B9CF3D98896D405F3F540D9C57962760FCD177C" + "DD101EB8A4148B9C29CED5EAD645A95B698F1CDC6E1DB6678B85074186080D68D13CD37E" + "07B16DE370CD9AFB9B25564A73A30E2AF8085EA37D310C474F0E67AC00CA992A5296FAED" + "AD7AA06ECD790F1E3D426558FA98383E3CD2ED483012F403B36550E6BEACCB34F6C3B2AB" + "F86634EE5383829C844F9B0C14DCF9A22FE3543CCBA8FD61E21CEE503E7A40B93B07A418" + "6A362D9E6F88DD48D4516635C6D0C253C03F12EFA6095618D647F5212C518C4A6AA7172B" + "C691530703FEDDFDB25ECF885A53FF2B4B98773979D61AE659E340489811512A5C2FD445" + "A4B0AE88A3A7F29ACE5B01ECF580D0993227BC408B602B0BC099920C17044FE66242372C" + "2B2E8CA5C1EEC0844BC19198ADADE47FB449DC9B30784952B3A8131B912CE928070D665C" + "0557EBE7484FDABFBCA0F2C2BFD4FBDDB6681C4689FD276C231B72B15AC4E5C3C088449D" + "E4785F1D4835AC44E39B119991EFF6E72C7D3B8C75CE588DB0B3AD69EB79C19B22CB518E" + "F964C9D985AFD3677F0D13015AD7BEA84CD01E335E68AF153B989FE8BEEC60A94753C638" + "535FA3F215F750F6954AC395F8702941409E7276910CE11819649641318B5BD1B78DECEA" + "DB2B562312CC286DB0BCC14A60C84CB21AB6E75E59DAFBE701D6405DD3F47D2F8A95422E" + "D8EB5ECE330C9886406B3B69180B697521F3865B4A05DF2BB51D16CAFEF05866E5D55C36" + "0C759F5B10E0D354D63D5A14E5BA19DBF9394E18E474E79063B4E877C2FE6BCA732ED39B" + "091B6D7A21DD9D6D6750C1CA2ABC5DEC2A81B5359771849E7B4560EB6D329E59455A70F5" + "7F035DFB50EC4354D7E068ADFAFAD4081ACA67FD18001220A28ED0C0D4697C870B56192C" + "F2AF86D7362398EB250F6A29BE3A0C4887F0D653"); struct LicenseInfo { std::string key_set_id; @@ -2129,9 +2242,10 @@ MATCHER_P(StrAndLenContains, str_vector, "") { TEST_F(DeviceCertificateTest, StoreCertificate) { MockFileSystem file_system; - std::string certificate(CdmRandom::RandomData(kCertificateLen)); - std::string wrapped_private_key(CdmRandom::RandomData(kWrappedKeyLen)); - std::string device_certificate_path = + const std::string certificate(CdmRandom::RandomData(kCertificateLen)); + const CryptoWrappedKey private_key(CryptoWrappedKey::kRsa, + CdmRandom::RandomData(kWrappedKeyLen)); + const std::string device_certificate_path = device_base_path_ + DeviceFiles::GetCertificateFileName(false); // Call to Open will return a unique_ptr, freeing this object. @@ -2141,21 +2255,21 @@ TEST_F(DeviceCertificateTest, StoreCertificate) { .WillOnce(Return(file)); EXPECT_CALL(*file, Write(_, _)) .With(AllArgs(StrAndLenContains( - std::vector{certificate, wrapped_private_key}))) + std::vector{certificate, private_key.key()}))) .WillOnce(ReturnArg<1>()); EXPECT_CALL(*file, Read(_, _)).Times(0); DeviceFiles device_files(&file_system); EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); - EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key)); + EXPECT_TRUE(device_files.StoreCertificate(certificate, private_key)); } TEST_P(DeviceCertificateTest, ReadCertificate) { MockFileSystem file_system; const bool atsc_mode = GetParam(); - std::string device_certificate_path = + const std::string device_certificate_path = device_base_path_ + DeviceFiles::GetCertificateFileName(atsc_mode); - std::string data = kTestCertificateFileData; + const std::string data = kTestCertificateFileData; // Call to Open will return a unique_ptr, freeing this object. MockFile* file = new MockFile(); @@ -2174,14 +2288,51 @@ TEST_P(DeviceCertificateTest, ReadCertificate) { DeviceFiles device_files(&file_system); EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); - std::string certificate, wrapped_private_key; + std::string certificate; + CryptoWrappedKey private_key; std::string serial_number; uint32_t system_id = 0; - ASSERT_TRUE(device_files.RetrieveCertificate(atsc_mode, &certificate, - &wrapped_private_key, - &serial_number, &system_id)); + ASSERT_TRUE(device_files.RetrieveCertificate( + atsc_mode, &certificate, &private_key, &serial_number, &system_id)); EXPECT_EQ(kTestCertificate, certificate); - EXPECT_EQ(kTestWrappedPrivateKey, wrapped_private_key); + EXPECT_EQ(kTestWrappedKey, private_key); + EXPECT_EQ("7CB49F987A635E1E0A52184694582D6E", b2a_hex(serial_number)); +} + +TEST_P(DeviceCertificateTest, ReadCertificateWithoutKeyType) { + // Stored files without an explicit key type should default to RSA. + MockFileSystem file_system; + const bool atsc_mode = GetParam(); + const std::string device_certificate_path = + device_base_path_ + DeviceFiles::GetCertificateFileName(atsc_mode); + const std::string data = kTestCertificateFileWithoutKeyTypeData; + + // Call to Open will return a unique_ptr, freeing this object. + MockFile* file = new MockFile(); + EXPECT_CALL(file_system, Exists(StrEq(device_certificate_path))) + .Times(2) + .WillRepeatedly(Return(true)); + EXPECT_CALL(file_system, FileSize(StrEq(device_certificate_path))) + .WillOnce(Return(data.size())); + EXPECT_CALL(file_system, DoOpen(StrEq(device_certificate_path), _)) + .WillOnce(Return(file)); + EXPECT_CALL(*file, Read(NotNull(), Eq(data.size()))) + .WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()), + Return(data.size()))); + EXPECT_CALL(*file, Write(_, _)).Times(0); + + DeviceFiles device_files(&file_system); + EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); + + std::string certificate; + CryptoWrappedKey private_key; + std::string serial_number; + uint32_t system_id = 0; + ASSERT_TRUE(device_files.RetrieveCertificate( + atsc_mode, &certificate, &private_key, &serial_number, &system_id)); + EXPECT_EQ(kTestCertificate, certificate); + EXPECT_EQ(kTestWrappedKey, private_key); + EXPECT_EQ("7CB49F987A635E1E0A52184694582D6E", b2a_hex(serial_number)); } TEST_P(DeviceCertificateTest, HasCertificate) { @@ -2210,7 +2361,8 @@ INSTANTIATE_TEST_CASE_P(AtscMode, DeviceCertificateTest, TEST_P(DeviceFilesSecurityLevelTest, SecurityLevel) { MockFileSystem file_system; std::string certificate(CdmRandom::RandomData(kCertificateLen)); - std::string wrapped_private_key(CdmRandom::RandomData(kWrappedKeyLen)); + const CryptoWrappedKey private_key(CryptoWrappedKey::kRsa, + CdmRandom::RandomData(kWrappedKeyLen)); CdmSecurityLevel security_level = GetParam(); std::string device_base_path; @@ -2226,13 +2378,13 @@ TEST_P(DeviceFilesSecurityLevelTest, SecurityLevel) { .WillOnce(Return(file)); EXPECT_CALL(*file, Write(_, _)) .With(AllArgs(StrAndLenContains( - std::vector{certificate, wrapped_private_key}))) + std::vector{certificate, private_key.key()}))) .WillOnce(ReturnArg<1>()); EXPECT_CALL(*file, Read(_, _)).Times(0); DeviceFiles device_files(&file_system); EXPECT_TRUE(device_files.Init(security_level)); - EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key)); + EXPECT_TRUE(device_files.StoreCertificate(certificate, private_key)); } INSTANTIATE_TEST_CASE_P(SecurityLevel, DeviceFilesSecurityLevelTest, diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index 74a3d6c2..786b0134 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -68,6 +68,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case CERT_PROVISIONING_RESPONSE_ERROR_8: *os << "CERT_PROVISIONING_RESPONSE_ERROR_8"; break; + case CERT_PROVISIONING_RESPONSE_ERROR_9: + *os << "CERT_PROVISIONING_RESPONSE_ERROR_9"; + break; case CLIENT_ID_AES_ENCRYPT_ERROR: *os << "CLIENT_ID_AES_ENCRYPT_ERROR"; break; diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index fc30d375..787ebf62 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -17,6 +17,7 @@ #include "arraysize.h" #include "cdm_identifier.h" #include "config_test_env.h" +#include "crypto_wrapped_key.h" #include "device_files.h" #include "device_files.pb.h" #include "file_store.h" @@ -2288,7 +2289,7 @@ TEST_F(WvCdmRequestLicenseTest, UnprovisionTest) { DeviceFiles handle(&file_system); EXPECT_TRUE(handle.Init(security_level)); std::string certificate; - std::string wrapped_private_key; + CryptoWrappedKey wrapped_private_key; std::string serial_number; uint32_t system_id; EXPECT_TRUE(handle.RetrieveCertificate( diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index 5d4820b3..eda2f4ce 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -298,10 +298,11 @@ enum { kLoadUsageEntryInvalidSession = ERROR_DRM_VENDOR_MIN + 313, kRestoreOfflineLicenseError3 = ERROR_DRM_VENDOR_MIN + 314, kNoSrmVersion = ERROR_DRM_VENDOR_MIN + 315, + kCertProvisioningResponseError9 = ERROR_DRM_VENDOR_MIN + 316, // This should always follow the last error code. // The offset value should be updated each time a new error code is added. - kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 315, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 316, // Used by crypto test mode kErrorTestMode = ERROR_DRM_VENDOR_MAX, diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h index ba0a92b6..b0ee42ed 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -103,6 +103,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kCertProvisioningResponseError7; case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_8: return kCertProvisioningResponseError8; + case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_9: + return kCertProvisioningResponseError9; case wvcdm::CLIENT_IDENTIFICATION_TOKEN_ERROR_1: return kClientIdentificationTokenError1; case wvcdm::CLIENT_ID_AES_ENCRYPT_ERROR: diff --git a/libwvdrmengine/include_hidl/mapErrors-inl.h b/libwvdrmengine/include_hidl/mapErrors-inl.h index fc7b2cf1..6952e126 100644 --- a/libwvdrmengine/include_hidl/mapErrors-inl.h +++ b/libwvdrmengine/include_hidl/mapErrors-inl.h @@ -358,6 +358,7 @@ static Status mapCdmResponseType_1_0(wvcdm::CdmResponseType res) { case wvcdm::LICENSE_USAGE_ENTRY_MISSING: case wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC: case wvcdm::NO_SRM_VERSION: + case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_9: ALOGW("Returns UNKNOWN error for legacy status: %d", res); return Status::ERROR_DRM_UNKNOWN; From 0ac0ee50eb4d9fb865b4ba22fcc7a7072f27de73 Mon Sep 17 00:00:00 2001 From: Edwin Wong Date: Mon, 22 Feb 2021 22:54:47 -0800 Subject: [PATCH 5/5] Display menu if no argument is given. If not argument is given, the app just sits and wait for stdin input, this can be confusing for the user. Add logic to display menu if no argument is given. Test: metrics_dump display menu Test: metrics_dump [bugreport from sabrina-q.gz] display mediadrm and widevine metrics Test: metrics_dump --mediadrm [adb shell dumpsys media.metrics output] display mediadrm metrics Test: metrics_dump --widevine [adb shell dumpsys media.metrics output] display widevine metrics Test: metrics_dump [bugreport from sabrina-q.gz] --widevine display menu because the order is app_name, options, input file Bug: 180983850 Change-Id: I9b35f782d8f59663661148d3950f89e4724b6bce Merged-In: I9b35f782d8f59663661148d3950f89e4724b6bce --- libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp b/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp index 8c2ecc78..b3029fcd 100644 --- a/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp +++ b/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp @@ -123,7 +123,7 @@ using std::cerr; using std::endl; using std::string; -void usage() { +void exit_with_menu() { cerr << "usage: metrics_dump [options] []" << endl; cerr << endl; cerr << "Displays the drm metrics that are generated by" << endl; @@ -146,7 +146,7 @@ void usage() { cerr << " --select |" << endl; cerr << " only show metrics from the specified package or component" << endl; - exit(-1); + exit(0); } int main(int argc, char **argv) { @@ -155,10 +155,11 @@ int main(int argc, char **argv) { GOOGLE_PROTOBUF_VERIFY_VERSION; int i = 1; + if (argc == 1) exit_with_menu(); while (i < argc) { string arg = argv[i]; if (arg == "--help") { - usage(); + exit_with_menu(); } else if (arg == "--no-gms") { metrics_dump::excluded_ones.push_back("com.google.android.gms"); } else if (arg == "--widevine") { @@ -184,7 +185,7 @@ int main(int argc, char **argv) { metrics_dump::selected_one = argv[++i]; metrics_dump::to_lower(metrics_dump::selected_one); } else { - usage(); + exit_with_menu(); } } i++;