Hình ảnh hệ điều hành Android sử dụng chữ ký mã hoá ở hai vị trí:
- Mỗi tệp
.apk
bên trong hình ảnh phải được ký. Trình quản lý gói của Android sử dụng chữ ký.apk
theo 2 cách:- Khi được thay thế, ứng dụng phải được ký bằng cùng một khoá với ứng dụng cũ để có quyền truy cập vào dữ liệu của ứng dụng cũ. Điều này đúng cả khi cập nhật ứng dụng của người dùng bằng cách ghi đè
.apk
và khi ghi đè ứng dụng hệ thống bằng phiên bản mới hơn được cài đặt trong/data
. - Nếu hai hoặc nhiều ứng dụng muốn chia sẻ mã nhận dạng người dùng (để có thể chia sẻ dữ liệu, v.v.), thì các ứng dụng đó phải được ký bằng cùng một khoá.
- Khi được thay thế, ứng dụng phải được ký bằng cùng một khoá với ứng dụng cũ để có quyền truy cập vào dữ liệu của ứng dụng cũ. Điều này đúng cả khi cập nhật ứng dụng của người dùng bằng cách ghi đè
- Gói cập nhật OTA phải được ký bằng một trong các khoá mà hệ thống dự kiến, nếu không, quá trình cài đặt sẽ từ chối các gói đó.
Khoá phát hành
Cây Android bao gồm test-keys trong build/target/product/security
. Việc tạo hình ảnh hệ điều hành Android bằng make
sẽ ký tất cả tệp .apk
bằng các khoá kiểm thử. Vì khoá kiểm thử được công khai, nên bất kỳ ai cũng có thể ký tệp .apk của riêng mình bằng cùng một khoá. Điều này có thể cho phép họ thay thế hoặc xâm nhập vào các ứng dụng hệ thống được tích hợp vào hình ảnh hệ điều hành của bạn. Vì lý do này, bạn cần phải ký mọi hình ảnh hệ điều hành Android được phát hành công khai hoặc triển khai bằng một bộ khoá phát hành đặc biệt mà chỉ bạn mới có quyền truy cập.
Để tạo bộ khoá phát hành duy nhất của riêng bạn, hãy chạy các lệnh sau từ gốc của cây Android:
subject='/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
mkdir ~/.android-certs
for x in releasekey platform shared media networkstack; do \ ./development/tools/make_key ~/.android-certs/$x "$subject"; \ done
Bạn nên thay đổi $subject
để phản ánh thông tin của tổ chức. Bạn có thể sử dụng bất kỳ thư mục nào, nhưng hãy cẩn thận chọn một vị trí được sao lưu và an toàn. Một số nhà cung cấp chọn mã hoá khoá riêng tư bằng cụm mật khẩu mạnh và lưu trữ khoá đã mã hoá trong phần kiểm soát nguồn; một số nhà cung cấp khác lưu trữ khoá phát hành ở một nơi khác, chẳng hạn như trên máy tính có cách ly mạng.
Để tạo hình ảnh phát hành, hãy sử dụng:
make dist
sign_target_files_apks \ -o \ # explained in the next section --default_key_mappings ~/.android-certs out/dist/*-target_files-*.zip \ signed-target_files.zip
Tập lệnh sign_target_files_apks
lấy tệp đích .zip
làm dữ liệu đầu vào và tạo một tệp đích .zip
mới trong đó tất cả tệp .apk
đã được ký bằng các khoá mới. Bạn có thể tìm thấy các hình ảnh mới ký trong IMAGES/
trong signed-target_files.zip
.
Ký gói OTA
Bạn có thể chuyển đổi tệp zip của tệp mục tiêu đã ký thành tệp zip cập nhật OTA đã ký bằng cách sử dụng quy trình sau:
ota_from_target_files \
-k (--package_key)
signed-target_files.zip \
signed-ota_update.zip
Chữ ký và tải không qua cửa hàng
Tính năng tải không qua cửa hàng không bỏ qua cơ chế xác minh chữ ký gói thông thường của tính năng khôi phục. Trước khi cài đặt một gói, tính năng khôi phục sẽ xác minh rằng gói đó được ký bằng một trong các khoá riêng tư khớp với khoá công khai được lưu trữ trong phân vùng khôi phục, giống như đối với một gói được phân phối qua mạng không dây.
Các gói cập nhật nhận được từ hệ thống chính thường được xác minh hai lần: một lần bởi hệ thống chính, sử dụng phương thức RecoverySystem.verifyPackage()
trong API Android, sau đó xác minh lại bằng cách khôi phục. API RecoverySystem kiểm tra chữ ký dựa trên khoá công khai được lưu trữ trong hệ thống chính, trong tệp /system/etc/security/otacerts.zip
(theo mặc định). Quá trình khôi phục sẽ kiểm tra chữ ký dựa trên các khoá công khai được lưu trữ trong ổ RAM của phân vùng khôi phục, trong tệp /res/keys
.
Theo mặc định, tệp mục tiêu .zip
do bản dựng tạo ra sẽ đặt chứng chỉ OTA khớp với khoá kiểm thử. Trên hình ảnh đã phát hành, phải sử dụng một chứng chỉ khác để các thiết bị có thể xác minh tính xác thực của gói cập nhật. Việc truyền cờ -o
đến sign_target_files_apks
, như minh hoạ trong phần trước, sẽ thay thế chứng chỉ khoá kiểm thử bằng chứng chỉ khoá phát hành từ thư mục chứng chỉ của bạn.
Thông thường, hình ảnh hệ thống và hình ảnh khôi phục lưu trữ cùng một bộ khoá công khai OTA. Bằng cách thêm một khoá vào chỉ tập hợp khoá khôi phục, bạn có thể ký các gói chỉ có thể cài đặt thông qua tính năng tải không qua cửa hàng (giả sử cơ chế tải bản cập nhật của hệ thống chính đang xác minh chính xác với otacerts.zip). Bạn có thể chỉ định các khoá bổ sung chỉ được đưa vào quá trình khôi phục bằng cách đặt biến PRODUCT_EXTRA_RECOVERY_KEYS trong định nghĩa sản phẩm:
vendor/yoyodyne/tardis/products/tardis.mk
[...] PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload
Tệp này bao gồm khoá công khai vendor/yoyodyne/security/tardis/sideload.x509.pem
trong tệp khoá khôi phục để có thể cài đặt các gói được ký bằng khoá đó. Tuy nhiên, khoá bổ sung không có trong otacerts.zip, vì vậy, các hệ thống xác minh chính xác gói đã tải xuống sẽ không gọi quy trình khôi phục đối với các gói được ký bằng khoá này.
Chứng chỉ và khoá riêng tư
Mỗi khoá có hai tệp: chứng chỉ có đuôi .x509.pem và khoá riêng tư có đuôi .pk8. Bạn cần giữ bí mật khoá riêng tư và dùng khoá này để ký gói. Khoá có thể được bảo vệ bằng mật khẩu. Ngược lại, chứng chỉ chỉ chứa một nửa khoá công khai, vì vậy, chứng chỉ có thể được phân phối rộng rãi. Dùng để xác minh một gói đã được ký bằng khoá riêng tương ứng.
Bản dựng Android tiêu chuẩn dùng 5 khoá, tất cả đều nằm trong
build/target/product/security
:
- testkey
- Khoá mặc định chung cho các gói không chỉ định khoá.
- nền tảng
- Khoá kiểm thử cho các gói thuộc nền tảng chính.
- đã chia sẻ
- Kiểm thử khoá cho những nội dung được chia sẻ trong quy trình nhà/danh bạ.
- truyền-thông
- Khoá kiểm thử cho các gói thuộc hệ thống nội dung nghe nhìn/hệ thống tải xuống.
Các gói riêng lẻ chỉ định một trong các khoá này bằng cách đặt LOCAL_CERTIFICATE trong tệp Android.mk. (testkey được sử dụng nếu bạn không đặt biến này.) Bạn cũng có thể chỉ định một khoá hoàn toàn khác theo đường dẫn, ví dụ:
device/yoyodyne/apps/SpecialApp/Android.mk
[...] LOCAL_CERTIFICATE := device/yoyodyne/security/special
Giờ đây, bản dựng sẽ sử dụng khoá device/yoyodyne/security/special.{x509.pem,pk8}
để ký SpecialApp.apk. Bản dựng chỉ có thể sử dụng các khoá riêng tư không được bảo vệ bằng mật khẩu.
Tuỳ chọn ký nâng cao
Thay thế khoá ký APK
Tập lệnh ký sign_target_files_apks
hoạt động trên các tệp mục tiêu được tạo cho một bản dựng. Tất cả thông tin về chứng chỉ và khoá riêng tư được sử dụng tại thời điểm tạo bản dựng đều có trong các tệp mục tiêu. Khi chạy tập lệnh ký để ký phát hành, bạn có thể thay thế khoá ký dựa trên tên khoá hoặc tên APK.
Sử dụng cờ --key_mapping
và --default_key_mappings
để chỉ định việc thay thế khoá dựa trên tên khoá:
- Cờ
--key_mapping src_key=dest_key
chỉ định việc thay thế cho một khoá tại một thời điểm. - Cờ
--default_key_mappings dir
chỉ định một thư mục có 5 khoá để thay thế tất cả các khoá trongbuild/target/product/security
; tương đương với việc sử dụng--key_mapping
5 lần để chỉ định ánh xạ.
build/target/product/security/testkey = dir/releasekey build/target/product/security/platform = dir/platform build/target/product/security/shared = dir/shared build/target/product/security/media = dir/media build/target/product/security/networkstack = dir/networkstack
Sử dụng cờ --extra_apks apk_name1,apk_name2,...=key
để chỉ định các khoá ký thay thế dựa trên tên APK. Nếu bạn để trống key
, tập lệnh sẽ coi các tệp APK được chỉ định là đã ký trước.
Đối với sản phẩm tardis giả định, bạn cần 6 khoá được bảo vệ bằng mật khẩu: 5 khoá để thay thế 5 khoá trong build/target/product/security
và 1 khoá để thay thế khoá bổ sung device/yoyodyne/security/special
mà SpecialApp yêu cầu trong ví dụ trên. Nếu các khoá nằm trong các tệp sau:
vendor/yoyodyne/security/tardis/releasekey.x509.pem vendor/yoyodyne/security/tardis/releasekey.pk8 vendor/yoyodyne/security/tardis/platform.x509.pem vendor/yoyodyne/security/tardis/platform.pk8 vendor/yoyodyne/security/tardis/shared.x509.pem vendor/yoyodyne/security/tardis/shared.pk8 vendor/yoyodyne/security/tardis/media.x509.pem vendor/yoyodyne/security/tardis/media.pk8 vendor/yoyodyne/security/tardis/networkstack.x509.pem vendor/yoyodyne/security/tardis/networkstack.pk8 vendor/yoyodyne/security/special.x509.pem vendor/yoyodyne/security/special.pk8 # NOT password protected vendor/yoyodyne/security/special-release.x509.pem vendor/yoyodyne/security/special-release.pk8 # password protected
Sau đó, bạn sẽ ký tất cả ứng dụng như sau:
./build/make/tools/releasetools/sign_target_files_apks \
--default_key_mappings vendor/yoyodyne/security/tardis \
--key_mapping vendor/yoyodyne/security/special=vendor/yoyodyne/security/special-release \
--extra_apks PresignedApp= \
-o tardis-target_files.zip \
signed-tardis-target_files.zip
Thao tác này sẽ hiển thị:
Enter password for vendor/yoyodyne/security/special-release key> Enter password for vendor/yoyodyne/security/tardis/networkstack key> Enter password for vendor/yoyodyne/security/tardis/media key> Enter password for vendor/yoyodyne/security/tardis/platform key> Enter password for vendor/yoyodyne/security/tardis/releasekey key> Enter password for vendor/yoyodyne/security/tardis/shared key> signing: Phone.apk (vendor/yoyodyne/security/tardis/platform) signing: Camera.apk (vendor/yoyodyne/security/tardis/media) signing: NetworkStack.apk (vendor/yoyodyne/security/tardis/networkstack) signing: Special.apk (vendor/yoyodyne/security/special-release) signing: Email.apk (vendor/yoyodyne/security/tardis/releasekey) [...] signing: ContactsProvider.apk (vendor/yoyodyne/security/tardis/shared) signing: Launcher.apk (vendor/yoyodyne/security/tardis/shared) NOT signing: PresignedApp.apk (skipped due to special cert string) rewriting SYSTEM/build.prop: replace: ro.build.description=tardis-user Eclair ERC91 15449 test-keys with: ro.build.description=tardis-user Eclair ERC91 15449 release-keys replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys signing: framework-res.apk (vendor/yoyodyne/security/tardis/platform) rewriting RECOVERY/RAMDISK/default.prop: replace: ro.build.description=tardis-user Eclair ERC91 15449 test-keys with: ro.build.description=tardis-user Eclair ERC91 15449 release-keys replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys using: vendor/yoyodyne/security/tardis/releasekey.x509.pem for OTA package verification done.
Sau khi nhắc người dùng nhập mật khẩu cho tất cả các khoá được bảo vệ bằng mật khẩu, tập lệnh sẽ ký lại tất cả tệp APK trong mục tiêu đầu vào .zip
bằng các khoá phát hành. Trước khi chạy lệnh, bạn cũng có thể đặt biến môi trường ANDROID_PW_FILE
thành tên tệp tạm thời; sau đó, tập lệnh sẽ gọi trình chỉnh sửa để cho phép bạn nhập mật khẩu cho tất cả các khoá (đây có thể là cách nhập mật khẩu thuận tiện hơn).
Thay thế khoá ký APEX
Android 10 giới thiệu định dạng tệp APEX để cài đặt các mô-đun hệ thống cấp thấp hơn. Như đã giải thích trong phần Ký APEX, mỗi tệp APEX được ký bằng hai khoá: một khoá cho hình ảnh hệ thống tệp mini trong APEX và khoá còn lại cho toàn bộ APEX.
Khi ký để phát hành, hai khoá ký cho tệp APEX sẽ được thay thế bằng khoá phát hành. Khoá tải trọng hệ thống tệp được chỉ định bằng cờ --extra_apex_payload
và toàn bộ khoá ký tệp APEX được chỉ định bằng cờ --extra_apks
.
Đối với sản phẩm tardis, giả sử bạn có cấu hình khoá sau đây cho các tệp APEX com.android.conscrypt.apex
, com.android.media.apex
và com.android.runtime.release.apex
.
name="com.android.conscrypt.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" name="com.android.media.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" name="com.android.runtime.release.apex" public_key="vendor/yoyodyne/security/testkeys/com.android.runtime.avbpubkey" private_key="vendor/yoyodyne/security/testkeys/com.android.runtime.pem" container_certificate="vendor/yoyodyne/security/testkeys/com.google.android.runtime.release_container.x509.pem" container_private_key="vendor/yoyodyne/security/testkeys/com.google.android.runtime.release_container.pk8"
Và bạn có các tệp sau đây chứa khoá phát hành:
vendor/yoyodyne/security/runtime_apex_container.x509.pem vendor/yoyodyne/security/runtime_apex_container.pk8 vendor/yoyodyne/security/runtime_apex_payload.pem
Lệnh sau đây sẽ ghi đè các khoá ký cho com.android.runtime.release.apex
và com.android.tzdata.apex
trong quá trình ký bản phát hành. Cụ thể, com.android.runtime.release.apex
được ký bằng các khoá phát hành được chỉ định (runtime_apex_container
cho tệp APEX và runtime_apex_payload
cho tải trọng hình ảnh tệp).
com.android.tzdata.apex
được coi là đã ký trước. Tất cả tệp APEX khác đều được xử lý theo cấu hình mặc định như được liệt kê trong tệp mục tiêu.
./build/make/tools/releasetools/sign_target_files_apks \
--default_key_mappings vendor/yoyodyne/security/tardis \
--extra_apks com.android.runtime.release.apex=vendor/yoyodyne/security/runtime_apex_container \
--extra_apex_payload_key com.android.runtime.release.apex=vendor/yoyodyne/security/runtime_apex_payload.pem \
--extra_apks com.android.media.apex= \
--extra_apex_payload_key com.android.media.apex= \
-o tardis-target_files.zip \
signed-tardis-target_files.zip
Việc chạy lệnh trên cung cấp các nhật ký sau:
[...] signing: com.android.runtime.release.apex container (vendor/yoyodyne/security/runtime_apex_container) : com.android.runtime.release.apex payload (vendor/yoyodyne/security/runtime_apex_payload.pem) NOT signing: com.android.conscrypt.apex (skipped due to special cert string) NOT signing: com.android.media.apex (skipped due to special cert string) [...]
Tùy chọn khác
Tập lệnh ký sign_target_files_apks
sẽ ghi đè nội dung mô tả bản dựng và vân tay số trong các tệp thuộc tính bản dựng để phản ánh rằng bản dựng đó là bản dựng đã ký. Cờ --tag_changes
kiểm soát những nội dung chỉnh sửa được thực hiện đối với vân tay. Chạy tập lệnh bằng -h
để xem tài liệu về tất cả cờ.
Tạo khoá theo cách thủ công
Android sử dụng khoá RSA 2048 bit với số mũ công khai là 3. Bạn có thể tạo cặp khoá riêng tư/chứng chỉ bằng cách sử dụng công cụ openssl từ openssl.org:
# generate RSA keyopenssl genrsa -3 -out temp.pem 2048
Generating RSA private key, 2048 bit long modulus ....+++ .....................+++ e is 3 (0x3) # create a certificate with the public part of the keyopenssl req -new -x509 -key temp.pem -out releasekey.x509.pem -days 10000 -subj '/C=US/ST=California/L=San Narciso/O=Yoyodyne, Inc./OU=Yoyodyne Mobility/CN=Yoyodyne/emailAddress=yoyodyne@example.com'
# create a PKCS#8-formatted version of the private keyopenssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt
# securely delete the temp.pem fileshred --remove temp.pem
Lệnh openssl pkcs8 nêu trên sẽ tạo một tệp .pk8 có mật khẩu no, phù hợp để sử dụng với hệ thống xây dựng. Để tạo một tệp .pk8 được bảo mật bằng mật khẩu (bạn nên thực hiện việc này cho tất cả các khoá phát hành thực tế), hãy thay thế đối số -nocrypt
bằng -passout stdin
; sau đó, openssl
sẽ mã hoá khoá riêng tư bằng mật khẩu được đọc từ dữ liệu đầu vào tiêu chuẩn. Không có lời nhắc nào được in, vì vậy nếu stdin là thiết bị đầu cuối, thì chương trình sẽ có vẻ như bị treo khi thực sự chỉ chờ bạn nhập mật khẩu. Bạn có thể sử dụng các giá trị khác cho đối số the-passout để đọc mật khẩu từ các vị trí khác; để biết thông tin chi tiết, hãy xem
tài liệu về openssl.
Tệp trung gian temp.pem chứa khoá riêng tư mà không có bất kỳ loại bảo vệ mật khẩu nào, vì vậy, hãy xử lý tệp này một cách cẩn thận khi tạo khoá phát hành. Cụ thể, tiện ích GNUshred có thể không hiệu quả trên mạng hoặc hệ thống tệp nhật ký. Bạn có thể sử dụng thư mục đang hoạt động nằm trong ổ RAM (chẳng hạn như phân vùng tmpfs) khi tạo khoá để đảm bảo các khoá trung gian không bị vô tình tiết lộ.
Tạo tệp hình ảnh
Khi đã có signed-target_files.zip
, bạn cần tạo hình ảnh để có thể đặt vào thiết bị.
Để tạo hình ảnh đã ký từ các tệp mục tiêu, hãy chạy lệnh sau từ thư mục gốc của cây Android:
img_from_target_files signed-target_files.zip signed-img.zipTệp kết quả
signed-img.zip
chứa tất cả các tệp .img
.
Để tải hình ảnh lên thiết bị, hãy sử dụng tính năng khởi động nhanh như sau:
fastboot update signed-img.zip