APK Signature Scheme v3

Android 9 รองรับการหมุนเวียนคีย์ของ APK ซึ่งช่วยให้แอปเปลี่ยนคีย์การรับรองได้เป็นส่วนหนึ่งของการอัปเดต APK APK ต้องระบุระดับความน่าเชื่อถือระหว่างคีย์ App Signing ใหม่และคีย์ App Signing เก่าเพื่อให้การหมุนเวียนคีย์ใช้งานได้จริง เราได้อัปเดตรูปแบบการรับรอง APK จาก v2 เป็น v3 เพื่อรองรับการหมุนเวียนคีย์ ซึ่งจะช่วยให้ใช้คีย์ใหม่และคีย์เก่าได้ V3 จะเพิ่มข้อมูลเกี่ยวกับเวอร์ชัน SDK ที่รองรับและโครงสร้างหลักฐานการหมุนเวียนลงในบล็อกการรับรอง APK

บล็อกการรับรอง APK

ระบบจะจัดเก็บลายเซ็น APK เวอร์ชัน 2 และ 3 ไว้ในบล็อกการรับรอง APK ซึ่งอยู่ก่อนไดเรกทอรีกลาง ZIP โดยตรง เพื่อรักษาความสามารถในการใช้งานร่วมกันย้อนหลังกับรูปแบบ APK เวอร์ชัน 1

รูปแบบบล็อกการรับรอง APK ของ v3 เหมือนกับ v2 ลายเซ็น v3 ของ APK จะจัดเก็บเป็นคู่รหัส-ค่าที่มีรหัส 0xf05368c0

บล็อก APK Signature Scheme v3

รูปแบบ v3 ออกแบบมาให้คล้ายกับรูปแบบ v2 อย่างมาก โดยจะมีรูปแบบทั่วไปเหมือนกันและรองรับรหัสอัลกอริทึมลายเซ็น ขนาดคีย์ และเส้นโค้ง EC เดียวกัน

แต่รูปแบบ v3 จะเพิ่มข้อมูลเกี่ยวกับเวอร์ชัน SDK ที่รองรับและโครงสร้าง proof-of-rotation

รูปแบบ

ระบบจะจัดเก็บบล็อก APK Signature Scheme v3 ไว้ในบล็อกการรับรอง APK ภายใต้รหัส 0xf05368c0

