diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index acad7d0f..93c58415 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -418,6 +418,7 @@ enum CdmResponseType : int32_t { NO_SRM_VERSION = 363, SESSION_NOT_FOUND_23 = 364, CERT_PROVISIONING_RESPONSE_ERROR_9 = 365, + CERT_PROVISIONING_RESPONSE_ERROR_10 = 366, // 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/certificate_provisioning.cpp b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp index 52413ae4..6d177b6e 100644 --- a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp +++ b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp @@ -118,6 +118,7 @@ using video_widevine::ProvisioningRequest; using video_widevine::ProvisioningResponse; using video_widevine::SignedDrmDeviceCertificate; using video_widevine::SignedProvisioningMessage; +using video_widevine::SignedProvisioningMessage_ProvisioningProtocolVersion_VERSION_1_1; CdmResponseType CertificateProvisioning::Init( const std::string& service_certificate) { @@ -298,6 +299,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest( } else { signed_provisioning_msg.set_oemcrypto_core_message(core_message); } + signed_provisioning_msg.set_protocol_version( + SignedProvisioningMessage_ProvisioningProtocolVersion_VERSION_1_1); std::string serialized_request; signed_provisioning_msg.SerializeToString(&serialized_request); @@ -393,6 +396,22 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse( return CERT_PROVISIONING_RESPONSE_ERROR_4; } + if (provisioning_response.has_status()) { + if (provisioning_response.status() != ProvisioningResponse::NO_ERROR) { + LOGE("Provisioning Response status: %d", provisioning_response.status()); + } + + switch (provisioning_response.status()) { + case ProvisioningResponse::NO_ERROR: + break; + case ProvisioningResponse::REVOKED_DEVICE_CREDENTIALS: + case ProvisioningResponse::REVOKED_DEVICE_SERIES: + return DEVICE_REVOKED; + default: + return CERT_PROVISIONING_RESPONSE_ERROR_10; + } + } + CryptoWrappedKey private_key; const CdmResponseType status = crypto_session_->LoadProvisioning( signed_message, core_message, signature, &private_key.key()); diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index 786b0134..586a828a 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -71,6 +71,10 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case CERT_PROVISIONING_RESPONSE_ERROR_9: *os << "CERT_PROVISIONING_RESPONSE_ERROR_9"; break; + case CERT_PROVISIONING_RESPONSE_ERROR_10: + *os << "CERT_PROVISIONING_RESPONSE_ERROR_10"; + break; + 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 787ebf62..d539bad7 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -76,7 +76,15 @@ const std::vector kCanDisableAnalogOutput = { using video_widevine::LicenseIdentification; using video_widevine::LicenseRequest_ContentIdentification; using video_widevine::ProvisioningResponse; +using video_widevine::ProvisioningResponse_ProvisioningStatus; +using video_widevine::ProvisioningResponse_ProvisioningStatus_NO_ERROR; +using video_widevine:: + ProvisioningResponse_ProvisioningStatus_REVOKED_DEVICE_CREDENTIALS; +using video_widevine:: + ProvisioningResponse_ProvisioningStatus_REVOKED_DEVICE_SERIES; using video_widevine::SignedProvisioningMessage; +using video_widevine:: + SignedProvisioningMessage_ProvisioningProtocolVersion_VERSION_1_1; // TODO(rfrias): refactor to print out the decryption test names struct SubSampleInfo { @@ -2468,6 +2476,113 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningSpoidTest) { alternate_cdm_id_2_serial_number_1); } +TEST_F(WvCdmRequestLicenseTest, ProvisioningRevocationTest) { + Unprovision(); + + CdmResponseType result = + decryptor_->OpenSession(config_.key_system(), nullptr, + kDefaultCdmIdentifier, nullptr, &session_id_); + + switch (result) { + case NO_ERROR: + decryptor_->CloseSession(session_id_); + return; + case NEED_PROVISIONING: + break; + default: + EXPECT_EQ(NO_ERROR, result); + return; + } + + std::string provisioning_server; + std::string cert_authority, provisioning_request; + + result = decryptor_->GetProvisioningRequest( + kCertificateWidevine, cert_authority, kDefaultCdmIdentifier, + kEmptyServiceCertificate, kLevelDefault, &provisioning_request, + &provisioning_server); + + EXPECT_EQ(wvcdm::NO_ERROR, result); + if (NO_ERROR != result) return; + EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + + if (!wvcdm::Properties::provisioning_messages_are_binary()) { + std::vector request = Base64SafeDecode(provisioning_request); + provisioning_request.assign(request.begin(), request.end()); + } + + // Verify that provisioning request has protocol version set correctly + SignedProvisioningMessage signed_provisioning_msg; + EXPECT_TRUE(signed_provisioning_msg.ParseFromString(provisioning_request)); + EXPECT_EQ(SignedProvisioningMessage_ProvisioningProtocolVersion_VERSION_1_1, + signed_provisioning_msg.protocol_version()); + const bool supports_core_messages = + signed_provisioning_msg.has_oemcrypto_core_message() && + !signed_provisioning_msg.oemcrypto_core_message().empty(); + + // Create provisioning responses with differing ProvisioningStatus values + const std::vector + provisioning_status{ + ProvisioningResponse_ProvisioningStatus_NO_ERROR, + ProvisioningResponse_ProvisioningStatus_REVOKED_DEVICE_CREDENTIALS, + ProvisioningResponse_ProvisioningStatus_REVOKED_DEVICE_SERIES, + // Add undefined ProvisioningStatus + static_cast( + ProvisioningResponse_ProvisioningStatus_REVOKED_DEVICE_SERIES + + 10)}; + + // Now form provisioning messages for each of the status values and verify + // that they have been handled correctly + for (ProvisioningResponse_ProvisioningStatus status : provisioning_status) { + result = decryptor_->GetProvisioningRequest( + kCertificateWidevine, cert_authority, kDefaultCdmIdentifier, + kEmptyServiceCertificate, kLevelDefault, &provisioning_request, + &provisioning_server); + + EXPECT_EQ(wvcdm::NO_ERROR, result); + if (NO_ERROR != result) return; + EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl); + + ProvisioningResponse provisioning_response; + provisioning_response.set_status(status); + + SignedProvisioningMessage signed_response; + signed_response.set_signature("fake signature"); + std::string message; + provisioning_response.SerializeToString(&message); + signed_response.set_message(message); + if (supports_core_messages) { + signed_response.set_oemcrypto_core_message("fake oemcrypto core msg"); + } + + std::string response; + signed_response.SerializeToString(&response); + + if (!wvcdm::Properties::provisioning_messages_are_binary()) { + std::vector response_vec(response.begin(), response.end()); + response = "\"signedResponse\": \""; + response.append(wvcdm::Base64SafeEncode(response_vec)); + response.append("\""); + } + + std::string cert, wrapped_key; + result = decryptor_->HandleProvisioningResponse( + kDefaultCdmIdentifier, response, kLevelDefault, &cert, &wrapped_key); + + switch (status) { + case ProvisioningResponse_ProvisioningStatus_REVOKED_DEVICE_CREDENTIALS: + case ProvisioningResponse_ProvisioningStatus_REVOKED_DEVICE_SERIES: + EXPECT_EQ(DEVICE_REVOKED, result) << "Provisioning status: " << status; + break; + default: + // ProvisioningResponse_ProvisioningStatus_NO_ERROR will not return + // NO_ERROR because signature, oemcrypto core message are fake + EXPECT_NE(DEVICE_REVOKED, result) << "Provisioning status: " << status; + break; + } + } +} + TEST_F(WvCdmRequestLicenseTest, PropertySetTest) { TestWvCdmClientPropertySet property_set_L1; TestWvCdmClientPropertySet property_set_L3; diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index eda2f4ce..dc6b0dc7 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -299,10 +299,11 @@ enum { kRestoreOfflineLicenseError3 = ERROR_DRM_VENDOR_MIN + 314, kNoSrmVersion = ERROR_DRM_VENDOR_MIN + 315, kCertProvisioningResponseError9 = ERROR_DRM_VENDOR_MIN + 316, + kCertProvisioningResponseError10 = ERROR_DRM_VENDOR_MIN + 317, // 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 + 316, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 317, // 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 b0ee42ed..5a871d92 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -105,6 +105,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kCertProvisioningResponseError8; case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_9: return kCertProvisioningResponseError9; + case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_10: + return kCertProvisioningResponseError10; 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 6952e126..3d904c48 100644 --- a/libwvdrmengine/include_hidl/mapErrors-inl.h +++ b/libwvdrmengine/include_hidl/mapErrors-inl.h @@ -359,6 +359,7 @@ static Status mapCdmResponseType_1_0(wvcdm::CdmResponseType res) { case wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC: case wvcdm::NO_SRM_VERSION: case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_9: + case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_10: ALOGW("Returns UNKNOWN error for legacy status: %d", res); return Status::ERROR_DRM_UNKNOWN; @@ -650,6 +651,11 @@ static S mapCdmResponseType(wvcdm::CdmResponseType res) { case wvcdm::LOAD_PROVISIONING_ERROR: err = ::drm::V1_4::Status::PROVISIONING_PARSE_ERROR; break; + /* TODO (b/180579631): Uncomment when DRM Status type + * PROVISIONING_REQUEST_REJECTED has been created + case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_10: + err = ::drm::V1_4::Status::PROVISIONING_REQUEST_REJECTED; + */ case wvcdm::EMPTY_PROVISIONING_CERTIFICATE_1: case wvcdm::EMPTY_PROVISIONING_CERTIFICATE_2: err = ::drm::V1_4::Status::RETRYABLE_PROVISIONING_ERROR;