Kho khóa được hỗ trợ bởi phần cứng

Tính khả dụng của môi trường thực thi đáng tin cậy trong hệ thống trên chip (SoC) mang đến cơ hội cho các thiết bị Android cung cấp các dịch vụ bảo mật mạnh mẽ, được phần cứng hỗ trợ cho HĐH Android, cho các dịch vụ nền tảng và thậm chí cho các ứng dụng của bên thứ ba. Các nhà phát triển đang tìm kiếm tiện ích mở rộng dành riêng cho Android nên truy cập android.security.keystore .

Trước Android 6.0, Android đã có API dịch vụ tiền điện tử đơn giản, được phần cứng hỗ trợ, được cung cấp bởi các phiên bản 0.2 và 0.3 của Lớp trừu tượng phần cứng Keymaster (HAL). Kho khóa cung cấp các hoạt động xác minh và ký kỹ thuật số, cộng với việc tạo và nhập các cặp khóa ký bất đối xứng. Điều này đã được triển khai trên nhiều thiết bị, nhưng có nhiều mục tiêu bảo mật không thể dễ dàng đạt được chỉ với một API chữ ký. Keystore trong Android 6.0 đã mở rộng Keystore API để cung cấp nhiều khả năng hơn.

Trong Android 6.0, Keystore đã thêm các nguyên hàm mật mã đối xứng , AES và HMAC cũng như hệ thống kiểm soát truy cập cho các khóa được phần cứng hỗ trợ. Kiểm soát truy cập được chỉ định trong quá trình tạo khóa và được thực thi trong suốt thời gian tồn tại của khóa. Các khóa có thể bị hạn chế chỉ sử dụng được sau khi người dùng đã được xác thực và chỉ dành cho các mục đích cụ thể hoặc với các tham số mật mã cụ thể. Để biết thêm thông tin, hãy xem các trang Chức năngThẻ ủy quyền .

Ngoài việc mở rộng phạm vi nguyên thủy mật mã, Keystore trong Android 6.0 đã thêm vào như sau:

  • Sơ đồ kiểm soát sử dụng cho phép hạn chế sử dụng khóa, để giảm thiểu rủi ro xâm phạm bảo mật do sử dụng sai khóa
  • Sơ đồ kiểm soát truy cập để cho phép hạn chế khóa đối với người dùng, ứng dụng khách được chỉ định và phạm vi thời gian xác định

Trong Android 7.0, Keymaster 2 đã thêm hỗ trợ cho chứng thực khóa và ràng buộc phiên bản. Chứng thực khóa cung cấp chứng chỉ khóa công khai có chứa mô tả chi tiết về khóa và các biện pháp kiểm soát quyền truy cập của khóa, để làm cho sự tồn tại của khóa trong phần cứng bảo mật và cấu hình của khóa có thể xác minh từ xa.

Liên kết phiên bản liên kết các khóa với hệ điều hành và phiên bản cấp bản vá. Điều này đảm bảo rằng kẻ tấn công phát hiện ra điểm yếu trong phiên bản cũ của hệ thống hoặc phần mềm TEE không thể khôi phục thiết bị về phiên bản dễ bị tấn công và sử dụng các khóa được tạo bằng phiên bản mới hơn. Ngoài ra, khi một khóa có phiên bản và cấp bản vá nhất định được sử dụng trên thiết bị đã được nâng cấp lên phiên bản hoặc cấp bản vá mới hơn, thì khóa đó sẽ được nâng cấp trước khi có thể sử dụng và phiên bản trước đó của khóa sẽ bị vô hiệu. Khi thiết bị được nâng cấp, các phím sẽ "gắn" về phía trước cùng với thiết bị, nhưng bất kỳ sự thay đổi nào của thiết bị về bản phát hành trước đó đều khiến các phím không sử dụng được.

Trong Android 8.0, Keymaster 3 đã chuyển đổi từ Lớp trừu tượng phần cứng cấu trúc C (HAL) kiểu cũ sang giao diện C++ HAL được tạo từ một định nghĩa trong Ngôn ngữ định nghĩa giao diện phần cứng (HIDL) mới. Là một phần của thay đổi, nhiều loại đối số đã thay đổi, mặc dù các loại và phương thức có sự tương ứng một đối một với các loại cũ và các phương thức cấu trúc HAL. Xem trang Chức năng để biết thêm chi tiết.

Ngoài bản sửa đổi giao diện này, Android 8.0 đã mở rộng tính năng chứng thực của Keymaster 2 để hỗ trợ chứng thực ID . Chứng thực ID cung cấp một cơ chế tùy chọn và có giới hạn để chứng thực mạnh mẽ các số nhận dạng phần cứng, chẳng hạn như số sê-ri thiết bị, tên sản phẩm và ID điện thoại (IMEI / MEID). Để triển khai phần bổ sung này, Android 8.0 đã thay đổi lược đồ chứng thực ASN.1 để thêm chứng thực ID. Việc triển khai Keymaster cần tìm một số cách an toàn để truy xuất các mục dữ liệu có liên quan, cũng như xác định cơ chế để vô hiệu hóa tính năng này một cách an toàn và vĩnh viễn.

Trong Android 9, các bản cập nhật bao gồm:

  • Cập nhật lên Keymaster 4
  • Hỗ trợ cho các yếu tố bảo mật được nhúng
  • Hỗ trợ nhập khóa an toàn
  • Hỗ trợ mã hóa 3DES
  • Thay đổi liên kết phiên bản để boot.img và system.img có các phiên bản được đặt riêng để cho phép cập nhật độc lập

