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

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

  1. 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á.
  2. 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.
networkstack
Khoá kiểm thử cho các gói thuộc hệ thống mạng. Khoá mạng được dùng để ký các tệp nhị phân được thiết kế dưới dạng Thành phần hệ thống mô-đun . Nếu bản cập nhật mô-đun được tạo riêng biệt và tích hợp dưới dạng bản dựng trước trong hình ảnh thiết bị, thì bạn có thể không cần tạo khoá ngăn xếp mạng 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 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--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á trong build/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.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ý 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 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 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.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 tính năng khởi động nhanh như sau:
fastboot update signed-img.zip