Skip to content

Commit

Permalink
add extra tmd error, add header/content_info_records len checks, use …
Browse files Browse the repository at this point in the history
…rstrip for u_issuer
  • Loading branch information
ihaveamac committed Sep 11, 2018
1 parent a861733 commit 2f55c65
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 6 deletions.
18 changes: 14 additions & 4 deletions fuse3ds/pyctr/types/tmd.py
Expand Up @@ -41,11 +41,15 @@ class TitleMetadataError(PyCTRError):
"""Generic exception for TitleMetadata operations."""


class InvalidSignatureTypeError(TitleMetadataError):
class InvalidTMDError(TitleMetadataError):
"""Title Metadata is invalid."""


class InvalidSignatureTypeError(InvalidTMDError):
"""Invalid signature type was used."""


class InvalidHashError(TitleMetadataError):
class InvalidHashError(InvalidTMDError):
"""Hash mismatch in the Title Metadata."""


Expand Down Expand Up @@ -125,13 +129,14 @@ class TitleMetadataReader:
'_u_signer_crl_version', '_u_reserved1', '_u_system_version', '_u_title_type', '_u_group_id',
'_u_reserved2', '_u_srl_flag', '_u_reserved3', '_u_access_rights', '_u_boot_count', '_u_padding')

# arguments prefixed with _u_ are values unused by the 3DS
# arguments prefixed with _u_ are values unused by the 3DS and/or are only kept around to generate the final tmd
def __init__(self, *, title_id: str, save_size: int, srl_save_size: int, title_version: TitleVersion,
info_records: 'Iterable[ContentInfoRecord]', chunk_records: 'Iterable[ContentChunkRecord]',
signature=BLANK_SIG_PAIR, _u_issuer='Root-CA00000003-CP0000000b', _u_version=1, _u_ca_crl_version=0,
_u_signer_crl_version=0, _u_reserved1=0, _u_system_version=b'\0' * 8, _u_title_type=b'\0\0\0@',
_u_group_id=b'\0\0', _u_reserved2=b'\0\0\0\0', _u_srl_flag=0, _u_reserved3=b'\0' * 0x31,
_u_access_rights=b'\0' * 4, _u_boot_count=b'\0\0', _u_padding=b'\0\0'):
# TODO: add checks
self.title_id = title_id.lower()
self.save_size = save_size
self.srl_save_size = srl_save_size
Expand Down Expand Up @@ -182,6 +187,8 @@ def load(cls, fp: 'BinaryIO', verify_hashes: bool = True) -> 'TitleMetadataReade
fp.read(sig_padding)

header = fp.read(0xC4)
if len(header) != 0xC4:
raise InvalidTMDError('Header length is not 0xC4')

# only values that actually have a use are loaded here. (currently)
# several fields in were left in from the Wii tmd and have no function on 3DS.
Expand All @@ -194,6 +201,9 @@ def load(cls, fp: 'BinaryIO', verify_hashes: bool = True) -> 'TitleMetadataReade
content_info_records_hash = header[0xA4:0xC4]

content_info_records_raw = fp.read(0x900)
if len(content_info_records_raw) != 0x900:
raise InvalidTMDError('Content info records length is not 0x900')

if verify_hashes:
real_hash = sha256(content_info_records_raw)
if content_info_records_hash != real_hash.digest():
Expand Down Expand Up @@ -221,7 +231,7 @@ def load(cls, fp: 'BinaryIO', verify_hashes: bool = True) -> 'TitleMetadataReade
hash=cr[16:48]))

# unused vales are loaded only for use when re-building the binary tmd
u_issuer = header[0:0x40].decode('ascii').strip('\0')
u_issuer = header[0:0x40].decode('ascii').rstrip('\0')
u_version = header[0x40]
u_ca_crl_version = header[0x41]
u_signer_crl_version = header[0x42]
Expand Down
4 changes: 2 additions & 2 deletions fuse3ds/pyctr/util.py
Expand Up @@ -19,12 +19,12 @@


def readle(b: bytes) -> int:
"""Return little-endian bytes to an int."""
"""Convert little-endian bytes to an int."""
return int.from_bytes(b, 'little')


def readbe(b: bytes) -> int:
"""Return big-endian bytes to an int."""
"""Convert big-endian bytes to an int."""
return int.from_bytes(b, 'big')


Expand Down

0 comments on commit 2f55c65

Please sign in to comment.