สถาปัตยกรรมการรับรองในอุปกรณ์

ตั้งแต่ Android 12 เป็นต้นไป โมดูล Android Runtime (ART) จะเป็นโมดูล Mainline การอัปเดตโมดูลอาจต้องสร้างอาร์ติแฟกต์การคอมไพล์ล่วงหน้า (AOT) ของ JAR ใน Bootclasspath และเซิร์ฟเวอร์ระบบขึ้นมาใหม่ เนื่องจากอาร์ติแฟกต์เหล่านี้มีความสำคัญต่อความปลอดภัย Android 12 จึงใช้ฟีเจอร์ที่เรียกว่าการทำ Signing ในอุปกรณ์เพื่อป้องกันไม่ให้มีการแก้ไขอาร์ติแฟกต์เหล่านี้ หน้านี้จะอธิบายสถาปัตยกรรมการทำ Signing ในอุปกรณ์และการโต้ตอบกับฟีเจอร์ความปลอดภัยอื่นๆ ของ Android

การออกแบบระดับสูง

การทำ Signing ในอุปกรณ์มีคอมโพเนนต์หลัก 2 อย่าง ได้แก่

  • odrefresh เป็นส่วนหนึ่งของโมดูล ART Mainline มีหน้าที่สร้างอาร์ติแฟกต์รันไทม์ ตรวจสอบอาร์ติแฟกต์ที่มีอยู่กับ ART โมดูลเวอร์ชันที่ติดตั้ง, JAR ใน Bootclasspath และ JAR ของเซิร์ฟเวอร์ระบบเพื่อดูว่าอาร์ติแฟกต์เป็นเวอร์ชันล่าสุดหรือต้องสร้างขึ้นใหม่ หากต้องสร้างขึ้นใหม่ odrefresh จะสร้างและจัดเก็บอาร์ติแฟกต์

  • odsign เป็นไบนารีที่เป็นส่วนหนึ่งของแพลตฟอร์ม Android ทำงานระหว่างการบูตช่วงแรกๆ ทันทีหลังจากที่เมานต์พาร์ติชัน /data หน้าที่หลักคือการเรียกใช้ odrefresh เพื่อตรวจสอบว่าต้องสร้างหรืออัปเดตอาร์ติแฟกต์หรือไม่ สำหรับอาร์ติแฟกต์ใหม่หรืออัปเดตที่ odrefresh สร้างขึ้น odsign จะคำนวณฟังก์ชันแฮช ผลลัพธ์ของการคำนวณแฮชดังกล่าวเรียกว่า File Digest สำหรับอาร์ติแฟกต์ที่มีอยู่แล้ว odsign จะยืนยันว่า Digest ของอาร์ติแฟกต์ที่มีอยู่ตรงกับ Digest ที่ odsign คำนวณไว้ก่อนหน้านี้ ซึ่งจะช่วยให้มั่นใจได้ว่าไม่มีการแก้ไขอาร์ติแฟกต์

ในกรณีที่เกิดข้อผิดพลาด เช่น เมื่อ Digest ของไฟล์ไม่ตรงกัน odrefresh และ odsign จะทิ้งอาร์ติแฟกต์ที่มีอยู่ทั้งหมดใน /data และพยายามสร้างขึ้นใหม่ หากไม่สำเร็จ ระบบจะกลับไปใช้โหมด JIT

odrefresh และ odsign ได้รับการปกป้องโดย dm-verity และเป็นส่วนหนึ่งของห่วงโซ่การเปิดเครื่องที่ได้รับการยืนยันของ Android

การคำนวณ File Digest ด้วย fs-verity

fs-verity เป็นฟีเจอร์ของเคอร์เนล Linux ที่ทำการยืนยันข้อมูลไฟล์ตาม Merkle Tree การเปิดใช้ fs-verity ในไฟล์จะทำให้ระบบไฟล์ สร้าง Merkle Tree ในข้อมูลของไฟล์โดยใช้แฮช SHA-256 จัดเก็บไว้ใน ตำแหน่งที่ซ่อนอยู่ข้างไฟล์ และทำเครื่องหมายไฟล์เป็นแบบอ่านอย่างเดียว fs-verity จะยืนยันข้อมูลของไฟล์กับ Merkle Tree โดยอัตโนมัติตามความต้องการเมื่อมีการ อ่าน fs-verity จะทำให้แฮชรูทของ Merkle Tree พร้อมใช้งานเป็นค่าที่เรียกว่า fs-verity File Digest และ fs-verity จะตรวจสอบว่าข้อมูลที่อ่าน จากไฟล์สอดคล้องกับ File Digest นี้

