نسخه صحافی

در Keymaster 1، تمام کلیدهای Keymaster به صورت رمزنگاری به Root of Trust دستگاه یا کلید بوت تأیید شده (Verified Boot key) متصل بودند. در Keymaster 2 و 3، تمام کلیدها به سیستم عامل و سطح وصله (patch level) تصویر سیستم نیز متصل هستند. این تضمین می‌کند که مهاجمی که ضعفی را در نسخه قدیمی سیستم یا نرم‌افزار TEE کشف می‌کند، نمی‌تواند دستگاه را به نسخه آسیب‌پذیر برگرداند و از کلیدهای ایجاد شده با نسخه جدیدتر استفاده کند. علاوه بر این، هنگامی که یک کلید با نسخه و سطح وصله مشخص در دستگاهی که به نسخه جدیدتر یا سطح وصله ارتقا یافته است استفاده می‌شود، کلید قبل از استفاده ارتقا می‌یابد و نسخه قبلی کلید نامعتبر می‌شود. به این ترتیب، با ارتقاء دستگاه، کلیدها *به‌صورت چرخشی* همراه با دستگاه به جلو می‌روند، اما هرگونه بازگشت دستگاه به نسخه قبلی باعث می‌شود که کلیدها غیرقابل استفاده شوند.

برای پشتیبانی از ساختار ماژولار Treble و شکستن اتصال system.img به boot.img، Keymaster 4 مدل اتصال نسخه کلید را تغییر داد تا برای هر پارتیشن سطوح پچ جداگانه‌ای داشته باشد. این امر به هر پارتیشن اجازه می‌دهد تا به‌طور مستقل به‌روزرسانی شود، در حالی که همچنان محافظت در برابر بازگشت به نسخه‌های قبلی را فراهم می‌کند.

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

  • دستگاه‌هایی که دارای Android Verified Boot (AVB) هستند می‌توانند تمام سطوح پچ و نسخه سیستم را در vbmeta قرار دهند، بنابراین بوت لودر می‌تواند آنها را در اختیار Keymaster قرار دهد. برای پارتیشن‌های زنجیره‌ای، اطلاعات نسخه پارتیشن در vbmeta زنجیره‌ای قرار دارد. به طور کلی، اطلاعات نسخه باید در vbmeta struct باشد که شامل داده‌های تأیید (هش یا درخت هش) برای یک پارتیشن مشخص است.
  • در دستگاه‌های بدون AVB:
    • پیاده‌سازی‌های بوت تأیید شده باید هشی از ابرداده‌های نسخه را به بوت‌لودر ارائه دهند تا بوت‌لودر بتواند هش را به Keymaster ارائه دهد.
    • boot.img می‌تواند به ذخیره سطح پچ در هدر ادامه دهد.
    • system.img می‌تواند به ذخیره سطح پچ و نسخه سیستم عامل در ویژگی‌های فقط خواندنی ادامه دهد.
    • vendor.img سطح وصله را در ویژگی فقط خواندنی ro.vendor.build.version.security_patch ذخیره می‌کند.
    • بوت لودر می‌تواند هشی از تمام داده‌های تأیید شده توسط Verified Boot را در اختیار Keymaster قرار دهد.
  • در اندروید ۹، از تگ‌های زیر برای ارائه اطلاعات نسخه برای پارتیشن‌های زیر استفاده کنید:
    • VENDOR_PATCH_LEVEL : پارتیشن vendor
    • BOOT_PATCH_LEVEL : پارتیشن boot
    • OS_PATCH_LEVEL و OS_VERSION : پارتیشن system . ( OS_VERSION از هدر boot.img حذف شده است.)
  • پیاده‌سازی‌های Keymaster باید با تمام سطوح پچ به طور مستقل رفتار کنند. کلیدها در صورتی قابل استفاده هستند که تمام اطلاعات نسخه با مقادیر مرتبط با یک کلید مطابقت داشته باشند و IKeymaster::upgradeDevice() در صورت نیاز به سطح پچ بالاتری منتقل می‌شود.

تغییرات HAL

برای پشتیبانی از اتصال نسخه و گواهی نسخه، اندروید ۷.۱ تگ‌های Tag::OS_VERSION و Tag::OS_PATCHLEVEL و متدهای configure و upgradeKey را اضافه کرد. تگ‌های نسخه به طور خودکار توسط پیاده‌سازی‌های Keymaster 2+ به تمام کلیدهای تازه تولید شده (یا به‌روزرسانی شده) اضافه می‌شوند. علاوه بر این، هرگونه تلاشی برای استفاده از کلیدی که نسخه سیستم عامل یا سطح وصله آن با نسخه سیستم عامل یا سطح وصله فعلی مطابقت نداشته باشد، با ErrorCode::KEY_REQUIRES_UPGRADE رد می‌شود.

