24 Commits

Author SHA1 Message Date
rlaphoenix
5c1b0e89ef Cdm: Support multiple forms of Service Certs in encrypt_client_id 2022-08-02 01:48:48 +01:00
rlaphoenix
0c85abb2d4 Cdm: Save Service Certificate in SignedMessage form
We may need the signature for external verification, and most APIs require it to be in a SignedMessage to be accepted, even though the SignedMessage is pretty much empty (not even actually signed lol).
2022-08-02 01:48:48 +01:00
rlaphoenix
e36411cfaf Cdm: Clear context for the challenge once loaded
This stops users from loading the license twice, which wouldn't do anything wrong, but without doing this context deletion we could possibly end up with a ton of memory that would likely go unused if the same Cdm session is used a lot for a long time.
2022-07-30 05:13:30 +01:00
rlaphoenix
3536caf5f9 Rework Cdm as a Session Key/Store Cdm
There's a few benefits to this but the main one being storage for each "request". We can now change Service Certificate per-session for example rather than for the entire Cdm object. In a multi-threaded scenario this can be a necessity more than anything.

The device is the only bit of data left that does not get stored in a session. This is mostly due to myself not seeing it being switched out often and setting it per-session would likely be cumbersome.

Some other small improvements are all around. There's a ton of doc-string improvements, typing improvements, verification of types, and there's now custom Exceptions.

In terms of bug fixes there isn't any I fixed explicitly but a possible issue in decrypt() relating the Key Labels may now be fixed.

I've moved the Keys from the return of parse_license() to the session data, with decrypt() now loading them from the session data instead. This keeps the decryption keys out of the view of the caller but it is by no way impossible to get those keys. It is incredibly trivial to access the session and get the keys from the Cdm manually.

A session limit of 50 is still set by the Cdm.
2022-07-30 04:50:18 +01:00
rlaphoenix
82d99d50d0 Cdm: Fix typing of type_ param on get_license_challenge()
`LicenseType` shouldn't be used as a type-hint as its not a Type.
2022-07-30 04:22:35 +01:00
rlaphoenix
3afcf9c01c Cdm: Improve readability of license signature exception 2022-07-30 03:13:58 +01:00
rlaphoenix
3a15c1050a Cdm: Fix context availability check in parse_license() 2022-07-30 03:11:21 +01:00
rlaphoenix
0bfbbdccc3 Cdm: Return the service cert provider id instead of the cert
There's no need for the user to get back the verified DrmCertificate as they could easily get it themselves. Instead return the provider ID which may be more useful to get.
2022-07-30 02:50:22 +01:00
rlaphoenix
d1974ad1fb Cdm: Improve parsing of service certificates 2022-07-30 02:44:34 +01:00
rlaphoenix
1cedba7e49 Cdm: Change param pssh to init_data
This is to signal what the Cdm really uses. Asking for a PSSH may sound like it uses a full PSSH when in reality all it cares for is the underlying init data (Widevine Cenc Header/WidevinePsshData).
2022-07-30 02:26:11 +01:00
rlaphoenix
b5ac0f45a2 Remove Cdm raw param, Improve PSSH.get_as_box()
The Cdm no longer requires you to specify if it's raw or not thanks to changes in PSSH.get_as_box() now supporting both dynamically.

It will parse the data and if its not a box, it will use the provided data in a newly crafted box.
2022-07-30 02:21:19 +01:00
rlaphoenix
a3102ded18 Cdm: Verify Signatures of Security Certificates
This improves Cdm security and prevents a trivial exploit on Privacy Mode allowing an attacker to bypass Privacy Mode by controlling their own Public/Private Key Pair on Service Certificates.

The attack is simple in which you create your own RSA-2048 key pair, replace the public key of a service certificate with your own, and now you have the corresponding private key to be able to decrypt Encrypted Client IDs. This trivial attack is often used on CDM re-implementations, proxies, and APIs to obtain sensitive Device Client ID information.

With this commit this attack is prevented on this Cdm implementation, making it more secure from attacks. A signed DRM Certificate must be provided now as the ability to provide a direct DrmCertificate has been removed.

The root certificate added alongside this commit has no private key and cannot be used to re-sign an altered DrmCertificate.
2022-07-29 22:14:48 +01:00
rlaphoenix
ac469383b8 Cdm: Validate License Message type in parse_license 2022-07-24 21:07:00 +01:00
rlaphoenix
93cdc7f44e Remove f-string without expression, mute unused variable in Cdm 2022-07-23 16:29:28 +01:00
rlaphoenix
943968f2c7 Cdm: Remove the use of .format() in decrypt() 2022-07-23 16:26:09 +01:00
rlaphoenix
95982725c3 Cdm: Support providing Service Cert as any 3 schemas
Some service's might provide the Service Certificate as a SignedDrmCertificate instead of a SignedMessage so I added support for supplying such format certificates. I also added support for supplying a DrmCertificate directly, though it's unlikely for a service to provide it raw without a signature like that.

The Service Certificate is now also stored as just the DrmCertificate internally, as it will not be using the signature.
2022-07-21 17:26:14 +01:00
rlaphoenix
e20f251aae Cdm: Simplify Session ID
The whole Session ID based on some weird half buggy reverse engineering is completely unnecessary.
2022-07-21 01:33:09 +01:00
rlaphoenix
23165f92de Cdm: Fix bug where context data may not correspond to the right license
We are using a trick with the request_id to be able to add an identifier between get_license_challenge() and parse_license() without any middleman data needing to be passed by the user.

Otherwise the user would need to either create the context data themselves after get_license_challenge() and pass it to get_license(), or something that is similar at its core to that.
2022-07-21 01:12:28 +01:00
rlaphoenix
68db728bf0 Cdm: Only store license request's context data
This reduces the amount of data needing to be stored, but also simplifies the key derivation.
2022-07-20 22:25:57 +01:00
rlaphoenix
53f7c1dd62 Cdm: Fix size and Improve code of Android Session IDs 2022-07-20 21:40:40 +01:00
rlaphoenix
909e83c199 Cdm: Return a DecodeError in set_service_certificate
This is to match with the doc-string stating it returns a DecodeError on failure.
2022-07-20 20:55:08 +01:00
rlaphoenix
2bb5c9e0b5 Cdm: Remove unnecessary raw class instance variable 2022-07-20 20:37:04 +01:00
rlaphoenix
7f60844ee1 Cdm: Move License Type from constructor to get_license_challenge() 2022-07-20 20:36:17 +01:00
rlaphoenix
36c83268c3 Add Widevine CDM Class
Please note that this CDM implementation isn't inherently secure. For more information see the README about Key and Output Security.

Also adds a utility to get an absolute path to something in the environment PATH, by multiple names, if found.
2022-07-20 14:41:42 +01:00