Bảng chú giải

Dưới đây là tổng quan nhanh về các thành phần Keystore và mối quan hệ của chúng.

AndroidKeystore là API và thành phần Android Framework được các ứng dụng sử dụng để truy cập chức năng Keystore. Nó được triển khai như một phần mở rộng cho API Kiến trúc mã hóa Java tiêu chuẩn và bao gồm mã Java chạy trong không gian quy trình riêng của ứng dụng. AndroidKeystore đáp ứng các yêu cầu của ứng dụng đối với hành vi của Kho khóa bằng cách chuyển tiếp chúng đến daemon kho khóa.

Trình nền kho khóa là một trình nền hệ thống Android cung cấp quyền truy cập vào tất cả chức năng của Kho khóa thông qua API Binder . Nó chịu trách nhiệm lưu trữ "các đốm màu chính", chứa tài liệu khóa bí mật thực tế, được mã hóa để Keystore có thể lưu trữ nhưng không sử dụng hoặc tiết lộ chúng.

keymasterd là một máy chủ HIDL cung cấp quyền truy cập vào Keymaster TA. (Tên này không được tiêu chuẩn hóa và dành cho mục đích khái niệm.)

Keymaster TA (ứng dụng đáng tin cậy) là phần mềm chạy trong ngữ cảnh an toàn, thường là trong TrustZone trên SoC ARM, cung cấp tất cả các hoạt động của Kho khóa an toàn, có quyền truy cập vào nguyên liệu khóa, xác thực tất cả các điều kiện kiểm soát truy cập trên khóa , vân vân.

LockSettingsService là thành phần hệ thống Android chịu trách nhiệm xác thực người dùng, cả mật khẩu và dấu vân tay. Nó không phải là một phần của Kho khóa, nhưng có liên quan vì nhiều thao tác với khóa của Kho khóa yêu cầu xác thực người dùng. LockSettingsService tương tác với TA của Gatekeeper và TA của Fingerprint để lấy mã thông báo xác thực mà nó cung cấp cho daemon kho khóa và cuối cùng sẽ được ứng dụng Keymaster TA sử dụng.

Gatekeeper TA (ứng dụng đáng tin cậy) là một thành phần khác chạy trong ngữ cảnh bảo mật, chịu trách nhiệm xác thực mật khẩu người dùng và tạo mã thông báo xác thực được sử dụng để chứng minh với Keymaster TA rằng xác thực đã được thực hiện cho một người dùng cụ thể tại một thời điểm cụ thể.

TA vân tay (ứng dụng đáng tin cậy) là một thành phần khác chạy trong ngữ cảnh bảo mật chịu trách nhiệm xác thực dấu vân tay của người dùng và tạo mã thông báo xác thực được sử dụng để chứng minh với Keymaster TA rằng xác thực đã được thực hiện cho một người dùng cụ thể tại một thời điểm cụ thể.

Ngành kiến ​​​​trúc

Android Keystore API và Keymaster HAL cơ bản cung cấp một bộ nguyên hàm mật mã cơ bản nhưng đầy đủ để cho phép triển khai các giao thức bằng cách sử dụng các khóa được phần cứng hỗ trợ, kiểm soát truy cập.

Keymaster HAL là một thư viện có thể tải động, do OEM cung cấp, được sử dụng bởi dịch vụ Keystore để cung cấp các dịch vụ mã hóa dựa trên phần cứng. Để giữ mọi thứ an toàn, việc triển khai HAL không thực hiện bất kỳ thao tác nhạy cảm nào trong không gian người dùng hoặc thậm chí trong không gian nhân. Các hoạt động nhạy cảm được ủy quyền cho một bộ xử lý an toàn đạt được thông qua một số giao diện hạt nhân. Kiến trúc kết quả trông như thế này:

Truy cập Keymaster

Hình 1. Truy cập vào Keymaster

Trong một thiết bị Android, "máy khách" của Keymaster HAL bao gồm nhiều lớp (ví dụ: ứng dụng, khung, trình nền Keystore), nhưng điều đó có thể bị bỏ qua vì mục đích của tài liệu này. Điều này có nghĩa là API Keymaster HAL được mô tả ở cấp độ thấp, được sử dụng bởi các thành phần bên trong nền tảng và không được hiển thị cho các nhà phát triển ứng dụng. API cấp cao hơn được mô tả trên trang web dành cho Nhà phát triển Android .

Mục đích của Keymaster HAL không phải là triển khai các thuật toán nhạy cảm về bảo mật mà chỉ để sắp xếp các yêu cầu theo thứ tự và không theo thứ tự đối với thế giới an toàn. Định dạng dây được xác định theo triển khai.

Khả năng tương thích với các phiên bản trước

Keymaster 1 HAL hoàn toàn không tương thích với các HAL đã phát hành trước đó, ví dụ Keymaster 0.2 và 0.3. Để hỗ trợ khả năng tương tác trên các thiết bị chạy Android 5.0 trở về trước đã ra mắt với Keymaster HAL cũ hơn, Keystore cung cấp bộ điều hợp triển khai Keymaster 1 HAL với các lệnh gọi đến thư viện phần cứng hiện có. Kết quả là không thể cung cấp đầy đủ các chức năng trong Keymaster 1 HAL. Cụ thể, nó chỉ hỗ trợ các thuật toán RSA và ECDSA và tất cả việc thực thi ủy quyền khóa được thực hiện bởi bộ điều hợp, trong thế giới không an toàn.

