امضاکردن ساخت‌ها برای انتشار

تصاویر سیستم‌عامل Android از امضاهای رمزنگاری در دو مکان استفاده می‌کنند:

  1. هر فایل .apk درون تصویر باید امضا شده باشد. «مدیر بسته» Android به دو روش از امضای .apk استفاده می‌کند:
    • وقتی برنامه‌ای جایگزین می‌شود، باید با همان کلید برنامه قدیمی امضا شود تا بتواند به داده‌های برنامه قدیمی دسترسی پیدا کند. این موضوع هم برای به‌روزرسانی برنامه‌های کاربر با بازنویسی .apk و هم برای لغو برنامه سیستم با نسخه جدیدتری که تحت /data نصب شده است صادق است.
    • اگر دو یا چند برنامه بخواهند شناسه کاربری را هم‌رسانی کنند (تا بتوانند داده‌ها و غیره را هم‌رسانی کنند)، باید با کلید یکسانی امضا شوند.
  2. بسته‌های به‌روزرسانی OTA باید با یکی از کلیدهای موردانتظار سیستم امضا شوند، درغیراین‌صورت فرایند نصب آن‌ها را رد خواهد کرد.

کلیدهای انتشار

درخت Android شامل test-keys در build/target/product/security است. ساختن تصویر سیستم‌عامل Android بااستفاده از make همه فایل‌های .apk را بااستفاده از کلیدهای آزمایشی امضا می‌کند. ازآنجایی‌که کلیدهای آزمایشی به‌صورت عمومی شناخته‌شده هستند، هر کسی می‌تواند فایل‌های ‎.apk خود را با همان کلیدها امضا کند، که ممکن است به آن‌ها اجازه دهد برنامه‌های سیستم را که در تصویر سیستم‌عامل شما ساخته شده‌اند جایگزین یا ربوده کنند. به همین دلیل، بسیار مهم است که هر تصویر سیستم‌عامل Android که به‌طور عمومی منتشر یا مستقر می‌شود با مجموعه ویژه‌ای از کلیدهای انتشار که فقط شما به آن‌ها دسترسی دارید امضا شود.

برای تولید مجموعه کلیدهای انتشار منحصربه‌فرد خودتان، این فرمان‌ها را از ریشه درخت 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

‫$subject باید تغییر کند تا اطلاعات سازمانتان را منعکس کند. می‌توانید از هر دایرکتوری استفاده کنید، اما دقت کنید که مکان پشتیبان‌گیری‌شده و امنی را انتخاب کنید. برخی‌از فروشندگان انتخاب می‌کنند که کلید خصوصی خود را با یک گذرعبارت قوی رمزگذاری کنند و کلید رمزگذاری‌شده را در کنترل منبع ذخیره کنند؛ برخی دیگر کلیدهای انتشار خود را در جایی کاملاً متفاوت ذخیره می‌کنند، مثلاً در رایانه‌ای که به اینترنت متصل نیست.

برای تولید تصویر نسخه پخش، از این استفاده کنید:

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

برنامه sign_target_files_apks فایل‌های هدف .zip را به‌عنوان ورودی می‌گیرد و فایل‌های هدف جدیدی .zip تولید می‌کند که در آن همه فایل‌های .apk با کلیدهای جدید امضا شده‌اند. تصاویر جدیداً امضاشده را می‌توانید در IMAGES/ در signed-target_files.zip پیدا کنید.

امضا کردن بسته‌های OTA

فایل zip هدف-فایل‌های امضاشده را می‌توان بااستفاده از روش زیر به فایل zip به‌روزرسانی ازطریق هوا امضاشده تبدیل کرد:
ota_from_target_files \
-k  (--package_key) 
signed-target_files.zip \
signed-ota_update.zip

امضاها و بارگیری جانبی

بارگذاری جانبی از سازوکار درستی‌سنجی امضای بسته عادی بازیابی عبور نمی‌کند—بازیابی قبل‌از نصب بسته درستی‌سنجی می‌کند که بسته با یکی از کلیدهای خصوصی منطبق با کلیدهای عمومی ذخیره‌شده در پارتیشن بازیابی امضا شده باشد، درست همان‌طور که برای بسته‌ای که ازطریق هوا ارسال می‌شود درستی‌سنجی می‌کند.

