Trong Keymaster 1, tất cả các khoá Keymaster đều được liên kết theo cách mã hoá với Root of Trust (Gốc tin cậy) của thiết bị hoặc khoá Xác minh quy trình khởi động. Trong Keymaster 2 và 3, tất cả các khoá cũng được liên kết với hệ điều hành và cấp bản vá của hình ảnh hệ thống. Đ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 phần mềm hệ thống hoặc 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 khoá được tạo bằng phiên bản mới hơn. Ngoài ra, khi một khoá có phiên bản và cấp độ vá nhất định được dùng trên một thiết bị đã nâng cấp lên phiên bản hoặc cấp độ vá mới hơn, khoá sẽ được nâng cấp trước khi có thể dùng và phiên bản trước của khoá sẽ không hợp lệ. Bằng cách này, khi thiết bị được nâng cấp, các khoá sẽ *tăng* lên cùng với thiết bị, nhưng mọi việc hạ cấp thiết bị về một bản phát hành trước đó sẽ khiến các khoá không dùng được.
Để hỗ trợ cấu trúc mô-đun của Treble và phá vỡ mối liên kết của system.img với boot.img, Keymaster 4 đã thay đổi mô hình liên kết phiên bản khoá để có các cấp độ vá riêng cho từng phân vùng. Điều này cho phép mỗi phân vùng được cập nhật độc lập, trong khi vẫn cung cấp khả năng bảo vệ khi quay lại phiên bản cũ.
Để triển khai hoạt động liên kết phiên bản này, ứng dụng đáng tin cậy (TA) KeyMint cần một cách để nhận an toàn phiên bản hệ điều hành và cấp độ bản vá hiện tại, đồng thời đảm bảo rằng thông tin mà ứng dụng này nhận được khớp với tất cả thông tin về hệ thống đang chạy.
- Các thiết bị có Quy trình khởi động được xác minh của Android (AVB) có thể đặt tất cả các cấp độ vá và phiên bản hệ thống trong vbmeta, nhờ đó trình tải khởi động có thể cung cấp các thông tin này cho Keymaster. Đối với các phân vùng được liên kết, thông tin phiên bản cho phân vùng nằm trong vbmeta được liên kết. Nhìn chung, thông tin phiên bản phải nằm trong
vbmeta struct
chứa dữ liệu xác minh (hàm băm hoặc hashtree) cho một phân vùng nhất định. - Trên thiết bị không có AVB:
- Các quy trình triển khai Xác minh quy trình khởi động cần cung cấp một hàm băm của siêu dữ liệu phiên bản cho trình tải khởi động, để trình tải khởi động có thể cung cấp hàm băm cho Keymaster.
boot.img
có thể tiếp tục lưu trữ cấp bản vá trong tiêu đềsystem.img
có thể tiếp tục lưu trữ cấp bản vá và phiên bản hệ điều hành trong các thuộc tính chỉ có thể đọcvendor.img
lưu trữ cấp bản vá trong thuộc tính chỉ có thể đọcro.vendor.build.version.security_patch
.- Trình tải khởi động có thể cung cấp một hàm băm của tất cả dữ liệu được Xác minh quy trình khởi động xác thực cho Keymaster.
- Trong Android 9, hãy dùng các thẻ sau để cung cấp thông tin phiên bản cho các phân vùng sau:
VENDOR_PATCH_LEVEL
: Phân vùngvendor
BOOT_PATCH_LEVEL
: Phân vùngboot
OS_PATCH_LEVEL
vàOS_VERSION
: phân vùngsystem
. (OS_VERSION
bị xoá khỏi tiêu đềboot.img
.
-
Các hoạt động triển khai Keymaster phải xử lý độc lập tất cả các cấp độ bản vá. Bạn có thể sử dụng các khoá nếu tất cả thông tin về phiên bản đều khớp với các giá trị được liên kết với một khoá và
IKeymaster::upgradeDevice()
chuyển sang cấp bản vá cao hơn nếu cần.
Thay đổi HAL
Để hỗ trợ hoạt động liên kết phiên bản và chứng thực phiên bản, Android 7.1 đã thêm các thẻ Tag::OS_VERSION
và Tag::OS_PATCHLEVEL
cũng như các phương thức configure
và upgradeKey
. Các thẻ phiên bản sẽ được các chế độ triển khai Keymaster 2+ tự động thêm vào tất cả các khoá mới được tạo (hoặc được cập nhật). Ngoài ra, mọi nỗ lực sử dụng khoá không có phiên bản hệ điều hành hoặc cấp độ bản vá tương ứng với phiên bản hệ điều hành hoặc cấp độ bản vá hiện tại của hệ thống đều bị từ chối bằng ErrorCode::KEY_REQUIRES_UPGRADE
.
Tag::OS_VERSION
là một giá trị UINT
biểu thị các phần chính, phụ và phụ-phụ của một phiên bản hệ thống Android dưới dạng MMmmss, trong đó MM là phiên bản chính, mm là phiên bản phụ và ss là phiên bản phụ-phụ. Ví dụ: 6.1.2 sẽ được biểu thị là 060102.
Tag::OS_PATCHLEVEL
là giá trị UINT
biểu thị năm và tháng của lần cập nhật gần đây nhất cho hệ thống dưới dạng YYYYMM, trong đó YYYY là năm gồm 4 chữ số và MM là tháng gồm 2 chữ số. Ví dụ: tháng 3 năm 2016 sẽ được biểu thị là 201603.
UpgradeKey
Để cho phép nâng cấp các khoá lên phiên bản hệ điều hành và cấp bản vá mới của hình ảnh hệ thống, Android 7.1 đã thêm phương thức upgradeKey
vào HAL:
Keymaster 3
upgradeKey(vec keyBlobToUpgrade, vec upgradeParams) generates(ErrorCode error, vec upgradedKeyBlob);
Keymaster 2
keymaster_error_t (*upgrade_key)(const struct keymaster2_device* dev, const keymaster_key_blob_t* key_to_upgrade, const keymaster_key_param_set_t* upgrade_params, keymaster_key_blob_t* upgraded_key);
dev
là cấu trúc thiết bịkeyBlobToUpgrade
là khoá cần được nâng cấpupgradeParams
là những tham số cần thiết để nâng cấp khoá. Các tham số này bao gồmTag::APPLICATION_ID
vàTag::APPLICATION_DATA
, cần thiết để giải mã blob khoá, nếu được cung cấp trong quá trình tạo.upgradedKeyBlob
là tham số đầu ra, dùng để trả về blob khoá mới.
Nếu upgradeKey
được gọi bằng một blob khoá không thể phân tích cú pháp hoặc không hợp lệ, thì hàm này sẽ trả về ErrorCode::INVALID_KEY_BLOB
. Nếu được gọi bằng một khoá có cấp độ bản vá lớn hơn giá trị hệ thống hiện tại, thì hàm này sẽ trả về ErrorCode::INVALID_ARGUMENT
. Nếu được gọi bằng một khoá có phiên bản hệ điều hành lớn hơn giá trị hệ thống hiện tại và giá trị hệ thống khác 0, thì hàm này sẽ trả về ErrorCode::INVALID_ARGUMENT
. Bạn có thể nâng cấp phiên bản hệ điều hành từ phiên bản khác 0 lên phiên bản 0. Trong trường hợp xảy ra lỗi khi giao tiếp với thế giới bảo mật, hàm này sẽ trả về một giá trị lỗi thích hợp (ví dụ: ErrorCode::SECURE_HW_ACCESS_DENIED
, ErrorCode::SECURE_HW_BUSY
). Nếu không, hàm này sẽ trả về ErrorCode::OK
và trả về một blob khoá mới trong upgradedKeyBlob
.
keyBlobToUpgrade
vẫn hợp lệ sau cuộc gọi upgradeKey
và về lý thuyết, có thể được dùng lại nếu thiết bị bị hạ cấp. Trong thực tế, kho khoá thường gọi deleteKey
trên blob keyBlobToUpgrade
ngay sau khi gọi đến upgradeKey
. Nếu keyBlobToUpgrade
có thẻ Tag::ROLLBACK_RESISTANT
, thì upgradedKeyBlob
cũng phải có thẻ đó (và phải có khả năng chống khôi phục).
Cấu hình an toàn
Để triển khai tính năng liên kết phiên bản, TA Keymaster cần một cách để nhận an toàn phiên bản hệ điều hành hiện tại và cấp độ bản vá (thông tin phiên bản), đồng thời đảm bảo rằng thông tin mà TA này nhận được hoàn toàn khớp với thông tin về hệ thống đang chạy.
Để hỗ trợ việc phân phối thông tin phiên bản một cách an toàn đến TA, một trường OS_VERSION
đã được thêm vào tiêu đề hình ảnh khởi động. Tập lệnh tạo hình ảnh khởi động sẽ tự động điền sẵn trường này. Các OEM và đơn vị triển khai Keymaster TA cần phối hợp với nhau để sửa đổi trình tải khởi động của thiết bị nhằm trích xuất thông tin phiên bản từ hình ảnh khởi động và truyền thông tin đó đến TA trước khi hệ thống không bảo mật được khởi động. Điều này đảm bảo rằng kẻ tấn công không thể can thiệp vào việc cung cấp thông tin phiên bản cho TA.
Bạn cũng cần đảm bảo rằng hình ảnh hệ thống có cùng thông tin phiên bản với hình ảnh khởi động. Để làm được điều đó, phương thức định cấu hình đã được thêm vào Keymaster HAL:
keymaster_error_t (*configure)(const struct keymaster2_device* dev, const keymaster_key_param_set_t* params);
Đối số params
chứa Tag::OS_VERSION
và Tag::OS_PATCHLEVEL
. Phương thức này được gọi bởi các ứng dụng keymaster2 sau khi mở HAL, nhưng trước khi gọi bất kỳ phương thức nào khác. Nếu bất kỳ phương thức nào khác được gọi trước khi định cấu hình, TA sẽ trả về ErrorCode::KEYMASTER_NOT_CONFIGURED
.
Lần đầu tiên configure
được gọi sau khi thiết bị khởi động, hàm này sẽ xác minh rằng thông tin phiên bản được cung cấp khớp với thông tin do trình tải khởi động cung cấp. Nếu thông tin phiên bản không khớp, configure
sẽ trả về ErrorCode::INVALID_ARGUMENT
và tất cả các phương thức Keymaster khác sẽ tiếp tục trả về ErrorCode::KEYMASTER_NOT_CONFIGURED
. Nếu thông tin trùng khớp, configure
sẽ trả về ErrorCode::OK
và các phương thức Keymaster khác sẽ bắt đầu hoạt động bình thường.
Các lệnh gọi tiếp theo đến configure
sẽ trả về cùng một giá trị do lệnh gọi đầu tiên trả về và không thay đổi trạng thái của Keymaster.
Vì configure
được gọi bởi hệ thống mà nội dung của hệ thống này được dùng để xác thực, nên kẻ tấn công có rất ít cơ hội xâm nhập vào hình ảnh hệ thống và buộc hệ thống cung cấp thông tin phiên bản khớp với hình ảnh khởi động, nhưng không phải là phiên bản thực tế của hệ thống. Sự kết hợp giữa quy trình xác minh hình ảnh khởi động, xác thực dm-verity nội dung hình ảnh hệ thống và thực tế là configure
được gọi rất sớm trong quá trình khởi động hệ thống sẽ khiến kẻ tấn công khó khai thác được cơ hội này.