Keymaster 2 đơn giản hóa hơn nữa giao diện HAL bằng cách loại bỏ các phương thức get_supported_* và cho phép phương thức finish() chấp nhận đầu vào. Điều này làm giảm số lần đi vòng tới TEE trong trường hợp đầu vào có sẵn cùng một lúc và đơn giản hóa việc thực hiện giải mã AEAD.

Trong Android 8.0, Keymaster 3 đã chuyển từ cấu trúc C kiểu cũ HAL sang giao diện C++ HAL được tạo từ một định nghĩa trong Ngôn ngữ định nghĩa giao diện phần cứng (HIDL) mới. Việc triển khai HAL kiểu mới được tạo bằng cách phân lớp con lớp IKeymasterDevice đã tạo và triển khai các phương thức ảo thuần túy. Là một phần của thay đổi, nhiều loại đối số đã thay đổi, mặc dù các loại và phương thức có sự tương ứng một đối một với các loại cũ và các phương thức cấu trúc HAL.

Tổng quan về HIDL

Ngôn ngữ định nghĩa giao diện phần cứng (HIDL) cung cấp cơ chế độc lập với ngôn ngữ triển khai để chỉ định giao diện phần cứng. Công cụ HIDL hiện hỗ trợ tạo giao diện C++ và Java. Hầu hết những người triển khai Môi trường Thực thi Tin cậy (TEE) sẽ thấy công cụ C++ thuận tiện hơn, vì vậy tài liệu này chỉ thảo luận về cách biểu diễn C++.

Giao diện HIDL bao gồm một tập hợp các phương thức, được thể hiện dưới dạng:

  methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);

Có nhiều loại được xác định trước khác nhau và HAL có thể xác định các loại cấu trúc và kiểu liệt kê mới. Để biết thêm chi tiết về HIDL, hãy xem phần Tham khảo .

Một phương pháp ví dụ từ Keymaster 3 IKeymasterDevice.hal là:

generateKey(vec<KeyParameter> keyParams)
        generates(ErrorCode error, vec<uint8_t> keyBlob,
                  KeyCharacteristics keyCharacteristics);

Điều này tương đương với những điều sau đây từ 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);

Trong phiên bản HIDL, đối số dev bị loại bỏ vì nó ẩn. Đối số params không còn là một cấu trúc chứa một con trỏ tham chiếu đến một mảng các đối tượng key_parameter_t , mà là một vec (vectơ) chứa các đối tượng KeyParameter . Các giá trị trả về được liệt kê trong mệnh đề " generates ", bao gồm một vectơ gồm các giá trị uint8_t cho đốm màu chính.

Phương thức ảo C++ được tạo bởi trình biên dịch HIDL là:

Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
                         generateKey_cb _hidl_cb) override;

Trong đó generateKey_cb là một con trỏ hàm được định nghĩa là:

std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                   const KeyCharacteristics& keyCharacteristics)>

Nghĩa là, generateKey_cb là một hàm nhận các giá trị trả về được liệt kê trong mệnh đề tạo. Lớp triển khai HAL ghi đè phương thức generateKey này và gọi con trỏ hàm generateKey_cb để trả về kết quả của thao tác cho người gọi. Lưu ý cuộc gọi con trỏ hàm là đồng bộ . Người gọi gọi generateKeygenerateKey gọi con trỏ hàm được cung cấp, con trỏ này thực thi cho đến khi hoàn thành, trả lại quyền kiểm soát cho việc triển khai generateKey , sau đó trả lại cho người gọi.

Để biết ví dụ chi tiết, hãy xem triển khai mặc định trong hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp . Việc triển khai mặc định cung cấp khả năng tương thích ngược cho các thiết bị có keymaster0, keymaster1 hoặc keymaster2 HALS kiểu cũ.

Kiểm soát truy cập

Quy tắc cơ bản nhất của kiểm soát truy cập Keystore là mỗi ứng dụng có không gian tên riêng. Nhưng đối với mỗi quy tắc có một ngoại lệ. Kho khóa có một số bản đồ được mã hóa cứng cho phép các thành phần hệ thống nhất định truy cập vào một số không gian tên khác. Đây là một công cụ rất cùn ở chỗ nó trao cho một thành phần toàn quyền kiểm soát đối với một không gian tên khác. Và sau đó là vấn đề về các thành phần của nhà cung cấp với tư cách là khách hàng của Keystore. Chúng tôi hiện không có cách nào thiết lập không gian tên cho các thành phần của nhà cung cấp, chẳng hạn như chất thay thế WPA.

Để phù hợp với các thành phần của nhà cung cấp và tổng quát hóa việc kiểm soát truy cập mà không có ngoại lệ được mã hóa cứng, Keystore 2.0 giới thiệu các miền và không gian tên SELinux.

Tên miền kho khóa

Với các miền Keystore, chúng tôi có thể tách các không gian tên khỏi UID. Khách hàng truy cập khóa trong Kho khóa phải chỉ định miền, không gian tên và bí danh mà họ muốn truy cập. Dựa trên bộ dữ liệu này và danh tính của người gọi, chúng tôi có thể xác định khóa nào mà người gọi muốn truy cập và liệu nó có quyền thích hợp hay không.

