Keystore با پشتیبانی سخت افزار

وجود یک محیط اجرای قابل اعتماد (TEE) در یک سیستم روی تراشه (SoC) فرصتی را برای دستگاه‌های اندروید فراهم می‌کند تا سرویس‌های امنیتی قوی و با پشتیبانی سخت‌افزاری را برای سیستم‌عامل اندروید، سرویس‌های پلتفرم و حتی برنامه‌های شخص ثالث (به شکل افزونه‌های مخصوص اندروید برای معماری رمزنگاری استاندارد جاوا، به KeyGenParameterSpec مراجعه کنید) ارائه دهند.

واژه‌نامه

در اینجا مروری سریع بر اجزای Keystore و روابط آنها ارائه شده است.

AndroidKeyStore
API و کامپوننت چارچوب اندروید که توسط برنامه‌ها برای دسترسی به قابلیت Keystore استفاده می‌شود. این یک پیاده‌سازی از APIهای استاندارد معماری رمزنگاری جاوا است، اما افزونه‌های مخصوص اندروید را نیز اضافه می‌کند و شامل کد جاوایی است که در فضای پردازش خود برنامه اجرا می‌شود. AndroidKeyStore درخواست‌های برنامه برای رفتار Keystore را با ارسال آنها به سرویس keystore انجام می‌دهد.
دیمن فروشگاه کلید
یک سرویس (daemon) سیستم اندروید که دسترسی به تمام قابلیت‌های Keystore را از طریق یک Binder API فراهم می‌کند. این سرویس مسئول ذخیره keyblob های ایجاد شده توسط پیاده‌سازی زیربنایی KeyMint (یا Keymaster) است که حاوی محتوای کلید مخفی هستند و رمزگذاری شده‌اند تا Keystore بتواند آنها را ذخیره کند اما نتواند از آنها استفاده یا فاش کند.
سرویس KeyMint HAL
یک سرور AIDL که IKeyMintDevice HAL را پیاده‌سازی می‌کند و دسترسی به KeyMint TA زیربنایی را فراهم می‌کند.
برنامه قابل اعتماد KeyMint (TA)
نرم‌افزاری که در یک بستر امن، اغلب در TrustZone روی یک ARM SoC، اجرا می‌شود و تمام عملیات رمزنگاری امن را فراهم می‌کند. این برنامه به مواد اولیه کلید دسترسی دارد و قبل از اجازه استفاده از کلیدها، تمام شرایط کنترل دسترسی روی آنها را تأیید می‌کند.
LockSettingsService
کامپوننت سیستم اندروید که مسئول احراز هویت کاربر، چه با رمز عبور و چه با اثر انگشت، است. این کامپوننت بخشی از Keystore نیست، اما به این دلیل مرتبط است که Keystore از مفهوم کلیدهای متصل به احراز هویت پشتیبانی می‌کند: کلیدهایی که فقط در صورت احراز هویت کاربر قابل استفاده هستند. LockSettingsService با Gatekeeper TA و Fingerprint TA تعامل دارد تا توکن‌های احراز هویت را دریافت کند، که آنها را در اختیار دیمن keystore قرار می‌دهد و توسط KeyMint TA مصرف می‌شوند.
دروازه‌بان TA
مؤلفه‌ای که در محیط امن اجرا می‌شود و مسئول احراز هویت رمزهای عبور کاربر و تولید توکن‌های احراز هویت است که برای اثبات به KeyMint TA مبنی بر انجام احراز هویت برای یک کاربر خاص در یک نقطه زمانی خاص استفاده می‌شود.
اثر انگشت TA
مؤلفه‌ای که در محیط امن اجرا می‌شود و مسئول احراز هویت اثر انگشت کاربر و تولید توکن‌های احراز هویت است که برای اثبات به KeyMint TA مبنی بر انجام احراز هویت برای یک کاربر خاص در یک نقطه زمانی خاص استفاده می‌شود.

معماری

رابط برنامه‌نویسی کاربردی (API) اندروید کی‌استور و KeyMint HAL زیربنایی، مجموعه‌ای ابتدایی اما کافی از اصول اولیه رمزنگاری را فراهم می‌کنند تا امکان پیاده‌سازی پروتکل‌ها با استفاده از کلیدهای سخت‌افزاریِ کنترل‌شده با دسترسی فراهم شود.

