تابلوهای ساخت برای انتشار

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

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

کلیدهای رهاسازی

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

برای تولید مجموعه منحصر به فرد کلیدهای انتشار خود، این دستورات را از ریشه درخت اندروید خود اجرا کنید:

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 را امضا کنید

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

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

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

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

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

معمولاً تصویر سیستم و تصویر بازیابی، مجموعه‌ی یکسانی از کلیدهای عمومی 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 دارد. کلید خصوصی باید مخفی نگه داشته شود و برای امضای یک بسته مورد نیاز است. خود کلید ممکن است توسط یک رمز عبور محافظت شود. در مقابل، گواهی‌نامه فقط شامل نیمه عمومی کلید است، بنابراین می‌توان آن را به طور گسترده توزیع کرد. از آن برای تأیید امضای یک بسته توسط کلید خصوصی مربوطه استفاده می‌شود.

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

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

بسته‌های جداگانه با تنظیم 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های مشخص شده به عنوان از پیش امضا شده رفتار می‌کند.

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

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

هنگام امضا برای انتشار، دو کلید امضای فایل APEX با کلیدهای انتشار جایگزین می‌شوند. کلید payload سیستم فایل با پرچم --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 برای فایل image 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 اجرا کنید تا مستندات مربوط به همه پرچم‌ها را ببینید.

تولید کلیدها به صورت دستی

اندروید از کلیدهای RSA 2048 بیتی با توان عمومی 3 استفاده می‌کند. می‌توانید با استفاده از ابزار 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 را دارید، باید ایمیج را ایجاد کنید تا بتوانید آن را روی دستگاه قرار دهید. برای ایجاد ایمیج امضا شده از فایل‌های هدف، دستور زیر را از ریشه درخت اندروید اجرا کنید:

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