Chúng tôi giới thiệu năm tham số miền chi phối cách truy cập các khóa. Chúng kiểm soát ngữ nghĩa của tham số không gian tên của bộ mô tả khóa và cách thực hiện kiểm soát truy cập.

  • DOMAIN_APP : Miền ứng dụng bao gồm hành vi cũ. Java Keystore SPI sử dụng tên miền này theo mặc định. Khi tên miền này được sử dụng, đối số không gian tên bị bỏ qua và thay vào đó, UID của người gọi được sử dụng. Quyền truy cập vào miền này được kiểm soát bởi nhãn Keystore cho lớp keystore_key trong chính sách SELinux.
  • DOMAIN_SELINUX : Miền này cho biết không gian tên có nhãn trong chính sách SELinux. Tham số không gian tên được tra cứu và dịch sang ngữ cảnh đích và kiểm tra quyền được thực hiện đối với ngữ cảnh SELinux đang gọi cho lớp keystore_key . Khi quyền đã được thiết lập cho thao tác nhất định, bộ dữ liệu đầy đủ được sử dụng để tra cứu khóa.
  • DOMAIN_GRANT : Miền cấp cho biết tham số không gian tên là mã định danh cấp. Tham số bí danh bị bỏ qua. Kiểm tra SELinux được thực hiện khi cấp được tạo. Kiểm soát truy cập hơn nữa chỉ kiểm tra xem UID của người gọi có khớp với UID của người được cấp của khoản trợ cấp được yêu cầu hay không.
  • DOMAIN_KEY_ID : Miền này cho biết tham số không gian tên là id khóa duy nhất. Bản thân khóa có thể đã được tạo bằng DOMAIN_APP hoặc DOMAIN_SELINUX . Kiểm tra quyền được thực hiện sau khi domainnamespace đã được tải từ cơ sở dữ liệu chính giống như cách blob được tải bởi bộ tên miền, không gian tên và bí danh. Cơ sở lý luận cho miền id chính là tính liên tục. Khi truy cập một khóa bằng bí danh, các cuộc gọi tiếp theo có thể hoạt động trên các khóa khác nhau, vì một khóa mới có thể đã được tạo hoặc nhập và liên kết với bí danh này. Tuy nhiên, key id không bao giờ thay đổi. Vì vậy, khi sử dụng một khóa theo id khóa sau khi nó đã được tải từ cơ sở dữ liệu Keystore bằng cách sử dụng bí danh một lần, người ta có thể chắc chắn rằng đó là cùng một khóa miễn là id khóa vẫn tồn tại. Chức năng này không được hiển thị cho các nhà phát triển ứng dụng. Thay vào đó, nó được sử dụng trong Android Keystore SPI để cung cấp trải nghiệm nhất quán hơn ngay cả khi được sử dụng đồng thời theo cách không an toàn.
  • DOMAIN_BLOB : Miền blob cho biết rằng người gọi tự quản lý blob. Điều này được sử dụng cho các máy khách cần truy cập Keystore trước khi phân vùng dữ liệu được gắn kết. Khóa blob được bao gồm trong trường blob của bộ mô tả khóa.

Sử dụng miền SELinux, chúng tôi có thể cấp cho các thành phần của nhà cung cấp quyền truy cập vào các không gian tên Keystore rất cụ thể mà các thành phần hệ thống có thể chia sẻ, chẳng hạn như hộp thoại cài đặt.

Chính sách SELinux cho keystore_key

Nhãn không gian tên được định cấu hình bằng tệp keystore2_key_context .
Mỗi dòng trong các tệp này ánh xạ id không gian tên dạng số thành nhãn SELinux. Ví dụ,

# 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

Sau khi đã thiết lập một không gian tên khóa mới theo cách này, chúng ta có thể cấp quyền truy cập vào nó bằng cách thêm một chính sách thích hợp. Ví dụ: để cho phép wpa_supplicant nhận và sử dụng các khóa trong không gian tên mới, chúng tôi sẽ thêm dòng sau vào hal_wifi_supplicant.te :

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

Sau khi thiết lập không gian tên mới, AndroidKeyStore có thể được sử dụng gần như bình thường. Sự khác biệt duy nhất là ID không gian tên phải được chỉ định. Để tải và nhập khóa từ và vào Keystore, id không gian tên được chỉ định bằng cách sử dụng AndroidKeyStoreLoadStoreParameter . Ví dụ,

import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
import java.security.KeyStore;

KeyStore keystore = KeyStore.getInstance("AndroidKeyStore");
keystore.load(new AndroidKeyStoreLoadStoreParameter(102));

Để tạo khóa trong một không gian tên nhất định, id không gian tên phải được cung cấp bằng cách sử dụng KeyGenParameterSpec.Builder#setNamespace():

import android.security.keystore.KeyGenParameterSpec;
KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder();
specBuilder.setNamespace(102);

Các tệp ngữ cảnh sau đây có thể được sử dụng để định cấu hình không gian tên Keystore 2.0 SELinux. Mỗi phân vùng có một phạm vi 10.000 id không gian tên dành riêng khác nhau để tránh xung đột.

Vách ngăn Phạm vi tập tin cấu hình
Hệ thống 0 ... 9,999
/system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts
Hệ thống mở rộng 10.000 ... 19.999
/system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts
Sản phẩm 20.000 ... 29.999
/product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts
Người bán 30.000 ... 39.999
/vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

Máy khách yêu cầu khóa bằng cách yêu cầu miền SELinux và không gian tên ảo mong muốn, trong trường hợp này là "wifi_key" , theo id số của nó.

