אנדרואיד 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 Signature Scheme v3
- אתר את בלוק החתימה של APK וודא ש:
- שני שדות בגודל של APK Signing Block מכילים את אותו ערך.
- ZIP Central Directory מלווה מיד ב-ZIP End של רשומת ה-Central Directory.
- ZIP End of Central Directory אינו מלווה במידע נוסף.
- אתר את בלוק ה-APK Signature Scheme v3 הראשון בתוך בלוק החתימה של APK. אם בלוק v3 קיים, המשך לשלב 3. אחרת, חזור לאימות ה-APK באמצעות ערכת v2 .
- עבור כל
signer
ב-APK Signature Scheme v3 Block עם גרסת SDK מינימלית ומקסימלית שנמצאת בטווח של הפלטפורמה הנוכחית:- בחר את
signature algorithm ID
הנתמך החזק ביותר מתוךsignatures
. סדר החוזק תלוי בכל גרסת יישום/פלטפורמה. - אמת את
signature
המתאימהsignatures
מולsigned data
באמצעותpublic key
. (עכשיו זה בטוח לנתחsigned data
). - ודא שגרסאות ה-SDK המינימליות והמקסימליות בנתונים החתומים תואמות לאלו שצוינו עבור
signer
. - ודא שהרשימה המסודרת של מזהי אלגוריתמי החתימות
digests
signatures
זהה. (זה כדי למנוע הפשטה/הוספה של חתימות.) - חשב את התקציר של תוכן ה-APK באמצעות אותו אלגוריתם תקציר כמו אלגוריתם התקציר המשמש את אלגוריתם החתימה.
- ודא שהתקציר המחושב זהה
digest
המתאיםdigests
. - ודא ש-SubjectPublicKeyInfo של
certificate
הראשון שלcertificates
זההpublic key
. - אם תכונת הוכחת סיבוב קיימת עבור
signer
ודא שהמבנה חוקיsigner
הזה הוא האישור האחרון ברשימה.
- בחר את
- האימות יצליח אם נמצא בדיוק
signer
אחד בטווח של הפלטפורמה הנוכחית ושלב 3 הצליח עבור אותוsigner
.
מַתַן תוֹקֵף
כדי לבדוק שהמכשיר שלך תומך כהלכה ב-v3, הפעל את בדיקות PkgInstallSignatureVerificationTest.java
CTS ב- cts/hostsidetests/appsecurity/src/android/appsecurity/cts/
.