بسته‌های به‌روزرسانی دریافتی از سیستم اصلی معمولاً دوبار درستی‌سنجی می‌شوند: یک‌بار توسط سیستم اصلی، بااستفاده از RecoverySystem.verifyPackage() روش در API اندروید، و سپس دوباره توسط بازیابی. ‫RecoverySystem API امضا را با کلیدهای عمومی ذخیره‌شده در سیستم اصلی، در فایل /system/etc/security/otacerts.zip (به‌طور پیش‌فرض)، بررسی می‌کند. «بازیابی» امضا را با کلیدهای عمومی ذخیره‌شده در دیسک RAM پارتیشن بازیابی، در فایل /res/keys، بررسی می‌کند.

به‌طور پیش‌فرض، فایل‌های هدف .zip تولیدشده توسط مجموعه‌های ساخت، گواهینامه OTA را تنظیم می‌کند تا با کلید آزمایشی مطابقت داشته باشد. در تصویر منتشرشده، باید از گواهینامه دیگری استفاده شود تا دستگاه‌ها بتوانند اصالت بسته به‌روزرسانی را تأیید کنند. ارسال پرچم -o به sign_target_files_apks، همان‌طور که در بخش قبلی نشان داده شده است، گواهی کلید آزمایشی را با گواهی کلید انتشار از فهرست راهنمای گواهی‌های شما جایگزین می‌کند.

معمولاً تصویر سیستم و روگرفت بازیابی مجموعه یکسانی از کلیدهای عمومی OTA را ذخیره می‌کنند. با افزودن کلید به فقط مجموعه کلیدهای بازیابی، می‌توان بسته‌هایی را امضا کرد که فقط ازطریق بارگیری جانبی قابل نصب هستند (با فرض اینکه سازوکار بارگیری به‌روزرسانی سیستم اصلی به‌درستی درستی‌سنجی دربرابر otacerts.zip را انجام می‌دهد). با تنظیم متغیر PRODUCT_EXTRA_RECOVERY_KEYS در تعریف محصولتان، می‌توانید کلیدهای اضافی را مشخص کنید تا فقط در بازیابی گنجانده شوند:

vendor/yoyodyne/tardis/products/tardis.mk
 [...]

PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload

این شامل کلید عمومی vendor/yoyodyne/security/tardis/sideload.x509.pem در فایل کلیدهای بازیابی می‌شود تا بتواند بسته‌های امضاشده با آن را نصب کند. کلید اضافی در otacerts.zip گنجانده نشده است، بنابراین سیستم‌هایی که بسته‌های بارگیری‌شده را به‌درستی تأیید می‌کنند، بازیابی را برای بسته‌های امضاشده با این کلید فراخوانی نمی‌کنند.

گواهینامه‌ها و کلیدهای خصوصی

هر کلید در دو فایل ارائه می‌شود: گواهی، که دارای پسوند .x509.pem است، و کلید خصوصی، که دارای پسوند .pk8 است. کلید خصوصی باید محرمانه نگه داشته شود و برای امضا کردن بسته لازم است. خود کلید ممکن است با گذرواژه محافظت شود. گواهینامه، درمقابل، فقط حاوی بخش عمومی کلید است، بنابراین می‌تواند به‌طور گسترده توزیع شود. از آن برای درستی‌سنجی اینکه بسته با کلید خصوصی مربوطه امضا شده است استفاده می‌شود.

ساخت استاندارد Android از پنج کلید استفاده می‌کند که همه آن‌ها در build/target/product/security قرار دارند:

کلید آزمایشی
کلید پیش‌فرض عمومی برای بسته‌هایی که کلید دیگری برای آن‌ها مشخص نشده است.
پلتفورم
کلید آزمایشی برای بسته‌هایی که بخشی از پلاتفرم اصلی هستند.
هم‌رسانی‌شده
کلید آزمایشی برای مواردی که در فرایند خانه/مخاطبین هم‌رسانی می‌شوند.
رسانه
کلید آزمایشی برای بسته‌هایی که بخشی از سیستم رسانه/بارگیری هستند.
پشته شبکه
کلید آزمایشی برای بسته‌هایی که بخشی از سیستم شبکه‌سازی هستند. از کلید networkstack برای امضای فایل‌های باینری طراحی‌شده به‌عنوان واحد‌های اصلی استفاده می‌شود. اگر به‌روزرسانی‌های ماژول شما به‌طور جداگانه ساخته شده و به‌عنوان پیش‌ساخته در تصویر دستگاه شما ادغام شده‌اند، ممکن است نیازی به تولید کلید networkstack در درخت منبع Android نداشته باشید.