Trên đó, các không gian tên sau đã được xác định. Nếu chúng thay thế các quy tắc đặc biệt, bảng sau đây cho biết UID mà chúng đã sử dụng để tương ứng.

ID không gian tên Nhãn SEPolicy UID Sự miêu tả
0 su_key không áp dụng Khóa siêu người dùng. Chỉ được sử dụng để thử nghiệm trên các bản dựng userdebug và eng. Không liên quan đến bản dựng của người dùng.
1 shell_key không áp dụng Không gian tên có sẵn cho shell. Chủ yếu được sử dụng để thử nghiệm, nhưng cũng có thể được sử dụng trên các bản dựng của người dùng từ dòng lệnh.
100 vold_key không áp dụng Dành cho sử dụng bởi vold.
101 odsing_key không áp dụng Được sử dụng bởi trình nền ký trên thiết bị.
102 wifi_key AID_WIFI(1010) Được sử dụng bởi hệ thống Wifi của Android bao gồm wpa_supplicant.
120 sơ yếu lý lịch_on_reboot_key AID_SYSTEM(1000) Được sử dụng bởi máy chủ hệ thống của Android để hỗ trợ tiếp tục khi khởi động lại.

truy cập vectơ

Lớp SELinux keystore_key đã cũ đi khá nhiều và một số quyền, chẳng hạn như verify hoặc sign đã mất ý nghĩa. Đây là nhóm quyền mới, keystore2_key , mà Keystore 2.0 sẽ thực thi.

Sự cho phép Nghĩa
delete Đã kiểm tra khi xóa khóa khỏi Keystore.
get_info Đã chọn khi siêu dữ liệu của khóa được yêu cầu.
grant Người gọi cần có quyền này để tạo một khoản trợ cấp cho khóa trong ngữ cảnh đích.
manage_blob Người gọi có thể sử dụng DOMAIN_BLOB trên không gian tên SELinux đã cho, do đó tự quản lý các đốm màu. Điều này đặc biệt hữu ích cho vold.
rebind Quyền này kiểm soát xem một bí danh có thể được phục hồi thành một khóa mới hay không. Điều này là cần thiết để chèn và ngụ ý rằng khóa được liên kết trước đó sẽ bị xóa. Về cơ bản, nó là quyền chèn, nhưng nó nắm bắt ngữ nghĩa của kho khóa tốt hơn.
req_forced_op Các máy khách có quyền này có thể tạo các thao tác không thể sửa lỗi và việc tạo thao tác không bao giờ thất bại trừ khi tất cả các vị trí thao tác được thực hiện bởi các thao tác không thể sửa lỗi.
update Bắt buộc phải cập nhật thành phần con của khóa.
use Đã chọn khi tạo thao tác Keymint sử dụng tài liệu khóa, ví dụ: để ký, mã hóa/giải mã.
use_dev_id Bắt buộc khi tạo thông tin nhận dạng thiết bị, chẳng hạn như chứng thực id thiết bị.

Ngoài ra, chúng tôi tách ra một tập hợp các quyền kho khóa cụ thể không phải khóa trong keystore2 của lớp bảo mật SELinux :

Sự cho phép Nghĩa
add_auth Yêu cầu bởi nhà cung cấp xác thực như Gatekeeper hoặc BiometricsManager để thêm mã thông báo xác thực.
clear_ns Trước đây là clear_uid, quyền này cho phép người không sở hữu không gian tên xóa tất cả các khóa trong không gian tên đó.
list Được hệ thống yêu cầu để liệt kê các khóa theo các thuộc tính khác nhau, chẳng hạn như quyền sở hữu hoặc giới hạn xác thực. Sự cho phép này không được yêu cầu bởi người gọi liệt kê các không gian tên riêng của họ. Điều này được bao phủ bởi quyền get_info .
lock Quyền này cho phép khóa Keystore, nghĩa là xóa khóa chính, sao cho các khóa bị ràng buộc xác thực trở nên không sử dụng được và không thể tạo được.
reset Quyền này cho phép đặt lại Keystore về mặc định ban đầu, xóa tất cả các khóa không quan trọng đối với hoạt động của HĐH Android.
unlock Cần có quyền này để tìm cách mở khóa khóa chính cho các khóa bị ràng buộc xác thực.
,

Tính khả dụng của môi trường thực thi đáng tin cậy trong hệ thống trên chip (SoC) mang đến cơ hội cho các thiết bị Android cung cấp các dịch vụ bảo mật mạnh mẽ, được phần cứng hỗ trợ cho HĐH Android, cho các dịch vụ nền tảng và thậm chí cho các ứng dụng của bên thứ ba. Các nhà phát triển đang tìm kiếm tiện ích mở rộng dành riêng cho Android nên truy cập android.security.keystore .

Trước Android 6.0, Android đã có API dịch vụ tiền điện tử đơn giản, được phần cứng hỗ trợ, được cung cấp bởi các phiên bản 0.2 và 0.3 của Lớp trừu tượng phần cứng Keymaster (HAL). Kho khóa cung cấp các hoạt động xác minh và ký kỹ thuật số, cộng với việc tạo và nhập các cặp khóa ký bất đối xứng. Điều này đã được triển khai trên nhiều thiết bị, nhưng có nhiều mục tiêu bảo mật không thể dễ dàng đạt được chỉ với một API chữ ký. Keystore trong Android 6.0 đã mở rộng Keystore API để cung cấp nhiều khả năng hơn.

