Ký bản dựng để phát hành

Hình ảnh hệ điều hành Android sử dụng chữ ký mật mã ở hai vị trí:

  1. Mỗi tệp .apk 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 hai 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 người dùng bằng cách ghi đè .apk và khi ghi đè một ứng dụng hệ thống bằng phiên bản mới hơn được cài đặt trong /data.
    • Nếu muốn chia sẻ mã nhận dạng người dùng (để có thể chia sẻ dữ liệu, v.v.), thì 2 hoặc nhiều ứng dụng phải được ký bằng cùng một khoá.
  2. Các 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 hoặc quy trình cài đặt sẽ từ chối các gói đó.

Khoá phát hành

Cây Android có test-keys trong build/target/product/security. Tạo một hình ảnh hệ điều hành Android bằng cách sử dụng make sẽ ký tất cả các tệp .apk bằng test-keys. Vì các khoá kiểm thử được công khai, nên bất kỳ ai cũng có thể ký các tệp .apk của riêng họ bằng các khoá tương tự. Điều này có thể cho phép họ thay thế hoặc chiếm đoạt 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, việc ký bất kỳ hình ảnh hệ điều hành Android nào được phát hành hoặc triển khai công khai bằng một bộ release-keys đặc biệt mà chỉ bạn mới có quyền truy cập là điều rất quan trọng.

Để tạo bộ khoá phát hành riêng biệt, 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à bảo mật. Một số nhà cung cấp chọn mã hoá khoá riêng tư của họ bằng một cụm mật khẩu mạnh và lưu trữ khoá đã mã hoá trong tính năng kiểm soát nguồn; những nhà cung cấp khác lưu trữ khoá phát hành ở một nơi hoàn toàn khác, chẳng hạn như trên máy tính không có kết nối Internet.

Để tạo một 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 .zip target-files làm đầu vào và tạo ra một .zip target-files mới, trong đó tất cả các tệp .apk đều đã được ký bằng các khoá mới. Bạn có thể tìm thấy các hình ảnh mới được ký trong IMAGES/ trong signed-target_files.zip.

Ký các gói OTA

Bạn có thể chuyển đổi tệp zip target-files đã ký thành tệp zip OTA update đã ký bằ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 qua một bên

Tính năng tải ứng dụng bên ngoài không bỏ qua cơ chế xác minh chữ ký gói thông thường của chế độ khôi phục – trước khi cài đặt một gói, chế độ 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 các 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.

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 do hệ thống chính thực hiện bằng phương thức RecoverySystem.verifyPackage() trong API Android, sau đó do quy trình khôi phục thực hiện lại. API RecoverySystem sẽ kiểm tra chữ ký dựa trên các 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 ổ đĩa RAM của phân vùng khôi phục, trong tệp /res/keys.

Theo mặc định, .zip target-files do bản dựng tạo ra sẽ đặt chứng chỉ OTA sao cho khớp với khoá kiểm thử. Trên một hình ảnh đã phát hành, bạn 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. 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 trong thư mục certs.