odsign ใช้ fs-verity เพื่อปรับปรุงประสิทธิภาพการบูตโดยการเพิ่มประสิทธิภาพการตรวจสอบสิทธิ์การเข้ารหัสลับของอาร์ติแฟกต์ที่คอมไพล์ในอุปกรณ์ในเวลาบูต เมื่อมีการสร้างอาร์ติแฟกต์ odsign จะเปิดใช้ fs-verity ในอาร์ติแฟกต์ เมื่อ odsign ยืนยันอาร์ติแฟกต์ ระบบจะยืนยัน fs-verity File Digest แทนแฮชไฟล์แบบเต็ม ซึ่งจะช่วยลดความจำเป็นในการอ่านและแฮชข้อมูลแบบเต็มของอาร์ติแฟกต์ในเวลาบูต ระบบจะแฮชข้อมูลอาร์ติแฟกต์ตามความต้องการโดย fs-verity เมื่อมีการใช้งานทีละบล็อก

ในอุปกรณ์ที่เคอร์เนลไม่รองรับ fs-verity odsign จะกลับไปคำนวณ File Digest ใน Userspace odsign ใช้แฮชอัลกอริทึมตาม Merkle Tree เดียวกันกับ fs-verity ดังนั้น Digest จึงเหมือนกันในทั้ง 2 กรณี fs-verity จำเป็นในอุปกรณ์ทั้งหมดที่เปิดตัวด้วย Android 11 ขึ้นไป

การจัดเก็บ File Digest

odsign จะจัดเก็บ File Digest ของอาร์ติแฟกต์ไว้ในไฟล์แยกต่างหากที่ชื่อว่า odsign.info `odsign` จะลงนาม odsign.info ด้วยคีย์ Signing ที่มีคุณสมบัติด้านความปลอดภัยที่สำคัญ เพื่อให้แน่ใจว่าไม่มีการแก้ไข odsign.info โดยเฉพาะอย่างยิ่ง คีย์สามารถสร้างและใช้ได้เฉพาะระหว่างการบูตช่วงแรกๆ ซึ่งมีเพียงโค้ดที่เชื่อถือได้เท่านั้นที่ทำงานอยู่ ดูรายละเอียดได้ที่ คีย์ Signing ที่เชื่อถือได้

การยืนยัน File Digest

ในการบูตทุกครั้ง หาก odrefresh ระบุว่าอาร์ติแฟกต์ที่มีอยู่เป็นเวอร์ชันล่าสุด odsign จะตรวจสอบว่าไม่มีการแก้ไขไฟล์ตั้งแต่มีการสร้างไฟล์ odsign จะดำเนินการนี้โดยการยืนยัน File Digest ขั้นแรก ระบบจะยืนยันลายเซ็นของ odsign.info หากลายเซ็นถูกต้อง odsign จะยืนยันว่า Digest ของแต่ละไฟล์ตรงกับ Digest ที่เกี่ยวข้อง ใน odsign.info

คีย์ Signing ที่เชื่อถือได้

Android 12 ขอแนะนำฟีเจอร์ใหม่ของ Keystore ที่เรียกว่าคีย์ระดับการบูต ซึ่งช่วยแก้ปัญหาด้านความปลอดภัยต่อไปนี้

  • อะไรจะป้องกันไม่ให้ผู้โจมตีใช้คีย์ Signing ของเราเพื่อลงนาม odsign.info เวอร์ชันของตนเอง
  • อะไรจะป้องกันไม่ให้ผู้โจมตีสร้างคีย์ Signing ของตนเองและใช้คีย์นั้นเพื่อลงนาม odsign.info เวอร์ชันของตนเอง

คีย์ระดับการบูตจะแบ่งวงจรการบูตของ Android ออกเป็นระดับต่างๆ และเชื่อมโยงการสร้างและการใช้คีย์กับระดับที่ระบุด้วยการเข้ารหัสลับ odsign จะสร้างคีย์ Signing ในระดับแรกๆ เมื่อมีเพียงโค้ดที่เชื่อถือได้เท่านั้นที่ทำงานอยู่ โดยได้รับการปกป้องผ่าน dm-verity

