סכימת חתימות APK v3

אנדרואיד 9 תומך בסיבוב מפתח APK , המעניק לאפליקציות את היכולת לשנות את מפתח החתימה שלהן כחלק מעדכון APK. כדי להפוך את הרוטציה למעשית, חבילות APK חייבות לציין רמות אמון בין מפתח החתימה החדש לישן. כדי לתמוך בסיבוב מפתחות, עדכנו את סכימת חתימת ה-APK מ-v2 ל-v3 כדי לאפשר שימוש במפתחות החדשים והישנים. V3 מוסיף מידע על גרסאות ה-SDK הנתמכות ומבנה הוכחת סיבוב לבלוק החתימה של APK.

חסימת חתימת APK

כדי לשמור על תאימות לאחור עם פורמט v1 APK, חתימות APK v2 ו-v3 מאוחסנות בתוך בלוק חתימת APK, הממוקם מיד לפני המדריך המרכזי של ZIP.

פורמט v3 APK Signing Block זהה ל-v2 . חתימת v3 של ה-APK מאוחסנת כזוג ערך מזהה עם מזהה 0xf05368c0.

APK Signature Scheme v3 Block

סכימת v3 תוכננה להיות דומה מאוד לסכימת v2 . יש לו אותו פורמט כללי ותומך באותם מזהי אלגוריתמי חתימה , גדלי מפתח ועיקולי EC.

עם זאת, סכימת v3 מוסיפה מידע על גרסאות ה-SDK הנתמכות ומבנה הוכחת סיבוב.

פוּרמָט

APK Signature Scheme v3 Block מאוחסן בתוך בלוק החתימה APK תחת המזהה 0xf05368c0 .

הפורמט של בלוק ה-APK Signature Scheme v3 עוקב אחר הפורמט של v2:

  • רצף עם קידומת אורך של signer עם קידומת אורך:
    • signed data עם קידומת אורך:
      • רצף עם קידומת אורך של digests עם קידומת אורך:
        • signature algorithm ID (4 בתים)
        • digest (קידומת אורך)
      • רצף עם קידומת אורך של certificates X.509 :
        • certificate X.509 עם קידומת אורך (טופס DER ASN.1)
      • minSDK (uint32) - יש להתעלם מהחותם הזה אם גרסת הפלטפורמה נמוכה ממספר זה.
      • maxSDK (uint32) - יש להתעלם מהחותם הזה אם גרסת הפלטפורמה היא מעל המספר הזה.
      • רצף עם קידומת אורך של additional attributes עם קידומת אורך:
        • ID (uint32)
        • value (אורך משתנה: אורך התכונה הנוספת - 4 בתים)
        • ID - 0x3ba06f8c
        • value - מבנה הוכחת סיבוב
    • minSDK (uint32) - שכפול של ערך minSDK בקטע נתונים חתומים - משמש כדי לדלג על אימות של חתימה זו אם הפלטפורמה הנוכחית אינה בטווח. חייב להתאים לערך הנתונים החתום.
    • maxSDK (uint32) - שכפול של ערך maxSDK בקטע הנתונים החתומים - משמש כדי לדלג על אימות של חתימה זו אם הפלטפורמה הנוכחית אינה בטווח. חייב להתאים לערך הנתונים החתום.
    • רצף של signatures עם קידומת אורך:
      • signature algorithm ID (uint32)
      • signature עם קידומת אורך על פני signed data
    • public key עם קידומת אורך (SubjectPublicKeyInfo, טופס ASN.1 DER)

מבנים של הוכחת סיבוב ומבנים מהימנים בעצמם

מבנה הוכחת הסיבוב מאפשר לאפליקציות לסובב את אישור החתימה שלהן מבלי להיחסם באפליקציות אחרות איתן הן מתקשרות. כדי להשיג זאת, חתימות אפליקציה מכילות שתי פיסות נתונים חדשות:

  • טענה עבור צדדים שלישיים שניתן לסמוך על אישור החתימה של האפליקציה בכל מקום שבו ניתן לסמוך על קודמיו
  • אישורי החתימה הישנים יותר של האפליקציה שהאפליקציה עצמה עדיין סומכת עליהם

תכונת הוכחת סיבוב במקטע נתונים חתומים מורכבת מרשימה מקושרת בודדת, כאשר כל צומת מכיל אישור חתימה המשמש לחתימה על גרסאות קודמות של האפליקציה. תכונה זו אמורה להכיל את מבני הנתונים המושגיים של הוכחת סיבוב ומבני נתוני אמון עצמיים-ישנים. הרשימה מסודרת לפי גרסה עם אישור החתימה הישן ביותר המתאים לצומת השורש. מבנה הנתונים של הוכחת סיבוב נבנה על ידי כך שה-cert בכל צומת סימן הבא ברשימה, ובכך החדירת הוכחות לכל מפתח חדש שהוא צריך להיות מהימן כמו המפתח/ים הישנים יותר.

מבנה הנתונים מהימן-עצמי של אישורים ישנים נבנה על ידי הוספת דגלים לכל צומת המציינים את החברות והמאפיינים שלו בסט. לדוגמה, עשוי להיות קיים דגל המציין שאישור החתימה בצומת נתון מהימן לקבלת הרשאות חתימה של Android. דגל זה מאפשר לאפליקציות אחרות החתומות על ידי האישור הישן יותר לקבל הרשאת חתימה שהוגדרה על ידי אפליקציה החתומה עם אישור החתימה החדש. מכיוון שכל תכונת הוכחת הסיבוב נמצאת בקטע הנתונים החתומים של שדה signer v3, היא מוגנת על ידי המפתח המשמש לחתימה על ה-apk המכיל.

פורמט זה מונע ריבוי מפתחות חתימה והתכנסות של תעודות חתימה קדומות שונות לאחד (מספר צמתים מתחילים לשקע משותף).

פוּרמָט

הוכחת הסיבוב מאוחסנת בתוך בלוק APK Signature Scheme v3 תחת מזהה 0x3ba06f8c . הפורמט שלו הוא:

  • רצף עם קידומת אורך של levels עם קידומת אורך:
    • signed data עם קידומת אורך (לפי אישור קודם - אם קיים)
      • certificate X.509 עם קידומת אורך (טופס DER ASN.1)
      • signature algorithm ID (uint32) - אלגוריתם בשימוש cert ברמה הקודמת
    • flags (uint32) - דגלים המציינים אם אישור זה צריך להיות במבנה ה-confirmed-old-certs אמין או לא, ועבור אילו פעולות.
    • signature algorithm ID (uint32) - חייב להתאים לזה ממקטע הנתונים החתומים ברמה הבאה.
    • signature עם קידומת אורך מעל signed data לעיל

מספר תעודות

אנדרואיד מתייחסת כרגע ל-APK שנחתם עם אישורים מרובים כבעל זהות חתימה ייחודית נפרדת מהאישורים הכוללים. לפיכך, תכונת הוכחת סיבוב במקטע נתונים חתומים יוצרת גרף א-ציקלי מכוון, שניתן לראות בצורה טובה יותר כרשימה עם קישור יחיד, כאשר כל קבוצה של חותמים עבור גרסה נתונה מייצגת צומת אחד. זה מוסיף מורכבות נוספת למבנה הוכחת סיבוב (גרסת ריבוי חתומים למטה). בפרט, ההזמנה הופכת לדאגה. יתרה מכך, כבר אי אפשר לחתום על חבילות APK באופן עצמאי, מכיוון שמבנה הוכחת הסיבוב חייב להחתים את אישורי החתימה הישנים על סט האישורים החדש, במקום לחתום עליהם אחד אחד. לדוגמה, APK חתום על ידי מפתח A שרוצה להיות חתום על ידי שני מפתחות חדשים B ו-C לא יכול היה לחתום B רק לכלול חתימה של A או B, כי זו זהות חתימה שונה מזו של B ו-C. כלומר, על החותמים לתאם לפני בניית מבנה כזה.

תכונת הוכחת סיבוב חותמים מרובים

  • רצף עם קידומת אורך של sets עם קידומת אורך:
    • signed data (לפי קבוצה קודמת - אם קיים)
      • רצף של certificates עם קידומת אורך
        • certificate X.509 עם קידומת אורך (טופס DER ASN.1)
      • רצף מזהי signature algorithm IDs (uint32) - אחד עבור כל תעודה מהקבוצה הקודמת, באותו סדר.
    • flags (uint32) - דגלים המציינים אם קבוצת אישורים זו צריכה להיות במבנה ה-confirmed-old-certs אמין או לא, ועבור אילו פעולות.
    • רצף של signatures עם קידומת אורך:
      • signature algorithm ID (uint32) - חייב להתאים לזה שבקטע הנתונים החתומים
      • signature עם קידומת אורך מעל signed data לעיל

אבות מרובים במבנה הוכחת סיבוב

סכימת v3 גם לא מטפלת בשני מפתחות שונים המסתובבים לאותו מפתח חתימה עבור אותה אפליקציה. זה שונה מהמקרה של רכישה, שבה החברה הרוכשת תרצה להעביר את האפליקציה הנרכשת לשימוש במפתח החתימה שלה כדי לשתף הרשאות. הרכישה נתפסת כמקרה שימוש נתמך מכיוון שהאפליקציה החדשה תיבדל בשם החבילה שלה ויכולה להכיל מבנה הוכחת סיבוב משלה. המקרה הלא נתמך, של אותה אפליקציה בעלת שני נתיבים שונים להגיע לאותו אישור, שובר הרבה מההנחות שנעשו בתכנון סיבוב המפתח.

אימות

ב-Android 9 ומעלה, ניתן לאמת את חבילות ה-APK בהתאם ל-APK Signature Scheme v3, v2, או v1. פלטפורמות ישנות יותר מתעלמות מחתימות v3 ומנסות לאמת חתימות v2, ואז v1.

תהליך אימות חתימת APK

איור 1. תהליך אימות חתימת APK

אימות APK Signature Scheme v3

  1. אתר את בלוק החתימה של APK וודא ש:
    1. שני שדות בגודל של APK Signing Block מכילים את אותו ערך.
    2. ZIP Central Directory מלווה מיד ב-ZIP End של רשומת ה-Central Directory.
    3. ZIP End of Central Directory אינו מלווה במידע נוסף.
  2. אתר את בלוק ה-APK Signature Scheme v3 הראשון בתוך בלוק החתימה של APK. אם בלוק v3 קיים, המשך לשלב 3. אחרת, חזור לאימות ה-APK באמצעות ערכת v2 .
  3. עבור כל signer ב-APK Signature Scheme v3 Block עם גרסת SDK מינימלית ומקסימלית שנמצאת בטווח של הפלטפורמה הנוכחית:
    1. בחר את signature algorithm ID הנתמך החזק ביותר מתוך signatures . סדר החוזק תלוי בכל גרסת יישום/פלטפורמה.
    2. אמת את signature המתאימה signatures מול signed data באמצעות public key . (עכשיו זה בטוח לנתח signed data ).
    3. ודא שגרסאות ה-SDK המינימליות והמקסימליות בנתונים החתומים תואמות לאלו שצוינו עבור signer .
    4. ודא שהרשימה המסודרת של מזהי אלגוריתמי החתימות digests signatures זהה. (זה כדי למנוע הפשטה/הוספה של חתימות.)
    5. חשב את התקציר של תוכן ה-APK באמצעות אותו אלגוריתם תקציר כמו אלגוריתם התקציר המשמש את אלגוריתם החתימה.
    6. ודא שהתקציר המחושב זהה digest המתאים digests .
    7. ודא ש-SubjectPublicKeyInfo של certificate הראשון של certificates זהה public key .
    8. אם תכונת הוכחת סיבוב קיימת עבור signer ודא שהמבנה חוקי signer הזה הוא האישור האחרון ברשימה.
  4. האימות יצליח אם נמצא בדיוק signer אחד בטווח של הפלטפורמה הנוכחית ושלב 3 הצליח עבור אותו signer .

מַתַן תוֹקֵף

כדי לבדוק שהמכשיר שלך תומך כהלכה ב-v3, הפעל את בדיקות PkgInstallSignatureVerificationTest.java CTS ב- cts/hostsidetests/appsecurity/src/android/appsecurity/cts/ .