بسته‌های تکی یکی از این کلیدها را با تنظیم LOCAL_CERTIFICATE در فایل Android.mk خود مشخص می‌کنند. (اگر این متغیر تنظیم نشده باشد، از testkey استفاده می‌شود.) همچنین می‌توانید کلید کاملاً متفاوتی را براساس نام مسیر مشخص کنید، برای مثال:

device/yoyodyne/apps/SpecialApp/Android.mk
 [...]

LOCAL_CERTIFICATE := device/yoyodyne/security/special

اکنون ساخت از کلید device/yoyodyne/security/special.{x509.pem,pk8} برای امضای SpecialApp.apk استفاده می‌کند. ساختمان فقط می‌تواند از کلیدهای خصوصی که با گذرواژه محافظت نمی‌شوند استفاده کند.

گزینه‌های پیشرفته امضا کردن

جایگزینی کلید امضای APK

نوشتار امضا sign_target_files_apks روی فایل‌های هدف تولیدشده برای ساخت کار می‌کند. همه اطلاعات مربوط به گواهی‌ها و کلیدهای خصوصی استفاده‌شده در زمان ساخت در فایل‌های هدف گنجانده شده است. هنگام اجرای نوشتار امضا برای امضا کردن نسخه پخش، کلیدهای امضا براساس نام کلید یا نام APK می‌توانند جایگزین شوند.

از پرچم‌های --key_mapping و --default_key_mappings برای مشخص کردن جایگزینی کلید براساس نام کلید استفاده کنید:

  • پرچم --key_mapping src_key=dest_key جایگزین هر کلید را به‌صورت جداگانه مشخص می‌کند.
  • پرچم --default_key_mappings dir دایرکتوری‌ای با پنج کلید را برای جایگزین کردن همه کلیدها در build/target/product/security مشخص می‌کند؛ این معادل استفاده از --key_mapping به‌مدت پنج بار برای مشخص کردن نگاشت‌ها است.
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

از پرچم --extra_apks apk_name1,apk_name2,...=key برای مشخص کردن جایگزین‌های کلید امضا براساس نام‌های APK استفاده کنید. اگر key خالی بماند، اسکریپت با APKهای مشخص‌شده به‌عنوان ازپیش امضاشده رفتار می‌کند.

برای محصول فرضی تاردیز، به شش کلید محافظت‌شده با گذرواژه نیاز دارید: پنج کلید برای جایگزینی پنج کلید در build/target/product/security، و یک کلید برای جایگزینی کلید اضافی device/yoyodyne/security/special که SpecialApp در مثال بالا به آن نیاز دارد. اگر کلیدها در فایل‌های زیر بودند:

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

سپس همه برنامه‌ها را به این صورت امضا می‌کنید:

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

این کار موارد زیر را نشان می‌دهد:

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.

پس‌از درخواست گذرواژه از کاربر برای همه کلیدهای محافظت‌شده با گذرواژه، دستورگان همه فایل‌های APK را در هدف ورودی .zip با کلیدهای انتشار مجدداً امضا می‌کند. قبل‌از اجرای فرمان، می‌توانید متغیر محیطی ANDROID_PW_FILE را روی نام فایل موقتی تنظیم کنید؛ سپس نوشتار ویرایشگرتان را فرا می‌خواند تا به شما امکان دهد گذرواژه‌های همه کلیدها را وارد کنید (این روش ممکن است برای وارد کردن گذرواژه‌ها راحت‌تر باشد).

جایگزینی کلید امضای APEX

‫Android 10 قالب فایل APEX را برای نصب واحد‌های سیستم سطح پایین معرفی می‌کند. همان‌طور که در امضای APEX توضیح داده شده است، هر فایل APEX با دو کلید امضا می‌شود: یکی برای تصویر سیستم فایل کوچک درون APEX و دیگری برای کل APEX.

هنگام امضا کردن برای انتشار، دو کلید امضا برای فایل APEX با کلیدهای انتشار جایگزین می‌شوند. کلید بار داده سیستم فایل با پرچم --extra_apex_payload و کلید امضای کل فایل APEX با پرچم --extra_apks مشخص می‌شود.

