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/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. 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