KeyMint HAL یک سرویس ارائه شده توسط OEM است که توسط سرویس Keystore برای ارائه خدمات رمزنگاری با پشتیبانی سخت‌افزاری استفاده می‌شود. برای ایمن نگه داشتن محتوای کلید خصوصی، پیاده‌سازی‌های HAL هیچ عملیات حساسی را در فضای کاربر یا حتی در فضای هسته انجام نمی‌دهند. در عوض، سرویس KeyMint HAL که در اندروید اجرا می‌شود، عملیات حساس را به یک TA که در نوعی محیط امن اجرا می‌شود، معمولاً با مرتب‌سازی و نامرتب‌سازی درخواست‌ها در قالب سیمی تعریف‌شده توسط پیاده‌سازی، واگذار می‌کند.

معماری حاصل به این شکل است:

دسترسی به کی‌مینت

شکل ۱. دسترسی به KeyMint.

رابط برنامه‌نویسی کاربردی KeyMint HAL سطح پایین است، توسط اجزای داخلی پلتفرم استفاده می‌شود و در دسترس توسعه‌دهندگان برنامه قرار ندارد. رابط برنامه‌نویسی کاربردی جاوا سطح بالاتر که برای برنامه‌ها در دسترس است، در سایت توسعه‌دهندگان اندروید شرح داده شده است.

کنترل دسترسی

اندروید کی‌استور یک جزء مرکزی برای ذخیره‌سازی و استفاده از کلیدهای رمزنگاری سخت‌افزاری، هم برای برنامه‌ها و هم برای سایر اجزای سیستم، فراهم می‌کند. به این ترتیب، دسترسی به هر کلید منحصراً به برنامه یا جزء سیستمی که کلید را ایجاد کرده است، محدود می‌شود.

دامنه‌های کی‌استور

برای پشتیبانی از این کنترل دسترسی، کلیدها با یک توصیف‌گر کلید به Keystore معرفی می‌شوند. این توصیف‌گر کلید، دامنه‌ای را که توصیف‌گر به آن تعلق دارد، به همراه یک هویت در آن دامنه، نشان می‌دهد.

برنامه‌های اندروید با استفاده از معماری رمزنگاری استاندارد جاوا به Keystore دسترسی پیدا می‌کنند، که کلیدها را با یک نام مستعار رشته‌ای شناسایی می‌کند. این روش شناسایی به صورت داخلی به دامنه Keystore APP نگاشت می‌شود؛ UID فراخواننده نیز برای رفع ابهام کلیدها از برنامه‌های مختلف گنجانده شده است و از دسترسی یک برنامه به کلیدهای برنامه دیگر جلوگیری می‌کند.

در داخل، کد فریم‌ورک‌ها پس از بارگذاری یک کلید، یک شناسه کلید عددی منحصر به فرد نیز دریافت می‌کند. این شناسه عددی به عنوان شناسه برای توصیف‌گرهای کلید در دامنه KEY_ID استفاده می‌شود. با این حال، کنترل دسترسی همچنان انجام می‌شود: حتی اگر یک برنامه شناسه کلید را برای کلید برنامه دیگری کشف کند، نمی‌تواند در شرایط عادی از آن استفاده کند.

با این حال، یک برنامه می‌تواند اجازه استفاده از یک کلید را به برنامه دیگری (که توسط UID شناسایی می‌شود) بدهد. این عملیات اعطای مجوز، یک شناسه اعطای منحصر به فرد را برمی‌گرداند که به عنوان شناسه برای توصیف‌گرهای کلید در دامنه GRANT استفاده می‌شود. باز هم، کنترل دسترسی همچنان انجام می‌شود: حتی اگر برنامه سومی شناسه اعطای کلید یک دریافت‌کننده مجوز را کشف کند، نمی‌تواند از آن استفاده کند.

