Skip to content
This repository was archived by the owner on May 12, 2025. It is now read-only.

Commit 0354c2f

Browse files
committed
validate indices and offsets and return them from extract_v1_sig_data()
1 parent ee5c161 commit 0354c2f

File tree

1 file changed

+31
-12
lines changed

1 file changed

+31
-12
lines changed

apksigcopier/__init__.py

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -461,9 +461,7 @@ def copy_apk(unsigned_apk: str, output_apk: str, *,
461461
realign = not skip_realignment
462462
if v1_sig:
463463
v1_sig_fhi = io.BytesIO(v1_sig)
464-
v1_infos, v1_datas, v1_comment_data = extract_v1_sig_data(v1_sig_fhi)
465-
v1_indices = {idx: i for i, (idx, _) in enumerate(v1_comment_data["offsets"])}
466-
v1_offsets = {off: i for i, (_, off) in enumerate(v1_comment_data["offsets"])}
464+
v1_infos, v1_datas, v1_comment_data, v1_indices, v1_offsets = extract_v1_sig_data(v1_sig_fhi)
467465
if "zfe_size" in v1_comment_data and not zfe_size:
468466
zfe_size = int(v1_comment_data["zfe_size"])
469467
v1_cd_offset = _zip_data(v1_sig_fhi, count=min(65536, len(v1_sig))).cd_offset
@@ -635,13 +633,17 @@ def extract_v1_sig(apkfile: str) -> Optional[bytes]:
635633
Created-By: 1.8.0_45-internal (Oracle Corporation)
636634
>>> zf.comment
637635
b'{"offsets":[[6,5109],[7,5595],[8,6706]]}'
638-
>>> v1_infos, v1_datas, v1_comment_data = extract_v1_sig_data(fh)
639-
>>> [x.filename for x in v1_infos]
636+
>>> infos, datas, comment_data, indices, offsets = extract_v1_sig_data(fh)
637+
>>> [x.filename for x in infos]
640638
['META-INF/RSA-2048.SF', 'META-INF/RSA-2048.RSA', 'META-INF/MANIFEST.MF']
641-
>>> [(k, len(v)) for k, v in v1_datas.items()]
639+
>>> [(k, len(v)) for k, v in datas.items()]
642640
[('META-INF/RSA-2048.SF', 664), ('META-INF/RSA-2048.RSA', 1160), ('META-INF/MANIFEST.MF', 589)]
643-
>>> v1_comment_data
641+
>>> comment_data
644642
{'offsets': [[6, 5109], [7, 5595], [8, 6706]]}
643+
>>> indices
644+
{6: 0, 7: 1, 8: 2}
645+
>>> offsets
646+
{5109: 0, 5595: 1, 6706: 2}
645647
646648
"""
647649
with zipfile.ZipFile(apkfile, "r") as zf:
@@ -770,9 +772,14 @@ def validate_zip_header(hdr: bytes, info: zipfile.ZipInfo, datas: Dict[str, byte
770772
return None
771773

772774

773-
def extract_v1_sig_data(fhi: BinaryIO) -> Tuple[List[zipfile.ZipInfo], Dict[str, bytes],
774-
Dict[str, Any]]:
775-
"""Extract data from v1_sig comment."""
775+
def extract_v1_sig_data(fhi: BinaryIO) -> Tuple[
776+
List[zipfile.ZipInfo], Dict[str, bytes], Dict[str, Any],
777+
Dict[int, int], Dict[int, int]]:
778+
"""
779+
Extract validated data from v1_sig comment.
780+
781+
Returns (infos, datas, comment_data, indices, offsets).
782+
"""
776783
with zipfile.ZipFile(fhi, "r") as zf:
777784
infos = zf.infolist()
778785
datas = {info.filename: zf.read(info.filename) for info in infos}
@@ -782,7 +789,9 @@ def extract_v1_sig_data(fhi: BinaryIO) -> Tuple[List[zipfile.ZipInfo], Dict[str,
782789
raise APKSigCopierError(f"Invalid {V1SIGZIP} comment: {e}") # pylint: disable=W0707
783790
if error := validate_v1_sig_data(comment_data, len(infos)):
784791
raise APKSigCopierError(f"Invalid {V1SIGZIP} comment: {error}")
785-
return infos, datas, comment_data
792+
indices = {idx: i for i, (idx, _) in enumerate(comment_data["offsets"])}
793+
offsets = {off: i for i, (_, off) in enumerate(comment_data["offsets"])}
794+
return infos, datas, comment_data, indices, offsets
786795

787796

788797
def validate_v1_sig_data(data: Dict[str, Any], n_infos: int) -> Optional[str]:
@@ -795,6 +804,10 @@ def validate_v1_sig_data(data: Dict[str, Any], n_infos: int) -> Optional[str]:
795804
True
796805
>>> validate_v1_sig_data(dict(offsets=[[1, 2], [3]]), 2)
797806
'.offsets[1] is not a list of 2 ints'
807+
>>> validate_v1_sig_data(dict(offsets=[[0, 42], [1, 42]]), 2)
808+
'.offsets contains duplicates'
809+
>>> validate_v1_sig_data(dict(offsets=[[0, 37], [0, 42]]), 2)
810+
'.offsets contains duplicates'
798811
799812
"""
800813
if set(data) - {"offsets", "zfe_size"}:
@@ -809,6 +822,12 @@ def validate_v1_sig_data(data: Dict[str, Any], n_infos: int) -> Optional[str]:
809822
if not isinstance(pair, list) or len(pair) != 2 or \
810823
not all(type(x) is int for x in pair):
811824
return f".offsets[{i}] is not a list of 2 ints"
825+
indices = set(idx for idx, _ in data["offsets"])
826+
offsets = set(off for _, off in data["offsets"])
827+
if len(indices) != n_infos or len(offsets) != n_infos:
828+
return ".offsets contains duplicates"
829+
if any(idx < 0 for idx in indices) or any(off < 0 for off in offsets):
830+
return ".offsets contains negative values"
812831
if "zfe_size" in data:
813832
if type(data["zfe_size"]) is not int:
814833
return ".zfe_size is not an int"
@@ -827,7 +846,7 @@ def validate_v1_sig(infos: List[zipfile.ZipInfo], datas: Dict[str, bytes],
827846
Returns None if valid, error otherwise.
828847
829848
>>> apk = "test/apks/apks/golden-aligned-v1v2v3-out.apk"
830-
>>> infos, datas, _ = extract_v1_sig_data(io.BytesIO(extract_v1_sig(apk)))
849+
>>> infos, datas, _, _, _ = extract_v1_sig_data(io.BytesIO(extract_v1_sig(apk)))
831850
>>> [x.filename for x in infos]
832851
['META-INF/RSA-2048.SF', 'META-INF/RSA-2048.RSA', 'META-INF/MANIFEST.MF']
833852
>>> validate_v1_sig(infos, datas) is None

0 commit comments

Comments
 (0)