Trong Android 6.0, Keystore đã thêm các nguyên hàm mật mã đối xứng , AES và HMAC cũng như hệ thống kiểm soát truy cập cho các khóa được phần cứng hỗ trợ. Kiểm soát truy cập được chỉ định trong quá trình tạo khóa và được thực thi trong suốt thời gian tồn tại của khóa. Các khóa có thể bị hạn chế chỉ sử dụng được sau khi người dùng đã được xác thực và chỉ dành cho các mục đích cụ thể hoặc với các tham số mật mã cụ thể. Để biết thêm thông tin, hãy xem các trang Chức năngThẻ ủy quyền .

Ngoài việc mở rộng phạm vi nguyên thủy mật mã, Keystore trong Android 6.0 đã thêm vào như sau:

  • Sơ đồ kiểm soát sử dụng cho phép hạn chế sử dụng khóa, để giảm thiểu rủi ro xâm phạm bảo mật do sử dụng sai khóa
  • Sơ đồ kiểm soát truy cập để cho phép hạn chế khóa đối với người dùng, ứng dụng khách được chỉ định và phạm vi thời gian xác định

Trong Android 7.0, Keymaster 2 đã thêm hỗ trợ cho chứng thực khóa và ràng buộc phiên bản. Chứng thực khóa cung cấp chứng chỉ khóa công khai có chứa mô tả chi tiết về khóa và các biện pháp kiểm soát quyền truy cập của khóa, để làm cho sự tồn tại của khóa trong phần cứng bảo mật và cấu hình của khóa có thể xác minh từ xa.

Liên kết phiên bản liên kết các khóa với hệ điều hành và phiên bản cấp bản vá. Điều này đảm bảo rằng kẻ tấn công phát hiện ra điểm yếu trong phiên bản cũ của hệ thống hoặc phần mềm TEE không thể khôi phục thiết bị về phiên bản dễ bị tấn công và sử dụng các khóa được tạo bằng phiên bản mới hơn. Ngoài ra, khi một khóa có phiên bản và cấp bản vá nhất định được sử dụng trên thiết bị đã được nâng cấp lên phiên bản hoặc cấp bản vá mới hơn, thì khóa đó sẽ được nâng cấp trước khi có thể sử dụng và phiên bản trước đó của khóa sẽ bị vô hiệu. Khi thiết bị được nâng cấp, các phím sẽ "gắn" về phía trước cùng với thiết bị, nhưng bất kỳ sự thay đổi nào của thiết bị về bản phát hành trước đó đều khiến các phím không sử dụng được.

Trong Android 8.0, Keymaster 3 đã chuyển đổi từ Lớp trừu tượng phần cứng cấu trúc C (HAL) kiểu cũ sang giao diện C++ HAL được tạo từ một định nghĩa trong Ngôn ngữ định nghĩa giao diện phần cứng (HIDL) mới. Là một phần của thay đổi, nhiều loại đối số đã thay đổi, mặc dù các loại và phương thức có sự tương ứng một đối một với các loại cũ và các phương thức cấu trúc HAL. Xem trang Chức năng để biết thêm chi tiết.

Ngoài bản sửa đổi giao diện này, Android 8.0 đã mở rộng tính năng chứng thực của Keymaster 2 để hỗ trợ chứng thực ID . Chứng thực ID cung cấp một cơ chế tùy chọn và có giới hạn để chứng thực mạnh mẽ các số nhận dạng phần cứng, chẳng hạn như số sê-ri thiết bị, tên sản phẩm và ID điện thoại (IMEI / MEID). Để triển khai phần bổ sung này, Android 8.0 đã thay đổi lược đồ chứng thực ASN.1 để thêm chứng thực ID. Việc triển khai Keymaster cần tìm một số cách an toàn để truy xuất các mục dữ liệu có liên quan, cũng như xác định cơ chế để vô hiệu hóa tính năng này một cách an toàn và vĩnh viễn.

Trong Android 9, các bản cập nhật bao gồm:

  • Cập nhật lên Keymaster 4
  • Hỗ trợ cho các yếu tố bảo mật được nhúng
  • Hỗ trợ nhập khóa an toàn
  • Hỗ trợ mã hóa 3DES
  • Thay đổi liên kết phiên bản để boot.img và system.img có các phiên bản được đặt riêng để cho phép cập nhật độc lập

Bảng chú giải

Dưới đây là tổng quan nhanh về các thành phần Keystore và mối quan hệ của chúng.

AndroidKeystore là API và thành phần Android Framework được các ứng dụng sử dụng để truy cập chức năng Keystore. Nó được triển khai như một phần mở rộng cho API Kiến trúc mã hóa Java tiêu chuẩn và bao gồm mã Java chạy trong không gian quy trình riêng của ứng dụng. AndroidKeystore đáp ứng các yêu cầu của ứng dụng đối với hành vi của Kho khóa bằng cách chuyển tiếp chúng đến daemon kho khóa.

Trình nền kho khóa là một trình nền hệ thống Android cung cấp quyền truy cập vào tất cả chức năng của Kho khóa thông qua API Binder . Nó chịu trách nhiệm lưu trữ "các đốm màu chính", chứa tài liệu khóa bí mật thực tế, được mã hóa để Keystore có thể lưu trữ nhưng không sử dụng hoặc tiết lộ chúng.

