video-dev / hls.js

HLS.js is a JavaScript library that plays HLS in browsers with support for MSE.
https://hlsjs.video-dev.org/demo
Other
14.66k stars 2.56k forks source link

#EXT-X-KEY URI value parsing assumes b64 PRO value for PlayReady, causing errors when those assumptions are not met #6574

Open cjpillsbury opened 1 month ago

cjpillsbury commented 1 month ago

What version of Hls.js are you using?

1.5.13

What browser (including version) are you using?

Edge 126.0.0.0

What OS (including version) are you using?

Windows 11 Home

Test stream

(none shareable publicly, but available on request)

Configuration

{}

Additional player setup steps

No response

Checklist

Steps to reproduce

  1. Attempt to play a PlayReady DRM-protected media playlist with an EXT-X-KEY URI value that is a spec-compliant, b64 encoded PSSH for PlayReady
  2. Note playback errors because the initData provided to EME's getRequest() is a PSSH wrapping another PSSH

Expected behaviour

Playback should not fail due to this, as the expected URI value is not well-defined from any formal specification. If the PSSH for PlayReady is available via the init segment, playback should succeed. hls.js should account for more plausible permutations of b64-encoded values, such as the case described in the example steps to reproduce (a full pssh).

What actually happened?

DRM playback failed due to trying to use the (bad) generated PSSH value from the EXT-X-KEY URI value in a manner that never retried/succeeded with the valid PSSH that would be signaled from EME via the MediaEncryptedEvent (of type 'message').

Console output

None.

Chrome media internals output

No response

cjpillsbury commented 1 month ago

Discussion begun on separate issue here: https://github.com/video-dev/hls.js/issues/6005#issuecomment-2245779771 Breaking out into its own issue, as these are not quite the same problem.

cjpillsbury commented 1 month ago

Callouts from @robwalch on details of solution from prior thread:

It should be a PlayReady Object. The fact that getDecryptData passes the entire decoded data URI to mp4pssh as pssh data (making an incorrect assumption as you've pointed out) appears to be a bug in hls.js.

The proposed solution for the bug in hls.js is to extract the pssh data (the 'Challenge' element) from the PRO. This can be achieved by moving the code from unpackPlayReadyKeyMessage to getDecryptData, where it actually belongs.

There are a couple of other points we should align on:

  1. The issue is in getDecryptData extracting (or identifying) pssh data in PlayReady KEY tags only
  2. mp4pssh does not require changes as the problem you identified is not related to embedding multiple PSSH boxes in KEY tags (this should have been filed as a new issue)
cjpillsbury commented 1 month ago

Workaround for folks who are encountering this issue before fix is merged and released:

Use a generateRequest callback to extract the pssh before a license request is made, as in https://github.com/muxinc/elements/pull/957

robwalch commented 1 month ago

The fact that getDecryptData passes the entire decoded data URI to mp4pssh as pssh data (making an incorrect assumption as you've pointed out) appears to be a bug in hls.js.

The proposed solution for the bug in hls.js is to extract the pssh data (the 'Challenge' element) from the PRO. This can be achieved by moving the code from unpackPlayReadyKeyMessage to `, where it actually belongs.

I need to go back on those statements after better understanding the issue.

The URI for a KEY tag with KEYFORMAT com.microsoft.playready is: data:text/plain;charset=UTF-16;base64,<base64 encoded PlayReady Object> (data:text/plain;charset=UTF-16;base64,<base64 encoded PSSH box> is the URI format for Widevine only)

https://learn.microsoft.com/en-us/playready/packaging/mp4-based-formats-supported-by-playready-clients?tabs=case4

'cbcs' encryption mode, with keys delivered by PlayReady: supported on Xbox One, One S, One X since the update of January 2018 Each individual playlist must include a PRO that contains a PRH that contains the KID of the playlist, using the #EXT-X-KEY:METHOD=SAMPLE-AES tag.

EXTM3U

EXT-X-VERSION:4

EXT-X-KEY:METHOD=SAMPLE-AES,KEYFORMAT="com.microsoft.playready",KEYFORMATVERSIONS="1",URI="data:text/plain;charset=UTF-16;base64,xAEAAAEAAQC6ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AdgBHAFYAagBOAEsAZwBZAE0ARQBxAHAATwBMAGgAMQBWAGQAUgBUADAAQQA9AD0APAAvAEsASQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA="