קישור לגרסה

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

כדי לתמוך במבנה המודולרי של Treble ולנתק את הקשר בין system.img ל-boot.img, במודל הקישור של גרסה 4 של Keymaster הוגדרו רמות תיקון נפרדות לכל מחיצה. כך אפשר לעדכן כל מחיצה בנפרד, ועדיין ליהנות מהגנה מפני רולבק לגרסה קודמת.

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

  • במכשירים עם הפעלה מאומתת של Android‏ (AVB), אפשר להכניס את כל רמות התיקון ואת גרסת המערכת ל-vbmeta, כך שתוכנת האתחול תוכל לספק אותן ל-Keymaster. במחיצות משורשרות, פרטי הגרסה של המחיצה נמצאים ב-vbmeta המשורשר. באופן כללי, פרטי הגרסה צריכים להיות בשדה vbmeta struct שמכיל את נתוני האימות (גיבוב או עץ גיבוב) של מחיצה נתונה.
  • במכשירים ללא AVB:
    • הטמעות של הפעלה מאומתת צריכות לספק גיבוב של מטא-נתוני הגרסה לטוען האתחול, כדי שטוען האתחול יוכל לספק את הגיבוב ל-Keymaster.
    • boot.img יכול להמשיך לאחסן את רמת התיקון בכותרת
    • system.img יכול להמשיך לאחסן את רמת התיקון ואת גרסת מערכת ההפעלה בנכסים לקריאה בלבד
    • vendor.img שומר את רמת התיקון במאפיין לקריאה בלבד ro.vendor.build.version.security_patch.
    • טוען האתחול יכול לספק ל-Keymaster גיבוב של כל הנתונים שאומתו על ידי אתחול מאומת.
  • ב-Android 9, משתמשים בתגים הבאים כדי לספק פרטי גרסה למחיצות הבאות:
    • VENDOR_PATCH_LEVEL: vendor partition
    • BOOT_PATCH_LEVEL: boot partition
    • OS_PATCH_LEVEL ו-OS_VERSION: מחיצה system. (OS_VERSION הוסר מהכותרת boot.img.
  • בהטמעות של Keymaster צריך להתייחס לכל רמות התיקון באופן עצמאי. אפשר להשתמש במפתחות אם כל פרטי הגרסה תואמים לערכים שמשויכים למפתח, ו-IKeymaster::upgradeDevice() עובר לרמת תיקון גבוהה יותר אם צריך.

שינויים ב-HAL

כדי לתמוך בקישור גרסה ובאימות גרסה, ב-Android 7.1 נוספו התגים Tag::OS_VERSION ו-Tag::OS_PATCHLEVEL והשיטות configure ו-upgradeKey. תגי הגרסה נוספים אוטומטית על ידי יישומי Keymaster 2 ואילך לכל המפתחות שנוצרו לאחרונה (או עודכנו). בנוסף, כל ניסיון להשתמש במפתח שאין לו גרסת מערכת הפעלה או רמת תיקון שמתאימות לגרסת מערכת ההפעלה או לרמת התיקון הנוכחית של המערכת, נדחה עם ErrorCode::KEY_REQUIRES_UPGRADE.

Tag::OS_VERSION הוא ערך UINT שמייצג את החלקים העיקריים, המשניים והמשניים המשניים של גרסת מערכת Android בפורמט MMmmss, כאשר MM היא הגרסה העיקרית, mm היא הגרסה המשנית ו-ss היא הגרסה המשנית המשנית. לדוגמה, 6.1.2 מיוצג כ-060102.

Tag::OS_PATCHLEVEL הוא ערך UINT שמייצג את השנה והחודש של העדכון האחרון למערכת בפורמט YYYYMM, כאשר YYYY הוא השנה בת 4 ספרות ו-MM הוא החודש בן 2 ספרות. לדוגמה, מרץ 2016 ייוצג כ-201603.

UpgradeKey

כדי לאפשר שדרוג של מפתחות לגרסת מערכת ההפעלה החדשה ולרמת התיקון של תמונת המערכת, ב-Android 7.1 נוספה השיטה upgradeKey ל-HAL:

Keymaster 3

    upgradeKey(vec keyBlobToUpgrade, vec upgradeParams)
        generates(ErrorCode error, vec upgradedKeyBlob);

Keymaster 2

keymaster_error_t (*upgrade_key)(const struct keymaster2_device* dev,
    const keymaster_key_blob_t* key_to_upgrade,
    const keymaster_key_param_set_t* upgrade_params,
    keymaster_key_blob_t* upgraded_key);
  • dev הוא מבנה המכשיר
  • keyBlobToUpgrade הוא המפתח שצריך לשדרג
  • upgradeParams הם פרמטרים שנדרשים לשדרוג המפתח. הם כוללים את Tag::APPLICATION_ID ו-Tag::APPLICATION_DATA, שנדרשים לפענוח של ה-blob של המפתח, אם הם סופקו במהלך היצירה.
  • upgradedKeyBlob הוא פרמטר הפלט שמשמש להחזרת ה-blob של המפתח החדש.

אם מתבצעת קריאה אל upgradeKey עם blob של מפתח שלא ניתן לנתח או שהוא לא תקין מסיבה אחרת, הפונקציה מחזירה ErrorCode::INVALID_KEY_BLOB. אם קוראים לה עם מפתח שרמת התיקון שלו גבוהה מהערך הנוכחי של המערכת, היא מחזירה ErrorCode::INVALID_ARGUMENT. אם הפונקציה נקראת עם מפתח שגרסת מערכת ההפעלה שלו גדולה מהערך הנוכחי של המערכת, והערך של המערכת שונה מאפס, הפונקציה מחזירה ErrorCode::INVALID_ARGUMENT. שדרוגים של גרסת מערכת ההפעלה ממספר שאינו אפס לאפס מותרים. במקרה של שגיאות בתקשורת עם העולם המאובטח, הפונקציה מחזירה ערך שגיאה מתאים (לדוגמה, ErrorCode::SECURE_HW_ACCESS_DENIED, ErrorCode::SECURE_HW_BUSY). אחרת, היא מחזירה ErrorCode::OK ומחזירה blob חדש של מפתח ב-upgradedKeyBlob.

האישור keyBlobToUpgrade נשאר בתוקף אחרי השיחה upgradeKey ואפשר להשתמש בו שוב באופן תיאורטי אם המכשיר ישודרג. בפועל, בדרך כלל keystore קורא ל-deleteKey ב-blob של keyBlobToUpgrade זמן קצר אחרי הקריאה ל-upgradeKey. אם keyBlobToUpgrade כלל את התג Tag::ROLLBACK_RESISTANT, אז גם upgradedKeyBlob צריך לכלול אותו (ולא להיות רגיש לרולבק).

תצורה מאובטחת

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

כדי לתמוך בהעברה מאובטחת של פרטי הגרסה אל ה-TA, נוסף OS_VERSION שדה לכותרת של תמונת האתחול. הסקריפט של בניית תמונת האתחול מאכלס את השדה הזה באופן אוטומטי. יצרני ציוד מקורי (OEM) ומיישמי Keymaster TA צריכים לעבוד יחד כדי לשנות את טועני האתחול של המכשיר, לחלץ את פרטי הגרסה מתמונת האתחול ולהעביר אותם ל-TA לפני שמערכת לא מאובטחת מאותחלת. כך אפשר לוודא שהתוקפים לא יוכלו לשבש את הקצאת מידע הגרסה ל-TA.

בנוסף, צריך לוודא שפרטי הגרסה של תמונת המערכת זהים לפרטי הגרסה של תמונת האתחול. לשם כך, נוספה שיטת ההגדרה ל-Keymaster HAL:

keymaster_error_t (*configure)(const struct keymaster2_device* dev,
  const keymaster_key_param_set_t* params);

הארגומנט params מכיל את הערכים Tag::OS_VERSION ו-Tag::OS_PATCHLEVEL. השיטה הזו נקראת על ידי לקוחות keymaster2 אחרי פתיחת ה-HAL, אבל לפני הקריאה לשיטות אחרות. אם קוראים לשיטה אחרת לפני configure, ה-TA מחזיר ErrorCode::KEYMASTER_NOT_CONFIGURED.

בפעם הראשונה שמתבצעת קריאה ל-configure אחרי הפעלת המכשיר, צריך לוודא שפרטי הגרסה שסופקו תואמים לפרטים שסופקו על ידי טוען האתחול. אם פרטי הגרסה לא תואמים, הפונקציה configure מחזירה ErrorCode::INVALID_ARGUMENT, וכל שאר הפונקציות של Keymaster ממשיכות להחזיר ErrorCode::KEYMASTER_NOT_CONFIGURED. אם המידע תואם, ‫configure מחזירה ErrorCode::OK, ושיטות אחרות של Keymaster מתחילות לפעול כרגיל.

קריאות עוקבות אל configure מחזירות את אותו ערך שהוחזר על ידי הקריאה הראשונה, ולא משנות את המצב של Keymaster.

מכיוון שהמערכת קוראת ל-configure כדי לאמת את התוכן שלה, יש חלון הזדמנויות קצר לתוקף לפגוע בתמונת המערכת ולאלץ אותה לספק פרטי גרסה שתואמים לתמונת האתחול, אבל לא לגרסה בפועל של המערכת. השילוב של אימות תמונת האתחול, אימות dm-verity של תוכן תמונת המערכת והעובדה שהפונקציה configure מופעלת בשלב מוקדם מאוד באתחול המערכת, אמורים להקשות על ניצול חלון ההזדמנויות הזה.