Tag::OS_VERSION یک مقدار UINT است که بخش‌های اصلی، فرعی و زیر-جزئی نسخه سیستم اندروید را به صورت MMmmss نشان می‌دهد، که در آن MM نسخه اصلی، mm نسخه فرعی و ss نسخه فرعی است. برای مثال، نسخه ۶.۱.۲ به صورت ۰۶۰۱۰۲ نمایش داده می‌شود.

Tag::OS_PATCHLEVEL یک مقدار UINT است که سال و ماه آخرین به‌روزرسانی سیستم را به صورت YYYYMM نشان می‌دهد، که در آن YYYY سال چهار رقمی و MM ماه دو رقمی است. برای مثال، مارس ۲۰۱۶ به صورت ۲۰۱۶۰۳ نمایش داده می‌شود.

کلید ارتقا

برای اینکه کلیدها بتوانند به نسخه جدید سیستم عامل و سطح پچ تصویر سیستم ارتقا یابند، اندروید ۷.۱ متد upgradeKey به HAL اضافه کرد:

کلیدساز ۳

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

کلیدساز ۲

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 می‌شوند که در صورت ارائه شدن در طول تولید، برای رمزگشایی بلوک کلید ضروری هستند.
  • upgradedKeyBlob پارامتر خروجی است که برای برگرداندن کلید جدید استفاده می‌شود.

اگر upgradeKey با یک حباب کلید فراخوانی شود که قابل تجزیه نباشد یا نامعتبر باشد، ErrorCode::INVALID_KEY_BLOB را برمی‌گرداند. اگر با کلیدی فراخوانی شود که سطح وصله آن بزرگتر از مقدار فعلی سیستم باشد، ErrorCode::INVALID_ARGUMENT را برمی‌گرداند. اگر با کلیدی فراخوانی شود که نسخه سیستم عامل آن بزرگتر از مقدار فعلی سیستم باشد و مقدار سیستم غیر صفر باشد، ErrorCode::INVALID_ARGUMENT را برمی‌گرداند. ارتقاء نسخه سیستم عامل از غیر صفر به صفر مجاز است. در صورت بروز خطا در برقراری ارتباط با دنیای امن، مقدار خطای مناسبی را برمی‌گرداند (برای مثال، ErrorCode::SECURE_HW_ACCESS_DENIED ، ErrorCode::SECURE_HW_BUSY ). در غیر این صورت، ErrorCode::OK را برمی‌گرداند و یک حباب کلید جدید در upgradedKeyBlob برمی‌گرداند.

keyBlobToUpgrade پس از فراخوانی upgradeKey معتبر باقی می‌ماند و از لحاظ تئوری در صورت تنزل رتبه دستگاه، می‌تواند دوباره مورد استفاده قرار گیرد. در عمل، keystore معمولاً deleteKey در keyBlobToUpgrade کمی پس از فراخوانی upgradeKey فراخوانی می‌کند. اگر keyBlobToUpgrade دارای تگ Tag::ROLLBACK_RESISTANT بود، upgradedKeyBlob نیز باید آن را داشته باشد (و باید در برابر بازگشت مقاوم باشد).

پیکربندی امن

برای پیاده‌سازی اتصال نسخه، مدیر فنی کلید (Keymaster TA) به روشی نیاز دارد تا به‌طور ایمن نسخه فعلی سیستم عامل و سطح وصله (اطلاعات نسخه) را دریافت کند و اطمینان حاصل کند که اطلاعات دریافتی کاملاً با اطلاعات مربوط به سیستم عامل در حال اجرا مطابقت دارد.

برای پشتیبانی از تحویل امن اطلاعات نسخه به TA، یک فیلد OS_VERSION به هدر تصویر بوت اضافه شده است. اسکریپت ساخت تصویر بوت به طور خودکار این فیلد را پر می‌کند. تولیدکنندگان اصلی تجهیزات (OEM) و مجریان TA کلیددار (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 است. این متد توسط کلاینت‌های 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 خیلی زود در بوت سیستم فراخوانی می‌شود، باید سوءاستفاده از این پنجره فرصت را دشوار کند.