@@ -461,9 +461,7 @@ def copy_apk(unsigned_apk: str, output_apk: str, *,
461
461
realign = not skip_realignment
462
462
if v1_sig :
463
463
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 )
467
465
if "zfe_size" in v1_comment_data and not zfe_size :
468
466
zfe_size = int (v1_comment_data ["zfe_size" ])
469
467
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]:
635
633
Created-By: 1.8.0_45-internal (Oracle Corporation)
636
634
>>> zf.comment
637
635
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 ]
640
638
['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()]
642
640
[('META-INF/RSA-2048.SF', 664), ('META-INF/RSA-2048.RSA', 1160), ('META-INF/MANIFEST.MF', 589)]
643
- >>> v1_comment_data
641
+ >>> comment_data
644
642
{'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}
645
647
646
648
"""
647
649
with zipfile .ZipFile (apkfile , "r" ) as zf :
@@ -770,9 +772,14 @@ def validate_zip_header(hdr: bytes, info: zipfile.ZipInfo, datas: Dict[str, byte
770
772
return None
771
773
772
774
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
+ """
776
783
with zipfile .ZipFile (fhi , "r" ) as zf :
777
784
infos = zf .infolist ()
778
785
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,
782
789
raise APKSigCopierError (f"Invalid { V1SIGZIP } comment: { e } " ) # pylint: disable=W0707
783
790
if error := validate_v1_sig_data (comment_data , len (infos )):
784
791
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
786
795
787
796
788
797
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]:
795
804
True
796
805
>>> validate_v1_sig_data(dict(offsets=[[1, 2], [3]]), 2)
797
806
'.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'
798
811
799
812
"""
800
813
if set (data ) - {"offsets" , "zfe_size" }:
@@ -809,6 +822,12 @@ def validate_v1_sig_data(data: Dict[str, Any], n_infos: int) -> Optional[str]:
809
822
if not isinstance (pair , list ) or len (pair ) != 2 or \
810
823
not all (type (x ) is int for x in pair ):
811
824
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"
812
831
if "zfe_size" in data :
813
832
if type (data ["zfe_size" ]) is not int :
814
833
return ".zfe_size is not an int"
@@ -827,7 +846,7 @@ def validate_v1_sig(infos: List[zipfile.ZipInfo], datas: Dict[str, bytes],
827
846
Returns None if valid, error otherwise.
828
847
829
848
>>> 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)))
831
850
>>> [x.filename for x in infos]
832
851
['META-INF/RSA-2048.SF', 'META-INF/RSA-2048.RSA', 'META-INF/MANIFEST.MF']
833
852
>>> validate_v1_sig(infos, datas) is None
0 commit comments