mirror of
https://github.com/hyugogirubato/KeyDive.git
synced 2026-07-15 18:40:02 +02:00
fix keybox system id resolver
This commit is contained in:
+23
-17
@@ -73,28 +73,31 @@ def CryptoSession_ExtractSystemIdFromOemCert(cert: Certificate) -> int:
|
|||||||
raise ValueError('The certificate does not contain a Widevine System ID extension.')
|
raise ValueError('The certificate does not contain a Widevine System ID extension.')
|
||||||
|
|
||||||
|
|
||||||
def CryptoSession_GetSecurityLevel(cert: Certificate) -> Optional[int]:
|
def CryptoSession_GetSecurityLevel(data: Union[Certificate, str]) -> int:
|
||||||
"""
|
"""
|
||||||
Determines the Widevine security level (L1, L2, or L3) from the subject field
|
Determines the Widevine security level (L1, L2, L3) from a certificate or a string.
|
||||||
of an X.509 certificate.
|
|
||||||
|
|
||||||
The level is inferred by searching for substrings like "_L1_", "_L2_", or "_L3_" in
|
The security level is inferred by looking for specific substrings in either:
|
||||||
the subject string, which typically reflects the provisioning level of the device
|
- The subject of an X.509 certificate (e.g., containing "_L1_")
|
||||||
(hardware-backed = L1, software-only = L3, etc).
|
- A plain string (e.g., containing "Level1")
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
cert (Certificate): An X.509 certificate whose subject may contain the security level marker.
|
data (Union[Certificate, str]): An X.509 certificate or a descriptive string.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[int]: The security level as an integer (1 = L1, 2 = L2, 3 = L3),
|
int: Security level as an integer (1 = L1, 2 = L2, 3 = L3).
|
||||||
or None if no level marker is found in the subject.
|
Defaults to level 3 if no recognizable pattern is found.
|
||||||
"""
|
"""
|
||||||
# Extract the certificate's subject string in a standardized format
|
if isinstance(data, Certificate):
|
||||||
subject = cert.subject.rfc4514_string()
|
# Extract the certificate's subject string in a standardized format
|
||||||
|
data = data.subject.rfc4514_string()
|
||||||
|
pattern = '_L{}_'
|
||||||
|
else:
|
||||||
|
pattern = 'Level{}'
|
||||||
|
|
||||||
# kSecurityLevel (L1, L2, L3, Unknown)
|
# Scan for each level from 1 to 3 in the input string using the appropriate pattern
|
||||||
# Check for known security level markers in the subject string
|
# If no match is found, assume the default security level is 3 (L3 - software-based)
|
||||||
return next((level for level in range(1, 4) if f'_L{level}_' in subject), None)
|
return next((l for l in range(1, 4) if pattern.format(l) in data), 3)
|
||||||
|
|
||||||
|
|
||||||
class Cdm:
|
class Cdm:
|
||||||
@@ -787,6 +790,8 @@ class Cdm:
|
|||||||
|
|
||||||
# Process all client IDs and their associated private keys
|
# Process all client IDs and their associated private keys
|
||||||
for key, client_id in self._client_id.items():
|
for key, client_id in self._client_id.items():
|
||||||
|
client_info = self.__client_info(client_id)
|
||||||
|
|
||||||
# Parse DRM certificate from the client token protobuf data
|
# Parse DRM certificate from the client token protobuf data
|
||||||
signed_drm_certificate = SignedDrmCertificate()
|
signed_drm_certificate = SignedDrmCertificate()
|
||||||
signed_drm_certificate.ParseFromString(client_id.token)
|
signed_drm_certificate.ParseFromString(client_id.token)
|
||||||
@@ -794,11 +799,12 @@ class Cdm:
|
|||||||
drm_certificate = DrmCertificate()
|
drm_certificate = DrmCertificate()
|
||||||
drm_certificate.ParseFromString(signed_drm_certificate.drm_certificate)
|
drm_certificate.ParseFromString(signed_drm_certificate.drm_certificate)
|
||||||
|
|
||||||
|
# Extract system ID and security level from client ID
|
||||||
system_id = drm_certificate.system_id
|
system_id = drm_certificate.system_id
|
||||||
|
level = CryptoSession_GetSecurityLevel(client_info['oem_crypto_build_information'])
|
||||||
|
|
||||||
# Derive a filesystem path from client info on the first iteration
|
# Derive a filesystem path from client info on the first iteration
|
||||||
if not path:
|
if not path:
|
||||||
client_info = self.__client_info(client_id)
|
|
||||||
path = Path() / unidec(client_info['company_name']) / unidec(client_info['model_name'])
|
path = Path() / unidec(client_info['company_name']) / unidec(client_info['model_name'])
|
||||||
|
|
||||||
# Attempt to find the private key matching the current client key
|
# Attempt to find the private key matching the current client key
|
||||||
@@ -807,7 +813,7 @@ class Cdm:
|
|||||||
# Initialize or retrieve existing record for this system ID
|
# Initialize or retrieve existing record for this system ID
|
||||||
item = items.get(system_id, {
|
item = items.get(system_id, {
|
||||||
'path': path,
|
'path': path,
|
||||||
'level': 3, # Default security level
|
'level': level, # Default security level
|
||||||
'device': [], # List of device keys associated
|
'device': [], # List of device keys associated
|
||||||
'keybox': None, # Associated keybox ID
|
'keybox': None, # Associated keybox ID
|
||||||
'certificate': None # Associated certificate ID
|
'certificate': None # Associated certificate ID
|
||||||
@@ -828,7 +834,7 @@ class Cdm:
|
|||||||
|
|
||||||
# Extract system ID and security level from certificate
|
# Extract system ID and security level from certificate
|
||||||
system_id = CryptoSession_ExtractSystemIdFromOemCert(intermediate_cert)
|
system_id = CryptoSession_ExtractSystemIdFromOemCert(intermediate_cert)
|
||||||
level = CryptoSession_GetSecurityLevel(intermediate_cert) or 3 # Default to level 3 if unknown
|
level = CryptoSession_GetSecurityLevel(intermediate_cert)
|
||||||
|
|
||||||
# Find matching private key for this certificate key
|
# Find matching private key for this certificate key
|
||||||
private_key = next((v for k, v in self._private_key.items() if k == key), None)
|
private_key = next((v for k, v in self._private_key.items() if k == key), None)
|
||||||
|
|||||||
Reference in New Issue
Block a user