รูปแบบของบล็อก APK Signature Scheme v3 เป็นไปตามรูปแบบของ v2 ดังนี้

  • ลำดับที่มีความยาวนำหน้าของ signer ที่มีความยาวนำหน้า ดังนี้
    • signed data ที่มีความยาวนำหน้า:
      • ลำดับที่มีความยาวนำหน้าของ digests ที่มีความยาวนำหน้า ดังนี้
        • signature algorithm ID (4 ไบต์)
        • digest (มีความยาวนำหน้า)
      • ลำดับ X.509 ที่มีความยาวนำหน้า certificates:
        • X.509 certificate ที่มีความยาวนำหน้า (รูปแบบ 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 และ self-trusted-old-certs

โครงสร้างหลักฐานการเปลี่ยนทำให้แอปเปลี่ยนใบรับรองการรับรองได้โดยไม่ถูกบล็อกในแอปอื่นๆ ที่แอปสื่อสารด้วย ลายเซ็นแอปจึงมีข้อมูลใหม่ 2 รายการดังต่อไปนี้

  • การยืนยันให้บุคคลที่สามทราบว่าสามารถเชื่อถือใบรับรองการรับรองของแอปได้ไม่ว่าจะเชื่อถือใบรับรองก่อนหน้าของแอปหรือไม่
  • ใบรับรองการรับรองแอปเวอร์ชันเก่าที่แอปยังคงเชื่อถือ

แอตทริบิวต์ proof-of-rotation ในส่วน signed-data ประกอบด้วยลิสต์แบบลิงก์เดี่ยว โดยแต่ละโหนดจะมีใบรับรองการรับรองที่ใช้ลงนามแอปเวอร์ชันก่อนหน้า แอตทริบิวต์นี้มีไว้เพื่อเก็บโครงสร้างข้อมูล proof-of-rotation และ self-trusted-old-certs เชิงแนวคิด รายการจะเรียงตามเวอร์ชันที่มีใบรับรองการรับรองที่เก่าที่สุดซึ่งสอดคล้องกับโหนดรูท โครงสร้างข้อมูลการพิสูจน์การหมุนเวียนสร้างขึ้นโดยให้ใบรับรองในแต่ละโหนดลงนามในรายการถัดไป ดังนั้นจึงมีการฝังหลักฐานไว้ในคีย์ใหม่แต่ละรายการว่าควรเชื่อถือได้เท่ากับคีย์เก่า

โครงสร้างข้อมูล self-trusted-old-certs สร้างขึ้นโดยการเพิ่ม Flag ไปยังโหนดแต่ละโหนดเพื่อระบุการเป็นสมาชิกและพร็อพเพอร์ตี้ของโหนดนั้นในชุด เช่น ธงอาจปรากฏขึ้นเพื่อระบุว่าใบรับรองการรับรองที่โหนดหนึ่งๆ เชื่อถือได้สำหรับการรับสิทธิ์การรับรอง Android Flag นี้ช่วยให้แอปอื่นๆ ที่ลงนามด้วยใบรับรองเก่ายังคงได้รับสิทธิ์การรับรองที่กําหนดโดยแอปที่ลงนามด้วยใบรับรองการรับรองใหม่ เนื่องจากแอตทริบิวต์พิสูจน์การหมุนเวียนทั้งหมดอยู่ในส่วนข้อมูลที่ลงนามของช่อง v3 signer จึงได้รับการปกป้องโดยคีย์ที่ใช้ลงนามใน APK ที่มี

รูปแบบนี้ไม่อนุญาตให้มีคีย์การรับรองหลายรายการ และการรวมใบรับรองการรับรองต้นทางที่แตกต่างกันเข้าด้วยกัน (โหนดเริ่มต้นหลายโหนดไปยังที่เก็บข้อมูลทั่วไป)

รูปแบบ

การพิสูจน์การหมุนเวียนจะจัดเก็บไว้ในบล็อก APK Signature Scheme v3 ภายใต้รหัส 0x3ba06f8c รูปแบบของไฟล์คือ

  • ลำดับที่มีความยาวนำหน้าของ levels ที่มีความยาวนำหน้า ดังนี้
    • signed data ที่มีความยาวนำหน้า (ตามใบรับรองก่อนหน้า หากมี)
      • X.509 certificate ที่มีความยาวนำหน้า (รูปแบบ ASN.1 DER)
      • signature algorithm ID (uint32) - อัลกอริทึมที่ใบรับรองใช้ในระดับก่อนหน้า
    • flags (uint32) - แฟล็กที่ระบุว่าใบรับรองนี้ควรอยู่ในโครงสร้าง self-trusted-old-certs หรือไม่ และสำหรับการดำเนินการใด
    • signature algorithm ID (uint32) - ต้องตรงกับค่าจากส่วนข้อมูลที่เซ็นชื่อในระดับถัดไป
    • signature ที่มีความยาวนำหน้ามากกว่า signed data ข้างต้น

ใบรับรองหลายรายการ

ระบบไม่รองรับผู้ลงนามหลายคน และ Google Play จะไม่เผยแพร่แอปที่ลงนามด้วยใบรับรองหลายรายการ

การยืนยัน

ใน Android 9 ขึ้นไป คุณสามารถยืนยัน APK ตาม APK Signature Scheme v3, v2 หรือ v1 แพลตฟอร์มเก่าๆ จะละเว้นลายเซ็น v3 และพยายามยืนยันลายเซ็น v2 ตามด้วย v1

กระบวนการยืนยันลายเซ็น APK

รูปที่ 1 กระบวนการยืนยันลายเซ็น APK

การยืนยัน APK Signature Scheme v3

  1. ค้นหาบล็อกการรับรอง APK และตรวจสอบสิ่งต่อไปนี้
    1. ช่องขนาด 2 ช่องของบล็อกการรับรอง APK มีค่าเดียวกัน
    2. ไดเรกทอรีส่วนกลางของ ZIP ตามด้วยระเบียน "สิ้นสุดไดเรกทอรีส่วนกลาง" ของ ZIP
    3. ไม่มีการติดตามข้อมูลเพิ่มเติมต่อจาก End of Central Directory ของ ZIP
  2. ค้นหาบล็อก APK Signature Scheme v3 แรกภายในบล็อกการรับรอง APK หากมีบล็อก v3 ให้ไปยังขั้นตอนที่ 3 มิฉะนั้น ให้กลับไปยืนยัน APK โดยใช้รูปแบบ v2
  3. สําหรับ signer แต่ละรายการในบล็อก Signature Scheme v3 ของ APK ที่มีเวอร์ชัน SDK ขั้นต่ำและสูงสุดซึ่งอยู่ในช่วงของแพลตฟอร์มปัจจุบัน ให้ทําดังนี้
    1. เลือก signature algorithm ID ที่แรงที่สุดที่รองรับจาก signatures ลำดับความแรงขึ้นอยู่กับแต่ละเวอร์ชันการใช้งาน/แพลตฟอร์ม
    2. ยืนยัน signature ที่เกี่ยวข้องจาก signatures กับ signed data โดยใช้ public key (ตอนนี้คุณแยกวิเคราะห์ signed data ได้แล้ว)
    3. ตรวจสอบว่าเวอร์ชัน SDK ขั้นต่ำและสูงสุดในข้อมูลที่เซ็นสัญญาตรงกับเวอร์ชันที่ระบุสำหรับ signer
    4. ตรวจสอบว่ารายการรหัสอัลกอริทึมลายเซ็นที่จัดเรียงใน digests และ signatures เหมือนกัน (การดำเนินการนี้มีไว้เพื่อป้องกันการลบ/เพิ่มลายเซ็น)
    5. คํานวณข้อมูลสรุปของเนื้อหา APK โดยใช้อัลกอริทึมข้อมูลสรุปเดียวกับอัลกอริทึมข้อมูลสรุปที่อัลกอริทึมการรับรองใช้
    6. ยืนยันว่าข้อมูลสรุปที่คำนวณได้ตรงกับ digest ที่เกี่ยวข้องจาก digests
    7. ตรวจสอบว่า SubjectPublicKeyInfo ของ certificate แรกใน certificates เหมือนกับ public key
    8. หากมีแอตทริบิวต์ proof-of-rotation สำหรับ signer ให้ตรวจสอบว่าโครงสร้างถูกต้องและ signer นี้เป็นใบรับรองสุดท้ายในรายการ
  4. การยืนยันจะสำเร็จหากพบ signer เพียงรายการเดียวในช่วงของแพลตฟอร์มปัจจุบัน และขั้นตอนที่ 3 สำเร็จสำหรับ signer รายการนั้น

การตรวจสอบความถูกต้อง

หากต้องการทดสอบว่าอุปกรณ์รองรับ v3 อย่างถูกต้อง ให้เรียกใช้PkgInstallSignatureVerificationTest.javaการทดสอบ CTS ใน cts/hostsidetests/appsecurity/src/android/appsecurity/cts/