Improve verification of proto parsing across Cdm, RemoteCdm and Device

This ensures that a partially parsing input (because of optional flags in the proto) does not get past any verification checks.

This prevents issues like an invalid License Challenging from getting an exception later down the line, as well as possibility of it also passing that check by pure luck, resulting in hard to debug issues.
This commit is contained in:
rlaphoenix 2022-09-05 12:35:06 +01:00
parent 23c766af71
commit fa499a6a53
3 changed files with 35 additions and 7 deletions

View File

@ -360,6 +360,8 @@ class Cdm:
signed_message = SignedMessage() signed_message = SignedMessage()
try: try:
signed_message.ParseFromString(license_message) signed_message.ParseFromString(license_message)
if signed_message.SerializeToString() != license_message:
raise DecodeError(license_message)
except DecodeError as e: except DecodeError as e:
raise InvalidLicenseMessage(f"Could not parse license_message as a SignedMessage, {e}") raise InvalidLicenseMessage(f"Could not parse license_message as a SignedMessage, {e}")
license_message = signed_message license_message = signed_message

View File

@ -110,20 +110,37 @@ class Device:
self.client_id = ClientIdentification() self.client_id = ClientIdentification()
try: try:
self.client_id.ParseFromString(client_id) self.client_id.ParseFromString(client_id)
except DecodeError: if self.client_id.SerializeToString() != client_id:
raise ValueError("Failed to parse client_id as a ClientIdentification") raise DecodeError("partial parse")
except DecodeError as e:
raise ValueError(f"Failed to parse client_id as a ClientIdentification, {e}")
self.vmp = FileHashes() self.vmp = FileHashes()
if self.client_id.vmp_data: if self.client_id.vmp_data:
try: try:
self.vmp.ParseFromString(self.client_id.vmp_data) self.vmp.ParseFromString(self.client_id.vmp_data)
except DecodeError: if self.vmp.SerializeToString() != self.client_id.vmp_data:
raise ValueError("Failed to parse Client ID's VMP data as a FileHashes") raise DecodeError("partial parse")
except DecodeError as e:
raise ValueError(f"Failed to parse Client ID's VMP data as a FileHashes, {e}")
signed_drm_certificate = SignedDrmCertificate() signed_drm_certificate = SignedDrmCertificate()
signed_drm_certificate.ParseFromString(self.client_id.token)
drm_certificate = DrmCertificate() drm_certificate = DrmCertificate()
drm_certificate.ParseFromString(signed_drm_certificate.drm_certificate)
try:
signed_drm_certificate.ParseFromString(self.client_id.token)
if signed_drm_certificate.SerializeToString() != self.client_id.token:
raise DecodeError("partial parse")
except DecodeError as e:
raise DecodeError(f"Failed to parse the Signed DRM Certificate of the Client ID, {e}")
try:
drm_certificate.ParseFromString(signed_drm_certificate.drm_certificate)
if drm_certificate.SerializeToString() != signed_drm_certificate.drm_certificate:
raise DecodeError("partial parse")
except DecodeError as e:
raise DecodeError(f"Failed to parse the DRM Certificate of the Client ID, {e}")
self.system_id = drm_certificate.system_id self.system_id = drm_certificate.system_id
def __repr__(self) -> str: def __repr__(self) -> str:
@ -190,6 +207,8 @@ class Device:
if data.vmp: if data.vmp:
try: try:
vmp.ParseFromString(data.vmp) vmp.ParseFromString(data.vmp)
if vmp.SerializeToString() != data.vmp:
raise DecodeError("partial parse")
except DecodeError as e: except DecodeError as e:
raise DecodeError(f"Failed to parse VMP data as FileHashes, {e}") raise DecodeError(f"Failed to parse VMP data as FileHashes, {e}")
data.vmp = vmp data.vmp = vmp
@ -197,6 +216,8 @@ class Device:
client_id = ClientIdentification() client_id = ClientIdentification()
try: try:
client_id.ParseFromString(data.client_id) client_id.ParseFromString(data.client_id)
if client_id.SerializeToString() != data.client_id:
raise DecodeError("partial parse")
except DecodeError as e: except DecodeError as e:
raise DecodeError(f"Failed to parse VMP data as FileHashes, {e}") raise DecodeError(f"Failed to parse VMP data as FileHashes, {e}")

View File

@ -175,8 +175,11 @@ class RemoteCdm(Cdm):
r = r["data"] r = r["data"]
try: try:
challenge = base64.b64decode(r["challenge_b64"])
license_message = SignedMessage() license_message = SignedMessage()
license_message.ParseFromString(base64.b64decode(r["challenge_b64"])) license_message.ParseFromString(challenge)
if license_message.SerializeToString() != challenge:
raise DecodeError("partial parse")
except DecodeError as e: except DecodeError as e:
raise InvalidLicenseMessage(f"Failed to parse license request, {e}") raise InvalidLicenseMessage(f"Failed to parse license request, {e}")
@ -196,6 +199,8 @@ class RemoteCdm(Cdm):
signed_message = SignedMessage() signed_message = SignedMessage()
try: try:
signed_message.ParseFromString(license_message) signed_message.ParseFromString(license_message)
if signed_message.SerializeToString() != license_message:
raise DecodeError("partial parse")
except DecodeError as e: except DecodeError as e:
raise InvalidLicenseMessage(f"Could not parse license_message as a SignedMessage, {e}") raise InvalidLicenseMessage(f"Could not parse license_message as a SignedMessage, {e}")
license_message = signed_message license_message = signed_message