diff options
author | sandersd <sandersd@chromium.org> | 2015-02-19 22:08:01 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-20 06:08:43 +0000 |
commit | f629e579c00a93751c75883d48c600d3df4d1ed6 (patch) | |
tree | 329beac97727e472bae498486f0207e6864be59f /media/blink | |
parent | 501da0af4e357859485bab20f37dec6d8dc34d18 (diff) | |
download | chromium_src-f629e579c00a93751c75883d48c600d3df4d1ed6.zip chromium_src-f629e579c00a93751c75883d48c600d3df4d1ed6.tar.gz chromium_src-f629e579c00a93751c75883d48c600d3df4d1ed6.tar.bz2 |
Implement checks for distinctiveIdentifier and persistentState in requestMediaKeySystemAccess().
Also includes additional metadata in KeySystemInfo to support those checks.
BUG=4484922
Review URL: https://codereview.chromium.org/923283002
Cr-Commit-Position: refs/heads/master@{#317257}
Diffstat (limited to 'media/blink')
-rw-r--r-- | media/blink/webencryptedmediaclient_impl.cc | 329 |
1 files changed, 242 insertions, 87 deletions
diff --git a/media/blink/webencryptedmediaclient_impl.cc b/media/blink/webencryptedmediaclient_impl.cc index 53b6583..c963df8 100644 --- a/media/blink/webencryptedmediaclient_impl.cc +++ b/media/blink/webencryptedmediaclient_impl.cc @@ -28,25 +28,97 @@ static bool IsSupportedContentType( const std::string& key_system, const std::string& mime_type, const std::string& codecs) { - // Per RFC 6838, "Both top-level type and subtype names are case-insensitive." - // TODO(sandersd): Check that |container| matches the capability: - // - audioCapabilitys: audio/mp4 or audio/webm. - // - videoCapabilitys: video/mp4 or video/webm. - // http://crbug.com/457384. + // TODO(sandersd): Move contentType parsing from Blink to here so that invalid + // parameters can be rejected. http://crbug.com/417561 + // TODO(sandersd): Pass in the media type (audio or video) and check that the + // container type matches. http://crbug.com/457384 std::string container = base::StringToLowerASCII(mime_type); - // Check that |codecs| are supported as specified (e.g. "mp4a.40.2"). + // Check that |codecs| are supported by the CDM. This check does not handle + // extended codecs, so extended codec information is stripped. + // TODO(sandersd): Reject codecs that do not match the media type. + // http://crbug.com/457386 std::vector<std::string> codec_vector; - net::ParseCodecString(codecs, &codec_vector, false); - if (!net::AreSupportedMediaCodecs(codec_vector)) + net::ParseCodecString(codecs, &codec_vector, true); + if (!IsSupportedKeySystemWithMediaMimeType(container, codec_vector, + key_system)) { return false; + } - // IsSupportedKeySystemWithMediaMimeType() only works with base codecs - // (e.g. "mp4a"), so reparse |codecs| to get the base only. + // Check that |codecs| are supported by Chrome. This is done primarily to + // validate extended codecs, but it also ensures that the CDM cannot support + // codecs that Chrome does not (which would be bad because it would require + // considering the accumulated configuration, and could affect whether secure + // decode is required). + // TODO(sandersd): Reject ambiguous codecs. http://crbug.com/374751 codec_vector.clear(); - net::ParseCodecString(codecs, &codec_vector, true); - return IsSupportedKeySystemWithMediaMimeType(container, codec_vector, - key_system); + net::ParseCodecString(codecs, &codec_vector, false); + return net::AreSupportedMediaCodecs(codec_vector); +} + +static bool GetSupportedCapabilities( + const std::string& key_system, + const blink::WebVector<blink::WebMediaKeySystemMediaCapability>& + capabilities, + std::vector<blink::WebMediaKeySystemMediaCapability>* + media_type_capabilities) { + // From https://w3c.github.io/encrypted-media/#get-supported-capabilities-for-media-type + // 1. Let accumulated capabilities be partial configuration. + // (Skipped as there are no configuration-based codec restrictions.) + // 2. Let media type capabilities be empty. + DCHECK_EQ(media_type_capabilities->size(), 0ul); + // 3. For each value in capabilities: + for (size_t i = 0; i < capabilities.size(); i++) { + // 3.1. Let contentType be the value's contentType member. + // 3.2. Let robustness be the value's robustness member. + const blink::WebMediaKeySystemMediaCapability& capability = capabilities[i]; + // 3.3. If contentType is the empty string, return null. + if (capability.mimeType.isEmpty()) + return false; + // 3.4-3.11. (Implemented by IsSupportedContentType().) + if (!base::IsStringASCII(capability.mimeType) || + !base::IsStringASCII(capability.codecs) || + !IsSupportedContentType(key_system, + base::UTF16ToASCII(capability.mimeType), + base::UTF16ToASCII(capability.codecs))) { + continue; + } + // 3.12. If robustness is not the empty string, run the following steps: + // (Robustness is not supported.) + // TODO(sandersd): Implement robustness. http://crbug.com/442586 + if (!capability.robustness.isEmpty()) { + LOG(WARNING) << "Configuration rejected because rubustness strings are " + << "not yet supported."; + continue; + } + // 3.13. If the user agent and implementation do not support playback of + // encrypted media data as specified by configuration, including all + // media types, in combination with accumulated capabilities, + // continue to the next iteration. + // (Skipped as there are no configuration-based codec restrictions.) + // 3.14. Add configuration to media type capabilities. + media_type_capabilities->push_back(capability); + // 3.15. Add configuration to accumulated capabilities. + // (Skipped as there are no configuration-based codec restrictions.) + } + // 4. If media type capabilities is empty, return null. + // 5. Return media type capabilities. + return !media_type_capabilities->empty(); +} + +static EmeFeatureRequirement ConvertRequirement( + blink::WebMediaKeySystemConfiguration::Requirement requirement) { + switch (requirement) { + case blink::WebMediaKeySystemConfiguration::Requirement::Required: + return EME_FEATURE_REQUIRED; + case blink::WebMediaKeySystemConfiguration::Requirement::Optional: + return EME_FEATURE_OPTIONAL; + case blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed: + return EME_FEATURE_NOT_ALLOWED; + } + + NOTREACHED(); + return EME_FEATURE_NOT_ALLOWED; } static bool GetSupportedConfiguration( @@ -54,92 +126,180 @@ static bool GetSupportedConfiguration( const blink::WebMediaKeySystemConfiguration& candidate, const blink::WebSecurityOrigin& security_origin, blink::WebMediaKeySystemConfiguration* accumulated_configuration) { + // When determining support, assume that permission could be granted. + // TODO(sandersd): Set to false if the permission is rejected. + bool is_permission_possible = true; + + // From https://w3c.github.io/encrypted-media/#get-supported-configuration + // 1. Let accumulated configuration be empty. (Done by caller.) + // 2. If candidate configuration's initDataTypes attribute is not empty, run + // the following steps: if (!candidate.initDataTypes.isEmpty()) { - std::vector<blink::WebString> init_data_types; + // 2.1. Let supported types be empty. + std::vector<blink::WebString> supported_types; + // 2.2. For each value in candidate configuration's initDataTypes attribute: for (size_t i = 0; i < candidate.initDataTypes.size(); i++) { + // 2.2.1. Let initDataType be the value. const blink::WebString& init_data_type = candidate.initDataTypes[i]; + // 2.2.2. If initDataType is the empty string, return null. if (init_data_type.isEmpty()) return false; + // 2.2.3. If the implementation supports generating requests based on + // initDataType, add initDataType to supported types. String + // comparison is case-sensitive. if (base::IsStringASCII(init_data_type) && IsSupportedKeySystemWithInitDataType( key_system, base::UTF16ToASCII(init_data_type))) { - init_data_types.push_back(init_data_type); + supported_types.push_back(init_data_type); } } - if (init_data_types.empty()) + // 2.3. If supported types is empty, return null. + if (supported_types.empty()) return false; - accumulated_configuration->initDataTypes = init_data_types; + // 2.4. Add supported types to accumulated configuration. + accumulated_configuration->initDataTypes = supported_types; } - // TODO(sandersd): Implement distinctiveIdentifier and persistentState checks. - if (candidate.distinctiveIdentifier != - blink::WebMediaKeySystemConfiguration::Requirement::Optional || - candidate.persistentState != - blink::WebMediaKeySystemConfiguration::Requirement::Optional) { + // 3. Follow the steps for the value of candidate configuration's + // distinctiveIdentifier attribute from the following list: + // - "required": If the implementation does not support a persistent + // Distinctive Identifier in combination with accumulated configuration, + // return null. + // - "optional": Continue. + // - "not-allowed": If the implementation requires a Distinctive + // Identifier in combination with accumulated configuration, return + // null. + EmeFeatureRequirement di_requirement = + ConvertRequirement(candidate.distinctiveIdentifier); + if (!IsDistinctiveIdentifierRequirementSupported(key_system, di_requirement, + is_permission_possible)) { return false; } - if (!candidate.audioCapabilities.isEmpty()) { - std::vector<blink::WebMediaKeySystemMediaCapability> audio_capabilities; + // 4. Add the value of the candidate configuration's distinctiveIdentifier + // attribute to accumulated configuration. + accumulated_configuration->distinctiveIdentifier = + candidate.distinctiveIdentifier; + + // 5. Follow the steps for the value of candidate configuration's + // persistentState attribute from the following list: + // - "required": If the implementation does not support persisting state + // in combination with accumulated configuration, return null. + // - "optional": Continue. + // - "not-allowed": If the implementation requires persisting state in + // combination with accumulated configuration, return null. + EmeFeatureRequirement ps_requirement = + ConvertRequirement(candidate.persistentState); + if (!IsPersistentStateRequirementSupported(key_system, ps_requirement, + is_permission_possible)) { + return false; + } - for (size_t i = 0; i < candidate.audioCapabilities.size(); i++) { - const blink::WebMediaKeySystemMediaCapability& capabilities = - candidate.audioCapabilities[i]; - if (capabilities.mimeType.isEmpty()) - return false; - if (!base::IsStringASCII(capabilities.mimeType) || - !base::IsStringASCII(capabilities.codecs) || - !IsSupportedContentType( - key_system, base::UTF16ToASCII(capabilities.mimeType), - base::UTF16ToASCII(capabilities.codecs))) { - continue; - } - // TODO(sandersd): Support robustness. - if (!capabilities.robustness.isEmpty()) - continue; - audio_capabilities.push_back(capabilities); + // 6. Add the value of the candidate configuration's persistentState + // attribute to accumulated configuration. + accumulated_configuration->persistentState = candidate.persistentState; + + // 7. If candidate configuration's videoCapabilities attribute is not empty, + // run the following steps: + if (!candidate.videoCapabilities.isEmpty()) { + // 7.1. Let video capabilities be the result of executing the Get Supported + // Capabilities for Media Type algorithm on Video, candidate + // configuration's videoCapabilities attribute, and accumulated + // configuration. + // 7.2. If video capabilities is null, return null. + std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities; + if (!GetSupportedCapabilities(key_system, candidate.videoCapabilities, + &video_capabilities)) { + return false; } - if (audio_capabilities.empty()) + // 7.3. Add video capabilities to accumulated configuration. + accumulated_configuration->videoCapabilities = video_capabilities; + } + + // 8. If candidate configuration's audioCapabilities attribute is not empty, + // run the following steps: + if (!candidate.audioCapabilities.isEmpty()) { + // 8.1. Let audio capabilities be the result of executing the Get Supported + // Capabilities for Media Type algorithm on Audio, candidate + // configuration's audioCapabilities attribute, and accumulated + // configuration. + // 8.2. If audio capabilities is null, return null. + std::vector<blink::WebMediaKeySystemMediaCapability> audio_capabilities; + if (!GetSupportedCapabilities(key_system, candidate.audioCapabilities, + &audio_capabilities)) { return false; + } + // 8.3. Add audio capabilities to accumulated configuration. accumulated_configuration->audioCapabilities = audio_capabilities; } - if (!candidate.videoCapabilities.isEmpty()) { - std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities; - - for (size_t i = 0; i < candidate.videoCapabilities.size(); i++) { - const blink::WebMediaKeySystemMediaCapability& capabilities = - candidate.videoCapabilities[i]; - if (capabilities.mimeType.isEmpty()) - return false; - if (!base::IsStringASCII(capabilities.mimeType) || - !base::IsStringASCII(capabilities.codecs) || - !IsSupportedContentType( - key_system, base::UTF16ToASCII(capabilities.mimeType), - base::UTF16ToASCII(capabilities.codecs))) { - continue; - } - // TODO(sandersd): Support robustness. - if (!capabilities.robustness.isEmpty()) - continue; - video_capabilities.push_back(capabilities); + // 9. If accumulated configuration's distinctiveIdentifier value is + // "optional", follow the steps for the first matching condition from the + // following list: + // - If the implementation requires a Distinctive Identifier for any of + // the combinations in accumulated configuration, change accumulated + // configuration's distinctiveIdentifier value to "required". + // - Otherwise, change accumulated configuration's distinctiveIdentifier + // value to "not-allowed". + // (Without robustness support, capabilities do not affect this.) + // TODO(sandersd): Implement robustness. http://crbug.com/442586 + if (accumulated_configuration->distinctiveIdentifier == + blink::WebMediaKeySystemConfiguration::Requirement::Optional) { + if (IsDistinctiveIdentifierRequirementSupported(key_system, + EME_FEATURE_NOT_ALLOWED, + is_permission_possible)) { + accumulated_configuration->distinctiveIdentifier = + blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed; + } else { + accumulated_configuration->distinctiveIdentifier = + blink::WebMediaKeySystemConfiguration::Requirement::Required; } + } - if (video_capabilities.empty()) - return false; + // 10. If accumulated configuration's persistentState value is "optional", + // follow the steps for the first matching condition from the following + // list: + // - If the implementation requires persisting state for any of the + // combinations in accumulated configuration, change accumulated + // configuration's persistentState value to "required". + // - Otherwise, change accumulated configuration's persistentState value + // to "not-allowed". + if (accumulated_configuration->persistentState == + blink::WebMediaKeySystemConfiguration::Requirement::Optional) { + if (IsPersistentStateRequirementSupported(key_system, + EME_FEATURE_NOT_ALLOWED, + is_permission_possible)) { + accumulated_configuration->persistentState = + blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed; + } else { + accumulated_configuration->persistentState = + blink::WebMediaKeySystemConfiguration::Requirement::Required; + } + } - accumulated_configuration->videoCapabilities = video_capabilities; + // 11. If implementation in the configuration specified by the combination of + // the values in accumulated configuration is not supported or not allowed + // in the origin, return null. + // TODO(sandersd): Implement prompting. http://crbug.com/446263 + // For now, assume that the permission was not granted. + di_requirement = + ConvertRequirement(accumulated_configuration->distinctiveIdentifier); + if (!IsDistinctiveIdentifierRequirementSupported(key_system, di_requirement, + false)) { + return false; } - // TODO(sandersd): Prompt for distinctive identifiers and/or persistent state - // if required. Make sure that future checks are silent. - // http://crbug.com/446263. + ps_requirement = + ConvertRequirement(accumulated_configuration->persistentState); + if (!IsPersistentStateRequirementSupported(key_system, ps_requirement, false)) + return false; + // 12. Return accumulated configuration. return true; } @@ -212,9 +372,9 @@ void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess( // Continued from requestMediaKeySystemAccess(), step 7, from // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess // - // 7.1 If keySystem is not one of the Key Systems supported by the user - // agent, reject promise with with a new DOMException whose name is - // NotSupportedError. String comparison is case-sensitive. + // 7.1. If keySystem is not one of the Key Systems supported by the user + // agent, reject promise with with a new DOMException whose name is + // NotSupportedError. String comparison is case-sensitive. if (!base::IsStringASCII(request.keySystem())) { request.requestNotSupported("Only ASCII keySystems are supported"); return; @@ -231,27 +391,21 @@ void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess( return; } - // 7.2 Let implementation be the implementation of keySystem. - // 7.3 For each value in supportedConfigurations, run the GetSupported - // Configuration algorithm and if successful, resolve promise with access - // and abort these steps. + // 7.2. Let implementation be the implementation of keySystem. + // 7.3. For each value in supportedConfigurations: const blink::WebVector<blink::WebMediaKeySystemConfiguration>& configurations = request.supportedConfigurations(); - - // TODO(sandersd): Remove once Blink requires the configurations parameter for - // requestMediaKeySystemAccess(). - if (configurations.isEmpty()) { - reporter->ReportSupported(); - request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create( - request.keySystem(), blink::WebMediaKeySystemConfiguration(), - request.securityOrigin(), weak_factory_.GetWeakPtr())); - return; - } - for (size_t i = 0; i < configurations.size(); i++) { - const blink::WebMediaKeySystemConfiguration& candidate = configurations[i]; + // 7.3.1. Let candidate configuration be the value. + const blink::WebMediaKeySystemConfiguration& candidate_configuration = + configurations[i]; + // 7.3.2. Let supported configuration be the result of executing the Get + // Supported Configuration algorithm on implementation, candidate + // configuration, and origin. + // 7.3.3. If supported configuration is not null, [initialize and return a + // new MediaKeySystemAccess object.] blink::WebMediaKeySystemConfiguration accumulated_configuration; - if (GetSupportedConfiguration(key_system, candidate, + if (GetSupportedConfiguration(key_system, candidate_configuration, request.securityOrigin(), &accumulated_configuration)) { reporter->ReportSupported(); @@ -262,7 +416,8 @@ void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess( } } - // 7.4 Reject promise with a new DOMException whose name is NotSupportedError. + // 7.4. Reject promise with a new DOMException whose name is + // NotSupportedError. request.requestNotSupported( "None of the requested configurations were supported."); } |