ระดับการบูตจะมีหมายเลขตั้งแต่ 0 ถึงหมายเลขวิเศษ 1000000000 ในระหว่างกระบวนการบูตของ Android คุณสามารถเพิ่มระดับการบูตได้โดยการตั้งค่าพร็อพเพอร์ตี้ของระบบจาก init.rc ตัวอย่างเช่น โค้ดต่อไปนี้จะตั้งค่าระดับการบูตเป็น 10

setprop keystore.boot_level 10

ไคลเอ็นต์ของ Keystore สามารถสร้างคีย์ที่เชื่อมโยงกับระดับการบูตที่เฉพาะเจาะจงได้ ตัวอย่างเช่น หากคุณสร้างคีย์สำหรับระดับการบูต 10 คีย์นั้นจะใช้ได้เฉพาะเมื่ออุปกรณ์อยู่ในระดับการบูต 10

odsign ใช้ระดับการบูต 30 และคีย์ Signing ที่สร้างขึ้นจะเชื่อมโยงกับระดับการบูตนั้น ก่อนที่จะใช้คีย์เพื่อลงนามอาร์ติแฟกต์ odsign จะยืนยันว่าคีย์เชื่อมโยงกับระดับการบูต 30

ซึ่งจะป้องกันการโจมตี 2 รูปแบบที่อธิบายไว้ก่อนหน้านี้ในส่วนนี้

  • ผู้โจมตีไม่สามารถใช้คีย์ที่สร้างขึ้นได้ เนื่องจากเมื่อผู้โจมตีมีโอกาสเรียกใช้โค้ดที่เป็นอันตราย ระดับการบูตจะเพิ่มขึ้นเกิน 30 แล้ว และ Keystore จะปฏิเสธการดำเนินการที่ใช้คีย์
  • ผู้โจมตีไม่สามารถสร้างคีย์ใหม่ได้ เนื่องจากเมื่อผู้โจมตีมีโอกาสเรียกใช้โค้ดที่เป็นอันตราย ระดับการบูตจะเพิ่มขึ้นเกิน 30 แล้ว และ Keystore จะปฏิเสธที่จะสร้างคีย์ใหม่ที่มีระดับการบูตนั้น หากผู้โจมตีสร้างคีย์ใหม่ที่ไม่ได้เชื่อมโยงกับระดับการบูต 30 odsign จะปฏิเสธคีย์นั้น

Keystore จะตรวจสอบว่ามีการบังคับใช้ระดับการบูตอย่างเหมาะสม ส่วนต่อไปนี้จะอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับวิธีดำเนินการนี้สำหรับ KeyMint (เดิมชื่อ Keymaster) เวอร์ชันต่างๆ

การติดตั้งใช้งาน Keymaster 4.0

Keymaster เวอร์ชันต่างๆ จะจัดการการติดตั้งใช้งานคีย์ระดับการบูตแตกต่างกัน ในอุปกรณ์ที่มี Keymaster 4.0 TEE/StrongBox, Keymaster จะจัดการการติดตั้งใช้งานดังนี้

  1. ในการบูตครั้งแรก Keystore จะสร้างคีย์สมมาตร K0 โดยตั้งค่าแท็ก MAX_USES_PER_BOOT เป็น 1 ซึ่งหมายความว่าคีย์จะใช้ได้เพียงครั้งเดียวต่อการบูต
  2. ในระหว่างการบูต หากระดับการบูตเพิ่มขึ้น ระบบจะสร้างคีย์ใหม่สำหรับระดับการบูตนั้นจาก K0 ได้โดยใช้ฟังก์ชัน HKDF: Ki+i=HKDF(Ki, "some_fixed_string") ตัวอย่างเช่น หากคุณย้ายจากระดับการบูต 0 ไปยังระดับการบูต 10 ระบบจะเรียกใช้ HKDF 10 ครั้งเพื่อสร้าง K10 จาก K0
  3. เมื่อระดับการบูตเปลี่ยนไป ระบบจะลบคีย์สำหรับระดับการบูตก่อนหน้าออกจากหน่วยความจำ และคีย์ที่เชื่อมโยงกับระดับการบูตก่อนหน้าจะไม่พร้อมใช้งานอีกต่อไป

    คีย์ K0 เป็นคีย์ MAX_USES_PER_BOOT=1 ซึ่งหมายความว่าคุณจะใช้คีย์นั้นในการบูตครั้งต่อไปไม่ได้เช่นกัน เนื่องจากจะมีการเปลี่ยนระดับการบูตอย่างน้อย 1 ครั้ง (ไปยังระดับการบูตสุดท้าย) เสมอ

