ความพร้อมใช้งานของสภาพแวดล้อมการดำเนินการที่เชื่อถือได้ในระบบบนชิป (SoC) มอบโอกาสสำหรับอุปกรณ์ Android ในการให้บริการการรักษาความปลอดภัยที่แข็งแกร่งที่สนับสนุนฮาร์ดแวร์แก่ระบบปฏิบัติการ Android บริการแพลตฟอร์ม และแม้แต่แอปของบุคคลที่สาม นักพัฒนาที่ต้องการส่วนขยายเฉพาะของ Android ควรไปที่ android.security.keystore
ก่อน Android 6.0 Android มี API บริการเข้ารหัสลับที่สนับสนุนฮาร์ดแวร์อย่างง่ายอยู่แล้ว ซึ่งให้บริการโดย Keymaster Hardware Abstraction Layer (HAL) เวอร์ชัน 0.2 และ 0.3 Keystore ให้บริการเซ็นชื่อแบบดิจิทัลและดำเนินการตรวจสอบ รวมถึงการสร้างและนำเข้าคู่คีย์การเซ็นชื่อแบบอสมมาตร สิ่งนี้ถูกนำมาใช้แล้วในอุปกรณ์จำนวนมาก แต่มีเป้าหมายด้านความปลอดภัยมากมายที่ไม่สามารถบรรลุได้อย่างง่ายดายด้วย API ลายเซ็นเพียงอย่างเดียว Keystore ใน Android 6.0 ขยาย Keystore API เพื่อมอบความสามารถที่หลากหลายยิ่งขึ้น
ใน Android 6.0, Keystore ได้เพิ่ม การเข้ารหัสแบบดั้งเดิมแบบสมมาตร , AES และ HMAC และระบบควบคุมการเข้าถึงสำหรับคีย์ที่สนับสนุนฮาร์ดแวร์ มีการระบุการควบคุมการเข้าถึงระหว่างการสร้างคีย์และบังคับใช้ตลอดอายุการใช้งานของคีย์ คีย์สามารถถูกจำกัดให้ใช้งานได้หลังจากที่ผู้ใช้ได้รับการพิสูจน์ตัวตนแล้วเท่านั้น และสำหรับวัตถุประสงค์ที่ระบุหรือด้วยพารามิเตอร์การเข้ารหัสที่ระบุเท่านั้น สำหรับข้อมูลเพิ่มเติม โปรดดูที่เพจ Authorization Tags and Functions
นอกเหนือจากการขยายช่วงของการเข้ารหัสแบบดั้งเดิมแล้ว Keystore ใน Android 6.0 ยังเพิ่มสิ่งต่อไปนี้:
- รูปแบบการควบคุมการใช้งานที่อนุญาตให้จำกัดการใช้คีย์ เพื่อลดความเสี่ยงของการประนีประนอมด้านความปลอดภัยเนื่องจากการใช้คีย์ในทางที่ผิด
- รูปแบบการควบคุมการเข้าถึงเพื่อเปิดใช้งานการจำกัดคีย์สำหรับผู้ใช้ที่ระบุ ไคลเอนต์ และช่วงเวลาที่กำหนด
ใน Android 7.0, Keymaster 2 ได้เพิ่มการสนับสนุนสำหรับการยืนยันคีย์และการผูกเวอร์ชัน การรับรองคีย์ ให้ใบรับรองคีย์สาธารณะที่มีคำอธิบายโดยละเอียดของคีย์และการควบคุมการเข้าถึง เพื่อทำให้การมีอยู่ของคีย์ในฮาร์ดแวร์ที่ปลอดภัยและการกำหนดค่าสามารถตรวจสอบได้จากระยะไกล
การผูกเวอร์ชัน จะผูกคีย์กับระบบปฏิบัติการและเวอร์ชันระดับแพตช์ สิ่งนี้ทำให้มั่นใจได้ว่าผู้โจมตีที่ค้นพบจุดอ่อนในระบบเวอร์ชันเก่าหรือซอฟต์แวร์ TEE ไม่สามารถย้อนกลับอุปกรณ์เป็นเวอร์ชันที่มีช่องโหว่และใช้คีย์ที่สร้างขึ้นด้วยเวอร์ชันที่ใหม่กว่าได้ นอกจากนี้ เมื่อใช้คีย์ที่มีเวอร์ชันและระดับแพตช์ที่กำหนดบนอุปกรณ์ที่ได้รับการอัปเกรดเป็นเวอร์ชันใหม่หรือระดับแพตช์ คีย์นั้นจะได้รับการอัปเกรดก่อนที่จะสามารถใช้งานได้ และคีย์เวอร์ชันก่อนหน้าจะใช้งานไม่ได้ เมื่ออุปกรณ์ได้รับการอัปเกรด ปุ่มจะ "วงล้อ" ไปข้างหน้าพร้อมกับอุปกรณ์ แต่การกลับอุปกรณ์เป็นรุ่นก่อนหน้าจะทำให้ปุ่มใช้งานไม่ได้
ใน Android 8.0, Keymaster 3 เปลี่ยนจาก C-structure Hardware Abstraction Layer (HAL) แบบเก่าเป็นอินเทอร์เฟซ C++ HAL ที่สร้างจากคำจำกัดความใน Hardware Interface Definition Language (HIDL) ใหม่ ในส่วนของการเปลี่ยนแปลง ประเภทอาร์กิวเมนต์จำนวนมากเปลี่ยนไป แม้ว่าประเภทและเมธอดจะมีความสอดคล้องกันแบบหนึ่งต่อหนึ่งกับประเภทเก่าและเมธอดโครงสร้าง HAL ดูหน้า ฟังก์ชัน สำหรับรายละเอียดเพิ่มเติม
นอกจากการแก้ไขอินเทอร์เฟซนี้แล้ว Android 8.0 ยังขยายคุณสมบัติการรับรองของ Keymaster 2 เพื่อรองรับ การรับรอง ID การรับรอง ID มีกลไกที่จำกัดและเป็นทางเลือกสำหรับการรับรองอย่างเข้มงวดกับตัวระบุฮาร์ดแวร์ เช่น หมายเลขซีเรียลของอุปกรณ์ ชื่อผลิตภัณฑ์ และรหัสโทรศัพท์ (IMEI / MEID) ในการดำเนินการเพิ่มเติมนี้ Android 8.0 ได้เปลี่ยนสคีมาการรับรอง ASN.1 เพื่อเพิ่มการรับรอง ID การใช้งานคีย์มาสเตอร์จำเป็นต้องหาวิธีที่ปลอดภัยในการดึงรายการข้อมูลที่เกี่ยวข้อง ตลอดจนกำหนดกลไกสำหรับการปิดใช้งานคุณลักษณะอย่างปลอดภัยและถาวร
ใน Android 9 การอัปเดตรวมถึง:
- อัปเดตเป็น คีย์มาสเตอร์ 4
- รองรับ Secure Elements แบบฝังตัว
- รองรับการนำเข้าคีย์ที่ปลอดภัย
- รองรับการเข้ารหัส 3DES
- การเปลี่ยนแปลงการรวมเวอร์ชันเพื่อให้ boot.img และ system.img ตั้งค่าเวอร์ชันแยกกันเพื่อให้สามารถอัปเดตแยกกันได้
อภิธานศัพท์
นี่คือภาพรวมโดยย่อของส่วนประกอบ Keystore และความสัมพันธ์
AndroidKeystore คือ Android Framework API และคอมโพเนนต์ที่แอปใช้เพื่อเข้าถึงการทำงานของ Keystore มีการนำมาใช้เป็นส่วนเสริมของ Java Cryptography Architecture APIs มาตรฐาน และประกอบด้วยโค้ด Java ที่ทำงานในพื้นที่กระบวนการของแอปเอง AndroidKeystore
ตอบสนองคำขอของแอพสำหรับพฤติกรรมของ Keystore โดยส่งต่อไปยัง keystore daemon
keystore daemon เป็น daemon ระบบ Android ที่ให้การเข้าถึงฟังก์ชัน Keystore ทั้งหมดผ่าน Binder API มีหน้าที่จัดเก็บ "key blobs" ซึ่งมีเนื้อหาของรหัสลับจริง เข้ารหัสเพื่อให้ Keystore สามารถจัดเก็บได้ แต่ห้ามใช้หรือเปิดเผย
keymasterd เป็นเซิร์ฟเวอร์ HIDL ที่ให้การเข้าถึง Keymaster TA (ชื่อนี้ไม่ได้มาตรฐานและมีวัตถุประสงค์เพื่อเป็นแนวคิด)
Keymaster TA (แอปพลิเคชันที่เชื่อถือได้) เป็นซอฟต์แวร์ที่ทำงานในบริบทที่ปลอดภัย ส่วนใหญ่มักจะอยู่ใน TrustZone บน ARM SoC ซึ่งให้การดำเนินการของ Keystore ที่ปลอดภัยทั้งหมด สามารถเข้าถึงวัตถุดิบของคีย์ ตรวจสอบเงื่อนไขการควบคุมการเข้าถึงทั้งหมดบนคีย์ ฯลฯ
LockSettingsService เป็นส่วนประกอบของระบบ Android ที่มีหน้าที่ตรวจสอบผู้ใช้ ทั้งรหัสผ่านและลายนิ้วมือ ไม่ใช่ส่วนหนึ่งของ Keystore แต่มีความเกี่ยวข้องเนื่องจากการดำเนินการคีย์ของ Keystore จำนวนมากต้องการการรับรองความถูกต้องของผู้ใช้ LockSettingsService
โต้ตอบกับ Gatekeeper TA และ Fingerprint TA เพื่อรับโทเค็นการพิสูจน์ตัวตน ซึ่งมอบให้กับ keystore daemon และสุดท้ายจะถูกใช้โดยแอปพลิเคชัน Keymaster TA
Gatekeeper TA (แอปพลิเคชันที่เชื่อถือได้) เป็นส่วนประกอบอื่นที่ทำงานในบริบทที่ปลอดภัย ซึ่งมีหน้าที่ตรวจสอบรหัสผ่านของผู้ใช้และสร้างโทเค็นการตรวจสอบสิทธิ์ที่ใช้เพื่อพิสูจน์ให้ Keymaster TA เห็นว่าการตรวจสอบสิทธิ์ได้ดำเนินการสำหรับผู้ใช้เฉพาะ ณ เวลาใดเวลาหนึ่ง
Fingerprint TA (แอปพลิเคชันที่เชื่อถือได้) เป็นอีกหนึ่งส่วนประกอบที่ทำงานในบริบทที่ปลอดภัยซึ่งมีหน้าที่ตรวจสอบลายนิ้วมือของผู้ใช้และสร้างโทเค็นการตรวจสอบสิทธิ์ที่ใช้เพื่อพิสูจน์ให้ Keymaster TA เห็นว่าการตรวจสอบสิทธิ์ได้ดำเนินการสำหรับผู้ใช้เฉพาะ ณ เวลาใดเวลาหนึ่ง
สถาปัตยกรรม
Android Keystore API และ Keymaster HAL พื้นฐานมีชุดพื้นฐานของการเข้ารหัสแบบพื้นฐานแต่เพียงพอเพื่อให้ใช้งานโปรโตคอลได้โดยใช้คีย์ที่ควบคุมการเข้าถึงและสำรองด้วยฮาร์ดแวร์
Keymaster HAL เป็นไลบรารีที่โหลดได้แบบไดนามิกที่จัดหาโดย OEM ซึ่งใช้โดยบริการ Keystore เพื่อให้บริการเข้ารหัสลับที่สนับสนุนฮาร์ดแวร์ เพื่อรักษาความปลอดภัย การนำ HAL ไปใช้จะไม่ดำเนินการใดๆ ที่ละเอียดอ่อนในพื้นที่ผู้ใช้ หรือแม้แต่ในพื้นที่เคอร์เนล การดำเนินการที่ละเอียดอ่อนได้รับการมอบหมายให้กับโปรเซสเซอร์ที่ปลอดภัยซึ่งเข้าถึงผ่านอินเทอร์เฟซเคอร์เนลบางตัว สถาปัตยกรรมที่ได้มีลักษณะดังนี้:

รูปที่ 1 การเข้าถึงคีย์มาสเตอร์
ภายในอุปกรณ์ Android "ไคลเอนต์" ของ Keymaster HAL ประกอบด้วยหลายเลเยอร์ (เช่น แอพ, เฟรมเวิร์ก, Keystore daemon) แต่สามารถละเว้นได้สำหรับวัตถุประสงค์ของเอกสารนี้ ซึ่งหมายความว่า Keymaster HAL API ที่อธิบายไว้นั้นเป็นระดับต่ำ ใช้โดยส่วนประกอบภายในแพลตฟอร์ม และไม่เปิดเผยต่อนักพัฒนาแอป API ระดับที่สูงกว่ามีอธิบายไว้ใน ไซต์นักพัฒนาซอฟต์แวร์ Android
จุดประสงค์ของ Keymaster HAL ไม่ใช่การนำอัลกอริทึมที่ไวต่อความปลอดภัยไปใช้ แต่เพียงเพื่อจัดการและยกเลิกการร้องขอไปยังโลกที่ปลอดภัย รูปแบบ Wire ถูกกำหนดโดยการใช้งาน
ความเข้ากันได้กับเวอร์ชันก่อนหน้า
Keymaster 1 HAL ไม่สามารถใช้งานร่วมกับ HAL ที่วางจำหน่ายก่อนหน้านี้ได้อย่างสมบูรณ์ เช่น Keymaster 0.2 และ 0.3 เพื่ออำนวยความสะดวกในการทำงานร่วมกันบนอุปกรณ์ที่ใช้ Android 5.0 และรุ่นก่อนหน้าที่เปิดตัวด้วย Keymaster HAL รุ่นเก่า Keystore จัดเตรียมอแด็ปเตอร์ที่ใช้ Keymaster 1 HAL ด้วยการเรียกไปยังไลบรารีฮาร์ดแวร์ที่มีอยู่ ผลลัพธ์ไม่สามารถให้ฟังก์ชันการทำงานเต็มรูปแบบใน Keymaster 1 HAL โดยเฉพาะอย่างยิ่ง สนับสนุนเฉพาะอัลกอริทึม RSA และ ECDSA และการบังคับใช้การอนุญาตคีย์ทั้งหมดดำเนินการโดยอแด็ปเตอร์ ในโลกที่ไม่ปลอดภัย
Keymaster 2 ทำให้อินเทอร์เฟซ HAL ง่ายขึ้นโดยการลบเมธอด get_supported_*
และอนุญาตให้ finish()
ยอมรับอินพุต ซึ่งช่วยลดจำนวนการเดินทางไป-กลับ TEE ในกรณีที่อินพุตพร้อมใช้งานทั้งหมดในคราวเดียว และทำให้การใช้งานการถอดรหัส AEAD ง่ายขึ้น
ใน Android 8.0, Keymaster 3 ได้เปลี่ยนจากโครงสร้าง C แบบเก่า HAL เป็นอินเทอร์เฟซ C++ HAL ที่สร้างจากคำจำกัดความใน Hardware Interface Definition Language (HIDL) ใหม่ การใช้งาน HAL แบบใหม่นั้นถูกสร้างขึ้นโดยการแบ่งคลาสย่อยของคลาส IKeymasterDevice
ที่สร้างขึ้น และการปรับใช้เมธอดเสมือนล้วน ในส่วนของการเปลี่ยนแปลง ประเภทอาร์กิวเมนต์จำนวนมากมีการเปลี่ยนแปลง แม้ว่าประเภทและเมธอดจะมีความสอดคล้องกันแบบหนึ่งต่อหนึ่งกับประเภทเก่าและเมธอดโครงสร้าง HAL
ภาพรวมของ HIDL
Hardware Interface Definition Language (HIDL) จัดเตรียมกลไกการใช้งานที่ไม่ขึ้นกับภาษาสำหรับการระบุอินเทอร์เฟซฮาร์ดแวร์ ขณะนี้เครื่องมือ HIDL รองรับการสร้างอินเตอร์เฟส C++ และ Java คาดว่าผู้ดำเนินการ Trusted Execution Environment (TEE) ส่วนใหญ่จะพบว่าเครื่องมือ C++ สะดวกกว่า ดังนั้นเอกสารนี้จึงกล่าวถึงเฉพาะการแสดง C++ เท่านั้น
อินเทอร์เฟซ HIDL ประกอบด้วยชุดของวิธีการ ซึ่งแสดงเป็น:
methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);
มีประเภทที่กำหนดไว้ล่วงหน้าหลายประเภท และ HAL สามารถกำหนดประเภทการแจกแจงและโครงสร้างใหม่ได้ สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ HIDL โปรดดู ส่วนข้อมูลอ้างอิง
วิธีการตัวอย่างจาก Keymaster 3 IKeymasterDevice.hal
คือ:
generateKey(vec<KeyParameter> keyParams) generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
นี่เทียบเท่ากับสิ่งต่อไปนี้จาก keymaster2 HAL:
keymaster_error_t (*generate_key)( const struct keymaster2_device* dev, const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics);
ในเวอร์ชัน HIDL อาร์กิวเมนต์ dev
จะถูกลบออก เนื่องจากเป็นนัย อาร์กิวเมนต์ params
ไม่ใช่โครงสร้างที่มีตัวชี้ที่อ้างอิงอาร์เรย์ของ key_parameter_t
อีกต่อไป แต่เป็น vec
(เวกเตอร์) ที่มี KeyParameter
ค่าที่ส่งคืนจะแสดงอยู่ในส่วนคำสั่ง " generates
" รวมถึงเวกเตอร์ของค่า uint8_t
สำหรับคีย์หยด
วิธีการเสมือน C ++ ที่สร้างขึ้นโดยคอมไพเลอร์ HIDL คือ:
Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams, generateKey_cb _hidl_cb) override;
โดยที่ generateKey_cb
เป็นตัวชี้ฟังก์ชันที่กำหนดเป็น:
std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob, const KeyCharacteristics& keyCharacteristics)>
นั่นคือ generateKey_cb
เป็นฟังก์ชันที่รับค่าส่งคืนที่แสดงอยู่ในส่วนคำสั่ง create คลาสการใช้งาน HAL จะแทนที่เมธอด generateKey
นี้ และเรียกตัวชี้ฟังก์ชัน generateKey_cb
เพื่อส่งคืนผลลัพธ์ของการดำเนินการไปยังผู้เรียก โปรดทราบว่าการเรียกตัวชี้ฟังก์ชันเป็น แบบซิงโครนัส ผู้เรียกเรียก generateKey
และ generateKey
เรียกตัวชี้ฟังก์ชันที่ให้มา ซึ่งดำเนินการจนเสร็จสิ้น ส่งคืนการควบคุมไปยังการใช้งาน generateKey
ซึ่งจะส่งคืนไปยังผู้เรียก
สำหรับตัวอย่างโดยละเอียด โปรดดูการใช้งานเริ่มต้นใน hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp
การใช้งานเริ่มต้นให้ความเข้ากันได้แบบย้อนหลังสำหรับอุปกรณ์ที่มี keymaster0, keymaster1 หรือ keymaster2 HALS แบบเก่า
การควบคุมการเข้าถึง
กฎพื้นฐานที่สุดของการควบคุมการเข้าถึง Keystore คือแต่ละแอปจะมีเนมสเปซของตัวเอง แต่สำหรับทุกกฎมีข้อยกเว้น Keystore มีฮาร์ดโค้ดแม็พที่อนุญาตให้คอมโพเนนต์ระบบบางอย่างเข้าถึงเนมสเปซอื่นได้ นี่เป็นเครื่องมือที่ทื่อมากโดยให้ส่วนประกอบหนึ่งสามารถควบคุมเนมสเปซอื่นได้อย่างเต็มที่ และจากนั้นก็มีเรื่องของส่วนประกอบของผู้ขายในฐานะไคลเอนต์ของ Keystore ขณะนี้เราไม่มีวิธีสร้างเนมสเปซสำหรับส่วนประกอบของผู้ขาย ตัวอย่างเช่น ผู้ร้องขอ WPA
เพื่อรองรับคอมโพเนนต์ของผู้ขายและควบคุมการเข้าถึงโดยทั่วไปโดยไม่มีข้อยกเว้นแบบตายตัว Keystore 2.0 จึงแนะนำโดเมนและเนมสเปซ SELinux
โดเมนที่เก็บคีย์
ด้วยโดเมน Keystore เราสามารถแยกเนมสเปซออกจาก UID ได้ ไคลเอนต์ที่เข้าถึงคีย์ใน Keystore จะต้องระบุโดเมน เนมสเปซ และนามแฝงที่พวกเขาต้องการเข้าถึง จากทูเพิลนี้และตัวตนของผู้โทร เราสามารถกำหนดได้ว่าคีย์ใดที่ผู้โทรต้องการเข้าถึงและมีสิทธิ์ที่เหมาะสมหรือไม่
เราแนะนำพารามิเตอร์โดเมนห้ารายการซึ่งควบคุมวิธีการเข้าถึงคีย์ พวกเขาควบคุมความหมายของพารามิเตอร์เนมสเปซของตัวอธิบายคีย์และวิธีการควบคุมการเข้าถึง
-
DOMAIN_APP
: โดเมนแอปครอบคลุมลักษณะการทำงานเดิม Java Keystore SPI ใช้โดเมนนี้โดยดีฟอลต์ เมื่อใช้โดเมนนี้ อาร์กิวเมนต์เนมสเปซจะถูกละเว้นและจะใช้ UID ของผู้โทรแทน การเข้าถึงโดเมนนี้ควบคุมโดยป้ายกำกับ Keystore ไปยังคลาสkeystore_key
ในนโยบาย SELinux -
DOMAIN_SELINUX
: โดเมนนี้ระบุว่าเนมสเปซมีป้ายกำกับในนโยบาย SELinux พารามิเตอร์เนมสเปซถูกค้นหาและแปลเป็นบริบทเป้าหมาย และดำเนินการตรวจสอบสิทธิ์สำหรับการเรียกใช้บริบท SELinux สำหรับคลาสkeystore_key
เมื่อมีการกำหนดสิทธิ์สำหรับการดำเนินการที่กำหนด ทูเพิลแบบเต็มจะถูกใช้สำหรับการค้นหาคีย์ -
DOMAIN_GRANT
: โดเมนให้ระบุว่าพารามิเตอร์เนมสเปซเป็นตัวระบุการให้สิทธิ์ พารามิเตอร์ alias ถูกละเว้น การตรวจสอบ SELinux จะดำเนินการเมื่อมีการสร้างการให้สิทธิ์ การควบคุมการเข้าถึงเพิ่มเติมจะตรวจสอบเฉพาะว่า UID ของผู้โทรตรงกับ UID ของผู้รับสิทธิ์ของสิทธิ์ที่ขอหรือไม่ -
DOMAIN_KEY_ID
: โดเมนนี้ระบุว่าพารามิเตอร์เนมสเปซเป็นรหัสคีย์เฉพาะ ตัวคีย์อาจถูกสร้างขึ้นด้วยDOMAIN_APP
หรือDOMAIN_SELINUX
การตรวจสอบสิทธิ์จะดำเนินการหลังจากโหลดdomain
และnamespace
จากฐานข้อมูลคีย์ในลักษณะเดียวกับที่โหลด blob โดยโดเมน เนมสเปซ และทูเพิลนามแฝง เหตุผลสำหรับโดเมนรหัสคีย์คือความต่อเนื่อง เมื่อเข้าถึงคีย์ด้วยนามแฝง การเรียกที่ตามมาอาจดำเนินการกับคีย์อื่น เนื่องจากอาจมีการสร้างหรือนำเข้าคีย์ใหม่และผูกไว้กับนามแฝงนี้ อย่างไรก็ตามรหัสคีย์ไม่เคยเปลี่ยนแปลง ดังนั้น เมื่อใช้รหัสตามรหัสรหัสหลังจากที่โหลดจากฐานข้อมูล Keystore โดยใช้นามแฝงแล้ว จะสามารถมั่นใจได้ว่าเป็นรหัสเดียวกันตราบเท่าที่รหัสรหัสยังคงอยู่ นักพัฒนาแอปไม่เปิดเผยฟังก์ชันนี้ แต่จะใช้ภายใน Android Keystore SPI เพื่อมอบประสบการณ์ที่สอดคล้องกันมากขึ้นแม้ว่าจะใช้พร้อมกันในลักษณะที่ไม่ปลอดภัยก็ตาม -
DOMAIN_BLOB
: โดเมน blob ระบุว่าผู้โทรจัดการ blob ด้วยตัวเอง สิ่งนี้ใช้สำหรับไคลเอ็นต์ที่ต้องเข้าถึง Keystore ก่อนที่จะติดตั้งพาร์ติชันข้อมูล คีย์บล็อบจะรวมอยู่ในฟิลด์blob
ของตัวอธิบายคีย์
เมื่อใช้โดเมน SELinux เราสามารถให้ส่วนประกอบผู้ขายเข้าถึงเนมสเปซ Keystore ที่เฉพาะเจาะจงมาก ซึ่งคอมโพเนนต์ของระบบสามารถแชร์ได้ เช่น กล่องโต้ตอบการตั้งค่า
นโยบาย SELinux สำหรับ keystore_key
เลเบลเนมสเปซถูกกำหนดค่าโดยใช้ไฟล์ keystore2_key_context
แต่ละบรรทัดในไฟล์เหล่านี้จะจับคู่ ID เนมสเปซที่เป็นตัวเลขกับป้ายกำกับ SELinux ตัวอย่างเช่น,
# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and # Settings to share keystore keys. 102 u:object_r:wifi_key:s0
หลังจากตั้งค่าเนมสเปซคีย์ใหม่ด้วยวิธีนี้แล้ว เราสามารถให้สิทธิ์การเข้าถึงได้โดยเพิ่มนโยบายที่เหมาะสม ตัวอย่างเช่น หากต้องการอนุญาตให้ wpa_supplicant
รับและใช้คีย์ในเนมสเปซใหม่ เราจะเพิ่มบรรทัดต่อไปนี้ใน hal_wifi_supplicant.te
:
allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };
หลังจากตั้งค่าเนมสเปซใหม่แล้ว AndroidKeyStore สามารถใช้งานได้ตามปกติ ข้อแตกต่างเพียงอย่างเดียวคือต้องระบุ ID เนมสเปซ สำหรับการโหลดและอิมพอร์ตคีย์จากและเข้าสู่ Keystore รหัสเนมสเปซจะถูกระบุโดยใช้ AndroidKeyStoreLoadStoreParameter
ตัวอย่างเช่น,
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; import java.security.KeyStore; KeyStore keystore = KeyStore.getInstance("AndroidKeyStore"); keystore.load(new AndroidKeyStoreLoadStoreParameter(102));
ในการสร้างคีย์ในเนมสเปซที่กำหนด จะต้องกำหนด ID เนมสเปซโดยใช้ KeyGenParameterSpec.Builder#setNamespace():
import android.security.keystore.KeyGenParameterSpec; KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(); specBuilder.setNamespace(102);
ไฟล์บริบทต่อไปนี้อาจใช้เพื่อกำหนดค่าเนมสเปซ Keystore 2.0 SELinux แต่ละพาร์ติชันมีช่วงที่สงวนไว้ต่างกันที่ 10,000 เนมสเปซ ids เพื่อหลีกเลี่ยงการชนกัน
ฉากกั้นห้อง | พิสัย | ไฟล์กำหนดค่า |
---|---|---|
ระบบ | 0 ... 9,999 | /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts |
ระบบขยาย | 10,000 ... 19,999 | /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts |
ผลิตภัณฑ์ | 20,000 ... 29,999 | /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts |
ผู้ขาย | 30,000 ... 39,999 | /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts |
ลูกค้าร้องขอคีย์โดยร้องขอโดเมน SELinux และเนมสเปซเสมือนที่ต้องการ ในกรณีนี้คือ "wifi_key"
โดยใช้รหัสตัวเลข
เหนือสิ่งอื่นใด มีการกำหนดเนมสเปซต่อไปนี้ หากใช้แทนที่กฎพิเศษ ตารางต่อไปนี้จะระบุ UID ที่ใช้เพื่อให้สอดคล้องกัน
รหัสเนมสเปซ | ป้ายนโยบาย SE | ยูไอดี | คำอธิบาย |
---|---|---|---|
0 | su_key | ไม่มีข้อมูล | รหัสผู้ใช้ขั้นสูง ใช้สำหรับการทดสอบการสร้าง userdebug และ eng เท่านั้น ไม่เกี่ยวข้องกับงานสร้างของผู้ใช้ |
1 | เชลล์_คีย์ | ไม่มีข้อมูล | เนมสเปซพร้อมใช้งานสำหรับเชลล์ ส่วนใหญ่ใช้สำหรับการทดสอบ แต่สามารถใช้กับรุ่นผู้ใช้ได้เช่นกันจากบรรทัดคำสั่ง |
100 | โวลด์_คีย์ | ไม่มีข้อมูล | มีไว้สำหรับใช้งานโดยโวล |
101 | odsing_key | ไม่มีข้อมูล | ใช้โดยภูตการลงนามบนอุปกรณ์ |
102 | wifi_key | AID_WIFI(1010) | ใช้โดยระบบ Wifi ของ Android รวมถึง wpa_supplicant |
120 | ดำเนินการต่อ_on_reboot_key | AID_SYSTEM(1,000) | ใช้โดยเซิร์ฟเวอร์ระบบของ Android เพื่อรองรับการดำเนินการต่อเมื่อรีบูต |
เข้าถึงเวกเตอร์
คลาส SELinux keystore_key
มีอายุค่อนข้างนานและสิทธิ์บางอย่างเช่น verify
หรือ sign
ได้สูญเสียความหมายไปแล้ว นี่คือชุดสิทธิ์ใหม่ keystore2_key
ที่ Keystore 2.0 จะบังคับใช้
การอนุญาต | ความหมาย |
---|---|
delete | ตรวจสอบเมื่อลบคีย์ออกจาก Keystore |
get_info | ตรวจสอบเมื่อมีการร้องขอข้อมูลเมตาของคีย์ |
grant | ผู้โทรต้องการการอนุญาตนี้เพื่อสร้างการอนุญาตให้กับคีย์ในบริบทเป้าหมาย |
manage_blob | ผู้โทรอาจใช้ DOMAIN_BLOB บนเนมสเปซ SELinux ที่กำหนด ดังนั้นจึงจัดการ blobs ด้วยตัวเอง สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับ vold |
rebind | การอนุญาตนี้ควบคุมว่านามแฝงอาจถูกเด้งกลับเป็นคีย์ใหม่หรือไม่ สิ่งนี้จำเป็นสำหรับการแทรกและบอกเป็นนัยว่าคีย์ที่ผูกไว้ก่อนหน้านี้จะถูกลบ โดยพื้นฐานแล้วเป็นการอนุญาตการแทรก แต่จะจับความหมายของที่เก็บคีย์ได้ดีกว่า |
req_forced_op | ไคลเอนต์ที่ได้รับอนุญาตนี้อาจสร้างการดำเนินการที่ป้องกันไม่ได้ และการสร้างการดำเนินการจะไม่มีวันล้มเหลว เว้นแต่ว่าช่องการดำเนินการทั้งหมดจะถูกดำเนินการโดยการดำเนินการที่แก้ไขไม่ได้ |
update | จำเป็นต้องอัปเดตส่วนประกอบย่อยของคีย์ |
use | ตรวจสอบเมื่อสร้างการดำเนินการ Keymint ที่ใช้วัสดุหลัก เช่น สำหรับการเซ็นชื่อ การเข้ารหัส/ถอดรหัส |
use_dev_id | จำเป็นเมื่อสร้างข้อมูลระบุอุปกรณ์ เช่น การรับรองรหัสอุปกรณ์ |
นอกจากนี้ เราแยกชุดของสิทธิ์ที่เก็บคีย์เฉพาะที่ไม่ใช่คีย์ใน keystore2
คลาสความปลอดภัย SELinux2 :
การอนุญาต | ความหมาย |
---|---|
add_auth | จำเป็นโดยผู้ให้บริการตรวจสอบความถูกต้อง เช่น Gatekeeper หรือ BiometricsManager สำหรับการเพิ่มโทเค็นการตรวจสอบสิทธิ์ |
clear_ns | เดิมคือ clear_uid การอนุญาตนี้อนุญาตให้ผู้ที่ไม่ใช่เจ้าของเนมสเปซสามารถลบคีย์ทั้งหมดในเนมสเปซนั้นได้ |
list | ระบบต้องการสำหรับการระบุคีย์ตามคุณสมบัติต่างๆ เช่น ความเป็นเจ้าของหรือขอบเขตการตรวจสอบสิทธิ์ การอนุญาตนี้ไม่จำเป็นสำหรับผู้โทรที่ระบุเนมสเปซของตนเอง สิ่งนี้ครอบคลุมโดยสิทธิ์ get_info |
lock | การอนุญาตนี้อนุญาตให้ล็อค Keystore ซึ่งก็คือ ยกเลิกคีย์หลัก ซึ่งทำให้คีย์ที่ตรวจสอบสิทธิ์ใช้ไม่ได้และไม่สามารถสร้างขึ้นได้ |
reset | การอนุญาตนี้อนุญาตให้รีเซ็ต Keystore เป็นค่าเริ่มต้นจากโรงงาน โดยลบคีย์ทั้งหมดที่ไม่สำคัญต่อการทำงานของระบบปฏิบัติการ Android |
unlock | การอนุญาตนี้จำเป็นต้องพยายามปลดล็อกมาสเตอร์คีย์สำหรับคีย์ที่ถูกผูกไว้สำหรับการตรวจสอบสิทธิ์ |
ความพร้อมใช้งานของสภาพแวดล้อมการดำเนินการที่เชื่อถือได้ในระบบบนชิป (SoC) มอบโอกาสสำหรับอุปกรณ์ Android ในการให้บริการการรักษาความปลอดภัยที่แข็งแกร่งที่สนับสนุนฮาร์ดแวร์แก่ระบบปฏิบัติการ Android บริการแพลตฟอร์ม และแม้แต่แอปของบุคคลที่สาม นักพัฒนาที่ต้องการส่วนขยายเฉพาะของ Android ควรไปที่ android.security.keystore
ก่อน Android 6.0 Android มี API บริการเข้ารหัสลับที่สนับสนุนฮาร์ดแวร์อย่างง่ายอยู่แล้ว ซึ่งให้บริการโดย Keymaster Hardware Abstraction Layer (HAL) เวอร์ชัน 0.2 และ 0.3 Keystore ให้บริการเซ็นชื่อแบบดิจิทัลและดำเนินการตรวจสอบ รวมถึงการสร้างและนำเข้าคู่คีย์การเซ็นชื่อแบบอสมมาตร สิ่งนี้ถูกนำมาใช้แล้วในอุปกรณ์จำนวนมาก แต่มีเป้าหมายด้านความปลอดภัยมากมายที่ไม่สามารถบรรลุได้อย่างง่ายดายด้วย API ลายเซ็นเพียงอย่างเดียว Keystore ใน Android 6.0 ขยาย Keystore API เพื่อมอบความสามารถที่หลากหลายยิ่งขึ้น
ใน Android 6.0, Keystore ได้เพิ่ม การเข้ารหัสแบบดั้งเดิมแบบสมมาตร , AES และ HMAC และระบบควบคุมการเข้าถึงสำหรับคีย์ที่สนับสนุนฮาร์ดแวร์ มีการระบุการควบคุมการเข้าถึงระหว่างการสร้างคีย์และบังคับใช้ตลอดอายุการใช้งานของคีย์ คีย์สามารถถูกจำกัดให้ใช้งานได้หลังจากที่ผู้ใช้ได้รับการพิสูจน์ตัวตนแล้วเท่านั้น และสำหรับวัตถุประสงค์ที่ระบุหรือด้วยพารามิเตอร์การเข้ารหัสที่ระบุเท่านั้น สำหรับข้อมูลเพิ่มเติม โปรดดูที่เพจ Authorization Tags and Functions
นอกเหนือจากการขยายช่วงของการเข้ารหัสแบบดั้งเดิมแล้ว Keystore ใน Android 6.0 ยังเพิ่มสิ่งต่อไปนี้:
- รูปแบบการควบคุมการใช้งานที่อนุญาตให้จำกัดการใช้คีย์ เพื่อลดความเสี่ยงของการประนีประนอมด้านความปลอดภัยเนื่องจากการใช้คีย์ในทางที่ผิด
- รูปแบบการควบคุมการเข้าถึงเพื่อเปิดใช้งานการจำกัดคีย์สำหรับผู้ใช้ที่ระบุ ไคลเอนต์ และช่วงเวลาที่กำหนด
ใน Android 7.0, Keymaster 2 ได้เพิ่มการสนับสนุนสำหรับการยืนยันคีย์และการผูกเวอร์ชัน การรับรองคีย์ ให้ใบรับรองคีย์สาธารณะที่มีคำอธิบายโดยละเอียดของคีย์และการควบคุมการเข้าถึง เพื่อทำให้การมีอยู่ของคีย์ในฮาร์ดแวร์ที่ปลอดภัยและการกำหนดค่าสามารถตรวจสอบได้จากระยะไกล
การผูกเวอร์ชัน จะผูกคีย์กับระบบปฏิบัติการและเวอร์ชันระดับแพตช์ สิ่งนี้ทำให้มั่นใจได้ว่าผู้โจมตีที่ค้นพบจุดอ่อนในระบบเวอร์ชันเก่าหรือซอฟต์แวร์ TEE ไม่สามารถย้อนกลับอุปกรณ์เป็นเวอร์ชันที่มีช่องโหว่และใช้คีย์ที่สร้างขึ้นด้วยเวอร์ชันที่ใหม่กว่าได้ นอกจากนี้ เมื่อใช้คีย์ที่มีเวอร์ชันและระดับแพตช์ที่กำหนดบนอุปกรณ์ที่ได้รับการอัปเกรดเป็นเวอร์ชันใหม่หรือระดับแพตช์ คีย์นั้นจะได้รับการอัปเกรดก่อนที่จะสามารถใช้งานได้ และคีย์เวอร์ชันก่อนหน้าจะใช้งานไม่ได้ เมื่ออุปกรณ์ได้รับการอัปเกรด ปุ่มจะ "วงล้อ" ไปข้างหน้าพร้อมกับอุปกรณ์ แต่การกลับอุปกรณ์เป็นรุ่นก่อนหน้าจะทำให้ปุ่มใช้งานไม่ได้
ใน Android 8.0, Keymaster 3 เปลี่ยนจาก C-structure Hardware Abstraction Layer (HAL) แบบเก่าเป็นอินเทอร์เฟซ C++ HAL ที่สร้างจากคำจำกัดความใน Hardware Interface Definition Language (HIDL) ใหม่ ในส่วนของการเปลี่ยนแปลง ประเภทอาร์กิวเมนต์จำนวนมากเปลี่ยนไป แม้ว่าประเภทและเมธอดจะมีความสอดคล้องกันแบบหนึ่งต่อหนึ่งกับประเภทเก่าและเมธอดโครงสร้าง HAL ดูหน้า ฟังก์ชัน สำหรับรายละเอียดเพิ่มเติม
นอกจากการแก้ไขอินเทอร์เฟซนี้แล้ว Android 8.0 ยังขยายคุณสมบัติการรับรองของ Keymaster 2 เพื่อรองรับ การรับรอง ID การรับรอง ID มีกลไกที่จำกัดและเป็นทางเลือกสำหรับการรับรองอย่างเข้มงวดกับตัวระบุฮาร์ดแวร์ เช่น หมายเลขซีเรียลของอุปกรณ์ ชื่อผลิตภัณฑ์ และรหัสโทรศัพท์ (IMEI / MEID) ในการดำเนินการเพิ่มเติมนี้ Android 8.0 ได้เปลี่ยนสคีมาการรับรอง ASN.1 เพื่อเพิ่มการรับรอง ID การใช้งานคีย์มาสเตอร์จำเป็นต้องหาวิธีที่ปลอดภัยในการดึงรายการข้อมูลที่เกี่ยวข้อง ตลอดจนกำหนดกลไกสำหรับการปิดใช้งานคุณลักษณะอย่างปลอดภัยและถาวร
ใน Android 9 การอัปเดตรวมถึง:
- อัปเดตเป็น คีย์มาสเตอร์ 4
- รองรับ Secure Elements แบบฝังตัว
- รองรับการนำเข้าคีย์ที่ปลอดภัย
- รองรับการเข้ารหัส 3DES
- การเปลี่ยนแปลงการรวมเวอร์ชันเพื่อให้ boot.img และ system.img ตั้งค่าเวอร์ชันแยกกันเพื่อให้สามารถอัปเดตแยกกันได้
อภิธานศัพท์
นี่คือภาพรวมโดยย่อของส่วนประกอบ Keystore และความสัมพันธ์
AndroidKeystore คือ Android Framework API และคอมโพเนนต์ที่แอปใช้เพื่อเข้าถึงการทำงานของ Keystore มีการนำมาใช้เป็นส่วนเสริมของ Java Cryptography Architecture APIs มาตรฐาน และประกอบด้วยโค้ด Java ที่ทำงานในพื้นที่กระบวนการของแอปเอง AndroidKeystore
ตอบสนองคำขอของแอพสำหรับพฤติกรรมของ Keystore โดยส่งต่อไปยัง keystore daemon
keystore daemon เป็น daemon ระบบ Android ที่ให้การเข้าถึงฟังก์ชัน Keystore ทั้งหมดผ่าน Binder API มีหน้าที่จัดเก็บ "key blobs" ซึ่งมีเนื้อหาของรหัสลับจริง เข้ารหัสเพื่อให้ Keystore สามารถจัดเก็บได้ แต่ห้ามใช้หรือเปิดเผย
keymasterd เป็นเซิร์ฟเวอร์ HIDL ที่ให้การเข้าถึง Keymaster TA (ชื่อนี้ไม่ได้มาตรฐานและมีวัตถุประสงค์เพื่อเป็นแนวคิด)
Keymaster TA (แอปพลิเคชันที่เชื่อถือได้) เป็นซอฟต์แวร์ที่ทำงานในบริบทที่ปลอดภัย ส่วนใหญ่มักจะอยู่ใน TrustZone บน ARM SoC ซึ่งให้การดำเนินการของ Keystore ที่ปลอดภัยทั้งหมด สามารถเข้าถึงวัตถุดิบของคีย์ ตรวจสอบเงื่อนไขการควบคุมการเข้าถึงทั้งหมดบนคีย์ ฯลฯ
LockSettingsService เป็นส่วนประกอบของระบบ Android ที่มีหน้าที่ตรวจสอบผู้ใช้ ทั้งรหัสผ่านและลายนิ้วมือ ไม่ใช่ส่วนหนึ่งของ Keystore แต่มีความเกี่ยวข้องเนื่องจากการดำเนินการคีย์ของ Keystore จำนวนมากต้องการการรับรองความถูกต้องของผู้ใช้ LockSettingsService
โต้ตอบกับ Gatekeeper TA และ Fingerprint TA เพื่อรับโทเค็นการพิสูจน์ตัวตน ซึ่งมอบให้กับ keystore daemon และสุดท้ายจะถูกใช้โดยแอปพลิเคชัน Keymaster TA
Gatekeeper TA (แอปพลิเคชันที่เชื่อถือได้) เป็นส่วนประกอบอื่นที่ทำงานในบริบทที่ปลอดภัย ซึ่งมีหน้าที่ตรวจสอบรหัสผ่านของผู้ใช้และสร้างโทเค็นการตรวจสอบสิทธิ์ที่ใช้เพื่อพิสูจน์ให้ Keymaster TA เห็นว่าการตรวจสอบสิทธิ์ได้ดำเนินการสำหรับผู้ใช้เฉพาะ ณ เวลาใดเวลาหนึ่ง
Fingerprint TA (แอปพลิเคชันที่เชื่อถือได้) เป็นอีกหนึ่งส่วนประกอบที่ทำงานในบริบทที่ปลอดภัยซึ่งมีหน้าที่ตรวจสอบลายนิ้วมือของผู้ใช้และสร้างโทเค็นการตรวจสอบสิทธิ์ที่ใช้เพื่อพิสูจน์ให้ Keymaster TA เห็นว่าการตรวจสอบสิทธิ์ได้ดำเนินการสำหรับผู้ใช้เฉพาะ ณ เวลาใดเวลาหนึ่ง
สถาปัตยกรรม
Android Keystore API และ Keymaster HAL พื้นฐานมีชุดพื้นฐานของการเข้ารหัสแบบพื้นฐานแต่เพียงพอเพื่อให้ใช้งานโปรโตคอลได้โดยใช้คีย์ที่ควบคุมการเข้าถึงและสำรองด้วยฮาร์ดแวร์
Keymaster HAL เป็นไลบรารีที่โหลดได้แบบไดนามิกที่จัดหาโดย OEM ซึ่งใช้โดยบริการ Keystore เพื่อให้บริการเข้ารหัสลับที่สนับสนุนฮาร์ดแวร์ เพื่อรักษาความปลอดภัย การนำ HAL ไปใช้จะไม่ดำเนินการใดๆ ที่ละเอียดอ่อนในพื้นที่ผู้ใช้ หรือแม้แต่ในพื้นที่เคอร์เนล การดำเนินการที่ละเอียดอ่อนได้รับการมอบหมายให้กับโปรเซสเซอร์ที่ปลอดภัยซึ่งเข้าถึงผ่านอินเทอร์เฟซเคอร์เนลบางตัว สถาปัตยกรรมที่ได้มีลักษณะดังนี้:

รูปที่ 1 การเข้าถึงคีย์มาสเตอร์
ภายในอุปกรณ์ Android "ไคลเอนต์" ของ Keymaster HAL ประกอบด้วยหลายเลเยอร์ (เช่น แอพ, เฟรมเวิร์ก, Keystore daemon) แต่สามารถละเว้นได้สำหรับวัตถุประสงค์ของเอกสารนี้ ซึ่งหมายความว่า Keymaster HAL API ที่อธิบายไว้นั้นเป็นระดับต่ำ ใช้โดยส่วนประกอบภายในแพลตฟอร์ม และไม่เปิดเผยต่อนักพัฒนาแอป API ระดับที่สูงกว่ามีอธิบายไว้ใน ไซต์นักพัฒนาซอฟต์แวร์ Android
จุดประสงค์ของ Keymaster HAL ไม่ใช่การนำอัลกอริทึมที่ไวต่อความปลอดภัยไปใช้ แต่เพียงเพื่อจัดการและยกเลิกการร้องขอไปยังโลกที่ปลอดภัย รูปแบบ Wire ถูกกำหนดโดยการใช้งาน
ความเข้ากันได้กับเวอร์ชันก่อนหน้า
Keymaster 1 HAL ไม่สามารถใช้งานร่วมกับ HAL ที่วางจำหน่ายก่อนหน้านี้ได้อย่างสมบูรณ์ เช่น Keymaster 0.2 และ 0.3 เพื่ออำนวยความสะดวกในการทำงานร่วมกันบนอุปกรณ์ที่ใช้ Android 5.0 และรุ่นก่อนหน้าที่เปิดตัวด้วย Keymaster HAL รุ่นเก่า Keystore จัดเตรียมอแด็ปเตอร์ที่ใช้ Keymaster 1 HAL ด้วยการเรียกไปยังไลบรารีฮาร์ดแวร์ที่มีอยู่ ผลลัพธ์ไม่สามารถให้ฟังก์ชันการทำงานเต็มรูปแบบใน Keymaster 1 HAL โดยเฉพาะอย่างยิ่ง สนับสนุนเฉพาะอัลกอริทึม RSA และ ECDSA และการบังคับใช้การอนุญาตคีย์ทั้งหมดดำเนินการโดยอแด็ปเตอร์ ในโลกที่ไม่ปลอดภัย
Keymaster 2 ทำให้อินเทอร์เฟซ HAL ง่ายขึ้นโดยการลบเมธอด get_supported_*
และอนุญาตให้ finish()
ยอมรับอินพุต ซึ่งช่วยลดจำนวนการเดินทางไป-กลับ TEE ในกรณีที่อินพุตพร้อมใช้งานทั้งหมดในคราวเดียว และทำให้การใช้งานการถอดรหัส AEAD ง่ายขึ้น
ใน Android 8.0, Keymaster 3 ได้เปลี่ยนจากโครงสร้าง C แบบเก่า HAL เป็นอินเทอร์เฟซ C++ HAL ที่สร้างจากคำจำกัดความใน Hardware Interface Definition Language (HIDL) ใหม่ การใช้งาน HAL แบบใหม่นั้นถูกสร้างขึ้นโดยการแบ่งคลาสย่อยของคลาส IKeymasterDevice
ที่สร้างขึ้น และการปรับใช้เมธอดเสมือนล้วน ในส่วนของการเปลี่ยนแปลง ประเภทอาร์กิวเมนต์จำนวนมากมีการเปลี่ยนแปลง แม้ว่าประเภทและเมธอดจะมีความสอดคล้องกันแบบหนึ่งต่อหนึ่งกับประเภทเก่าและเมธอดโครงสร้าง HAL
ภาพรวมของ HIDL
Hardware Interface Definition Language (HIDL) จัดเตรียมกลไกการใช้งานที่ไม่ขึ้นกับภาษาสำหรับการระบุอินเทอร์เฟซฮาร์ดแวร์ ขณะนี้เครื่องมือ HIDL รองรับการสร้างอินเตอร์เฟส C++ และ Java คาดว่าผู้ดำเนินการ Trusted Execution Environment (TEE) ส่วนใหญ่จะพบว่าเครื่องมือ C++ สะดวกกว่า ดังนั้นเอกสารนี้จึงกล่าวถึงเฉพาะการแสดง C++ เท่านั้น
อินเทอร์เฟซ HIDL ประกอบด้วยชุดของวิธีการ ซึ่งแสดงเป็น:
methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);
มีประเภทที่กำหนดไว้ล่วงหน้าหลายประเภท และ HAL สามารถกำหนดประเภทการแจกแจงและโครงสร้างใหม่ได้ สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ HIDL โปรดดู ส่วนข้อมูลอ้างอิง
วิธีการตัวอย่างจาก Keymaster 3 IKeymasterDevice.hal
คือ:
generateKey(vec<KeyParameter> keyParams) generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
นี่เทียบเท่ากับสิ่งต่อไปนี้จาก keymaster2 HAL:
keymaster_error_t (*generate_key)( const struct keymaster2_device* dev, const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics);
ในเวอร์ชัน HIDL อาร์กิวเมนต์ dev
จะถูกลบออก เนื่องจากเป็นนัย อาร์กิวเมนต์ params
ไม่ใช่โครงสร้างที่มีตัวชี้ที่อ้างอิงอาร์เรย์ของ key_parameter_t
อีกต่อไป แต่เป็น vec
(เวกเตอร์) ที่มีออบเจ็กต์ KeyParameter
ค่าที่ส่งคืนจะแสดงอยู่ในส่วนคำสั่ง " generates
" รวมถึงเวกเตอร์ของค่า uint8_t
สำหรับคีย์หยด
วิธีการเสมือน C ++ ที่สร้างขึ้นโดยคอมไพเลอร์ HIDL คือ:
Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams, generateKey_cb _hidl_cb) override;
โดยที่ generateKey_cb
เป็นตัวชี้ฟังก์ชันที่กำหนดเป็น:
std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob, const KeyCharacteristics& keyCharacteristics)>
นั่นคือ generateKey_cb
เป็นฟังก์ชันที่รับค่าส่งคืนที่แสดงอยู่ในส่วนคำสั่ง create คลาสการใช้งาน HAL จะแทนที่เมธอด generateKey
นี้ และเรียกตัวชี้ฟังก์ชัน generateKey_cb
เพื่อส่งคืนผลลัพธ์ของการดำเนินการไปยังผู้เรียก โปรดทราบว่าการเรียกตัวชี้ฟังก์ชันเป็น แบบซิงโครนัส ผู้เรียกเรียก generateKey
และ generateKey
เรียกตัวชี้ฟังก์ชันที่ให้มา ซึ่งดำเนินการจนเสร็จสิ้น ส่งคืนการควบคุมไปยังการใช้งาน generateKey
ซึ่งจะส่งคืนไปยังผู้เรียก
สำหรับตัวอย่างโดยละเอียด โปรดดูการใช้งานเริ่มต้นใน hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp
การใช้งานเริ่มต้นให้ความเข้ากันได้แบบย้อนหลังสำหรับอุปกรณ์ที่มี keymaster0, keymaster1 หรือ keymaster2 HALS แบบเก่า
การควบคุมการเข้าถึง
กฎพื้นฐานที่สุดของการควบคุมการเข้าถึง Keystore คือแต่ละแอปจะมีเนมสเปซของตัวเอง แต่สำหรับทุกกฎมีข้อยกเว้น Keystore มีฮาร์ดโค้ดแม็พที่อนุญาตให้คอมโพเนนต์ระบบบางอย่างเข้าถึงเนมสเปซอื่นได้ นี่เป็นเครื่องมือที่ทื่อมากโดยให้ส่วนประกอบหนึ่งสามารถควบคุมเนมสเปซอื่นได้อย่างเต็มที่ และจากนั้นก็มีเรื่องของส่วนประกอบของผู้ขายในฐานะไคลเอนต์ของ Keystore ขณะนี้เราไม่มีวิธีสร้างเนมสเปซสำหรับส่วนประกอบของผู้ขาย ตัวอย่างเช่น ผู้ร้องขอ WPA
เพื่อรองรับคอมโพเนนต์ของผู้จำหน่ายและควบคุมการเข้าถึงโดยทั่วไปโดยไม่มีข้อยกเว้นแบบตายตัว Keystore 2.0 จึงแนะนำโดเมนและเนมสเปซ SELinux
โดเมนที่เก็บคีย์
ด้วยโดเมน Keystore เราสามารถแยกเนมสเปซออกจาก UID ได้ ไคลเอนต์ที่เข้าถึงคีย์ใน Keystore จะต้องระบุโดเมน เนมสเปซ และนามแฝงที่พวกเขาต้องการเข้าถึง จากทูเพิลนี้และตัวตนของผู้โทร เราสามารถกำหนดได้ว่าคีย์ใดที่ผู้โทรต้องการเข้าถึงและมีสิทธิ์ที่เหมาะสมหรือไม่
เราแนะนำพารามิเตอร์โดเมนห้ารายการซึ่งควบคุมวิธีการเข้าถึงคีย์ พวกเขาควบคุมความหมายของพารามิเตอร์เนมสเปซของตัวอธิบายคีย์และวิธีการควบคุมการเข้าถึง
-
DOMAIN_APP
: โดเมนแอปครอบคลุมลักษณะการทำงานเดิม Java Keystore SPI ใช้โดเมนนี้โดยดีฟอลต์ เมื่อใช้โดเมนนี้ อาร์กิวเมนต์เนมสเปซจะถูกละเว้นและจะใช้ UID ของผู้โทรแทน การเข้าถึงโดเมนนี้ควบคุมโดยป้ายกำกับ Keystore ไปยังคลาสkeystore_key
ในนโยบาย SELinux -
DOMAIN_SELINUX
: โดเมนนี้ระบุว่าเนมสเปซมีป้ายกำกับในนโยบาย SELinux พารามิเตอร์เนมสเปซถูกค้นหาและแปลเป็นบริบทเป้าหมาย และดำเนินการตรวจสอบสิทธิ์สำหรับการเรียกใช้บริบท SELinux สำหรับคลาสkeystore_key
เมื่อมีการกำหนดสิทธิ์สำหรับการดำเนินการที่กำหนด ทูเพิลแบบเต็มจะถูกใช้สำหรับการค้นหาคีย์ -
DOMAIN_GRANT
: โดเมนให้ระบุว่าพารามิเตอร์เนมสเปซเป็นตัวระบุการให้สิทธิ์ The alias parameter is ignored. SELinux checks are performed when the grant is created. Further access control only checks if the caller UID matches the grantees UID of the requested grant. -
DOMAIN_KEY_ID
: This domain indicates that the namespace parameter is a unique key id. The key itself may have been created withDOMAIN_APP
orDOMAIN_SELINUX
. The permission check is performed after thedomain
and thenamespace
have been loaded from the key database in the same way as if the blob was loaded by the domain, namespace, and alias tuple. The rationale for the key id domain is continuity. When accessing a key by alias, subsequent calls may operate on different keys, because a new key may have been generated or imported and bound to this alias. The key id, however, never changes. So when using a key by key id after it has been loaded from the Keystore database using the alias once, one can be certain that it is the same key as long as the key id still exists. This functionality is not exposed to app developers. Instead, it is used within the Android Keystore SPI to provide a more consistent experience even when used concurrently in an unsafe way. -
DOMAIN_BLOB
: The blob domain indicates that the caller manages the blob by itself. This is used for clients that need to access the Keystore before the data partition is mounted. The key blob is included in theblob
field of the key descriptor.
Using the SELinux domain, we can give vendor components access to very specific Keystore namespaces which can be shared by system components such as the settings dialog.
SELinux policy for keystore_key
Namespace labels are configured using the keystore2_key_context
file.
Each line in these files maps a numeric namespace id to an SELinux label. For example,
# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and # Settings to share keystore keys. 102 u:object_r:wifi_key:s0
After having set up a new key namespace in this way, we can give access to it by adding an appropriate policy. For example, to allow wpa_supplicant
to get and use keys in the new namespace we would add the following line to hal_wifi_supplicant.te
:
allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };
After setting up the new namespace, AndroidKeyStore can be used almost as usual. The only difference is that the namespace ID must be specified. For loading and importing keys from and into Keystore, the namespace id is specified using the AndroidKeyStoreLoadStoreParameter
. For example,
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; import java.security.KeyStore; KeyStore keystore = KeyStore.getInstance("AndroidKeyStore"); keystore.load(new AndroidKeyStoreLoadStoreParameter(102));
To generate a key in a given namespace, the namespace id must be given using KeyGenParameterSpec.Builder#setNamespace():
import android.security.keystore.KeyGenParameterSpec; KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(); specBuilder.setNamespace(102);
The following context files may be used to configure Keystore 2.0 SELinux namespaces. Each partition has a different reserved range of 10,000 namespace ids to avoid collisions.
Partition | Range | Config files |
---|---|---|
System | 0 ... 9,999 | /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts |
Extended System | 10,000 ... 19,999 | /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts |
Product | 20,000 ... 29,999 | /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts |
Vendor | 30,000 ... 39,999 | /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts |
The client requests the key by requesting the SELinux domain and the desired virtual namespace, in this case "wifi_key"
, by its numeric id.
Above that, the following namespaces have been defined. If they replace special rules, the following table indicates the UID they used to correspond to.
Namespace ID | SEPolicy Label | UID | คำอธิบาย |
---|---|---|---|
0 | su_key | N/A | Super user key. Only used for testing on userdebug and eng builds. Not relevant on user builds. |
1 | shell_key | N/A | Namespace available to shell. Mostly used for testing, but can be used on user builds as well from the command line. |
100 | vold_key | N/A | Intended for use by vold. |
101 | odsing_key | N/A | Used by the on-device signing daemon. |
102 | wifi_key | AID_WIFI(1010) | Used by Android's Wifi sybsystem including wpa_supplicant. |
120 | resume_on_reboot_key | AID_SYSTEM(1000) | Used by Android's system server to support resume on reboot. |
Access Vectors
The SELinux class keystore_key
has aged quite a bit and some of the permissions, such as verify
or sign
have lost their meaning. Here is the new set of permissions, keystore2_key
, that Keystore 2.0 will enforce.
การอนุญาต | Meaning |
---|---|
delete | Checked when removing keys from Keystore. |
get_info | Checked when a key's metadata is requested. |
grant | The caller needs this permission to create a grant to the key in the target context. |
manage_blob | The caller may use DOMAIN_BLOB on the given SELinux namespace, thereby managing blobs by itself. This is specifically useful for vold. |
rebind | This permission controls if an alias may be rebound to a new key. This is required for insertion and implies that the previously bound key will be deleted. It is basically an insert permission, but it captures the semantic of keystore better. |
req_forced_op | Clients with this permission may create unpruneable operations, and operation creation never fails unless all operation slots are taken by unpruneable operations. |
update | Required to update the subcomponent of a key. |
use | Checked when creating a Keymint operation that uses the key material, eg, for signing, en/decryption. |
use_dev_id | Required when generating device identifying information, such as device id attestation. |
Additionally, we split out a set of non key specific keystore permissions in the SELinux security class keystore2
:
การอนุญาต | Meaning |
---|---|
add_auth | Required by authentication provider such as Gatekeeper or BiometricsManager for adding auth tokens. |
clear_ns | Formerly clear_uid, this permission allows a non owner of a namespace to delete all keys in that namespace. |
list | Required by the system for enumerating keys by various properties, such as ownership or auth boundedness. This permission is not required by callers enumerating their own namespaces. This is covered by the get_info permission. |
lock | This permission allows to lock Keystore, that is, evict the master key, such that auth bound keys become unusable and uncreatable. |
reset | This permission allows to reset Keystore to factory default, deleting all keys that are not vital to the functioning of the Android OS. |
unlock | This permission is required to attempt to unlock the master key for auth bound keys. |