برای محصول tardis، فرض کنید پیکربندی کلید زیر را برای فایل‌های com.android.conscrypt.apex، com.android.media.apex، و com.android.runtime.release.apex 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"

و فایل‌های زیر را دارید که حاوی کلیدهای انتشار است:

vendor/yoyodyne/security/runtime_apex_container.x509.pem
vendor/yoyodyne/security/runtime_apex_container.pk8
vendor/yoyodyne/security/runtime_apex_payload.pem

فرمان زیر کلیدهای امضا را برای com.android.runtime.release.apex و com.android.tzdata.apex درطول امضای نسخه برگردان لغو می‌کند. به‌طور خاص، com.android.runtime.release.apex با کلیدهای انتشار مشخص‌شده امضا شده است (runtime_apex_container برای فایل APEX، و runtime_apex_payload برای بار داده تصویر فایل). ‫com.android.tzdata.apex به‌عنوان پیش‌امضاشده درنظر گرفته می‌شود. همه فایل‌های APEX دیگر توسط پیکربندی پیش‌فرض همان‌طور که در فایل‌های هدف فهرست شده است مدیریت می‌شوند.

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

با اجرای فرمان بالا، گزارش‌های زیر ارائه می‌شود:

        [...]
    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)
        [...]

گزینه‌های دیگر

برنامه sign_target_files_apks امضاکننده فیلمنامه شرح ساخت و اثر انگشت را در فایل‌های ویژگی ساخت بازنویسی می‌کند تا نشان دهد ساخت یک ساخت امضاشده است. پرچم --tag_changes کنترل می‌کند که چه ویرایش‌هایی روی اثر انگشت انجام شود. برای دیدن اسناد مربوط به همه پرچم‌ها، اسکریپت را با -h اجرا کنید.

تولید دستی کلیدها

‫Android از کلیدهای RSA ۲۰۴۸ بیتی با توان عمومی ۳ استفاده می‌کند. می‌توانید جفت‌های گواهینامه/کلید خصوصی را بااستفاده از ابزار openssl از 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

دستور openssl pkcs8 که در بالا داده شده است یک فایل pk8 .با بدون گذرواژه ایجاد می‌کند که برای استفاده با سیستم ساخت مناسب است. برای ایجاد فایل .pk8 ایمن‌شده با گذرواژه (که باید برای همه کلیدهای انتشار واقعی انجام دهید)، آرگومان -nocrypt را با -passout stdin جایگزین کنید؛ سپس openssl کلید خصوصی را با گذرواژه‌ای که از ورودی استاندارد خوانده می‌شود رمزگذاری می‌کند. پیام‌واره‌ای چاپ نمی‌شود، بنابراین اگر stdin ترمینال باشد، برنامه به‌نظر می‌رسد که معلق است، درحالی‌که درواقع فقط منتظر است تا گذرواژه را وارد کنید. از مقادیر دیگر می‌توان برای پارامتر -passout استفاده کرد تا گذرواژه از مکان‌های دیگر خوانده شود؛ برای جزئیات، به اسناد openssl مراجعه کنید.

فایل واسطه temp.pem حاوی کلید خصوصی بدون هیچ‌گونه محافظت گذرواژه است، بنابراین هنگام تولید کلیدهای نسخه پخش، آن را با دقت دور بیندازید. به‌طور خاص، ابزار GNUshred ممکن است در شبکه‌ها یا سیستم‌های فایل ثبت‌شده مؤثر نباشد. هنگام تولید کلیدها، می‌توانید از دایرکتوری کاری واقع در دیسک RAM (مانند پارتیشن tmpfs) استفاده کنید تا مطمئن شوید که واسطه‌ها به‌طور ناخواسته فاش نمی‌شوند.

ایجاد فایل‌های تصویر

وقتی signed-target_files.zip را دارید، باید تصویر را بسازید تا بتوانید آن را در دستگاه قرار دهید. برای ایجاد تصویر امضاشده از فایل‌های هدف، فرمان زیر را از ریشه درخت Android اجرا کنید:

img_from_target_files signed-target_files.zip signed-img.zip
فایل حاصل، signed-img.zip، حاوی همه .img فایل است. برای بار کردن تصویر در دستگاه، از fastboot به‌صورت زیر استفاده کنید:
fastboot update signed-img.zip