הזמינות של סביבת ביצוע מהימנה במערכת על שבב (SoC) מציעה הזדמנות למכשירי אנדרואיד לספק שירותי אבטחה חזקים מגובי חומרה למערכת ההפעלה אנדרואיד, לשירותי פלטפורמה ואפילו לאפליקציות של צד שלישי. מפתחים המחפשים את ההרחבות הספציפיות לאנדרואיד צריכים לעבור אל android.security.keystore .
לפני אנדרואיד 6.0, לאנדרואיד כבר היה ממשק API פשוט, מגובה חומרה של שירותי קריפטו, שסופק על ידי גרסאות 0.2 ו-0.3 של Keymaster Hardware Abstraction Layer (HAL). Keystore סיפקה פעולות חתימה ואימות דיגיטליים, בתוספת יצירה וייבוא של צמדי מפתחות חתימה אסימטריים. זה כבר מיושם במכשירים רבים, אבל יש הרבה יעדי אבטחה שלא ניתן להשיג בקלות רק עם API חתימה. Keystore באנדרואיד 6.0 הרחיב את ה-API של Keystore כדי לספק מגוון רחב יותר של יכולות.
באנדרואיד 6.0, Keystore הוסיפה פרימיטיבים קריפטוגרפיים סימטריים , AES ו-HMAC, ומערכת בקרת גישה למפתחות מגובי חומרה. בקרות הגישה מוגדרות במהלך יצירת המפתחות ונאכפות למשך כל חיי המפתח. ניתן להגביל מפתחות לשימוש רק לאחר אימות המשתמש, ורק למטרות מוגדרות או עם פרמטרים קריפטוגרפיים מוגדרים. למידע נוסף, עיין בדפי הרשאות תגיות ופונקציות .
בנוסף להרחבת מגוון הפרימיטיבים ההצפנה, Keystore באנדרואיד 6.0 הוסיפה את הדברים הבאים:
- ערכת בקרת שימוש המאפשרת הגבלת השימוש במפתחות, כדי להפחית את הסיכון של פגיעה באבטחה עקב שימוש לרעה במפתחות
- ערכת בקרת גישה לאפשר הגבלת מפתחות למשתמשים, לקוחות וטווח זמן מוגדר
באנדרואיד 7.0, Keymaster 2 הוסיפה תמיכה עבור אישור מפתח וקשירת גרסאות. אישור מפתח מספק אישורי מפתח ציבורי המכילים תיאור מפורט של המפתח ובקרות הגישה שלו, כדי להפוך את קיומו של המפתח בחומרה מאובטחת ואת התצורה שלו לניתנים לאימות מרחוק.
כריכת גרסה קושרת מפתחות למערכת ההפעלה ולגרסת רמת התיקון. זה מבטיח שתוקף שמגלה חולשה בגרסה ישנה של המערכת או בתוכנת TEE לא יוכל להחזיר מכשיר לגרסה הפגיעה ולהשתמש במפתחות שנוצרו עם הגרסה החדשה יותר. בנוסף, כאשר נעשה שימוש במפתח עם גרסה ורמת תיקון נתונות במכשיר ששודרג לגרסה חדשה יותר או לרמת תיקון, המפתח משודרג לפני שניתן להשתמש בו, והגרסה הקודמת של המפתח בטלה. עם השדרוג של המכשיר, המקשים "מתרוצצים" קדימה יחד עם המכשיר, אך כל החזרה של המכשיר למהדורה קודמת גורמת לכך שהמפתחות לא ניתנים לשימוש.
באנדרואיד 8.0, Keymaster 3 עבר משכבת הפשטת החומרה (HAL) בסגנון הישן של מבנה C לממשק C++ HAL שנוצר מהגדרה בשפת הגדרת ממשק החומרה החדשה (HIDL). כחלק מהשינוי, רבים מסוגי הטיעונים השתנו, אם כי לסוגים ולשיטות יש התאמה אחד לאחד עם הטיפוסים הישנים ושיטות מבנה HAL. עיין בדף הפונקציות לפרטים נוספים.
בנוסף לגרסה זו של הממשק, אנדרואיד 8.0 הרחיבה את תכונת האישור של Keymaster 2 כדי לתמוך באישור מזהה . אישור מזהה מספק מנגנון מוגבל ואופציונלי להעיד חזק על מזהי חומרה, כגון מספר סידורי המכשיר, שם המוצר ומזהה הטלפון (IMEI / MEID). כדי ליישם תוספת זו, אנדרואיד 8.0 שינתה את סכימת האישור של ASN.1 כדי להוסיף אישור מזהה. יישומי Keymaster צריכים למצוא דרך מאובטחת כלשהי לאחזר את פריטי הנתונים הרלוונטיים, כמו גם להגדיר מנגנון לביטול מאובטח ולתמיד של התכונה.
באנדרואיד 9, עדכונים כללו:
- עדכון ל- Keymaster 4
- תמיכה ב-Secure Elements משובצים
- תמיכה בייבוא מפתח מאובטח
- תמיכה בהצפנת 3DES
- שינויים בקישור גרסאות כך ש-boot.img ו-system.img הגדירו גרסאות בנפרד כדי לאפשר עדכונים עצמאיים
מילון מונחים
הנה סקירה מהירה של רכיבי Keystore והקשרים ביניהם.
AndroidKeystore הוא ה-API והרכיב של Android Framework המשמש אפליקציות לגישה לפונקציונליות של Keystore. הוא מיושם כהרחבה לממשקי ה-API הסטנדרטיים של Java Cryptography Architecture, ומורכב מקוד Java הפועל במרחב התהליך של האפליקציה עצמה. AndroidKeystore
ממלא בקשות אפליקציה להתנהגות Keystore על ידי העברתן לדמון מאגר המפתחות.
דמון מאגר המפתחות הוא דמון מערכת אנדרואיד המספק גישה לכל הפונקציונליות של מאגר המפתחות באמצעות ממשק API של Binder . היא אחראית לאחסון "כתמי מפתח", המכילים את חומר המפתח הסודי בפועל, מוצפן כך ש-Keystore תוכל לאחסן אותם אך לא להשתמש בהם או לחשוף אותם.
keymasterd הוא שרת HIDL המספק גישה ל-Keymaster TA. (שם זה אינו סטנדרטי והוא מיועד למטרות מושגיות.)
Keymaster TA (יישום מהימן) היא התוכנה הפועלת בהקשר מאובטח, לרוב ב-TrustZone ב-ARM SoC, המספקת את כל הפעולות המאובטחות של Keystore, בעלת גישה לחומר המפתח הגולמי, מאמתת את כל תנאי בקרת הגישה במפתחות , וכו.
LockSettingsService הוא רכיב מערכת אנדרואיד האחראי על אימות המשתמש, הן סיסמה והן טביעת אצבע. זה לא חלק מ-Keystore, אבל רלוונטי מכיוון שהרבה פעולות מפתח של Keystore דורשות אימות משתמש. LockSettingsService
מקיים אינטראקציה עם Gatekeeper TA ו-Fingerprint TA כדי להשיג אסימוני אימות, אותם הוא מספק לדמון מאגר המפתחות, ואשר נצרכים בסופו של דבר על ידי אפליקציית Keymaster TA.
Gatekeeper TA (יישום מהימן) הוא רכיב נוסף הפועל בהקשר המאובטח, שאחראי על אימות סיסמאות משתמש ויצירת אסימוני אימות המשמשים להוכחה ל-Keymaster TA שבוצע אימות עבור משתמש מסוים בנקודת זמן מסוימת.
טביעת אצבע TA (יישום מהימן) הוא רכיב נוסף הפועל בהקשר המאובטח אשר אחראי על אימות טביעות אצבע של משתמש ויצירת אסימוני אימות המשמשים להוכחה ל-Keymaster TA שבוצע אימות עבור משתמש מסוים בנקודת זמן מסוימת.
ארכיטקטורה
ה-API של Android Keystore וה-Keymaster HAL הבסיסי מספקים קבוצה בסיסית אך מספקת של פרימיטיבים קריפטוגרפיים כדי לאפשר יישום של פרוטוקולים באמצעות מפתחות מבוקרי גישה, מגובי חומרה.
ה-Keymaster HAL הוא ספרייה הניתנת לטעינה דינמית המסופקת על ידי OEM המשמשת את שירות Keystore כדי לספק שירותי קריפטוגרפיה מגובי חומרה. כדי לשמור על אבטחת הדברים, יישומי HAL אינם מבצעים שום פעולות רגישות במרחב המשתמש, או אפילו בחלל הקרנל. פעולות רגישות מואצלות למעבד מאובטח שמגיע דרך ממשק ליבה כלשהו. הארכיטקטורה שהתקבלה נראית כך:

איור 1. גישה ל-Keymaster
בתוך מכשיר אנדרואיד, ה"לקוח" של Keymaster HAL מורכב משכבות מרובות (למשל אפליקציה, מסגרת, דמון Keystore), אך ניתן להתעלם מכך למטרות מסמך זה. המשמעות היא שה-Keymaster HAL API המתואר הוא ברמה נמוכה, בשימוש על ידי רכיבים פנימיים של הפלטפורמה, ואינו חשוף למפתחי אפליקציות. ה-API ברמה גבוהה יותר מתואר באתר המפתחים של Android .
מטרת ה-Keymaster HAL היא לא ליישם את האלגוריתמים הרגישים לאבטחה, אלא רק לבקשות של מרשל ו-unmarshal לעולם המאובטח. פורמט החוט מוגדר ביישום.
תאימות עם גרסאות קודמות
ה-Keymaster 1 HAL אינו תואם לחלוטין ל-HALs שפורסמו בעבר, למשל Keymaster 0.2 ו-0.3. כדי להקל על יכולת פעולה הדדית במכשירים המריצים אנדרואיד 5.0 ואילך שהושקו עם ה-Keymaster HALs הישנים יותר, Keystore מספקת מתאם שמיישם את Keymaster 1 HAL עם קריאות לספריית החומרה הקיימת. התוצאה אינה יכולה לספק את כל מגוון הפונקציונליות ב-Keymaster 1 HAL. בפרט, הוא תומך רק באלגוריתמים RSA ו-ECDSA, וכל אכיפת ההרשאות העיקרית מתבצעת על ידי המתאם, בעולם הלא מאובטח.
Keymaster 2 פישט עוד יותר את ממשק HAL על ידי הסרת שיטות get_supported_*
ואפשר לשיטת finish()
לקבל קלט. זה מקטין את מספר הנסיעות הלוך ושוב ל-TEE במקרים שבהם הקלט זמין בבת אחת, ומפשט את היישום של פענוח AEAD.
באנדרואיד 8.0, Keymaster 3 עבר מ-HAL בסגנון הישן של מבנה C לממשק C++ HAL שנוצר מהגדרה ב-Hardware Interface Definition Language (HIDL). מימוש HAL בסגנון חדש נוצר על ידי סיווג משנה של המחלקה IKeymasterDevice
שנוצרה ויישום השיטות הוירטואליות הטהורות. כחלק מהשינוי, רבים מסוגי הטיעונים השתנו, אם כי לסוגים ולשיטות יש התכתבות אחד לאחד עם הטיפוסים הישנים ושיטות מבנה HAL.
סקירה כללית של HIDL
שפת הגדרת ממשק החומרה (HIDL) מספקת מנגנון בלתי תלוי בשפה לציון ממשקי חומרה. כלי ה-HIDL תומך כיום בדור של ממשקי C++ ו-Java. צפוי שרוב המיישמים של סביבת ביצוע מהימנה (TEE) ימצאו את כלי ה-C++ נוח יותר, ולכן מסמך זה דן רק בייצוג C++.
ממשקי HIDL מורכבים מסט של שיטות, המתבטאות כ:
methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);
ישנם סוגים שונים שהוגדרו מראש, ו-HALs יכולים להגדיר סוגים חדשים שנמנו ומבנה. לפרטים נוספים על HIDL, עיין בסעיף הפניה .
שיטה לדוגמה מ- Keymaster 3 IKeymasterDevice.hal
היא:
generateKey(vec<KeyParameter> keyParams) generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
זוהי המקבילה של הדברים הבאים מ-keymaster2 HAL:
keymaster_error_t (*generate_key)( const struct keymaster2_device* dev, const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics);
בגרסת HIDL, הארגומנט dev
מוסר, מכיוון שהוא מרומז. הארגומנט params
אינו עוד מבנה המכיל מצביע המפנה למערך של אובייקטים key_parameter_t
, אלא vec
(וקטור) המכיל אובייקטים KeyParameter
. ערכי ההחזרה מפורטים בסעיף " generates
", כולל וקטור של ערכי uint8_t
עבור ה-key blob.
השיטה הוירטואלית C++ שנוצרה על ידי מהדר HIDL היא:
Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams, generateKey_cb _hidl_cb) override;
כאשר generateKey_cb
הוא מצביע פונקציה המוגדר כ:
std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob, const KeyCharacteristics& keyCharacteristics)>
כלומר, generateKey_cb
היא פונקציה שלוקחת את ערכי ההחזרה הרשומים בסעיף generate. מחלקת היישום HAL עוקפת את שיטת generateKey
זו וקוראת למצביע הפונקציה generateKey_cb
כדי להחזיר את תוצאת הפעולה למתקשר. שים לב שקריאת מצביע הפונקציה היא סינכרונית . המתקשר קורא generateKey
ו- generateKey
קורא למצביע הפונקציה שסופק, המופעל עד תום, ומחזיר את השליטה למימוש ה- generateKey
, אשר לאחר מכן חוזר למתקשר.
לדוגמא מפורטת, עיין ביישום ברירת המחדל ב- hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp
. יישום ברירת המחדל מספק תאימות לאחור עבור מכשירים עם keymaster0, keymaster1 או keymaster2 HALS בסגנון ישן.
בקרת גישה
הכלל הבסיסי ביותר של בקרת הגישה של Keystore הוא שלכל אפליקציה יש מרחב שמות משלה. אבל לכל כלל יש יוצא מן הכלל. ל-Keystore יש כמה מפות מקודדות המאפשרות לרכיבי מערכת מסוימים גישה למרחבי שמות מסוימים אחרים. זהו מכשיר בוטה מאוד בכך שהוא נותן לרכיב אחד שליטה מלאה על מרחב שמות אחר. ואז יש את העניין של רכיבי הספק כלקוחות ל-Keystore. כרגע אין לנו דרך להקים מרחב שמות עבור רכיבי ספקים, למשל, מבקש WPA.
על מנת להתאים לרכיבי הספק ולהכליל בקרת גישה ללא חריגים מקודדים, Keystore 2.0 מציגה דומיינים ומרחבי שמות של SELinux.
דומיינים של מאגר מפתחות
עם דומיינים של Keystore, אנו יכולים לנתק מרחבי שמות מ-UID. לקוחות הניגשים למפתח ב-Keystore צריכים לציין את הדומיין, מרחב השמות והכינוי שאליהם הם רוצים לגשת. בהתבסס על הטפול הזה וזהות המתקשר נוכל לקבוע לאיזה מפתח המתקשר רוצה לגשת ואם יש לו הרשאות מתאימות.
אנו מציגים חמישה פרמטרים של תחום שקובעים כיצד ניתן לגשת למפתחות. הם שולטים בסמנטיקה של פרמטר מרחב השמות של מתאר המפתח ובאופן ביצוע בקרת הגישה.
-
DOMAIN_APP
: תחום האפליקציה מכסה את ההתנהגות מדור קודם. ה-SPI של Java Keystore משתמש בדומיין זה כברירת מחדל. כאשר נעשה שימוש בדומיין זה, מתעלמים מארגומנט מרחב השמות ובמקום זאת נעשה שימוש ב-UID של המתקשר. הגישה לדומיין זה נשלטת על ידי התווית Keystore למחלקהkeystore_key
במדיניות SELinux. -
DOMAIN_SELINUX
: תחום זה מציין שלמרחב השמות יש תווית במדיניות SELinux. פרמטר מרחב השמות נבדק ומתורגם להקשר יעד, ובדיקת הרשאות מתבצעת עבור ההקשר הקורא SELinux עבור מחלקתkeystore_key
. כאשר הוקמה ההרשאה עבור הפעולה הנתונה, ה-tuple המלא משמש לחיפוש המפתח. -
DOMAIN_GRANT
: תחום ההענקה מציין שפרמטר מרחב השמות הוא מזהה הענקה. הפרמטר הכינוי מתעלם. בדיקות SELinux מבוצעות בעת יצירת המענק. בקרת גישה נוספת בודקת רק אם ה-UID המתקשר תואם ל-UID של המענקים של המענק המבוקש. -
DOMAIN_KEY_ID
: תחום זה מציין שפרמטר מרחב השמות הוא מזהה מפתח ייחודי. ייתכן שהמפתח עצמו נוצר עםDOMAIN_APP
אוDOMAIN_SELINUX
. בדיקת ההרשאה מתבצעת לאחרdomain
ומרחבnamespace
נטענו ממסד הנתונים של המפתחות באותו אופן כאילו ה-blob נטען על ידי הדומיין, מרחב השמות והכינוי tuple. הרציונל לתחום מזהה המפתח הוא המשכיות. בעת גישה למפתח באמצעות כינוי, שיחות עוקבות עשויות לפעול על מקשים שונים, מכיוון שייתכן שמפתח חדש נוצר או יובא ונקשר לכינוי זה. עם זאת, מזהה המפתח לעולם אינו משתנה. אז כשמשתמשים במפתח לפי מזהה מפתח אחרי שהוא נטען ממסד הנתונים של Keystore באמצעות הכינוי פעם אחת, אפשר להיות בטוח שזה אותו מפתח כל עוד מזהה המפתח עדיין קיים. פונקציונליות זו אינה חשופה למפתחי אפליקציות. במקום זאת, נעשה בו שימוש ב-Android Keystore SPI כדי לספק חוויה עקבית יותר גם כאשר משתמשים בו במקביל בצורה לא בטוחה. -
DOMAIN_BLOB
: תחום ה-blob מציין שהמתקשר מנהל את ה-blob בעצמו. זה משמש עבור לקוחות שצריכים לגשת ל-Keystore לפני הרכבת מחיצת הנתונים. כתם המפתח נכלל בשדהblob
של מתאר המפתח.
באמצעות תחום ה-SELinux, אנו יכולים להעניק לרכיבי הספק גישה למרחבי שמות ספציפיים מאוד של מאגר מפתחות אשר יכולים להיות משותפים על ידי רכיבי מערכת כגון תיבת הדו-שיח של ההגדרות.
מדיניות SELinux עבור keystore_key
תוויות מרחב השמות מוגדרות באמצעות קובץ keystore2_key_context
.
כל שורה בקבצים אלו ממפה מזהה מרחב שמות מספרי לתווית SELinux. לדוגמה,
# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and # Settings to share keystore keys. 102 u:object_r:wifi_key:s0
לאחר שהגדרנו מרחב שמות מפתח חדש בדרך זו, נוכל לתת לו גישה על ידי הוספת מדיניות מתאימה. לדוגמה, כדי לאפשר wpa_supplicant
לקבל ולהשתמש במפתחות במרחב השמות החדש, נוסיף את השורה הבאה ל- hal_wifi_supplicant.te
:
allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };
לאחר הגדרת מרחב השמות החדש, ניתן להשתמש ב-AndroidKeyStore כמעט כרגיל. ההבדל היחיד הוא שיש לציין את מזהה מרחב השמות. לטעינה וייבוא של מפתחות מ-Keystore ואל תוך, מזהה מרחב השמות מצוין באמצעות AndroidKeyStoreLoadStoreParameter
. לדוגמה,
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; import java.security.KeyStore; KeyStore keystore = KeyStore.getInstance("AndroidKeyStore"); keystore.load(new AndroidKeyStoreLoadStoreParameter(102));
כדי ליצור מפתח במרחב שמות נתון, יש לתת את מזהה מרחב השמות באמצעות KeyGenParameterSpec.Builder#setNamespace():
import android.security.keystore.KeyGenParameterSpec; KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(); specBuilder.setNamespace(102);
ניתן להשתמש בקובצי ההקשר הבאים כדי להגדיר את מרחבי השמות של Keystore 2.0 SELinux. לכל מחיצה יש טווח שמור שונה של 10,000 מזהי מרחב שמות כדי למנוע התנגשויות.
חֲלוּקָה | טווח | קבצי תצורה |
---|---|---|
מערכת | 0 ... 9,999 | /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts |
מערכת מורחבת | 10,000 ... 19,999 | /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts |
מוצר | 20,000 ... 29,999 | /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts |
מוֹכֵר | 30,000 ... 39,999 | /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts |
הלקוח מבקש את המפתח על ידי בקשת הדומיין של SELinux ומרחב השמות הווירטואלי הרצוי, במקרה זה "wifi_key"
, לפי המזהה המספרי שלו.
מעל זה, הוגדרו מרחבי השמות הבאים. אם הם מחליפים כללים מיוחדים, הטבלה הבאה מציינת את ה-UID שהם נהגו להתאים אליו.
מזהה מרחב שמות | תווית SEPolicy | UID | תיאור |
---|---|---|---|
0 | su_key | לא | מפתח משתמש סופר. משמש רק לבדיקה ב-userdebug ו-eng builds. לא רלוונטי בבניית משתמש. |
1 | shell_key | לא | מרחב שמות זמין למעטפת. משמש בעיקר לבדיקות, אך ניתן להשתמש בו גם בבניית משתמש משורת הפקודה. |
100 | vold_key | לא | מיועד לשימוש על ידי vold. |
101 | odsing_key | לא | בשימוש על ידי דמון החתימה במכשיר. |
102 | wifi_key | AID_WIFI(1010) | בשימוש על ידי מערכת Wifi של אנדרואיד כולל wpa_supplicant. |
120 | resume_on_reboot_key | AID_SYSTEM(1000) | משמש את שרת המערכת של אנדרואיד כדי לתמוך בקורות חיים באתחול מחדש. |
גישה לוקטורים
מחלקת SELinux keystore_key
התיישנה לא מעט וחלק מההרשאות, כגון verify
או sign
איבדו את משמעותן. הנה ערכת ההרשאות החדשה, keystore2_key
, ש-Keystore 2.0 תאכוף.
רְשׁוּת | מַשְׁמָעוּת |
---|---|
delete | מסומן בעת הסרת מפתחות מחנות המפתחות. |
get_info | מסומן כאשר מתבקשים מטא נתונים של מפתח. |
grant | המתקשר זקוק להרשאה זו כדי ליצור הענקה למפתח בהקשר היעד. |
manage_blob | המתקשר עשוי להשתמש DOMAIN_BLOB במרחב השמות הנתון של SELinux, ובכך לנהל בלובים בעצמו. זה שימושי במיוחד עבור vold. |
rebind | הרשאה זו קובעת אם כינוי עשוי להיות משוחזר למפתח חדש. זה נדרש להכנסה ומרמז שהמפתח המחובר הקודם יימחק. זוהי בעצם הרשאת הוספה, אבל היא לוכדת את הסמנטיקה של מאגר המפתחות טוב יותר. |
req_forced_op | לקוחות בעלי הרשאה זו עלולים ליצור פעולות בלתי ניתנות לגזירה, ויצירת פעולות לעולם לא נכשלת אלא אם כן כל משבצות הפעולה נלקחות על ידי פעולות שאינן ניתנות לגזירה. |
update | נדרש לעדכון רכיב המשנה של מפתח. |
use | מסומן בעת יצירת פעולת Keymint המשתמשת בחומר המפתח, למשל, עבור חתימה, en/פענוח. |
use_dev_id | נדרש בעת יצירת מידע מזהה מכשיר, כגון אישור מזהה מכשיר. |
בנוסף, חילקנו קבוצה של הרשאות מאגר מפתחות שאינן ספציפיות למפתחות במאגר המפתחות של מחלקת האבטחה keystore2
:
רְשׁוּת | מַשְׁמָעוּת |
---|---|
add_auth | נדרש על ידי ספק אימות כגון Gatekeeper או BiometricsManager להוספת אסימוני אימות. |
clear_ns | בעבר clear_uid, הרשאה זו מאפשרת למי שאינו בעלים של מרחב שמות למחוק את כל המפתחות במרחב השמות הזה. |
list | נדרש על ידי המערכת לספירת מפתחות לפי מאפיינים שונים, כגון בעלות או תגבול אישור. הרשאה זו אינה נדרשת על ידי מתקשרים המונים את מרחבי השמות שלהם. זה מכוסה על ידי הרשאת get_info . |
lock | הרשאה זו מאפשרת לנעול את Keystore, כלומר, להוציא את המפתח הראשי, כך שמפתחות הקשורים לאישור הופכים לבלתי שמישים ולא ניתנים ליצירה. |
reset | הרשאה זו מאפשרת לאפס את מאגר המקשים לברירת המחדל של היצרן, ולמחוק את כל המקשים שאינם חיוניים לתפקוד מערכת ההפעלה אנדרואיד. |
unlock | הרשאה זו נדרשת כדי לנסות לבטל את נעילת המפתח הראשי עבור מפתחות מאושרים. |
הזמינות של סביבת ביצוע מהימנה במערכת על שבב (SoC) מציעה הזדמנות למכשירי אנדרואיד לספק שירותי אבטחה חזקים מגובי חומרה למערכת ההפעלה אנדרואיד, לשירותי פלטפורמה ואפילו לאפליקציות של צד שלישי. מפתחים המחפשים את ההרחבות הספציפיות לאנדרואיד צריכים לעבור אל android.security.keystore .
לפני אנדרואיד 6.0, לאנדרואיד כבר היה ממשק API פשוט, מגובה חומרה של שירותי קריפטו, שסופק על ידי גרסאות 0.2 ו-0.3 של Keymaster Hardware Abstraction Layer (HAL). Keystore סיפקה פעולות חתימה ואימות דיגיטליים, בתוספת יצירה וייבוא של צמדי מפתחות חתימה אסימטריים. זה כבר מיושם במכשירים רבים, אבל יש הרבה יעדי אבטחה שלא ניתן להשיג בקלות רק עם API חתימה. Keystore באנדרואיד 6.0 הרחיב את ה-API של Keystore כדי לספק מגוון רחב יותר של יכולות.
באנדרואיד 6.0, Keystore הוסיפה פרימיטיבים קריפטוגרפיים סימטריים , AES ו-HMAC, ומערכת בקרת גישה למפתחות מגובי חומרה. בקרות הגישה מוגדרות במהלך יצירת המפתחות ונאכפות למשך כל חיי המפתח. ניתן להגביל מפתחות לשימוש רק לאחר אימות המשתמש, ורק למטרות מוגדרות או עם פרמטרים קריפטוגרפיים מוגדרים. למידע נוסף, עיין בדפי הרשאות תגיות ופונקציות .
בנוסף להרחבת מגוון הפרימיטיבים ההצפנה, Keystore באנדרואיד 6.0 הוסיפה את הדברים הבאים:
- ערכת בקרת שימוש המאפשרת הגבלת השימוש במפתחות, כדי להפחית את הסיכון של פגיעה באבטחה עקב שימוש לרעה במפתחות
- ערכת בקרת גישה לאפשר הגבלת מפתחות למשתמשים, לקוחות וטווח זמן מוגדר
באנדרואיד 7.0, Keymaster 2 הוסיפה תמיכה עבור אישור מפתח וקשירת גרסאות. אישור מפתח מספק אישורי מפתח ציבורי המכילים תיאור מפורט של המפתח ובקרות הגישה שלו, כדי להפוך את קיומו של המפתח בחומרה מאובטחת ואת התצורה שלו לניתנים לאימות מרחוק.
כריכת גרסה קושרת מפתחות למערכת ההפעלה ולגרסת רמת התיקון. זה מבטיח שתוקף שמגלה חולשה בגרסה ישנה של המערכת או בתוכנת TEE לא יוכל להחזיר מכשיר לגרסה הפגיעה ולהשתמש במפתחות שנוצרו עם הגרסה החדשה יותר. בנוסף, כאשר נעשה שימוש במפתח עם גרסה ורמת תיקון נתונות במכשיר ששודרג לגרסה חדשה יותר או לרמת תיקון, המפתח משודרג לפני שניתן להשתמש בו, והגרסה הקודמת של המפתח בטלה. עם השדרוג של המכשיר, המקשים "מתרוצצים" קדימה יחד עם המכשיר, אך כל החזרה של המכשיר למהדורה קודמת גורמת לכך שהמפתחות לא ניתנים לשימוש.
באנדרואיד 8.0, Keymaster 3 עבר משכבת הפשטת החומרה (HAL) בסגנון הישן של מבנה C לממשק C++ HAL שנוצר מהגדרה בשפת הגדרת ממשק החומרה החדשה (HIDL). כחלק מהשינוי, רבים מסוגי הטיעונים השתנו, אם כי לסוגים ולשיטות יש התאמה אחד לאחד עם הטיפוסים הישנים ושיטות מבנה HAL. עיין בדף הפונקציות לפרטים נוספים.
בנוסף לגרסה זו של הממשק, אנדרואיד 8.0 הרחיבה את תכונת האישור של Keymaster 2 כדי לתמוך באישור מזהה . אישור מזהה מספק מנגנון מוגבל ואופציונלי להעיד חזק על מזהי חומרה, כגון מספר סידורי המכשיר, שם המוצר ומזהה הטלפון (IMEI / MEID). כדי ליישם תוספת זו, אנדרואיד 8.0 שינתה את סכימת האישור של ASN.1 כדי להוסיף אישור מזהה. יישומי Keymaster צריכים למצוא דרך מאובטחת כלשהי לאחזר את פריטי הנתונים הרלוונטיים, כמו גם להגדיר מנגנון לביטול מאובטח ולתמיד של התכונה.
באנדרואיד 9, עדכונים כללו:
- עדכון ל- Keymaster 4
- תמיכה ב-Secure Elements משובצים
- תמיכה בייבוא מפתח מאובטח
- תמיכה בהצפנת 3DES
- שינויים בקישור גרסאות כך ש-boot.img ו-system.img הגדירו גרסאות בנפרד כדי לאפשר עדכונים עצמאיים
מילון מונחים
הנה סקירה מהירה של רכיבי Keystore והקשרים ביניהם.
AndroidKeystore הוא ה-API והרכיב של Android Framework המשמש אפליקציות לגישה לפונקציונליות של Keystore. הוא מיושם כהרחבה לממשקי ה-API הסטנדרטיים של Java Cryptography Architecture, ומורכב מקוד Java הפועל במרחב התהליך של האפליקציה עצמה. AndroidKeystore
ממלא בקשות אפליקציה להתנהגות Keystore על ידי העברתן לדמון מאגר המפתחות.
דמון מאגר המפתחות הוא דמון מערכת אנדרואיד המספק גישה לכל הפונקציונליות של מאגר המפתחות באמצעות ממשק API של Binder . היא אחראית לאחסון "כתמי מפתח", המכילים את חומר המפתח הסודי בפועל, מוצפן כך ש-Keystore תוכל לאחסן אותם אך לא להשתמש בהם או לחשוף אותם.
keymasterd הוא שרת HIDL המספק גישה ל-Keymaster TA. (שם זה אינו סטנדרטי והוא מיועד למטרות מושגיות.)
Keymaster TA (יישום מהימן) היא התוכנה הפועלת בהקשר מאובטח, לרוב ב-TrustZone ב-ARM SoC, המספקת את כל הפעולות המאובטחות של Keystore, בעלת גישה לחומר המפתח הגולמי, מאמתת את כל תנאי בקרת הגישה במפתחות , וכו.
LockSettingsService הוא רכיב מערכת אנדרואיד האחראי על אימות המשתמש, הן סיסמה והן טביעת אצבע. זה לא חלק מ-Keystore, אבל רלוונטי מכיוון שהרבה פעולות מפתח של Keystore דורשות אימות משתמש. LockSettingsService
מקיים אינטראקציה עם Gatekeeper TA ו-Fingerprint TA כדי להשיג אסימוני אימות, אותם הוא מספק לדמון מאגר המפתחות, ואשר נצרכים בסופו של דבר על ידי אפליקציית Keymaster TA.
Gatekeeper TA (יישום מהימן) הוא רכיב נוסף הפועל בהקשר המאובטח, שאחראי על אימות סיסמאות משתמש ויצירת אסימוני אימות המשמשים להוכחה ל-Keymaster TA שבוצע אימות עבור משתמש מסוים בנקודת זמן מסוימת.
טביעת אצבע TA (יישום מהימן) הוא רכיב נוסף הפועל בהקשר המאובטח אשר אחראי על אימות טביעות אצבע של משתמש ויצירת אסימוני אימות המשמשים להוכחה ל-Keymaster TA שבוצע אימות עבור משתמש מסוים בנקודת זמן מסוימת.
ארכיטקטורה
ה-API של Android Keystore וה-Keymaster HAL הבסיסי מספקים קבוצה בסיסית אך מספקת של פרימיטיבים קריפטוגרפיים כדי לאפשר יישום של פרוטוקולים באמצעות מפתחות מבוקרי גישה, מגובי חומרה.
ה-Keymaster HAL הוא ספרייה הניתנת לטעינה דינמית המסופקת על ידי OEM המשמשת את שירות Keystore כדי לספק שירותי קריפטוגרפיה מגובי חומרה. כדי לשמור על אבטחת הדברים, יישומי HAL אינם מבצעים שום פעולות רגישות במרחב המשתמש, או אפילו בחלל הקרנל. פעולות רגישות מואצלות למעבד מאובטח שמגיע דרך ממשק ליבה כלשהו. הארכיטקטורה שהתקבלה נראית כך:

איור 1. גישה ל-Keymaster
בתוך מכשיר אנדרואיד, ה"לקוח" של Keymaster HAL מורכב משכבות מרובות (למשל אפליקציה, מסגרת, דמון Keystore), אך ניתן להתעלם מכך למטרות מסמך זה. המשמעות היא שה-Keymaster HAL API המתואר הוא ברמה נמוכה, בשימוש על ידי רכיבים פנימיים של הפלטפורמה, ואינו חשוף למפתחי אפליקציות. ה-API ברמה גבוהה יותר מתואר באתר המפתחים של Android .
מטרת ה-Keymaster HAL היא לא ליישם את האלגוריתמים הרגישים לאבטחה, אלא רק לבקשות של מרשל ו-unmarshal לעולם המאובטח. פורמט החוט מוגדר ביישום.
תאימות עם גרסאות קודמות
ה-Keymaster 1 HAL אינו תואם לחלוטין ל-HALs שפורסמו בעבר, למשל Keymaster 0.2 ו-0.3. כדי להקל על יכולת פעולה הדדית במכשירים המריצים אנדרואיד 5.0 ואילך שהושקו עם ה-Keymaster HALs הישנים יותר, Keystore מספקת מתאם שמיישם את Keymaster 1 HAL עם קריאות לספריית החומרה הקיימת. התוצאה אינה יכולה לספק את כל מגוון הפונקציונליות ב-Keymaster 1 HAL. בפרט, הוא תומך רק באלגוריתמים RSA ו-ECDSA, וכל אכיפת ההרשאות העיקרית מתבצעת על ידי המתאם, בעולם הלא מאובטח.
Keymaster 2 פישט עוד יותר את ממשק HAL על ידי הסרת שיטות get_supported_*
ואפשר לשיטת finish()
לקבל קלט. זה מקטין את מספר הנסיעות הלוך ושוב ל-TEE במקרים שבהם הקלט זמין בבת אחת, ומפשט את היישום של פענוח AEAD.
באנדרואיד 8.0, Keymaster 3 עבר מ-HAL בסגנון הישן של מבנה C לממשק C++ HAL שנוצר מהגדרה ב-Hardware Interface Definition Language (HIDL). מימוש HAL בסגנון חדש נוצר על ידי סיווג משנה של המחלקה IKeymasterDevice
שנוצרה ויישום השיטות הוירטואליות הטהורות. כחלק מהשינוי, רבים מסוגי הטיעונים השתנו, אם כי לסוגים ולשיטות יש התכתבות אחד לאחד עם הטיפוסים הישנים ושיטות מבנה HAL.
סקירה כללית של HIDL
שפת הגדרת ממשק החומרה (HIDL) מספקת מנגנון בלתי תלוי בשפה לציון ממשקי חומרה. כלי ה-HIDL תומך כיום בדור של ממשקי C++ ו-Java. צפוי שרוב המיישמים של סביבת ביצוע מהימנה (TEE) ימצאו את כלי ה-C++ נוח יותר, ולכן מסמך זה דן רק בייצוג C++.
ממשקי HIDL מורכבים מסט של שיטות, המתבטאות כ:
methodName(INPUT ARGUMENTS) generates (RESULT ARGUMENTS);
ישנם סוגים שונים שהוגדרו מראש, ו-HALs יכולים להגדיר סוגים חדשים שנמנו ומבנה. לפרטים נוספים על HIDL, עיין בסעיף הפניה .
שיטה לדוגמה מ- Keymaster 3 IKeymasterDevice.hal
היא:
generateKey(vec<KeyParameter> keyParams) generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
זוהי המקבילה של הדברים הבאים מ-keymaster2 HAL:
keymaster_error_t (*generate_key)( const struct keymaster2_device* dev, const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics);
בגרסת HIDL, הארגומנט dev
מוסר, מכיוון שהוא מרומז. הארגומנט params
אינו עוד מבנה המכיל מצביע המפנה למערך של אובייקטים key_parameter_t
, אלא vec
(וקטור) המכיל אובייקטים KeyParameter
. ערכי ההחזרה מפורטים בסעיף " generates
", כולל וקטור של ערכי uint8_t
עבור ה-key blob.
השיטה הוירטואלית C++ שנוצרה על ידי מהדר HIDL היא:
Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams, generateKey_cb _hidl_cb) override;
כאשר generateKey_cb
הוא מצביע פונקציה המוגדר כ:
std::function<void(ErrorCode error, const hidl_vec<uint8_t>& keyBlob, const KeyCharacteristics& keyCharacteristics)>
כלומר, generateKey_cb
היא פונקציה שלוקחת את ערכי ההחזרה הרשומים בסעיף generate. מחלקת היישום HAL עוקפת את שיטת generateKey
זו וקוראת למצביע הפונקציה generateKey_cb
כדי להחזיר את תוצאת הפעולה למתקשר. שים לב שקריאת מצביע הפונקציה היא סינכרונית . המתקשר קורא generateKey
ו- generateKey
קורא למצביע הפונקציה שסופק, המופעל עד תום, ומחזיר את השליטה למימוש ה- generateKey
, אשר לאחר מכן חוזר למתקשר.
לדוגמא מפורטת, עיין ביישום ברירת המחדל ב- hardware/interfaces/keymaster/3.0/default/KeymasterDevice.cpp
. יישום ברירת המחדל מספק תאימות לאחור עבור מכשירים עם keymaster0, keymaster1 או keymaster2 HALS בסגנון ישן.
בקרת גישה
הכלל הבסיסי ביותר של בקרת הגישה של Keystore הוא שלכל אפליקציה יש מרחב שמות משלה. אבל לכל כלל יש יוצא מן הכלל. ל-Keystore יש כמה מפות מקודדות המאפשרות לרכיבי מערכת מסוימים גישה למרחבי שמות מסוימים אחרים. זהו מכשיר בוטה מאוד בכך שהוא נותן לרכיב אחד שליטה מלאה על מרחב שמות אחר. ואז יש את העניין של רכיבי הספק כלקוחות ל-Keystore. כרגע אין לנו דרך להקים מרחב שמות עבור רכיבי ספקים, למשל, מבקש WPA.
על מנת להתאים לרכיבי הספק ולהכליל בקרת גישה ללא חריגים מקודדים, Keystore 2.0 מציגה דומיינים ומרחבי שמות של SELinux.
דומיינים של מאגר מפתחות
עם דומיינים של Keystore, אנו יכולים לנתק מרחבי שמות מ-UID. לקוחות הניגשים למפתח ב-Keystore צריכים לציין את הדומיין, מרחב השמות והכינוי שאליהם הם רוצים לגשת. בהתבסס על הטפול הזה וזהות המתקשר נוכל לקבוע לאיזה מפתח המתקשר רוצה לגשת ואם יש לו הרשאות מתאימות.
אנו מציגים חמישה פרמטרים של תחום שקובעים כיצד ניתן לגשת למפתחות. הם שולטים בסמנטיקה של פרמטר מרחב השמות של מתאר המפתח ובאופן ביצוע בקרת הגישה.
-
DOMAIN_APP
: תחום האפליקציה מכסה את ההתנהגות מדור קודם. ה-SPI של Java Keystore משתמש בדומיין זה כברירת מחדל. כאשר נעשה שימוש בדומיין זה, מתעלמים מארגומנט מרחב השמות ובמקום זאת נעשה שימוש ב-UID של המתקשר. הגישה לדומיין זה נשלטת על ידי התווית Keystore למחלקהkeystore_key
במדיניות SELinux. -
DOMAIN_SELINUX
: תחום זה מציין שלמרחב השמות יש תווית במדיניות SELinux. פרמטר מרחב השמות נבדק ומתורגם להקשר יעד, ובדיקת הרשאות מתבצעת עבור ההקשר הקורא SELinux עבור מחלקתkeystore_key
. כאשר הוקמה ההרשאה עבור הפעולה הנתונה, ה-tuple המלא משמש לחיפוש המפתח. -
DOMAIN_GRANT
: The grant domain indicates that the namespace parameter is a grant identifier. The alias parameter is ignored. SELinux checks are performed when the grant is created. Further access control only checks if the caller UID matches the grantees UID of the requested grant. -
DOMAIN_KEY_ID
: This domain indicates that the namespace parameter is a unique key id. The key itself may have been created withDOMAIN_APP
orDOMAIN_SELINUX
. The permission check is performed after thedomain
and thenamespace
have been loaded from the key database in the same way as if the blob was loaded by the domain, namespace, and alias tuple. The rationale for the key id domain is continuity. When accessing a key by alias, subsequent calls may operate on different keys, because a new key may have been generated or imported and bound to this alias. The key id, however, never changes. So when using a key by key id after it has been loaded from the Keystore database using the alias once, one can be certain that it is the same key as long as the key id still exists. This functionality is not exposed to app developers. Instead, it is used within the Android Keystore SPI to provide a more consistent experience even when used concurrently in an unsafe way. -
DOMAIN_BLOB
: The blob domain indicates that the caller manages the blob by itself. This is used for clients that need to access the Keystore before the data partition is mounted. The key blob is included in theblob
field of the key descriptor.
Using the SELinux domain, we can give vendor components access to very specific Keystore namespaces which can be shared by system components such as the settings dialog.
SELinux policy for keystore_key
Namespace labels are configured using the keystore2_key_context
file.
Each line in these files maps a numeric namespace id to an SELinux label. For example,
# wifi_key is a keystore2_key namespace intended to be used by wpa supplicant and # Settings to share keystore keys. 102 u:object_r:wifi_key:s0
After having set up a new key namespace in this way, we can give access to it by adding an appropriate policy. For example, to allow wpa_supplicant
to get and use keys in the new namespace we would add the following line to hal_wifi_supplicant.te
:
allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };
After setting up the new namespace, AndroidKeyStore can be used almost as usual. The only difference is that the namespace ID must be specified. For loading and importing keys from and into Keystore, the namespace id is specified using the AndroidKeyStoreLoadStoreParameter
. For example,
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter; import java.security.KeyStore; KeyStore keystore = KeyStore.getInstance("AndroidKeyStore"); keystore.load(new AndroidKeyStoreLoadStoreParameter(102));
To generate a key in a given namespace, the namespace id must be given using KeyGenParameterSpec.Builder#setNamespace():
import android.security.keystore.KeyGenParameterSpec; KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(); specBuilder.setNamespace(102);
The following context files may be used to configure Keystore 2.0 SELinux namespaces. Each partition has a different reserved range of 10,000 namespace ids to avoid collisions.
Partition | Range | Config files |
---|---|---|
System | 0 ... 9,999 | /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts |
Extended System | 10,000 ... 19,999 | /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts |
Product | 20,000 ... 29,999 | /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts |
Vendor | 30,000 ... 39,999 | /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts |
The client requests the key by requesting the SELinux domain and the desired virtual namespace, in this case "wifi_key"
, by its numeric id.
Above that, the following namespaces have been defined. If they replace special rules, the following table indicates the UID they used to correspond to.
Namespace ID | SEPolicy Label | UID | תיאור |
---|---|---|---|
0 | su_key | N/A | Super user key. Only used for testing on userdebug and eng builds. Not relevant on user builds. |
1 | shell_key | N/A | Namespace available to shell. Mostly used for testing, but can be used on user builds as well from the command line. |
100 | vold_key | N/A | Intended for use by vold. |
101 | odsing_key | N/A | Used by the on-device signing daemon. |
102 | wifi_key | AID_WIFI(1010) | Used by Android's Wifi sybsystem including wpa_supplicant. |
120 | resume_on_reboot_key | AID_SYSTEM(1000) | Used by Android's system server to support resume on reboot. |
Access Vectors
The SELinux class keystore_key
has aged quite a bit and some of the permissions, such as verify
or sign
have lost their meaning. Here is the new set of permissions, keystore2_key
, that Keystore 2.0 will enforce.
Permission | Meaning |
---|---|
delete | Checked when removing keys from Keystore. |
get_info | Checked when a key's metadata is requested. |
grant | The caller needs this permission to create a grant to the key in the target context. |
manage_blob | The caller may use DOMAIN_BLOB on the given SELinux namespace, thereby managing blobs by itself. This is specifically useful for vold. |
rebind | This permission controls if an alias may be rebound to a new key. This is required for insertion and implies that the previously bound key will be deleted. It is basically an insert permission, but it captures the semantic of keystore better. |
req_forced_op | Clients with this permission may create unpruneable operations, and operation creation never fails unless all operation slots are taken by unpruneable operations. |
update | Required to update the subcomponent of a key. |
use | Checked when creating a Keymint operation that uses the key material, eg, for signing, en/decryption. |
use_dev_id | Required when generating device identifying information, such as device id attestation. |
Additionally, we split out a set of non key specific keystore permissions in the SELinux security class keystore2
:
Permission | Meaning |
---|---|
add_auth | Required by authentication provider such as Gatekeeper or BiometricsManager for adding auth tokens. |
clear_ns | Formerly clear_uid, this permission allows a non owner of a namespace to delete all keys in that namespace. |
list | Required by the system for enumerating keys by various properties, such as ownership or auth boundedness. This permission is not required by callers enumerating their own namespaces. This is covered by the get_info permission. |
lock | This permission allows to lock Keystore, that is, evict the master key, such that auth bound keys become unusable and uncreatable. |
reset | This permission allows to reset Keystore to factory default, deleting all keys that are not vital to the functioning of the Android OS. |
unlock | This permission is required to attempt to unlock the master key for auth bound keys. |