ב-Android 9 יש תמיכה ברוטציית מפתחות של APK, שמאפשרת לאפליקציות לשנות את מפתח החתימה שלהן כחלק מעדכון APK. כדי שהסבב יהיה מעשי, בחבילות ה-APK צריך לציין את רמות האמון בין מפתח החתימה החדש לבין מפתח החתימה הישן. כדי לתמוך בסיבוב מפתחות, עדכנו את סכימת החתימה של קובצי APK מגרסה 2 לגרסה 3, כדי לאפשר שימוש במפתחות החדשים והישנים. בגרסה 3 נוספים למקטע החתימה של ה-APK מידע על גרסאות ה-SDK הנתמכות ומבנה של הוכחת רוטציה.
בלוק לחתימה על קובץ APK
כדי לשמור על תאימות לאחור לפורמט APK v1, חתימות APK בגרסה 2 ובגרסה 3 מאוחסנות בתוך בלוק חתימה של APK, שנמצא מיד לפני הספרייה המרכזית של קובץ ה-ZIP.
פורמט הבלוק לחתימה על APK בגרסה 3 הוא זהה לפורמט של גרסה 2. החתימה של גרסה 3 של קובץ ה-APK מאוחסנת כצמד מזהה-ערך עם המזהה 0xf05368c0.
חסימה של סכמת החתימה של APK v3
הסכימה של גרסה 3 דומה מאוד להסכימה של גרסה 2. יש לו את אותו פורמט כללי, והוא תומך באותם מזהים של אלגוריתמים לחתימה, באותו גודל מפתחות ובאותן עקומות EC.
עם זאת, בתוכנית v3 מתווסף מידע על גרסאות ה-SDK הנתמכות ועל המבנה של הוכחת הסיבוב.
פורמט
הבלוק של סכמת החתימה של APK בגרסה 3 מאוחסן בתוך הבלוק של חתימת ה-APK, עם המזהה 0xf05368c0
.
הפורמט של הבלוק של סכמת החתימה של APK בגרסה 3 זהה לפורמט של גרסת v2:
- רצף עם קידומת אורך של
signer
עם קידומת אורך:signed data
עם קידומת באורך:- רצף עם קידומת אורך של
digests
עם קידומת אורך:signature algorithm ID
(4 בייטים)digest
(length-prefixed)
- רצף עם קידומת באורך של X.509
certificates
:certificate
של X.509 עם קידומת באורך (ASN.1 DER form)
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 form)
מבנים של הוכחת סבב מפתחות ומבנים של אישורים ישנים מהימנים לעצמם
המבנה של הוכחת הסיבוב מאפשר לאפליקציות לבצע רוטציה של אישור החתימה שלהן בלי להיחסם באפליקציות אחרות שהן מתקשרות איתן. כדי לעשות זאת, חתימות האפליקציות מכילות שני נתונים חדשים:
- טענת נכוֹנוּת (assertion) לצדדים שלישיים שאפשר לסמוך על אישור החתימה של האפליקציה בכל מקום שבו יש אמון בקודמים שלו
- אישורי החתימה הישנים של האפליקציה שעדיין מהימנים לאפליקציה עצמה
המאפיין proof-of-rotation בקטע הנתונים החתומים מורכב מרשימת קישורים יחידה, שבכל צומת שלה יש אישור חתימה ששימש לחתימה על גרסאות קודמות של האפליקציה. המאפיין הזה אמור להכיל את מבני הנתונים הרעיוניים של proof-of-rotation ושל self-trusted-old-certs. הרשימה ממוינת לפי גרסה, כאשר אישור החתימה הישן ביותר תואם לצומת הבסיס. מבנה הנתונים של הוכחת הרוטציה נוצר על ידי חתימת האישור בכל צומת על המפתח הבא ברשימה, וכך הוספת הוכחה לכל מפתח חדש שהוא אמין כמו המפתחות הישנים.
מבנה הנתונים של self-trusted-old-certs נוצר על ידי הוספת דגלים לכל צומת, שמציינים את החברות שלו בקבוצה ואת המאפיינים שלו בקבוצה. לדוגמה, יכול להיות שיופיע דגל שמציין שאישור החתימה בצומת מסוים מהימן לקבלת הרשאות חתימה ב-Android. הדגל הזה מאפשר לאפליקציות אחרות שנחתמו על ידי האישור הישן לקבל עדיין הרשאת חתימה שמוגדרת על ידי אפליקציה שנחתמה באמצעות אישור החתימה החדש. מכיוון שכל המאפיין של הוכחת הרוטציה נמצא בקטע הנתונים החתומים בשדה v3 signer
, הוא מוגן על ידי המפתח שמשמש לחתימה על קובץ ה-apk שמכיל אותו.
הפורמט הזה לא מאפשר שימוש במספר מפתחות חתימה ואיחוד של אישורי חתימה שונים של ישות אב לאחד (מספר צמתים מתחילים לבור נתונים משותף).
פורמט
הוכחת הרוטציה מאוחסנת בתוך הבלוק של סכמת החתימה של APK v3, במזהה 0x3ba06f8c
. הפורמט שלו הוא:
- רצף עם קידומת אורך של
levels
עם קידומת אורך:signed data
עם קידומת באורך (על ידי האישור הקודם – אם קיים)certificate
של X.509 עם קידומת באורך (ASN.1 DER form)signature algorithm ID
(uint32) – האלגוריתם שבו נעשה שימוש על ידי האישור ברמה הקודמת
flags
(uint32) – דגלים שמציינים אם האישור הזה צריך להיכלל במבנה self-trusted-old-certs, ואילו פעולות הוא רלוונטי אליהן.signature algorithm ID
(uint32) – חייב להתאים לערך שמופיע בקטע של הנתונים החתומים ברמה הבאה.signature
עם קידומת אורך מעלsigned data
שלמעלה
כמה אישורים
אין תמיכה בחתימות של מספר גורמים, ו-Google Play לא מפרסם אפליקציות שחתומות על ידי כמה אישורים.
אימות
ב-Android 9 ואילך, אפשר לאמת קובצי APK לפי סכמת החתימה על APK v3, v2 או v1. פלטפורמות ישנות יותר מתעלמות מחתימות בגרסה 3 ומנסות לאמת חתימות בגרסה 2 ואז בגרסה 1.
איור 1. תהליך אימות החתימה של קובץ ה-APK
אימות של סכמת חתימה של APK v3
- מאתרים את הבלוק של חתימה על קובץ ה-APK ומוודאים:
- שני שדות גודל של בלוק החתימה של קובץ ה-APK מכילים את אותו ערך.
- אחרי הרשומה ZIP Central Directory מופיעה הרשומה ZIP End of Central Directory.
- אחרי ZIP End of Central Directory לא מופיעים נתונים נוספים.
- מאתרים את הבלוק הראשון של סכמת החתימה APK v3 בתוך הבלוק של חתימת ה-APK. אם הבלוק v3 קיים, ממשיכים לשלב 3. אחרת, עוברים לאימות של ה-APK באמצעות סכמה v2.
- לכל
signer
בבלוק של סכמת החתימה של APK v3 עם גרסת SDK מינימלית וגרסה מקסימלית שנמצאות בטווח של הפלטפורמה הנוכחית:- בוחרים את
signature algorithm ID
הנתמכת ביותר מ-signatures
. סדר החוזק נקבע לפי כל גרסה של הטמעה או פלטפורמה. - מוודאים שה-
signature
התואם מ-signatures
תואם ל-signed data
באמצעותpublic key
. (עכשיו אפשר לנתח אתsigned data
). - מוודאים שגרסת ה-SDK המינימלית והמקסימלית בנתונים החתומים תואמות לאלה שצוינו ב-
signer
. - מוודאים שהרשימה הממוזערת של מזהי אלגוריתמי החתימה ב-
digests
וב-signatures
זהה. (המטרה היא למנוע הסרה או הוספה של חתימות). - מחשבים את המסכם של תוכן ה-APK באמצעות אותו אלגוריתם של המסכם שבו נעשה שימוש באלגוריתם החתימה.
- מוודאים שה-digest המחושב זהה ל-
digest
התואם מ-digests
. - מוודאים ש-SubjectPublicKeyInfo של ה-
certificate
הראשון שלcertificates
זהה ל-public key
. - אם המאפיין proof-of-rotation קיים ב-
signer
, צריך לוודא שהמבנה תקין ושה-signer
הזה הוא האישור האחרון ברשימה.
- בוחרים את
- האימות יצליח אם נמצא בדיוק
signer
אחד בטווח של הפלטפורמה הנוכחית, ושלב 3 הצליח עבורsigner
הזה.
אימות
כדי לבדוק שהמכשיר תומך ב-v3 כראוי, מריצים את PkgInstallSignatureVerificationTest.java
בדיקות CTS ב-cts/hostsidetests/appsecurity/src/android/appsecurity/cts/
.