קישור לגרסה

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

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

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

  • במכשירים עם הפעלה מאומתת של 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 מחיצה
    • BOOT_PATCH_LEVEL: boot מחיצה
    • 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 ואפשר להשתמש בו שוב באופן תיאורטי אם המכשיר ישודרג לאחור. בפועל, בדרך כלל מתבצעת קריאה ל-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 נקראת בשלב מוקדם מאוד באתחול המערכת, אמורים להקשות על ניצול חלון ההזדמנויות הזה.