keymasterd là một máy chủ HIDL cung cấp quyền truy cập vào Keymaster TA. (Tên này không được tiêu chuẩn hóa và dành cho mục đích khái niệm.)

Keymaster TA (ứng dụng đáng tin cậy) là phần mềm chạy trong ngữ cảnh an toàn, thường là trong TrustZone trên SoC ARM, cung cấp tất cả các hoạt động của Kho khóa an toàn, có quyền truy cập vào nguyên liệu khóa, xác thực tất cả các điều kiện kiểm soát truy cập trên khóa , vân vân.

LockSettingsService là thành phần hệ thống Android chịu trách nhiệm xác thực người dùng, cả mật khẩu và dấu vân tay. Nó không phải là một phần của Kho khóa, nhưng có liên quan vì nhiều thao tác với khóa của Kho khóa yêu cầu xác thực người dùng. LockSettingsService tương tác với TA của Gatekeeper và TA của Fingerprint để lấy mã thông báo xác thực mà nó cung cấp cho daemon kho khóa và cuối cùng sẽ được ứng dụng Keymaster TA sử dụng.

Gatekeeper TA (ứng dụng đáng tin cậy) là một thành phần khác chạy trong ngữ cảnh bảo mật, chịu trách nhiệm xác thực mật khẩu người dùng và tạo mã thông báo xác thực được sử dụng để chứng minh với Keymaster TA rằng xác thực đã được thực hiện cho một người dùng cụ thể tại một thời điểm cụ thể.

TA vân tay (ứng dụng đáng tin cậy) là một thành phần khác chạy trong ngữ cảnh bảo mật chịu trách nhiệm xác thực dấu vân tay của người dùng và tạo mã thông báo xác thực được sử dụng để chứng minh với Keymaster TA rằng xác thực đã được thực hiện cho một người dùng cụ thể tại một thời điểm cụ thể.

Ngành kiến ​​​​trúc

Android Keystore API và Keymaster HAL cơ bản cung cấp một bộ nguyên hàm mật mã cơ bản nhưng đầy đủ để cho phép triển khai các giao thức bằng cách sử dụng các khóa được phần cứng hỗ trợ, kiểm soát truy cập.

Keymaster HAL là một thư viện có thể tải động, do OEM cung cấp, được sử dụng bởi dịch vụ Keystore để cung cấp các dịch vụ mã hóa dựa trên phần cứng. Để giữ mọi thứ an toàn, việc triển khai HAL không thực hiện bất kỳ thao tác nhạy cảm nào trong không gian người dùng hoặc thậm chí trong không gian nhân. Các hoạt động nhạy cảm được ủy quyền cho một bộ xử lý an toàn đạt được thông qua một số giao diện hạt nhân. Kiến trúc kết quả trông như thế này:

Truy cập Keymaster

Hình 1. Truy cập vào Keymaster

Trong một thiết bị Android, "máy khách" của Keymaster HAL bao gồm nhiều lớp (ví dụ: ứng dụng, khung, trình nền Keystore), nhưng điều đó có thể bị bỏ qua vì mục đích của tài liệu này. Điều này có nghĩa là API Keymaster HAL được mô tả ở cấp độ thấp, được sử dụng bởi các thành phần bên trong nền tảng và không được hiển thị cho các nhà phát triển ứng dụng. API cấp cao hơn được mô tả trên trang web dành cho Nhà phát triển Android .

Mục đích của Keymaster HAL không phải là triển khai các thuật toán nhạy cảm về bảo mật mà chỉ để sắp xếp các yêu cầu theo thứ tự và không theo thứ tự đối với thế giới an toàn. Định dạng dây được xác định theo triển khai.

Khả năng tương thích với các phiên bản trước

Keymaster 1 HAL hoàn toàn không tương thích với các HAL đã phát hành trước đó, ví dụ Keymaster 0.2 và 0.3. Để hỗ trợ khả năng tương tác trên các thiết bị chạy Android 5.0 trở về trước đã ra mắt với Keymaster HAL cũ hơn, Keystore cung cấp bộ điều hợp triển khai Keymaster 1 HAL với các lệnh gọi đến thư viện phần cứng hiện có. Kết quả là không thể cung cấp đầy đủ các chức năng trong Keymaster 1 HAL. Cụ thể, nó chỉ hỗ trợ các thuật toán RSA và ECDSA và tất cả việc thực thi ủy quyền khóa được thực hiện bởi bộ điều hợp, trong thế giới không an toàn.

Keymaster 2 đơn giản hóa hơn nữa giao diện HAL bằng cách loại bỏ các phương thức get_supported_* và cho phép phương thức finish() chấp nhận đầu vào. Điều này làm giảm số lần đi vòng tới TEE trong trường hợp đầu vào có sẵn cùng một lúc và đơn giản hóa việc thực hiện giải mã AEAD.

Trong Android 8.0, Keymaster 3 đã chuyển từ cấu trúc C kiểu cũ HAL sang giao diện C++ HAL được tạo từ một định nghĩa trong Ngôn ngữ định nghĩa giao diện phần cứng (HIDL) mới. Việc triển khai HAL kiểu mới được tạo bằng cách phân lớp con lớp IKeymasterDevice đã tạo và triển khai các phương thức ảo thuần túy. Là một phần của thay đổi, nhiều loại đối số đã thay đổi, mặc dù các loại và phương thức có sự tương ứng một đối một với các loại cũ và các phương thức cấu trúc HAL.

Tổng quan về HIDL