Keystore همچنین از دو دامنه دیگر برای توصیف‌گرهای کلید پشتیبانی می‌کند که برای سایر اجزای سیستم استفاده می‌شوند و برای کلیدهای ایجاد شده توسط برنامه در دسترس نیستند:

  • دامنه BLOB نشان می‌دهد که هیچ شناسه‌ای برای کلید در توصیف‌گر کلید وجود ندارد؛ در عوض، توصیف‌گر کلید، خودِ keyblob را در خود نگه می‌دارد و کلاینت، ذخیره‌سازی keyblob را مدیریت می‌کند. این دامنه توسط کلاینت‌هایی (برای مثال، vold ) که نیاز به دسترسی به Keystore قبل از نصب پارتیشن داده دارند، استفاده می‌شود.
  • دامنه SELINUX به اجزای سیستم اجازه می‌دهد تا کلیدها را به اشتراک بگذارند، و دسترسی توسط یک شناسه عددی که مربوط به یک برچسب SELinux است، کنترل می‌شود ( برای keystore_key به سیاست SELinux مراجعه کنید).

سیاست SELinux برای keystore_key

مقادیر شناسه مورد استفاده برای توصیف‌گرهای کلید Domain::SELINUX در فایل سیاست SELinux 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

کامپوننتی که نیاز به دسترسی به کلید با شناسه ۱۰۲ در دامنه SELINUX دارد، باید سیاست SELinux مربوطه را داشته باشد. برای مثال، برای اینکه به wpa_supplicant اجازه داده شود این کلیدها را دریافت و استفاده کند، خط زیر را به hal_wifi_supplicant.te اضافه کنید:

allow hal_wifi_supplicant wifi_key:keystore2_key { get, use };

شناسه‌های عددی برای کلیدهای Domain::SELINUX به محدوده‌هایی تقسیم می‌شوند تا از پارتیشن‌های مختلف بدون تداخل پشتیبانی کنند:

پارتیشن محدوده فایل‌های پیکربندی
سیستم ۰ ... ۹,۹۹۹ /system/etc/selinux/keystore2_key_contexts, /plat_keystore2_key_contexts
سیستم توسعه‌یافته ۱۰،۰۰۰ ... ۱۹،۹۹۹ /system_ext/etc/selinux/system_ext_keystore2_key_contexts, /system_ext_keystore2_key_contexts
محصول ۲۰،۰۰۰ ... ۲۹۹۹۹ /product/etc/selinux/product_keystore2_key_contexts, /product_keystore2_key_contexts
فروشنده ۳۰،۰۰۰ ... ۳۹،۹۹۹ /vendor/etc/selinux/vendor_keystore2_key_contexts, /vendor_keystore2_key_contexts

مقادیر خاص زیر برای پارتیشن سیستم تعریف شده‌اند:

شناسه فضای نام برچسب سیاست SE شناسه کاربری توضیحات
0 su_key ناموجود کلید کاربر ویژه. فقط برای آزمایش در نسخه‌های userdebug و eng استفاده می‌شود. در نسخه‌های user-bugg کاربردی ندارد.
۱ shell_key ناموجود فضای نام موجود برای پوسته. بیشتر برای آزمایش استفاده می‌شود، اما می‌تواند در نسخه‌های کاربری و همچنین از طریق خط فرمان مورد استفاده قرار گیرد.
۱۰۰ vold_key ناموجود برای استفاده توسط vold در نظر گرفته شده است.
۱۰۱ odsign_key ناموجود توسط سرویس امضای روی دستگاه استفاده می‌شود.
۱۰۲ wifi_key AID_WIFI(1010) توسط زیرسیستم وای‌فای اندروید از جمله wpa_supplicant استفاده می‌شود.
۱۰۳ locksettings_key ناموجود استفاده شده توسط LockSettingsService
۱۲۰ resume_on_reboot_key AID_SYSTEM(1000) توسط سرور سیستم اندروید برای پشتیبانی از ادامه‌ی کار پس از راه‌اندازی مجدد استفاده می‌شود.

بردارهای دسترسی

Keystore علاوه بر کنترل دسترسی کلی به یک کلید، امکان کنترل عملیات قابل انجام روی آن را نیز فراهم می‌کند. مجوزهای keystore2_key در فایل KeyPermission.aidl شرح داده شده‌اند.

مجوزهای سیستم

علاوه بر کنترل‌های دسترسی به ازای هر کلید که در سیاست SELinux برای keystore_key شرح داده شده است، جدول زیر سایر مجوزهای SELinux را که برای انجام عملیات مختلف سیستم و نگهداری مورد نیاز هستند، شرح می‌دهد:

