ตั้งแต่ Android 12 เป็นต้นไป โมดูล Android Runtime (ART) เป็นโมดูล Mainline การอัปเดตโมดูลอาจต้องสร้างอาร์ติแฟกต์การคอมไพล์ล่วงหน้า (AOT) ของไฟล์ JAR ใน Bootclasspath และเซิร์ฟเวอร์ระบบใหม่ เนื่องจากอาร์ติแฟกต์เหล่านี้มีความละเอียดอ่อนด้านความปลอดภัย Android 12 จึงใช้ฟีเจอร์ที่เรียกว่าการลงนามในอุปกรณ์เพื่อ ป้องกันไม่ให้อาร์ติแฟกต์เหล่านี้ถูกดัดแปลง หน้านี้ครอบคลุมสถาปัตยกรรมการลงนามในอุปกรณ์และการโต้ตอบกับฟีเจอร์ความปลอดภัยอื่นๆ ของ Android
การออกแบบระดับสูง
การลงนามในอุปกรณ์มีองค์ประกอบหลัก 2 อย่าง ได้แก่
odrefresh
เป็นส่วนหนึ่งของโมดูล ART Mainline ซึ่งมีหน้าที่ สร้างอาร์ติแฟกต์รันไทม์ โดยจะตรวจสอบอาร์ติแฟกต์ที่มีอยู่กับ โมดูล ART เวอร์ชันที่ติดตั้ง, ไฟล์ JAR ของ Bootclasspath และไฟล์ JAR ของเซิร์ฟเวอร์ระบบ เพื่อพิจารณาว่าอาร์ติแฟกต์เป็นเวอร์ชันล่าสุดหรือต้องสร้างใหม่ หากต้องสร้างใหม่odrefresh
จะสร้างและจัดเก็บรหัสเหล่านั้นodsign
เป็นไบนารีที่เป็นส่วนหนึ่งของแพลตฟอร์ม Android โดยจะทำงานในระหว่าง การบูตช่วงแรกๆ ทันทีหลังจากที่ติดตั้งพาร์ติชัน/data
หน้าที่หลักของเครื่องมือนี้คือการเรียกใช้odrefresh
เพื่อตรวจสอบว่าต้องสร้างหรืออัปเดตอาร์ติแฟกต์หรือไม่ สำหรับอาร์ติแฟกต์ใหม่หรืออัปเดตที่odrefresh
สร้างขึ้นodsign
จะคำนวณฟังก์ชันแฮช ผลลัพธ์ของการคำนวณแฮชดังกล่าวเรียกว่าข้อมูลสรุปของไฟล์ สำหรับอาร์ติแฟกต์ที่มีอยู่แล้วodsign
จะตรวจสอบว่าสรุปข้อความของอาร์ติแฟกต์ที่มีอยู่ตรงกับ สรุปข้อความที่odsign
คำนวณไว้ก่อนหน้านี้ ซึ่งช่วยให้มั่นใจได้ว่าไม่มีการดัดแปลง อาร์ติแฟกต์
ในกรณีที่เกิดข้อผิดพลาด เช่น เมื่อค่าแฮชของไฟล์ไม่ตรงกัน
odrefresh
และ odsign
จะทิ้งอาร์ติแฟกต์ที่มีอยู่ทั้งหมดใน /data
และ
พยายามสร้างอาร์ติแฟกต์ขึ้นมาใหม่ หากไม่สำเร็จ ระบบจะกลับไปใช้โหมด JIT
odrefresh
และ odsign
ได้รับการปกป้องโดย dm-verity
และเป็นส่วนหนึ่งของ
ห่วงโซ่การเปิดเครื่องที่ได้รับการยืนยันของ Android
การคำนวณข้อมูลสรุปของไฟล์ด้วย fs-verity
fs-verity เป็นฟีเจอร์ของเคอร์เนล Linux ที่ทำการยืนยันข้อมูลไฟล์ตามโครงสร้างต้นไม้ Merkle การเปิดใช้ fs-verity ในไฟล์จะทําให้ระบบไฟล์ สร้างต้นไม้ Merkle เหนือข้อมูลของไฟล์โดยใช้แฮช SHA-256 จัดเก็บไว้ใน ตําแหน่งที่ซ่อนอยู่ข้างไฟล์ และทําเครื่องหมายไฟล์เป็นแบบอ่านอย่างเดียว fs-verity จะตรวจสอบข้อมูลของไฟล์กับต้นไม้ Merkle โดยอัตโนมัติตามต้องการเมื่อมีการ อ่าน fs-verity จะทําให้แฮชรูทของต้นไม้ Merkle พร้อมใช้งานเป็นค่าที่เรียกว่าสรุปไฟล์ fs-verity และ fs-verity จะตรวจสอบว่าข้อมูลใดก็ตามที่อ่าน จากไฟล์สอดคล้องกับสรุปไฟล์นี้
odsign
ใช้ fs-verity เพื่อปรับปรุงประสิทธิภาพการเปิดเครื่องโดยการเพิ่มประสิทธิภาพ
การตรวจสอบสิทธิ์ด้วยการเข้ารหัสของอาร์ติแฟกต์ที่คอมไพล์ในอุปกรณ์ในเวลาเปิดเครื่อง เมื่อสร้างอาร์ติแฟกต์ odsign
จะเปิดใช้ fs-verity ในอาร์ติแฟกต์นั้น เมื่อ odsign
ยืนยันอาร์ติแฟกต์ ระบบจะยืนยันข้อมูลสรุปของไฟล์ fs-verity แทนแฮชของไฟล์
ทั้งหมด ซึ่งช่วยให้ไม่ต้องอ่านและแฮชข้อมูลทั้งหมดของอาร์ติแฟกต์ในเวลาบูต แต่ fs-verity จะแฮชข้อมูลอาร์ติแฟกต์ตามต้องการ
เมื่อมีการใช้งานทีละบล็อก
ในอุปกรณ์ที่เคอร์เนลไม่รองรับ fs-verity odsign
จะกลับไปใช้
การคำนวณข้อมูลสรุปของไฟล์ในพื้นที่ผู้ใช้ odsign
ใช้อัลกอริทึมแฮชที่อิงตาม Merkle Tree เดียวกันกับ fs-verity ดังนั้นค่าแฮชจึงเหมือนกันในทั้ง 2 กรณี
อุปกรณ์ทั้งหมดที่เปิดตัวด้วย Android 11 ขึ้นไปต้องใช้ fs-verity
การจัดเก็บข้อมูลสรุปของไฟล์
odsign
จะจัดเก็บข้อมูลสรุปของไฟล์อาร์ติแฟกต์ไว้ในไฟล์แยกต่างหากชื่อ
odsign.info
odsign.info
ได้รับการลงนามด้วยคีย์การลงนามที่มีคุณสมบัติด้านความปลอดภัยที่สำคัญ เพื่อให้มั่นใจว่า odsign.info
จะไม่ถูกดัดแปลง โดยเฉพาะอย่างยิ่ง คีย์จะสร้างและใช้ได้เฉพาะในระหว่างการบูตช่วงแรกเท่านั้น ซึ่งเป็นช่วงที่โค้ดที่เชื่อถือได้เท่านั้นที่ทำงานอยู่ ดูรายละเอียดได้ที่คีย์การลงนามที่เชื่อถือได้
การยืนยันค่าแฮชของไฟล์
ทุกครั้งที่บูต หาก odrefresh
พบว่าอาร์ติแฟกต์ที่มีอยู่เป็นเวอร์ชันล่าสุด odsign
จะตรวจสอบว่าไม่มีการดัดแปลงไฟล์ตั้งแต่มีการสร้างไฟล์ odsign
ทำเช่นนี้โดยการยืนยันข้อมูลสรุปของไฟล์ ก่อนอื่นจะ
ยืนยันลายเซ็นของ odsign.info
หากลายเซ็นถูกต้อง odsign
จะตรวจสอบว่าค่าแฮชของแต่ละไฟล์ตรงกับค่าแฮชที่เกี่ยวข้องใน odsign.info
คีย์การลงชื่อที่เชื่อถือได้
Android 12 เปิดตัวฟีเจอร์ใหม่ของ Keystore ที่เรียกว่า คีย์ระยะการบูต ซึ่งจะช่วยแก้ไขข้อกังวลด้านความปลอดภัยต่อไปนี้
- อะไรที่ป้องกันไม่ให้ผู้โจมตีใช้คีย์การลงนามของเราเพื่อลงนามใน
odsign.info
เวอร์ชันของตนเอง - อะไรที่ป้องกันไม่ให้ผู้โจมตีสร้างคีย์ Signing ของตนเองและใช้คีย์นั้นเพื่อลงนามใน
odsign.info
เวอร์ชันของตนเอง
คีย์ในระยะการบูตจะแบ่งวงจรการบูตของ Android ออกเป็นระดับต่างๆ และเชื่อมโยงการสร้างและการใช้คีย์กับระดับที่ระบุด้วยการเข้ารหัส
odsign
สร้างคีย์การลงนาม
ตั้งแต่ระดับต้นๆ เมื่อมีเพียงโค้ดที่เชื่อถือได้เท่านั้นที่ทำงาน โดยได้รับการปกป้อง
ผ่าน dm-verity
ระดับขั้นตอนการบูตจะมีหมายเลขตั้งแต่ 0 ถึงหมายเลขวิเศษ 1000000000 ในระหว่างกระบวนการบูตของ Android คุณสามารถเพิ่มระดับการบูตได้โดยการตั้งค่าพร็อพเพอร์ตี้ของระบบจาก init.rc
ตัวอย่างเช่น โค้ดต่อไปนี้จะตั้งค่าระดับการบูตเป็น
10
setprop keystore.boot_level 10
ไคลเอ็นต์ของ Keystore สามารถสร้างคีย์ที่เชื่อมโยงกับระดับการบูตที่เฉพาะเจาะจงได้ เช่น หากคุณสร้างคีย์สำหรับระดับการบูต 10 คีย์นั้นจะใช้ได้ก็ต่อเมื่ออุปกรณ์อยู่ในระดับการบูต 10 เท่านั้น
odsign
ใช้ระดับการบูต 30 และคีย์การลงนามที่สร้างจะเชื่อมโยงกับระดับการบูตนั้น
ก่อนใช้คีย์เพื่อลงนามในอาร์ติแฟกต์ odsign
จะยืนยันว่าคีย์เชื่อมโยงกับระดับการบูต 30
ซึ่งจะป้องกันการโจมตี 2 รูปแบบที่อธิบายไว้ก่อนหน้านี้ในส่วนนี้
- ผู้โจมตีใช้คีย์ที่สร้างขึ้นไม่ได้ เนื่องจากเมื่อผู้โจมตีมีโอกาสรันโค้ดที่เป็นอันตราย ระดับการบูตจะเพิ่มขึ้นเกิน 30 และ Keystore จะปฏิเสธการดำเนินการที่ใช้คีย์
- ผู้โจมตีจะสร้างคีย์ใหม่ไม่ได้ เนื่องจากเมื่อผู้โจมตีมีโอกาสรันโค้ดที่เป็นอันตราย ระดับการบูตจะเพิ่มขึ้นเกิน 30 และ Keystore จะปฏิเสธที่จะสร้างคีย์ใหม่ที่มีระดับการบูตดังกล่าว หากผู้โจมตี
สร้างคีย์ใหม่ที่ไม่ได้เชื่อมโยงกับระดับการบูต 30
odsign
จะปฏิเสธคีย์ดังกล่าว
Keystore ช่วยให้มั่นใจได้ว่ามีการบังคับใช้ระดับการบูตอย่างเหมาะสม ส่วนต่อไปนี้จะอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับวิธีดำเนินการนี้สำหรับ KeyMint (เดิมคือ Keymaster) เวอร์ชันต่างๆ
การติดตั้งใช้งาน Keymaster 4.0
Keymaster เวอร์ชันต่างๆ จะจัดการการใช้งานคีย์ในระยะการบูต แตกต่างกัน ในอุปกรณ์ที่มี TEE/StrongBox Keymaster 4.0 Keymaster จะจัดการ การติดตั้งใช้งานดังนี้
- ในการบูตครั้งแรก Keystore จะสร้างคีย์แบบสมมาตร K0 โดยมี
MAX_USES_PER_BOOT
แท็กตั้งค่าเป็น1
ซึ่งหมายความว่าคีย์จะใช้ได้เพียงครั้งเดียวต่อการบูต - ในระหว่างการบูต หากมีการเพิ่มระดับการบูต ระบบจะสร้างคีย์ใหม่สำหรับระดับการบูตนั้นจาก K0 โดยใช้ฟังก์ชัน HKDF:
Ki+i=HKDF(Ki, "some_fixed_string")
เช่น หากคุณย้ายจากระดับการบูต 0 ไปยังระดับการบูต 10 ระบบจะเรียกใช้ HKDF 10 ครั้งเพื่อสร้าง K10 จาก K0 เมื่อระดับการบูตเปลี่ยนไป ระบบจะลบคีย์สำหรับระดับการบูตก่อนหน้า ออกจากหน่วยความจำ และคีย์ที่เชื่อมโยงกับระดับการบูตก่อนหน้าจะ ใช้ไม่ได้อีกต่อไป
คีย์ K0 คือคีย์
MAX_USES_PER_BOOT=1
ซึ่งหมายความว่าคุณจะใช้คีย์นั้นในภายหลังเมื่อบูตไม่ได้ด้วย เนื่องจากจะมีการเปลี่ยนระดับการบูตอย่างน้อย 1 ครั้ง (เป็นการเปลี่ยนไปที่ระดับการบูตสุดท้าย) เสมอ
เมื่อไคลเอ็นต์ Keystore เช่น odsign
ขอให้สร้างคีย์ในระดับการบูต i
ระบบจะเข้ารหัส Blob ด้วยคีย์ 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
สร้างคีย์ได้ในระหว่างการบูตช่วงแรกเท่านั้น
คอมโพเนนต์สาธารณะของคีย์การลงชื่อที่เชื่อถือได้
odsign
ดึงข้อมูลคอมโพเนนต์คีย์สาธารณะของคีย์การลงนามจากคีย์สโตร์
อย่างไรก็ตาม Keystore จะไม่เรียกคีย์สาธารณะดังกล่าวจาก TEE/SE ที่มี
คีย์ส่วนตัวที่เกี่ยวข้อง แต่จะดึงคีย์สาธารณะจากฐานข้อมูลในดิสก์ของตัวเองแทน ซึ่งหมายความว่าผู้โจมตีที่บุกรุกระบบไฟล์
สามารถแก้ไขฐานข้อมูลคีย์สโตร์ให้มีคีย์สาธารณะซึ่งเป็นส่วนหนึ่ง
ของคู่คีย์สาธารณะ/ส่วนตัวภายใต้การควบคุมของตนได้
odsign
จะสร้างคีย์ HMAC เพิ่มเติมที่มี
ระดับการบูตเดียวกันกับคีย์การลงนามเพื่อป้องกันการโจมตีนี้ จากนั้นเมื่อสร้างคีย์การลงนาม odsign
จะใช้คีย์ HMAC นี้เพื่อสร้างลายเซ็นของคีย์สาธารณะและจัดเก็บไว้ใน
ดิสก์ ในการบูตครั้งต่อๆ ไป เมื่อเรียกคีย์สาธารณะของคีย์การลงนาม ระบบจะใช้คีย์ HMAC เพื่อยืนยันว่าลายเซ็นในดิสก์ตรงกับลายเซ็นของคีย์สาธารณะที่เรียกมา หากตรงกัน คีย์สาธารณะจะเชื่อถือได้เนื่องจาก
ใช้คีย์ HMAC ได้เฉพาะในระดับการบูตช่วงแรกเท่านั้น จึงเป็นไปไม่ได้ที่
ผู้โจมตีจะสร้างคีย์ดังกล่าว