APK Signature Scheme v3

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-value ด้วย 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 การตั้งค่าสถานะนี้อนุญาตให้แอปอื่นๆ ที่ลงนามโดยใบรับรองที่เก่ากว่ายังคงได้รับการอนุญาตลายเซ็นที่กำหนดโดยแอปที่ลงนามด้วยใบรับรองการลงนามใหม่ เนื่องจากแอตทริบิวต์การพิสูจน์การหมุนทั้งหมดอยู่ในส่วนข้อมูลที่ลงนามของช่อง 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 ซึ่งประสงค์จะลงนามโดยคีย์ใหม่ 2 คีย์ 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

ขั้นตอนการตรวจสอบลายเซ็น APK

รูปที่ 1. ขั้นตอนการตรวจสอบลายเซ็น APK

APK Signature Scheme v3 การตรวจสอบ

  1. ค้นหา APK Signing Block และตรวจสอบว่า:
    1. ฟิลด์ขนาดสองช่องของ APK Signing Block มีค่าเท่ากัน
    2. ZIP Central Directory ตามด้วย ZIP End of Central Directory ทันที
    3. ZIP End of Central Directory ไม่ได้ตามด้วยข้อมูลเพิ่มเติม
  2. ค้นหา APK Signature Scheme v3 Block แรกภายใน APK Signing Block หากมีบล็อก v3 ให้ไปยังขั้นตอนที่ 3 มิฉะนั้น ให้กลับไปตรวจสอบ APK โดยใช้ v2 scheme
  3. สำหรับ signer แต่ละคนใน APK Signature Scheme v3 Block ที่มีเวอร์ชัน SDK ขั้นต่ำและสูงสุดซึ่งอยู่ในช่วงของแพลตฟอร์มปัจจุบัน:
    1. เลือก signature algorithm ID ที่รองรับที่แข็งแกร่งที่สุดจาก signatures ลำดับความแรงนั้นขึ้นอยู่กับแต่ละรุ่นของการใช้งาน/แพลตฟอร์ม
    2. ตรวจสอบ signature ที่สอดคล้องกันจาก signatures กับ signed data โดยใช้ public key (ขณะนี้สามารถแยกวิเคราะห์ signed data อย่างปลอดภัย)
    3. ตรวจสอบเวอร์ชัน SDK ขั้นต่ำและสูงสุดในข้อมูลที่ลงนามแล้วตรงกับที่ระบุสำหรับ signer
    4. ตรวจสอบว่ารายการลำดับของ ID อัลกอริธึ 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/