ב-Keymaster 1, כל מפתחות Keymaster היו קשורים באופן קריפטוגרפי לשורש האמון של המכשיר או למפתח של אתחול מאומת. ב-Keymaster 2 ו-3, כל המפתחות קשורים גם למערכת ההפעלה ולרמת הטלאי של קובץ אימג' של המערכת. כך אפשר לוודא שתוקף שמגלה חולשה בגרסה ישנה של מערכת או של תוכנת TEE לא יוכל להחזיר מכשיר לגרסה הפגיעה ולהשתמש במפתחות שנוצרו בגרסה החדשה יותר. בנוסף, כשמשתמשים במפתח עם גרסה ורמת תיקון מסוימות במכשיר ששודרג לגרסה או לרמת תיקון חדשות יותר, המפתח משודרג לפני שאפשר להשתמש בו, והגרסה הקודמת של המפתח הופכת ללא תקפה. כך, כשהמכשיר משודרג, המפתחות מתקדמים יחד עם המכשיר, אבל אם המכשיר חוזר לגרסה קודמת, אי אפשר להשתמש במפתחות.
כדי לתמוך במבנה המודולרי של Treble ולנתק את הקישור של system.img ל-boot.img, במודל הקישור של גרסת המפתח ב-Keymaster 4 הוגדרו רמות תיקון נפרדות לכל מחיצה. כך אפשר לעדכן כל מחיצה בנפרד, ועדיין ליהנות מהגנה מפני רולבק לגרסה קודמת.
כדי להטמיע את הקישור הזה לגרסה, אפליקציית KeyMint המהימנה (TA) צריכה לקבל בצורה מאובטחת את גרסת מערכת ההפעלה הנוכחית ואת רמות התיקון, ולוודא שהמידע שהיא מקבלת תואם לכל המידע על המערכת הפועלת.
- במכשירים עם הפעלה מאומתת של Android (AVB), אפשר להכניס את כל רמות התיקון ואת גרסת המערכת ל-vbmeta, כך שטוען האתחול יכול לספק אותן ל-Keymaster. במחיצות בשרשרת, פרטי הגרסה של המחיצה נמצאים בקובץ vbmeta בשרשרת. באופן כללי, פרטי הגרסה צריכים להיות בשדה
vbmeta structשמכיל את נתוני האימות (hash או hashtree) של מחיצה נתונה. - במכשירים ללא AVB:
- הטמעות של הפעלה מאומתת צריכות לספק גיבוב (hash) של מטא-נתוני הגרסה לתוכנת האתחול, כדי שתוכנת האתחול תוכל לספק את הגיבוב ל-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.
בנוסף, צריך לוודא שפרטי הגרסה של קובץ אימג' של המערכת זהים לפרטי הגרסה של קובץ אימג' לאתחול. לשם כך, נוספה שיטת ההגדרה (configure) ל-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. ה-method הזו מופעלת על ידי לקוחות keymaster2 אחרי פתיחת ה-HAL, אבל לפני הפעלת method אחרת. אם מפעילים שיטה אחרת לפני 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 נקראת בשלב מוקדם מאוד באתחול המערכת, אמורים להקשות על ניצול חלון ההזדמנויות הזה.