اجازه معنی
add_auth برای افزودن توکن‌های احراز هویت به Keystore مورد نیاز است؛ توسط ارائه‌دهندگان احراز هویت مانند Gatekeeper یا BiometricManager استفاده می‌شود.
clear_ns برای حذف تمام کلیدها در یک فضای نام خاص مورد نیاز است؛ هنگام حذف برنامه‌ها به عنوان یک عملیات نگهداری استفاده می‌شود.
list سیستم برای شمارش کلیدها بر اساس ویژگی‌های مختلف، مانند مالکیت یا اینکه آیا آنها به احراز هویت وابسته هستند یا خیر، به این مجوز نیاز دارد. این مجوز برای تماس‌گیرندگانی که فضاهای نام خود را (که توسط مجوز get_info پوشش داده می‌شوند) شمارش می‌کنند، لازم نیست.
lock برای اطلاع‌رسانی به keystore مبنی بر قفل شدن دستگاه مورد نیاز است، که به نوبه خود super-keyها را حذف می‌کند تا اطمینان حاصل شود که کلیدهای مربوط به احراز هویت در دسترس نیستند.
unlock لازم است به keystore اطلاع داده شود که دستگاه قفل‌گشایی شده است و دسترسی به super-keyهایی که از کلیدهای مربوط به احراز هویت محافظت می‌کنند، بازیابی شود.
reset برای تنظیم مجدد Keystore به تنظیمات پیش‌فرض کارخانه و حذف تمام کلیدهایی که برای عملکرد سیستم عامل اندروید حیاتی نیستند، مورد نیاز است.

تاریخچه

در اندروید ۵ و پایین‌تر، اندروید یک API ساده و مبتنی بر سخت‌افزار برای خدمات رمزنگاری داشت که توسط نسخه‌های ۰.۲ و ۰.۳ لایه انتزاعی سخت‌افزاری Keymaster (HAL) ارائه می‌شد. Keystore عملیات امضای دیجیتال و تأیید هویت، به علاوه تولید و وارد کردن جفت کلیدهای امضای نامتقارن را فراهم می‌کرد. این قابلیت در حال حاضر در بسیاری از دستگاه‌ها پیاده‌سازی شده است، اما اهداف امنیتی زیادی وجود دارد که به راحتی نمی‌توان تنها با یک API امضا به آنها دست یافت. اندروید ۶.۰ API Keystore را گسترش داد تا طیف وسیع‌تری از قابلیت‌ها را ارائه دهد.

اندروید ۶.۰

در اندروید ۶.۰، Keymaster 1.0 اصول اولیه رمزنگاری متقارن ، AES و HMAC و یک سیستم کنترل دسترسی برای کلیدهای سخت‌افزاری را اضافه کرد. کنترل‌های دسترسی در طول تولید کلید مشخص شده و در طول عمر کلید اعمال می‌شوند. کلیدها را می‌توان محدود کرد تا فقط پس از احراز هویت کاربر و فقط برای اهداف مشخص یا با پارامترهای رمزنگاری مشخص، قابل استفاده باشند.

علاوه بر گسترش دامنه‌ی اصول رمزنگاری، Keystore در اندروید ۶.۰ موارد زیر را نیز اضافه کرده است:

  • یک طرح کنترل استفاده برای محدود کردن استفاده از کلید، به منظور کاهش خطر به خطر افتادن امنیت به دلیل سوءاستفاده از کلیدها
  • یک طرح کنترل دسترسی برای محدود کردن کلیدها به کاربران، کلاینت‌های مشخص و یک محدوده زمانی تعریف‌شده

اندروید ۷.۰

در اندروید ۷.۰، Keymaster 2 پشتیبانی از گواهی کلید و اتصال نسخه را اضافه کرد.

تأیید کلید، گواهی‌های کلید عمومی را ارائه می‌دهد که شامل شرح مفصلی از کلید و کنترل‌های دسترسی آن است تا وجود کلید در سخت‌افزار امن و پیکربندی آن از راه دور قابل تأیید باشد.

