castlabs / electron-releases

castLabs Electron for Content Security
https://castlabs.com/resources/downstream/
MIT License
226 stars 43 forks source link

Requests made to Widevine licenses server proxy at playback time, despite electron.exe is VPM-signed w/ EVS for production content... #177

Closed loicraux closed 10 months ago

loicraux commented 10 months ago
{
  "electronVersion": "28.1.3", // Note : this is CastLabs' ECS 
  "nodeVersion": "18.18.2",
  "chromeVersion": "120.0.6099.199",
  "shakaPlayerVersion": "4.7.6",
  "widevineCDMVersion": "4.10.2710.0",
  "operatingSystem": "Windows 11 x64 10.0.22621"
}

I've created a prototype of offline player for protected (by Widevine DRM) videos.

I make use of Shaka-Player (latest version 4.7.6), the DRM provider EZDRM and ECS. Note that I am using Windows.

Since the video content I want to play is production content, I am not using Widevine UAT servers accepting development clients, consequently I have signed my electron binary for production, using CastLabs's Cloud-based EVS service :

python3 -m castlabs_evs.vmp sign-pkg --persistent node_modules/electron/dist/

The electron.exe is correctly signed :

Signing: node_modules/electron/dist\electron.exe
 - Verifying existing VMP signature
 - Signature invalid: Certificate is valid for development only
 - Verifying matching VMP signature in cache
 - Signature is valid [persistent, 2368 days of validity], use cached signature

I have also check the same with the following command :

python3 -m castlabs_evs.vmp verify-pkg --persistent node_modules/electron/dist/
Verifying signature for: node_modules/electron/dist\electron.exe
 - Signature is valid [persistent, 2368 days of validity]

To download offline content, here is basically my shaka-player setup :

    const GOOGLE_WIDEVINE_KEY_SYSTEM = 'com.widevine.alpha';

    const { drm } = await shaka.Player.probeSupport();
    const arePersistentLicensesSupported = drm[GOOGLE_WIDEVINE_KEY_SYSTEM]?.persistentState ?? false;
    logInfo(`Persistent licenses are ${arePersistentLicensesSupported ? 'supported' : 'not supported'}`);

    player.configure({
        drm: {
            logLicenseExchange: true, // TODO: change value depending on build mode.
            preferredKeySystems: [GOOGLE_WIDEVINE_KEY_SYSTEM],
            // True to configure drm to try playback with given persistent session ids
            // before requesting a license. Also prevents the session removal at playback stop,
            // as-to be able to re-use it later :
            persistentSessionOnlinePlayback: arePersistentLicensesSupported,
            advanced: {
                [GOOGLE_WIDEVINE_KEY_SYSTEM]: {
                    videoRobustness: 'SW_SECURE_CRYPTO',
                    audioRobustness: 'SW_SECURE_CRYPTO',
                    // True if the application requires the key system to support persistent state,
                    // e.g., for persistent license storage :
                    persistentStateRequired: arePersistentLicensesSupported
                }
            },
            servers: {
                [GOOGLE_WIDEVINE_KEY_SYSTEM]: getLicenseServerUrl(username, video)
            }
        },
        offline: {
            usePersistentLicense: arePersistentLicensesSupported,
            progressCallback,
            trackSelectionCallback
        }
    });

Then I use storage.store API from shaka-player to download the contents... Everything is OK, two POST requests are made to EZDRM's widevine license server proxy, and both are successfum (HTTP code 200 returned)

Creating new persistent-license session
shaka-player-ui.js?v=8001658b:2116 EME init data: type= cenc data= AAAAVHBzc2gAAAAA7e-LqXnWSs6jyCfc1R0h7QAAADQIARIQqZxKFTq9VH6BOWGMTUmCYhoIbW92aWRvbmUiEMyRd5Wf9b9NiYMUxq-hK58qAlNE
shaka-player-ui.js?v=8001658b:2116 EME license request ...
shaka-player-ui.js?v=8001658b:2116 EME license response ...
shaka-player-ui.js?v=8001658b:2116 EME license request ...
shaka-player-ui.js?v=8001658b:2116 EME license response ...

Here is the content in the IndexDB shaka_offline_db database manifest_v5 table :

drmInfo:
    audioRobustness: "SW SECURE CRYPTO"
    distinctiveIdentifierRequired: false
    ▼initData: Array(0)
        length: 0
    keyIds: Set(1)
        ▼[[Entries]]
        ▼0: "a99c4a153abd547e8139618c4d498262"
            value: "a99c4a153abd547e8139618c4d498262"
        size: 1
    keysystem: "com.widevine.alpha"
    licenseServerUri: "https://widevine-dash.ezdrm.com/proxy?username=xyz%40artefrance.fr&contentId=HDS_139940_0-VOF&PX-BASEDC"
    persistentStateRequired: true
    ▾ serverCertificate: Uint8Array(0)
        buffer: ArrayBuffer(0)
        bytetength: 0
        byteoffset: 0
        length: 0
        Symbol(Symbol.toStringTag): "Uint8Array"
    serverCertificateUri: ""
    sessionType: "persistent-license"
    videoRobustness: "SW SECURE CRYPTO"
duration: 730.090666
expiration: Infinity
isIncomplete: false
originalManifesturi: "https://boutique-arte-streams.lab.arte.tv/origin/HLS_139940_0-VOF-cenc.ism/stream.mpd"
sequenceMode: false
▼sessionIds: Array(0)
    length: 0
size: 57083255
streams: Array(2)
    : {id: 3, originalid: 'audio=192000', groupId: null, primary: true, type: 'audio', } 1: (id: 5, originalld: 'video-424000', groupId: null, primary: true, type: 'video', )
    length: 2
type: "DASH"

What did you expect to happen? Now, once the download is complete, I go offline and I attempt to play the downloaded contents. I would expect no HTTP requests to be made to EZDRM's widevine licenses server proxy

I would expect playback of offline content not to require any network connection, since I have set usePersistentLicense to true and persistent license storage is supported by my VPM-signed ECS...

What actually happened? Two requests (probably because drm.retryParameters.maxAttempts is set to 2 ?) are made, which obvisouly fails since there is no network connectivity....

Consequently, the playback of the video when offline does not work...

What could cause shaka-player to request once again license at playback time ? I can't find the reason why... (tell me if you need additional details !)

I have of course created an issue on shaka-player repository for the same, but cross-posted the issue here so that someone from CastLabs can give me insights / tips ....

Feel free to answer here or close this issue and reply in shaka player issue : https://github.com/shaka-project/shaka-player/issues/6141

Thanks !

khwaaj commented 10 months ago

I'd say this is a shaka-player issue, since the Widevine requests themselves are successful. I'd guess the mapping between the Widevine session-id and the content is lost somewhere along the way, and this mapping needs to be maintained by the player (the CDM and/or browser will not do it for you) or the correct persisted session will not be able to load.

loicraux commented 10 months ago

I'd say this is a shaka-player issue, since the Widevine requests themselves are successful. I'd guess the mapping between the Widevine session-id and the content is lost somewhere along the way, and this mapping needs to be maintained by the player (the CDM and/or browser will not do it for you) or the correct persisted session will not be able to load.

Yes this is indeed a shaka player issue, a PR has already been submitted on their side.