Thông thường, hình ảnh hệ thống và hình ảnh khôi phục sẽ 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 phương thức tải lên từ bên ngoài (giả sử cơ chế tải bản cập nhật xuống của hệ thống chính đang thực hiện quy trình xác minh chính xác đối 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

Trong đó có 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á này. Tuy nhiên, khoá bổ sung không có trong otacerts.zip, vì vậy, những hệ thống xác minh chính xác các gói đã tải xuống sẽ không gọi quy trình khôi phục cho các gói được ký bằng khoá này.

Chứng chỉ và khoá riêng tư

Mỗi khoá có trong hai tệp: chứng chỉ có đuôi .x509.pem và khoá riêng tư có đuôi .pk8. Bạn phải giữ bí mật khoá riêng tư và cần có khoá này để ký một gói. Bản thân khoá cũng có thể được bảo vệ bằng mật khẩu. Ngược lại, chứng chỉ chỉ chứa nửa công khai của khoá, vì vậy, chứng chỉ có thể được phân phối rộng rãi. Khoá này dùng để xác minh rằng một gói đã được ký bằng khoá riêng tư tương ứng.

Bản dựng Android tiêu chuẩn sử 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 cốt lõi.
đã chia sẻ
Khoá kiểm thử 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/tải xuống.
networkstack
Khoá kiểm thử cho các gói thuộc hệ thống mạng. Khoá networkstack được dùng để ký các tệp nhị phân được thiết kế dưới dạng Các thành phần hệ thống theo mô-đun . Nếu các bản cập nhật mô-đun được tạo riêng và tích hợp dưới dạng các bản dựng sẵn trong hình ảnh thiết bị, thì bạn có thể không cần tạo khoá networkstack trong cây nguồn Android.

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 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 tên đườ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.

Các lựa 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 dùng tại thời điểm tạo bản dựng đều có trong các tệp đích. Khi chạy tập lệnh ký để ký cho bản phát hành, bạn có thể thay thế các khoá ký dựa trên tên khoá hoặc tên APK.

Dùng cờ --key_mapping--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 nội dung thay thế cho từng khoá một.
  • Cờ --default_key_mappings dir chỉ định một thư mục có 5 khoá để thay thế tất cả các khoá trong build/target/product/security; tương đương với việc sử dụng --key_mapping 5 lần để chỉ định các mối liên kết.
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 nội dung thay thế khoá ký dựa trên tên APK. Nếu bạn để trống key, tập lệnh sẽ coi các 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ả cá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ị những thông tin sau:

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ả cá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 thuận tiện hơn để nhập mật khẩu).

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. 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, 2 khoá ký cho một tệp APEX sẽ được thay thế bằng các khoá phát hành. Khoá tải trọng của 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.apexcom.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.apexcom.android.tzdata.apex trong quá trình ký phát hành. Cụ thể, com.android.runtime.release.apex được ký bằng các khoá phát hành đã 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ả các tệp APEX khác đều được xử lý bằng cấu hình mặc định như được liệt kê trong các tệp đích.

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

Khi chạy lệnh trên, bạn sẽ thấy 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

Kịch bản ký sign_target_files_apks sẽ ghi lại 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à một 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á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ác cặp chứng chỉ/khoá riêng tư bằng công cụ openssl từ openssl.org:

# generate RSA key
openssl 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 key
openssl 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 key
openssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt

# securely delete the temp.pem file
shred --remove temp.pem

Lệnh openssl pkcs8 ở trên sẽ tạo một tệp .pk8 không có mật khẩu, phù hợp để sử dụng với hệ thống tạo bản dựng. Để tạo một tệp .pk8 được bảo mật bằng mật khẩu (bạn nên làm 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 từ đầ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, chương trình sẽ xuất hiện để treo khi thực sự chỉ chờ bạn nhập mật khẩu. Bạn có thể dùng các giá trị khác cho đối số -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 openssl.

Tệp trung gian temp.pem chứa khoá riêng tư mà không có bất kỳ loại mật khẩu bảo vệ nào, vì vậy, hãy loại bỏ 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 hệ thống tệp nhật ký hoặc mạng. Bạn có thể sử dụng một thư mục đang hoạt động nằm trong đĩa RAM (chẳng hạn như phân vùng tmpfs) khi tạo khoá để đảm bảo các tệp trung gian không bị vô tình lộ ra.

Tạo tệp hình ảnh

Khi có signed-target_files.zip, bạn cần tạo hình ảnh để có thể đưa hình ảnh đó vào một thiết bị. Để tạo hình ảnh đã ký từ các tệp đích, hãy chạy lệnh sau từ gốc của cây Android:

img_from_target_files signed-target_files.zip signed-img.zip
Tệ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 fastboot như sau:
fastboot update signed-img.zip