اتصال نسخه، کلیدها را به سیستم عامل و نسخه سطح وصله (patch level) متصل می‌کند. این تضمین می‌کند که مهاجمی که ضعفی را در نسخه قدیمی سیستم یا نرم‌افزار TEE کشف می‌کند، نمی‌تواند دستگاه را به نسخه آسیب‌پذیر برگرداند و از کلیدهای ایجاد شده با نسخه جدیدتر استفاده کند. علاوه بر این، هنگامی که یک کلید با نسخه و سطح وصله مشخص در دستگاهی که به نسخه جدیدتر یا سطح وصله ارتقا یافته است استفاده می‌شود، کلید قبل از استفاده ارتقا می‌یابد و نسخه قبلی کلید نامعتبر می‌شود. با ارتقا دستگاه، کلیدها همراه با دستگاه به جلو حرکت می‌کنند، اما هرگونه بازگشت دستگاه به نسخه قبلی باعث می‌شود که کلیدها غیرقابل استفاده شوند.

اندروید ۸.۰

در اندروید ۸.۰، Keymaster 3 از ساختار قدیمی HAL به زبان C++ HAL که از تعریفی در زبان تعریف رابط سخت‌افزاری جدید (HIDL) تولید شده بود، تغییر کرد. به عنوان بخشی از این تغییر، بسیاری از انواع آرگومان‌ها تغییر کردند، اگرچه انواع و روش‌ها با انواع قدیمی و روش‌های ساختار HAL تناظر یک به یک دارند.

علاوه بر این اصلاح رابط کاربری، اندروید ۸.۰ ویژگی گواهی Keymaster 2 را برای پشتیبانی از گواهی ID گسترش داد. گواهی ID یک مکانیسم محدود و اختیاری برای گواهی قوی شناسه‌های سخت‌افزاری، مانند شماره سریال دستگاه، نام محصول و شناسه تلفن (IMEI یا MEID) فراهم می‌کند. برای پیاده‌سازی این قابلیت، اندروید ۸.۰ طرح گواهی ASN.1 را تغییر داد تا گواهی ID را اضافه کند. پیاده‌سازی‌های Keymaster باید راهی امن برای بازیابی اقلام داده مربوطه و همچنین تعریف مکانیسمی برای غیرفعال کردن ایمن و دائمی این ویژگی پیدا کنند.

اندروید ۹

در اندروید ۹، به‌روزرسانی‌ها شامل موارد زیر بودند:

  • به‌روزرسانی به کی‌مستر ۴
  • پشتیبانی از عناصر امنیتی تعبیه‌شده
  • پشتیبانی از وارد کردن کلید امن
  • پشتیبانی از رمزگذاری 3DES
  • تغییرات در اتصال نسخه به طوری که boot.img و system.img نسخه‌های جداگانه‌ای دارند تا به‌روزرسانی‌های مستقل امکان‌پذیر باشد.

اندروید ۱۰

اندروید ۱۰ نسخه ۴.۱ از Keymaster HAL را معرفی کرد که موارد زیر را اضافه کرد:

  • پشتیبانی از کلیدهایی که فقط هنگام باز شدن قفل دستگاه قابل استفاده هستند
  • پشتیبانی از کلیدهایی که فقط در مراحل اولیه بوت قابل استفاده هستند
  • پشتیبانی اختیاری برای کلیدهای ذخیره‌سازی سخت‌افزاری
  • پشتیبانی اختیاری برای گواهی منحصر به فرد دستگاه در StrongBox

اندروید ۱۲

اندروید ۱۲، KeyMint HAL جدید را معرفی کرد که جایگزین Keymaster HAL شده اما عملکرد مشابهی را ارائه می‌دهد. علاوه بر تمام ویژگی‌های فوق، KeyMint HAL شامل موارد زیر نیز می‌شود:

  • پشتیبانی از توافق‌نامه کلید ECDH
  • پشتیبانی از کلیدهای تأیید هویت مشخص شده توسط کاربر
  • Supoprt برای کلیدهایی با تعداد استفاده محدود

اندروید ۱۲ همچنین شامل نسخه جدیدی از دیمن سیستم keystore است که با زبان Rust بازنویسی شده و با نام keystore2 شناخته می‌شود.

اندروید ۱۳

اندروید ۱۳ نسخه ۲ از KeyMint HAL را اضافه کرد که پشتیبانی از Curve25519 را هم برای امضا و هم برای توافق کلید اضافه می‌کند.