סכימת חתימת APK גרסה 4

Android 11 תומך בסכמת חתימה תואמת לסטרימינג עם ה-APK Signature Scheme v4. חתימת גרסה 4 מבוססת על עץ הגיבוב של Merkle שמחושבת לכל הבייטים של ה-APK. הוא תואם בדיוק למבנה של עץ הגיבוב (hash) fs-verity (לדוגמה, אפס מרווח פנימי את ה-salt ואת המרווח הפנימי בבלוק האחרון). החתימה נשמרת ב-Android 11 בקובץ נפרד, <apk name>.apk.idsigחתימת v4 מחייבת חתימת v2 או v3 משלימה.

תבנית קובץ

כל השדות המספריים מופיעים באותיות קטנות. כל השדות מכילים מספר מדויק של בייטים בתור 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 הוא הפרמטרים שמשמשים לעץ הגיבוב (hash) יצירה + גיבוב (hash) של השורש:

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, או אם לא, נוכחי, מחסימת גרסה 2 (מידע נוסף זמין בכתובת 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;
};
  1. merkle_tree הוא עץ Merkle המלא של ה-APK, המחושב כפי שמתואר במסמכי התיעוד של fs-verity.

יצרנים וצרכנים

apksigner כלי Android SDK יוצר עכשיו את קובץ החתימה בגרסה 4 אם משתמשים בו עם פרמטרים שמוגדרים כברירת מחדל. ניתן להשבית את חתימת V4 באותה הדרך כמו הונאות החתימה האחרות. הוא יכול גם לוודא שחתימת V4 תקין.

adb מצפה שקובץ ה- .APK.idsig יופיע לצד ה-APK כאשר: הרצת הפקודה adb install --incremental
היא תשתמש גם בקובץ ה- .idsig כדי לנסות התקנה מצטברת באמצעות כברירת מחדל, תתבצע חזרה להתקנה רגילה אם היא חסרה או לא תקין.

כשיוצרים סשן התקנה, ממשק ה-API החדש להתקנת סטרימינג ב-PackageInstaller מקבל את הפסים חתימת v4 כארגומנט נפרד כשמוסיפים קובץ לסשן. בשלב הזה, signing_info מועבר ל-incfs בתור ב-blob. Incfs שולף את גיבוב השורש מה-blob.

כאשר מתבצעת מחויבות להפעלת ההתקנה, PackageManagerService מבצע ioctl לאחזור ה-blob של sign_info מ-incf, מנתח אותו ומאמת את החתימה.

הרכיב של הכלי לטעינת נתונים מצטבר צפוי להזרים את החלק של עץ Merkle של החתימה דרך ה-API המקורי של טוען הנתונים.
פקודת מעטפת השירות install-incremental של package מקבל את קובץ החתימה v4 הפגום שמקודד כ-base64 כפרמטר נוסף קובץ. צריך לשלוח את עץ ה-Merkle המתאים stdin

APK_digest

apk_digest הוא תקציר התוכן הזמין הראשון לפי הסדר:

  1. V3, בלוק 1MB, SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512),
  2. V3, בלוק 4KB, SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256),
  3. V3, בלוק 1MB, SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256),
  4. V2, SHA2-512,
  5. V2, SHA2-256.

לעיון בקטע אורך עם קידומת רצף של חתימות עם קידומת באורך מצטבר ב-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. לאחר מכן Flash ה-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