ความพร้อมใช้งานของสภาพแวดล้อมการดำเนินการที่เชื่อถือได้ในระบบบนชิป (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 และระบบควบคุมการเข้าถึงสำหรับคีย์ที่สนับสนุนด้วยฮาร์ดแวร์ การควบคุมการเข้าถึงจะถูกระบุในระหว่างการสร้างคีย์และบังคับใช้ตลอดอายุการใช้งานของคีย์ สามารถจำกัดคีย์ให้ใช้งานได้หลังจากที่ผู้ใช้ได้รับการรับรองความถูกต้องแล้วเท่านั้น และสำหรับวัตถุประสงค์ที่ระบุหรือด้วยพารามิเตอร์การเข้ารหัสที่ระบุเท่านั้น สำหรับข้อมูลเพิ่มเติม โปรดดูหน้า แท็กการอนุญาต และ ฟังก์ชัน
นอกเหนือจากการขยายช่วงของการเข้ารหัสแบบดั้งเดิมแล้ว Keystore ใน Android 6.0 ยังเพิ่มสิ่งต่อไปนี้:
- รูปแบบการควบคุมการใช้งานเพื่อให้จำกัดการใช้งานคีย์ เพื่อลดความเสี่ยงของการประนีประนอมด้านความปลอดภัยเนื่องจากการใช้คีย์ในทางที่ผิด
- รูปแบบการควบคุมการเข้าถึงเพื่อเปิดใช้การจำกัดคีย์สำหรับผู้ใช้ ไคลเอ็นต์ และช่วงเวลาที่กำหนด
ใน Android 7.0 นั้น Keymaster 2 ได้เพิ่มการรองรับสำหรับการรับรองคีย์และการเชื่อมโยงเวอร์ชัน การรับรองคีย์ จะมอบใบรับรองคีย์สาธารณะที่มีคำอธิบายโดยละเอียดของคีย์และการควบคุมการเข้าถึง เพื่อให้คีย์นั้นมีอยู่ในฮาร์ดแวร์ที่ปลอดภัยและการกำหนดค่าของคีย์นั้นสามารถตรวจสอบได้จากระยะไกล
การเชื่อมโยงเวอร์ชัน จะผูกคีย์กับระบบปฏิบัติการและเวอร์ชันระดับแพตช์ สิ่งนี้ทำให้แน่ใจได้ว่าผู้โจมตีที่ค้นพบจุดอ่อนในระบบเวอร์ชันเก่าหรือซอฟต์แวร์ TEE จะไม่สามารถย้อนกลับอุปกรณ์กลับไปเป็นเวอร์ชันที่มีช่องโหว่และใช้คีย์ที่สร้างด้วยเวอร์ชันที่ใหม่กว่าได้ นอกจากนี้ เมื่อใช้คีย์ที่มีเวอร์ชันและระดับแพตช์ที่กำหนดบนอุปกรณ์ที่ได้รับการอัปเกรดเป็นเวอร์ชันใหม่หรือระดับแพตช์ คีย์จะได้รับการอัปเกรดก่อนจึงจะสามารถใช้งานได้ และคีย์เวอร์ชันก่อนหน้าจะใช้งานไม่ได้ เมื่ออุปกรณ์ได้รับการอัปเกรด ปุ่มจะ "วงล้อ" ไปข้างหน้าพร้อมกับอุปกรณ์ แต่การพลิกกลับของอุปกรณ์ไปเป็นรุ่นก่อนหน้าจะทำให้ปุ่มใช้งานไม่ได้
ใน Android 8.0 Keymaster 3 ได้เปลี่ยนจาก Hardware Abstraction Layer (HAL) โครงสร้าง C แบบเก่าไปเป็นอินเทอร์เฟซ C++ HAL ที่สร้างจากคำจำกัดความใน Hardware Interface Definition Language (HIDL) ใหม่ ส่วนหนึ่งของการเปลี่ยนแปลงนี้ ประเภทอาร์กิวเมนต์หลายประเภทมีการเปลี่ยนแปลง แม้ว่าประเภทและวิธีการจะมีการโต้ตอบแบบหนึ่งต่อหนึ่งกับประเภทเก่าและวิธีการสร้าง HAL ดูหน้า ฟังก์ชั่น สำหรับรายละเอียดเพิ่มเติม
นอกเหนือจากการแก้ไขอินเทอร์เฟซนี้แล้ว Android 8.0 ยังขยายคุณสมบัติการรับรองของ Keymaster 2 เพื่อรองรับ การรับรอง ID การรับรองรหัสมีกลไกทางเลือกที่จำกัดและเป็นทางเลือกสำหรับการรับรองตัวระบุฮาร์ดแวร์ เช่น หมายเลขซีเรียลของอุปกรณ์ ชื่อผลิตภัณฑ์ และรหัสโทรศัพท์ (IMEI / MEID) เพื่อดำเนินการเพิ่มเติมนี้ Android 8.0 ได้เปลี่ยนสคีมาการรับรอง ASN.1 เพื่อเพิ่มการรับรองรหัส การใช้งานคีย์มาสเตอร์จำเป็นต้องค้นหาวิธีที่ปลอดภัยในการเรียกข้อมูลรายการข้อมูลที่เกี่ยวข้อง ตลอดจนกำหนดกลไกในการปิดใช้งานคุณลักษณะนี้อย่างปลอดภัยและถาวร
ใน Android 9 มีการอัปเดตดังนี้:
- อัปเดตเป็น คีย์มาสเตอร์ 4
- รองรับองค์ประกอบความปลอดภัยแบบฝัง
- รองรับการนำเข้าคีย์ที่ปลอดภัย
- รองรับการเข้ารหัส 3DES
- การเปลี่ยนแปลงการเชื่อมโยงเวอร์ชันเพื่อให้ boot.img และ system.img มีเวอร์ชันที่ตั้งค่าแยกกันเพื่อให้สามารถอัปเดตได้อย่างอิสระ
อภิธานศัพท์
นี่คือภาพรวมโดยย่อของส่วนประกอบ Keystore และความสัมพันธ์
AndroidKeystore คือ Android Framework API และส่วนประกอบที่แอปใช้เพื่อเข้าถึงฟังก์ชันการทำงานของ Keystore ได้รับการปรับใช้เป็นส่วนขยายของ Java Cryptography Architecture API มาตรฐาน และประกอบด้วยโค้ด 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 และ TA ลายนิ้วมือเพื่อรับโทเค็นการตรวจสอบสิทธิ์ ซึ่งโทเค็นจะมอบให้กับที่เก็บคีย์ daemon และท้ายที่สุดจะถูกใช้โดยแอปพลิเคชัน Keymaster TA
Gatekeeper TA (แอปพลิเคชันที่เชื่อถือได้) เป็นอีกองค์ประกอบหนึ่งที่ทำงานในบริบทที่ปลอดภัย ซึ่งรับผิดชอบในการตรวจสอบรหัสผ่านของผู้ใช้และสร้างโทเค็นการตรวจสอบสิทธิ์ที่ใช้ในการพิสูจน์ต่อ Keymaster TA ว่าการตรวจสอบสิทธิ์ได้กระทำสำหรับผู้ใช้รายใดรายหนึ่ง ณ จุดใดจุดหนึ่งในเวลาใดเวลาหนึ่ง
ลายนิ้วมือ TA (แอปพลิเคชันที่เชื่อถือได้) เป็นอีกองค์ประกอบหนึ่งที่ทำงานในบริบทที่ปลอดภัย ซึ่งรับผิดชอบในการตรวจสอบลายนิ้วมือของผู้ใช้ และสร้างโทเค็นการตรวจสอบสิทธิ์ที่ใช้ในการพิสูจน์ต่อ Keymaster TA ว่าการตรวจสอบสิทธิ์ได้กระทำสำหรับผู้ใช้รายใดรายหนึ่ง ณ จุดใดจุดหนึ่งในเวลาใดเวลาหนึ่ง
สถาปัตยกรรม
Android Keystore API และ Keymaster HAL พื้นฐานจัดเตรียมชุดพื้นฐานการเข้ารหัสลับที่เพียงพอเพื่อให้สามารถใช้งานโปรโตคอลโดยใช้คีย์ที่ควบคุมการเข้าถึงและสนับสนุนด้วยฮาร์ดแวร์
Keymaster HAL เป็นไลบรารีที่โหลดได้แบบไดนามิกที่จัดทำโดย OEM ซึ่งใช้โดยบริการ Keystore เพื่อให้บริการการเข้ารหัสลับที่สนับสนุนด้วยฮาร์ดแวร์ เพื่อให้สิ่งต่างๆ ปลอดภัย การใช้งาน HAL จะไม่ดำเนินการใดๆ ที่ละเอียดอ่อนในพื้นที่ผู้ใช้ หรือแม้แต่ในพื้นที่เคอร์เนล การดำเนินการที่ละเอียดอ่อนได้รับการมอบหมายให้กับโปรเซสเซอร์ที่ปลอดภัยที่เข้าถึงได้ผ่านอินเทอร์เฟซเคอร์เนลบางตัว สถาปัตยกรรมที่ได้จะมีลักษณะดังนี้:
ภายในอุปกรณ์ Android "ไคลเอนต์" ของ Keymaster HAL ประกอบด้วยหลายเลเยอร์ (เช่น แอป เฟรมเวิร์ก Keystore daemon) แต่สามารถละเว้นได้เพื่อวัตถุประสงค์ของเอกสารนี้ ซึ่งหมายความว่า Keymaster HAL API ที่อธิบายไว้นั้นเป็นระดับต่ำ ใช้งานโดยส่วนประกอบภายในแพลตฟอร์ม และไม่เปิดเผยต่อนักพัฒนาแอป API ระดับสูงกว่ามีการอธิบายไว้ใน ไซต์นักพัฒนาซอฟต์แวร์ Android
วัตถุประสงค์ของ Keymaster HAL ไม่ใช่เพื่อใช้อัลกอริธึมที่คำนึงถึงความปลอดภัย แต่เพียงเพื่อส่งคำขอแบบ marshal และ unmarshal ไปยังโลกที่ปลอดภัยเท่านั้น รูปแบบการโยงถูกกำหนดโดยการใช้งาน
ความเข้ากันได้กับเวอร์ชันก่อนหน้า
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 เปลี่ยนจาก HAL โครงสร้าง C แบบเก่าไปเป็นอินเทอร์เฟซ 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
เป็นฟังก์ชันที่รับค่าส่งคืนที่แสดงอยู่ในส่วนคำสั่ง Generate คลาสการใช้งาน 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
: โดเมนการให้สิทธิ์ระบุว่าพารามิเตอร์เนมสเปซเป็นตัวระบุการให้สิทธิ์ พารามิเตอร์นามแฝงจะถูกละเว้น การตรวจสอบ SELinux จะดำเนินการเมื่อมีการสร้างสิทธิ์ การควบคุมการเข้าถึงเพิ่มเติมจะตรวจสอบว่า UID ของผู้โทรตรงกับ UID ของผู้รับสิทธิ์ของการอนุญาตที่ร้องขอเท่านั้น -
DOMAIN_KEY_ID
: โดเมนนี้ระบุว่าพารามิเตอร์เนมสเปซเป็นรหัสคีย์เฉพาะ ตัวคีย์อาจถูกสร้างขึ้นด้วยDOMAIN_APP
หรือDOMAIN_SELINUX
การตรวจสอบสิทธิ์จะดำเนินการหลังจากdomain
และnamespace
ถูกโหลดจากฐานข้อมูลคีย์ในลักษณะเดียวกับที่ blob ถูกโหลดโดยโดเมน เนมสเปซ และทูเพิลนามแฝง เหตุผลสำหรับโดเมนรหัสคีย์คือความต่อเนื่อง เมื่อเข้าถึงคีย์ด้วยนามแฝง การเรียกครั้งต่อ ๆ ไปอาจดำเนินการกับคีย์ที่แตกต่างกัน เนื่องจากอาจมีการสร้างหรือนำเข้าคีย์ใหม่ และเชื่อมโยงกับนามแฝงนี้ อย่างไรก็ตาม รหัสคีย์ไม่เคยเปลี่ยนแปลง ดังนั้นเมื่อใช้คีย์ด้วยรหัสคีย์หลังจากที่โหลดจากฐานข้อมูล Keystore โดยใช้นามแฝงหนึ่งครั้งแล้ว เราจึงมั่นใจได้ว่าจะเป็นคีย์เดียวกันตราบใดที่รหัสคีย์ยังคงมีอยู่ นักพัฒนาแอปไม่ได้เปิดเผยฟังก์ชันการทำงานนี้ แต่จะใช้ภายใน Android Keystore SPI เพื่อมอบประสบการณ์ที่สอดคล้องกันมากขึ้น แม้ว่าจะใช้งานพร้อมกันในลักษณะที่ไม่ปลอดภัยก็ตาม -
DOMAIN_BLOB
: โดเมน blob บ่งชี้ว่าผู้โทรจัดการ blob ด้วยตัวเอง ใช้สำหรับไคลเอ็นต์ที่ต้องการเข้าถึง Keystore ก่อนติดตั้งพาร์ติชันข้อมูล Blob คีย์จะรวมอยู่ในฟิลด์blob
ของตัวอธิบายคีย์
การใช้โดเมน SELinux ทำให้เราสามารถให้ส่วนประกอบของผู้ขายเข้าถึงเนมสเปซ Keystore ที่เฉพาะเจาะจงมาก ซึ่งสามารถแชร์โดยส่วนประกอบของระบบ เช่น กล่องโต้ตอบการตั้งค่า
นโยบาย SELinux สำหรับ keystore_key
เลเบลเนมสเปซถูกกำหนดค่าโดยใช้ไฟล์ keystore2_key_context
แต่ละบรรทัดในไฟล์เหล่านี้จะจับคู่รหัสเนมสเปซที่เป็นตัวเลขกับป้ายกำกับ 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));
หากต้องการสร้างคีย์ในเนมสเปซที่กำหนด จะต้องกำหนดรหัสเนมสเปซโดยใช้ KeyGenParameterSpec.Builder#setNamespace():
import android.security.keystore.KeyGenParameterSpec; KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(); specBuilder.setNamespace(102);
ไฟล์บริบทต่อไปนี้อาจใช้เพื่อกำหนดค่าเนมสเปซ Keystore 2.0 SELinux แต่ละพาร์ติชันมีช่วงที่สงวนไว้ 10,000 รหัสเนมสเปซที่แตกต่างกันเพื่อหลีกเลี่ยงการชนกัน
ฉากกั้นห้อง | พิสัย | กำหนดค่าไฟล์ |
---|---|---|
ระบบ | 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 | UID | คำอธิบาย |
---|---|---|---|
0 | ซู_คีย์ | ไม่มี | รหัสผู้ใช้ขั้นสูง ใช้สำหรับการทดสอบกับ userdebug และ eng builds เท่านั้น ไม่เกี่ยวข้องกับบิลด์ผู้ใช้ |
1 | เชลล์_คีย์ | ไม่มี | เนมสเปซพร้อมใช้งานสำหรับเชลล์ ส่วนใหญ่ใช้สำหรับการทดสอบ แต่สามารถใช้กับบิลด์ผู้ใช้ได้เช่นกันจากบรรทัดคำสั่ง |
100 | vold_key | ไม่มี | มีไว้สำหรับการใช้งานโดย volold |
101 | odsing_key | ไม่มี | ใช้โดย daemon การลงนามบนอุปกรณ์ |
102 | wifi_key | AID_WIFI (1010) | ใช้โดยระบบ Wifi ของ Android รวมถึง wpa_supplicant |
120 | resume_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 ที่กำหนด ดังนั้นจึงจัดการ Blob ได้ด้วยตัวเอง สิ่งนี้มีประโยชน์โดยเฉพาะสำหรับ vold |
rebind | การอนุญาตนี้จะควบคุมว่านามแฝงอาจถูกเชื่อมโยงกับคีย์ใหม่หรือไม่ สิ่งนี้จำเป็นสำหรับการแทรกและบอกเป็นนัยว่าคีย์ที่ผูกไว้ก่อนหน้านี้จะถูกลบ โดยพื้นฐานแล้วเป็นการอนุญาตการแทรก แต่จะจับความหมายของที่เก็บคีย์ได้ดีกว่า |
req_forced_op | ไคลเอนต์ที่มีสิทธิ์นี้อาจสร้างการดำเนินการที่ไม่สามารถตัดออกได้ และการสร้างการดำเนินการจะไม่ล้มเหลว เว้นแต่ช่องการดำเนินการทั้งหมดจะถูกยึดโดยการดำเนินการที่ไม่สามารถตัดทอนได้ |
update | จำเป็นต้องอัปเดตองค์ประกอบย่อยของคีย์ |
use | ตรวจสอบเมื่อสร้างการดำเนินการ Keymint ที่ใช้เนื้อหาหลัก เช่น สำหรับการลงนาม en/ถอดรหัส |
use_dev_id | จำเป็นเมื่อสร้างข้อมูลระบุอุปกรณ์ เช่น การรับรองรหัสอุปกรณ์ |
นอกจากนี้ เรายังแยกชุดสิทธิ์ของที่เก็บคีย์เฉพาะที่ไม่ใช่คีย์ในคลาสความปลอดภัย SELinux keystore2
:
การอนุญาต | ความหมาย |
---|---|
add_auth | จำเป็นโดยผู้ให้บริการการรับรองความถูกต้อง เช่น Gatekeeper หรือ BiometricsManager สำหรับการเพิ่มโทเค็นการรับรองความถูกต้อง |
clear_ns | ก่อนหน้านี้ clear_uid การอนุญาตนี้อนุญาตให้ผู้ที่ไม่ใช่เจ้าของเนมสเปซสามารถลบคีย์ทั้งหมดในเนมสเปซนั้นได้ |
list | จำเป็นโดยระบบสำหรับการแจงนับคีย์ตามคุณสมบัติต่างๆ เช่น ความเป็นเจ้าของหรือขอบเขตการรับรองความถูกต้อง การอนุญาตนี้ไม่จำเป็นสำหรับผู้โทรเพื่อระบุเนมสเปซของตนเอง สิ่งนี้ครอบคลุมโดยสิทธิ์ get_info |
lock | การอนุญาตนี้อนุญาตให้ล็อก Keystore กล่าวคือ ยกเลิกคีย์หลัก ซึ่งจะทำให้คีย์ที่ผูกกับการรับรองความถูกต้องใช้งานไม่ได้และไม่สามารถสร้างได้ |
reset | การอนุญาตนี้อนุญาตให้รีเซ็ต Keystore เป็นค่าเริ่มต้นจากโรงงาน โดยจะลบคีย์ทั้งหมดที่ไม่สำคัญต่อการทำงานของระบบปฏิบัติการ Android |
unlock | การอนุญาตนี้จำเป็นสำหรับการพยายามปลดล็อกคีย์หลักสำหรับคีย์ที่ผูกกับการตรวจสอบสิทธิ์ |