Ngôn ngữ định nghĩa giao diện phần cứng (HIDL) cung cấp cơ chế độc lập với ngôn ngữ triển khai để chỉ định giao diện phần cứng. Công cụ HIDL hiện hỗ trợ tạo giao diện C++ và Java. Hầu hết những người triển khai Môi trường Thực thi Tin cậy (TEE) sẽ thấy công cụ C++ thuận tiện hơn, vì vậy tài liệu này chỉ thảo luận về cách biểu diễn C++.

Giao diện HIDL bao gồm một tập hợp các phương thức, được thể hiện dưới dạng:

  methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);

Có nhiều loại được xác định trước khác nhau và HAL có thể xác định các loại cấu trúc và kiểu liệt kê mới. Để biết thêm chi tiết về HIDL, hãy xem phần Tham khảo .

Một phương pháp ví dụ từ Keymaster 3 IKeymasterDevice.hal là:

generateKey(vec<KeyParameter> keyParams)
        generates(ErrorCode error, vec<uint8_t> keyBlob,
                  KeyCharacteristics keyCharacteristics);

Điều này tương đương với những điều sau đây từ 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);

Trong phiên bản HIDL, đối số dev bị loại bỏ vì nó ẩn. Đối số params không còn là một cấu trúc chứa một con trỏ tham chiếu đến một mảng các đối tượng key_parameter_t , mà là một vec (vectơ) chứa các đối tượng KeyParameter . Các giá trị trả về được liệt kê trong mệnh đề " generates ", bao gồm một vectơ gồm các giá trị uint8_t cho đốm màu chính.

Phương thức ảo C++ được tạo bởi trình biên dịch HIDL là:

Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
                         generateKey_cb _hidl_cb) override;

Trong đó generateKey_cb là một con trỏ hàm được định nghĩa là:

std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                   const KeyCharacteristics& keyCharacteristics)>

Nghĩa là, generateKey_cb là một hàm nhận các giá trị trả về được liệt kê trong mệnh đề tạo. Lớp triển khai HAL ghi đè phương thức generateKey này và gọi con trỏ hàm generateKey_cb để trả về kết quả của thao tác cho người gọi. Lưu ý cuộc gọi con trỏ hàm là đồng bộ . Người gọi gọi generateKeygenerateKey gọi con trỏ hàm được cung cấp, con trỏ này thực thi cho đến khi hoàn thành, trả lại quyền kiểm soát cho việc triển khai generateKey , sau đó trả lại cho người gọi.

Để biết ví dụ chi tiết, hãy xem triển khai mặc định trong hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp . Việc triển khai mặc định cung cấp khả năng tương thích ngược cho các thiết bị có keymaster0, keymaster1 hoặc keymaster2 HALS kiểu cũ.

Kiểm soát truy cập

Quy tắc cơ bản nhất của kiểm soát truy cập Keystore là mỗi ứng dụng có không gian tên riêng. Nhưng đối với mỗi quy tắc có một ngoại lệ. Kho khóa có một số bản đồ được mã hóa cứng cho phép các thành phần hệ thống nhất định truy cập vào một số không gian tên khác. Đây là một công cụ rất cùn ở chỗ nó trao cho một thành phần toàn quyền kiểm soát đối với một không gian tên khác. Và sau đó là vấn đề về các thành phần của nhà cung cấp với tư cách là khách hàng của Keystore. Chúng tôi hiện không có cách nào thiết lập không gian tên cho các thành phần của nhà cung cấp, chẳng hạn như chất thay thế WPA.

Để phù hợp với các thành phần của nhà cung cấp và tổng quát hóa việc kiểm soát truy cập mà không có ngoại lệ được mã hóa cứng, Keystore 2.0 giới thiệu các miền và không gian tên SELinux.

Tên miền kho khóa

Với các miền Keystore, chúng tôi có thể tách các không gian tên khỏi UID. Khách hàng truy cập khóa trong Kho khóa phải chỉ định miền, không gian tên và bí danh mà họ muốn truy cập. Dựa trên bộ dữ liệu này và danh tính của người gọi, chúng tôi có thể xác định khóa nào mà người gọi muốn truy cập và liệu nó có quyền thích hợp hay không.

Chúng tôi giới thiệu năm tham số miền chi phối cách truy cập các khóa. Chúng kiểm soát ngữ nghĩa của tham số không gian tên của bộ mô tả khóa và cách thực hiện kiểm soát truy cập.

  • DOMAIN_APP : Miền ứng dụng bao gồm hành vi cũ. Java Keystore SPI sử dụng tên miền này theo mặc định. Khi tên miền này được sử dụng, đối số không gian tên sẽ bị bỏ qua và thay vào đó, UID của người gọi được sử dụng. Quyền truy cập vào miền này được kiểm soát bởi nhãn Keystore cho lớp keystore_key trong chính sách SELinux.
  • DOMAIN_SELINUX : Miền này cho biết không gian tên có nhãn trong chính sách SELinux. Tham số không gian tên được tra cứu và dịch sang ngữ cảnh đích và kiểm tra quyền được thực hiện đối với ngữ cảnh SELinux đang gọi cho lớp keystore_key . Khi quyền đã được thiết lập cho thao tác nhất định, bộ dữ liệu đầy đủ được sử dụng để tra cứu khóa.
  • DOMAIN_GRANT : The grant domain indicates that the namespace parameter is a grant identifier. 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 Sự miêu tả
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.

Permission 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 :

Permission 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.