ที่เก็บคีย์ที่ได้รับการสนับสนุนจากฮาร์ดแวร์

ความพร้อมใช้งานของสภาพแวดล้อมการดำเนินการที่เชื่อถือได้ในระบบบนชิป (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 with DOMAIN_APP or DOMAIN_SELINUX . The permission check is performed after the domain and the namespace 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 the blob 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.