เมื่อไคลเอ็นต์ Keystore เช่น odsign ขอให้สร้างคีย์ในระดับการบูต i บล็อบของคีย์จะได้รับการเข้ารหัสด้วยคีย์ Ki เนื่องจาก Ki ไม่พร้อมใช้งาน หลังจากระดับการบูต i จึงไม่สามารถสร้างหรือถอดรหัสคีย์นี้ในระยะการบูต ต่อๆ ไปได้

การติดตั้งใช้งาน Keymaster 4.1 และ KeyMint 1.0

การติดตั้งใช้งาน Keymaster 4.1 และ KeyMint 1.0 ส่วนใหญ่จะเหมือนกับการติดตั้งใช้งาน Keymaster 4.0 ความแตกต่างหลักคือ K0 ไม่ใช่คีย์ MAX_USES_PER_BOOT แต่เป็นคีย์ EARLY_BOOT_ONLY ซึ่งเปิดตัวใน Keymaster 4.1 คีย์ EARLY_BOOT_ONLY จะใช้ได้เฉพาะในช่วงแรกๆ ของการบูต เมื่อไม่มีโค้ดที่ไม่น่าเชื่อถือทำงานอยู่ ซึ่งจะให้การปกป้องอีกระดับหนึ่ง ในการติดตั้งใช้งาน Keymaster 4.0 ผู้โจมตีที่บุกรุกระบบไฟล์และ SELinux จะแก้ไขฐานข้อมูล Keystore เพื่อสร้างคีย์ MAX_USES_PER_BOOT=1 ของตนเองเพื่อลงนามอาร์ติแฟกต์ได้ การโจมตีดังกล่าวเป็นไปไม่ได้ในการติดตั้งใช้งาน Keymaster 4.1 และ KeyMint 1.0 เนื่องจากคีย์ EARLY_BOOT_ONLY จะสร้างได้เฉพาะในระหว่างการเปิดเครื่องก่อนกำหนด

คอมโพเนนต์สาธารณะของคีย์ Signing ที่เชื่อถือได้

odsign จะดึงคอมโพเนนต์คีย์สาธารณะของคีย์ Signing จาก Keystore อย่างไรก็ตาม Keystore จะไม่ดึงคีย์สาธารณะนั้นจาก TEE/SE ที่เก็บคีย์ส่วนตัวที่เกี่ยวข้อง แต่จะดึงคีย์สาธารณะจากฐานข้อมูลในดิสก์ของตัวเองแทน ซึ่งหมายความว่าผู้โจมตีที่บุกรุกระบบไฟล์จะแก้ไขฐานข้อมูล Keystore ให้มีคีย์สาธารณะที่เป็นส่วนหนึ่งของคู่คีย์สาธารณะ/ส่วนตัวที่ตนควบคุมได้

odsign จะสร้างคีย์ HMAC เพิ่มเติมที่มีระดับการบูตเดียวกันกับคีย์ Signing เพื่อป้องกันการโจมตีนี้ จากนั้นเมื่อสร้างคีย์ Signing odsign จะใช้คีย์ HMAC นี้เพื่อสร้างลายเซ็นของคีย์สาธารณะและจัดเก็บไว้ในดิสก์ ในการบูตครั้งต่อๆ ไป เมื่อดึงคีย์สาธารณะของคีย์ Signing ระบบจะใช้คีย์ HMAC เพื่อยืนยันว่าลายเซ็นในดิสก์ตรงกับลายเซ็นของคีย์สาธารณะที่ดึงมา หากตรงกัน คีย์สาธารณะจะน่าเชื่อถือ เนื่องจากคีย์ HMAC ใช้ได้เฉพาะในระดับการเปิดเครื่องก่อนกำหนด จึงเป็นไปไม่ได้ที่ผู้โจมตีจะสร้างคีย์นี้