Android 9 รองรับ การหมุนคีย์ APK ซึ่งทำให้แอปสามารถเปลี่ยนคีย์การลงนามโดยเป็นส่วนหนึ่งของการอัปเดต APK เพื่อให้การหมุนเวียนเป็นไปได้จริง APK ต้องระบุระดับความน่าเชื่อถือระหว่างคีย์การลงนามใหม่และเก่า เพื่อรองรับการหมุนคีย์ เราได้อัปเดต รูปแบบลายเซ็น APK จาก v2 เป็น v3 เพื่อให้สามารถใช้คีย์ใหม่และคีย์เก่าได้ V3 เพิ่มข้อมูลเกี่ยวกับเวอร์ชัน SDK ที่รองรับและโครงสร้างการพิสูจน์การหมุนไปยังบล็อกการลงนาม APK
บล็อกการลงชื่อ APK
เพื่อรักษาความเข้ากันได้แบบย้อนหลังกับรูปแบบ APK v1 ลายเซ็น APK v2 และ v3 จะถูกเก็บไว้ใน APK Signing Block ซึ่งอยู่ตรงหน้า ZIP Central Directory
รูปแบบ v3 APK Signing Block เหมือนกับ v2 ลายเซ็น v3 ของ APK ถูกจัดเก็บเป็นคู่ค่า ID ที่มี ID 0xf05368c0
APK Signature Scheme v3 Block
โครงร่าง v3 ได้รับการออกแบบให้คล้ายกับ โครงร่าง v2 มาก มีรูปแบบทั่วไปเหมือนกันและสนับสนุน ID อัลกอริทึมลายเซ็น ขนาดคีย์ และเส้นโค้ง EC
อย่างไรก็ตาม โครงร่าง v3 จะเพิ่มข้อมูลเกี่ยวกับเวอร์ชัน SDK ที่รองรับและโครงสร้างการพิสูจน์การหมุน
รูปแบบ
APK Signature Scheme v3 Block ถูกเก็บไว้ใน APK Signing Block ภายใต้ ID 0xf05368c0
รูปแบบของ APK Signature Scheme v3 Block เป็นไปตามรูปแบบ v2:
- ลำดับที่นำหน้าความยาวของ
signer
ที่นำหน้าความยาว :-
signed data
นำหน้าความยาว:- ลำดับความยาวนำหน้าของไดเจสต์ที่นำหน้าความ
digests
:-
signature algorithm ID
(4 ไบต์) -
digest
สต์ (นำหน้าด้วยความยาว)
-
- ลำดับนำหน้าตามความยาวของ
certificates
X.509 :-
certificate
X.509 นำหน้าความยาว (แบบฟอร์ม ASN.1 DER)
-
-
minSDK
(uint32) - ผู้ลงนามนี้ควรถูกละเว้นหากเวอร์ชันของแพลตฟอร์มต่ำกว่าตัวเลขนี้ -
maxSDK
(uint32) - ผู้ลงนามนี้ควรถูกละเว้นหากเวอร์ชันของแพลตฟอร์มอยู่เหนือตัวเลขนี้ - ลำดับความยาวนำหน้า
additional attributes
ที่นำหน้าความยาว:-
ID
(uint32) -
value
(ความยาวตัวแปร: ความยาวของแอตทริบิวต์เพิ่มเติม - 4 ไบต์) -
ID - 0x3ba06f8c
-
value -
โครงสร้างการพิสูจน์การหมุน
-
- ลำดับความยาวนำหน้าของไดเจสต์ที่นำหน้าความ
-
minSDK
(uint32) - ทำซ้ำค่า minSDK ในส่วนข้อมูลที่ลงนาม - ใช้เพื่อข้ามการตรวจสอบลายเซ็นนี้หากแพลตฟอร์มปัจจุบันไม่อยู่ในช่วง ต้องตรงกับค่าข้อมูลที่ลงนาม -
maxSDK
(uint32) - ทำซ้ำค่า maxSDK ในส่วนข้อมูลที่ลงนาม - ใช้เพื่อข้ามการตรวจสอบลายเซ็นนี้หากแพลตฟอร์มปัจจุบันไม่อยู่ในช่วง ต้องตรงกับค่าข้อมูลที่ลงนาม - ลำดับของ
signatures
นำหน้าความยาว :-
signature algorithm ID
(uint32) -
signature
นำหน้ายาวเหนือsigned data
-
-
public key
นำหน้าความยาว (SubjectPublicKeyInfo, แบบฟอร์ม ASN.1 DER)
-
หลักฐานการหมุนเวียนและโครงสร้างใบรับรองเก่าที่เชื่อถือได้
โครงสร้างการพิสูจน์การหมุนช่วยให้แอปสามารถหมุนใบรับรองการลงนามโดยไม่ถูกบล็อกในแอปอื่นๆ ที่พวกเขาสื่อสารด้วย ในการทำให้สำเร็จ ลายเซ็นแอพประกอบด้วยข้อมูลใหม่สองส่วน:
- การยืนยันสำหรับบุคคลที่สามว่าใบรับรองการลงนามของแอปสามารถเชื่อถือได้ไม่ว่ารุ่นก่อนจะเชื่อถือได้
- ใบรับรองการเซ็นชื่อเก่าของแอพซึ่งตัวแอพเองยังคงไว้วางใจ
แอตทริบิวต์ proof-of-rotation ในส่วนข้อมูลที่มีการลงนามประกอบด้วยรายการที่เชื่อมโยงโดยลำพัง โดยแต่ละโหนดมีใบรับรองการลงนามที่ใช้เพื่อลงนามแอปเวอร์ชันก่อนหน้า คุณลักษณะนี้มีขึ้นเพื่อให้มีโครงสร้างข้อมูลการพิสูจน์การหมุนเวียนของแนวคิดและโครงสร้างข้อมูลใบรับรองเก่าที่เชื่อถือได้ในตนเอง รายการเรียงลำดับตามเวอร์ชันที่มีใบรับรองการลงนามที่เก่าที่สุดที่สอดคล้องกับโหนดรูท โครงสร้างข้อมูลการพิสูจน์การหมุนถูกสร้างขึ้นโดยให้ใบรับรองในแต่ละโหนดลงนามในรายการถัดไป และทำให้คีย์ใหม่แต่ละอันมีหลักฐานว่าควรเชื่อถือได้เท่ากับคีย์ที่เก่ากว่า
โครงสร้างข้อมูลใบรับรองเก่าที่เชื่อถือได้สร้างขึ้นโดยการเพิ่มแฟล็กให้กับแต่ละโหนดที่ระบุถึงความเป็นสมาชิกและคุณสมบัติในชุด ตัวอย่างเช่น อาจมีแฟล็กแสดงว่าใบรับรองการลงนามที่โหนดที่กำหนดนั้นเชื่อถือได้สำหรับการรับสิทธิ์ลายเซ็น Android การตั้งค่าสถานะนี้อนุญาตให้แอปอื่นๆ ที่ลงนามโดยใบรับรองที่เก่ากว่ายังคงได้รับการอนุญาตลายเซ็นที่กำหนดโดยแอปที่ลงนามด้วยใบรับรองการลงนามใหม่ เนื่องจากแอตทริบิวต์ proof-of-rotation ทั้งหมดอยู่ในส่วนข้อมูลที่ลงนามของช่อง signer
v3 จึงได้รับการปกป้องโดยคีย์ที่ใช้ลงนาม apk ที่มีอยู่
รูปแบบนี้ไม่ รวมคีย์การเซ็นชื่อหลายรายการ และการบรรจบกันของ ใบรับรองการเซ็นชื่อ ระดับบนสุดที่แตกต่างกันไปเป็นหนึ่ง (โหนดเริ่มต้นหลายโหนดไปยังซิงก์ทั่วไป)
รูปแบบ
หลักฐานการหมุนเวียนถูกเก็บไว้ใน APK Signature Scheme v3 Block ภายใต้ ID 0x3ba06f8c
รูปแบบของมันคือ:
- ลำดับความยาวนำหน้า
levels
ความยาวนำหน้า :-
signed data
นำหน้าความยาว (โดยใบรับรองก่อนหน้า - ถ้ามี)-
certificate
X.509 นำหน้าความยาว (แบบฟอร์ม ASN.1 DER) -
signature algorithm ID
(uint32) - อัลกอริทึมที่ใช้โดยใบรับรองในระดับก่อนหน้า
-
-
flags
ก (uint32) - แฟล็กที่ระบุว่าใบรับรองนี้ควรอยู่ในโครงสร้างใบรับรองเก่าที่เชื่อถือได้ในตัวเองหรือไม่ และสำหรับการดำเนินการใด -
signature algorithm ID
(uint32) - ต้องตรงกับรหัสจากส่วนข้อมูลที่ลงนามในระดับถัดไป -
signature
นำหน้ายาวเหนือsigned data
ข้างต้น
-
ใบรับรองหลายใบ
ปัจจุบัน Android ปฏิบัติต่อ APK ที่ลงนามด้วยใบรับรองหลายฉบับโดยมีข้อมูลระบุตัวตนการลงนามที่ไม่ซ้ำกันซึ่งแยกจากใบรับรองที่ประกอบด้วย ดังนั้น แอตทริบิวต์การพิสูจน์การหมุนเวียนในส่วนข้อมูลที่มีการลงนามจะสร้างกราฟ acyclic ที่กำหนดทิศทาง ซึ่งสามารถมองได้ดีกว่าว่าเป็นรายการที่เชื่อมโยงโดยลำพัง โดยแต่ละชุดของผู้ลงนามสำหรับเวอร์ชันที่กำหนดจะเป็นตัวแทนของโหนดเดียว สิ่งนี้จะเพิ่มความซับซ้อนเป็นพิเศษให้กับโครงสร้างการพิสูจน์การหมุน (เวอร์ชันผู้ลงนามหลายคนด้านล่าง) โดยเฉพาะอย่างยิ่ง การสั่งซื้อกลายเป็นเรื่องที่น่ากังวล ยิ่งไปกว่านั้น เป็นไปไม่ได้ที่จะลงนาม APK อย่างอิสระอีกต่อไป เนื่องจากโครงสร้างการพิสูจน์การหมุนเวียนต้องมีใบรับรองการลงนามแบบเก่าที่ลงนามในใบรับรองชุดใหม่ แทนที่จะลงนามทีละรายการ ตัวอย่างเช่น APK ที่ลงนามโดยคีย์ A ซึ่งประสงค์จะลงนามโดยคีย์ใหม่สองคีย์ B และ C ไม่สามารถมีผู้ลงนาม B เพียงแค่รวมลายเซ็นโดย A หรือ B เนื่องจากเป็นข้อมูลประจำตัวการลงนามที่แตกต่างจาก B และ C ซึ่งจะ หมายความว่าผู้ลงนามต้องประสานงานก่อนสร้างโครงสร้างดังกล่าว
แอตทริบิวต์การพิสูจน์การหมุนเวียนของผู้ลงนามหลายคน
- ลำดับความยาวนำหน้า
sets
ความยาวนำหน้า :-
signed data
(ตามชุดก่อนหน้า - ถ้ามี)- ลำดับที่นำหน้าความยาวของ
certificates
-
certificate
X.509 นำหน้าความยาว (แบบฟอร์ม ASN.1 DER)
-
- ลำดับของ
signature algorithm IDs
(uint32) - หนึ่งรายการสำหรับแต่ละใบรับรองจากชุดก่อนหน้า ในลำดับเดียวกัน
- ลำดับที่นำหน้าความยาวของ
-
flags
ก (uint32) - แฟล็กที่ระบุว่าชุดใบรับรองนี้ควรอยู่ในโครงสร้างใบรับรองเก่าที่เชื่อถือได้ในตัวเองหรือไม่ และสำหรับการดำเนินการใด - ลำดับของ
signatures
นำหน้าความยาว :-
signature algorithm ID
(uint32) - ต้องตรงกับรหัสจากส่วนข้อมูลที่ลงนาม -
signature
นำหน้ายาวเหนือsigned data
ข้างต้น
-
-
บรรพบุรุษหลายคนในโครงสร้างการพิสูจน์การหมุน
สคีม v3 ยังไม่รองรับคีย์ที่แตกต่างกันสองปุ่มที่หมุนไปยังคีย์การลงนามเดียวกันสำหรับแอปเดียวกัน ซึ่งแตกต่างจากกรณีของการได้มาซึ่งบริษัทที่ซื้อกิจการต้องการย้ายแอปที่ได้มาเพื่อใช้คีย์การลงนามเพื่อแชร์การอนุญาต การได้มาถูกมองว่าเป็นกรณีการใช้งานที่ได้รับการสนับสนุน เนื่องจากแอปใหม่จะแยกความแตกต่างด้วยชื่อแพ็กเกจและอาจมีโครงสร้างการพิสูจน์การหมุนของแอปเอง กรณีที่ไม่รองรับของแอปเดียวกันที่มีสองเส้นทางที่แตกต่างกันเพื่อไปยังใบรับรองเดียวกัน ทำลายสมมติฐานมากมายในการออกแบบการหมุนเวียนคีย์
การยืนยัน
ใน Android 9 ขึ้นไป สามารถตรวจสอบ APK ได้ตามแผน APK Signature Scheme v3, v2 หรือ v1 แพลตฟอร์มเก่าละเว้นลายเซ็น v3 และพยายามตรวจสอบลายเซ็น v2 จากนั้น v1
รูปที่ 1. ขั้นตอนการตรวจสอบลายเซ็น APK
APK Signature Scheme v3 การตรวจสอบ
- ค้นหา APK Signing Block และตรวจสอบว่า:
- ฟิลด์ขนาดสองช่องของ APK Signing Block มีค่าเท่ากัน
- ZIP Central Directory ตามด้วย ZIP End of Central Directory ทันที
- ZIP End of Central Directory ไม่ได้ตามด้วยข้อมูลเพิ่มเติม
- ค้นหา APK Signature Scheme v3 Block แรกภายใน APK Signing Block หากมีบล็อก v3 ให้ไปยังขั้นตอนที่ 3 มิฉะนั้น ให้กลับไปตรวจสอบ APK โดยใช้ v2 scheme
- สำหรับ
signer
แต่ละคนใน APK Signature Scheme v3 Block ที่มีเวอร์ชัน SDK ขั้นต่ำและสูงสุดซึ่งอยู่ในช่วงของแพลตฟอร์มปัจจุบัน:- เลือก
signature algorithm ID
ที่รองรับที่แข็งแกร่งที่สุดจากsignatures
ลำดับความแรงนั้นขึ้นอยู่กับการใช้งาน/เวอร์ชันของแพลตฟอร์มแต่ละเวอร์ชัน - ตรวจสอบ
signature
ที่สอดคล้องกันจากsignatures
กับsigned data
โดยใช้public key
(ขณะนี้สามารถแยกวิเคราะห์signed data
อย่างปลอดภัยแล้ว) - ตรวจสอบเวอร์ชัน SDK ขั้นต่ำและสูงสุดในข้อมูลที่ลงนามแล้วตรงกับที่ระบุสำหรับ
signer
- ตรวจสอบว่ารายการลำดับของ ID อัลกอริธึ
digests
เซ็นในไดเจสต์และsignatures
เหมือนกัน (เพื่อป้องกันการลอก/เพิ่มลายเซ็น) - คำนวณไดเจสต์ของเนื้อหา APK โดยใช้อัลกอริธึมไดเจสต์เดียวกันกับอัลกอริธึมไดเจสต์ที่ใช้โดยอัลกอริธึมลายเซ็น
- ตรวจสอบว่าไดเจสต์ที่คำนวณแล้วเหมือนกับไดเจสต์ที่เกี่ยวข้องจาก
digest
digests
สต์ - ตรวจสอบว่า SubjectPublicKeyInfo ของ
certificate
certificates
เหมือนกับpublic key
- หากมีแอตทริบิวต์ proof-of-rotation สำหรับ
signer
ให้ตรวจสอบว่าโครงสร้างถูกต้องและsigner
นี้เป็นใบรับรองสุดท้ายในรายการ
- เลือก
- การยืนยันสำเร็จหากพบ
signer
เพียงรายเดียวในช่วงของแพลตฟอร์มปัจจุบัน และขั้นตอนที่ 3 สำเร็จสำหรับsigner
นั้น
การตรวจสอบความถูกต้อง
ในการทดสอบว่าอุปกรณ์ของคุณรองรับ v3 อย่างถูกต้อง ให้รันการทดสอบ PkgInstallSignatureVerificationTest.java
CTS ใน cts/hostsidetests/appsecurity/src/android/appsecurity/cts/