Android 11 תומך בשיטת חתימה שמתאימה לסטרימינג עם APK signature scheme v4. החתימה בגרסה 4 מבוססת על עץ הגיבוב של מרקל (Merkle hash tree)
שמחושב על כל הבייטים של ה-APK. הסכימה זהה בדיוק למבנה של עץ הגיבוב fs-verity (לדוגמה, ריפוד המלח באפסים וריפוד הבלוק האחרון באפסים). ב-Android 11, החתימה מאוחסנת בקובץ נפרד, <apk name>.apk.idsig. חתימת v4 דורשת חתימה משלימה מסוג v2 או v3.
תבנית קובץ
כל השדות המספריים הם בפורמט little endian. כל השדות תופסים בדיוק את מספר הבייטים שמופיע ב-sizeof() שלהם, ללא ריפוד או יישור מרומזים.
מבנה העזרה הבא מפשט את ההגדרות:
template <class SizeT> struct sized_bytes { SizeT size; byte bytes[size]; };
התוכן של הקובץ הראשי:
struct V4Signature {
int32 version; // only version 2 is supported as of now
sized_bytes<int32> hashing_info;
sized_bytes<int32> signing_info;
sized_bytes<int32> merkle_tree; // optional
};hashing_info הוא הפרמטר שמשמש ליצירת עץ גיבוב
בתוספת גיבוב השורש:
struct hashing_info.bytes {
int32 hash_algorithm; // only 1 == SHA256 supported
int8 log2_blocksize; // only 12 (block size 4096) supported now
sized_bytes<int32> salt; // used exactly as in fs-verity, 32 bytes max
sized_bytes<int32> raw_root_hash; // salted digest of the first Merkle tree page
};signing_info הוא המבנה הבא:
struct signing_info.bytes {
sized_bytes<int32> apk_digest; // used to match with the corresponding APK
sized_bytes<int32> x509_certificate; // ASN.1 DER form
sized_bytes<int32> additional_data; // a free-form binary data blob
sized_bytes<int32> public_key; // ASN.1 DER, must match the x509_certificate
int32 signature_algorithm_id; // see the APK v2 doc for the list
sized_bytes<int32> signature;
};הערך apk_digest נלקח מחסימת החתימה v3 של ה-APK. אם החסימה הזו לא קיימת, היא נלקחת מהחסימה v2 (ראו apk_digest).
כדי ליצור ולאמת, קוד signature צריך לבצע סריאליזציה של הנתונים הבאים ל-blob בינארי ולהעביר אותו לאלגוריתם החתימה והאימות כנתונים חתומים:
struct V4DataForSigning {
int32 size;
int64 file_size; // the size of the file that's been hashed.
hashing_info.hash_algorithm;
hashing_info.log2_blocksize;
hashing_info.salt;
hashing_info.raw_root_hash;
signing_info.apk_digest;
signing_info.x509_certificate;
signing_info.additional_data;
};merkle_tree הוא עץ מרקל המלא של ה-APK, שמחושב כמו שמתואר במסמכי התיעוד של fs-verity.
יצרנים וצרכנים
apksigner הכלי Android SDK יוצר את קובץ החתימה v4 אם מריצים אותו עם פרמטרים שמוגדרים כברירת מחדל. אפשר להשבית את חתימה בגרסה 4 באותה דרך שבה משביתים את שיטות החתימה האחרות. הכלי יכול גם לאמת אם חתימת v4 תקפה.
adb מצפה שקובץ .apk.idsig יהיה לצד קובץ ה-APK כשמריצים את הפקודה adb install --incremental. adb גם משתמש בקובץ IDSIG
כדי לנסות התקנה מצטברת כברירת מחדל, ואם הקובץ חסר או לא תקין, הוא חוזר להתקנה רגילה.
כשיוצרים סשן התקנה, ה-API החדש להתקנה בהזרמה ב-PackageInstaller מקבל את חתימת v4 המוסרת כארגומנט נפרד כשמוסיפים קובץ לסשן.
בשלב הזה, signing_info מועבר ל-IncFS כבלוב שלם. מערכת IncFS מחלצת את הגיבוב הבסיסי מה-blob.
כשמבצעים קומיט של סשן ההתקנה, PackageManagerService מבצע קריאה של ioctl כדי לאחזר את ה-blob של signing_info מ-IncFS, מנתח אותו ומאמת את החתימה.
רכיב Incremental Data Loader מעביר בסטרימינג את החלק של עץ מרקל בחתימה דרך ה-API המקורי של כלי העברת הנתונים. הפקודה package service shell install-incremental מקבלת את קובץ החתימה v4 שבו הוסרו נתונים, בקידוד Base64, כפרמטר לכל קובץ שנוסף. צריך לשלוח את עץ מרקל המתאים ל-stdin של הפקודה.
apk_digest
apk_digest הוא סיכום התוכן הראשון שזמין בסדר הבא:
- V3, בלוק של 1 MB, SHA2-512 (
CONTENT_DIGEST_CHUNKED_SHA512) - V3, בלוק של 4 KB, SHA2-256 (
CONTENT_DIGEST_VERITY_CHUNKED_SHA256) - V3, בלוק של 1 MB, SHA2-256 (
CONTENT_DIGEST_CHUNKED_SHA256) - V2, SHA2-512
- V2, SHA2-256
מידע נוסף זמין בקטע length-prefixed sequence of length-prefixed signer ב-APK signature scheme v3.
אימות ובדיקה
האיור הבא מציג את תהליך האימות של APK בגרסה 4:

איור 1. תהליך אימות APK גרסה 4.
מאמתים את ההטמעה באמצעות בדיקות יחידה של התכונה ו-CTS:
CtsIncrementalInstallHostTestCases/android/cts/hostsidetests/incrementalinstall
בדיקת פורמט החתימה
כדי לבדוק את פורמט החתימה, מגדירים סביבת בנייה ומריצים את הבדיקות הידניות הבאות:
$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest
בדיקת פורמט החתימה באמצעות Android SDK (ADB ו-apksigner)
כדי לבדוק את פורמט החתימה באמצעות Android SDK:
- מגדירים סביבת בנייה ומוודאים שהשלמתם את ההטמעה של IncFS.
- מצמידים את גרסת ה-build למכשיר פיזי או לאמולטור.
- יוצרים או מקבלים APK קיים ואז יוצרים מפתח חתימה לניפוי באגים.
- חותמים על ה-APK ומתקינים אותו בפורמט חתימה v4
מתיקיית build-tools.
כניסה
$ ./apksigner sign --ks debug.keystore game.apk
התקנה
$ ./adb install game.apk
איפה אפשר למצוא את הניסויים האלה
/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java