वर्शन बाइंडिंग

Keymaster 1 में, सभी Keymaster कुंजियां क्रिप्टोग्राफ़िक तौर पर डिवाइस के रूट ऑफ़ ट्रस्ट या वेरिफ़ाइड बूट कुंजी से जुड़ी होती थीं. Keymaster 2 और 3 में, सभी कुंजियां ऑपरेटिंग सिस्टम और सिस्टम इमेज के पैच लेवल से भी जुड़ी होती हैं. इससे यह पक्का होता है कि सिस्टम या टीईई सॉफ़्टवेयर के पुराने वर्शन में कोई गड़बड़ी ढूंढने वाला हमलावर, डिवाइस को गड़बड़ी वाले वर्शन पर वापस नहीं ला सकता. साथ ही, नए वर्शन से बनाए गए कुंजियों का इस्तेमाल नहीं कर सकता. इसके अलावा, जब किसी डिवाइस पर दिए गए वर्शन और पैच लेवल वाली पासकी का इस्तेमाल किया जाता है, तो उसे नए वर्शन या पैच लेवल पर अपग्रेड किया जाता है. ऐसा तब होता है, जब डिवाइस को नए वर्शन या पैच लेवल पर अपग्रेड किया गया हो. पासकी को अपग्रेड करने के बाद ही उसका इस्तेमाल किया जा सकता है. साथ ही, पासकी के पिछले वर्शन को अमान्य कर दिया जाता है. इस तरह, डिवाइस को अपग्रेड करने पर, कुंजियां डिवाइस के साथ-साथ आगे बढ़ती हैं. हालांकि, डिवाइस को पिछली रिलीज़ पर वापस लाने पर, कुंजियों का इस्तेमाल नहीं किया जा सकता.

Treble के मॉड्यूलर स्ट्रक्चर के साथ काम करने और system.img को boot.img से अलग करने के लिए, Keymaster 4 ने कुंजी के वर्शन को बाइंड करने वाले मॉडल में बदलाव किया है. इससे हर पार्टीशन के लिए पैच लेवल अलग-अलग हो जाते हैं. इससे हर पार्टीशन को अलग-अलग अपडेट किया जा सकता है. साथ ही, सिस्टम को पुराने वर्शन पर रोल बैक होने से रोकने की सुविधा भी मिलती है.

इस वर्शन बाइंडिंग को लागू करने के लिए, KeyMint के भरोसेमंद ऐप्लिकेशन (टीए) को मौजूदा ओएस वर्शन और पैच लेवल को सुरक्षित तरीके से पाने का तरीका चाहिए. साथ ही, यह पक्का करने का तरीका भी चाहिए कि उसे मिली जानकारी, चालू सिस्टम के बारे में मौजूद सभी जानकारी से मेल खाती हो.

  • Android Verified Boot (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() को ज़्यादा पैच लेवल पर रोल किया जाता है.

एचएएल में बदलाव

वर्शन बाइंडिंग और वर्शन अटेस्टेशन की सुविधा देने के लिए, 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 चार अंकों वाला साल और MM दो अंकों वाला महीना है. उदाहरण के लिए, मार्च 2016 को 201603 के तौर पर दिखाया जाएगा.

UpgradeKey

सिस्टम इमेज के नए ओएस वर्शन और पैच लेवल पर कुंजियों को अपग्रेड करने की अनुमति देने के लिए, Android 7.1 ने HAL में upgradeKey तरीका जोड़ा है:

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 आउटपुट पैरामीटर है. इसका इस्तेमाल, नए कुंजी ब्लोब को वापस लाने के लिए किया जाता है.

अगर 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 कॉल के बाद भी मान्य रहता है. अगर डिवाइस को डाउनग्रेड किया जाता है, तो इसका फिर से इस्तेमाल किया जा सकता है. आम तौर पर, कीस्टोर upgradeKey को कॉल करने के कुछ ही समय बाद, keyBlobToUpgrade पर deleteKey को कॉल करता है. अगर keyBlobToUpgrade में Tag::ROLLBACK_RESISTANT टैग है, तो upgradedKeyBlob में भी यह टैग होना चाहिए. साथ ही, यह रोलबैक को रोकने वाला होना चाहिए.

सुरक्षित कॉन्फ़िगरेशन

वर्शन बाइंडिंग को लागू करने के लिए, Keymaster TA को मौजूदा ओएस वर्शन और पैच लेवल (वर्शन की जानकारी) को सुरक्षित तरीके से पाने का तरीका चाहिए. साथ ही, यह पक्का करना होगा कि उसे मिली जानकारी, चालू सिस्टम की जानकारी से मेल खाती हो.

टीए को वर्शन की जानकारी सुरक्षित तरीके से देने के लिए, बूट इमेज हेडर में एक OS_VERSION फ़ील्ड जोड़ा गया है. बूट इमेज बनाने वाली स्क्रिप्ट, इस फ़ील्ड को अपने-आप भर देती है. ओईएम और Keymaster TA को लागू करने वालों को एक साथ काम करना होगा, ताकि डिवाइस के बूटलोडर में बदलाव किया जा सके. इससे बूट इमेज से वर्शन की जानकारी निकाली जा सकेगी और असुरक्षित सिस्टम के बूट होने से पहले, इसे टीए को भेजा जा सकेगा. इससे यह पक्का किया जाता है कि हमलावर, टीए को वर्शन की जानकारी देने में दख़ल न दे पाएं.

यह भी ज़रूरी है कि सिस्टम इमेज में, बूट इमेज के वर्शन की जानकारी मौजूद हो. इसके लिए, Keymaster एचएएल में कॉन्फ़िगर करने का तरीका जोड़ा गया है:

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 से पहले किसी अन्य तरीके को कॉल किया जाता है, तो टीए ErrorCode::KEYMASTER_NOT_CONFIGURED दिखाता है.

डिवाइस बूट होने के बाद, जब पहली बार configure को कॉल किया जाता है, तो उसे यह पुष्टि करनी चाहिए कि दी गई वर्शन की जानकारी, बूटलोडर से मिली जानकारी से मेल खाती है. अगर वर्शन की जानकारी मेल नहीं खाती है, तो configure ErrorCode::INVALID_ARGUMENT दिखाता है. साथ ही, Keymaster के अन्य सभी तरीके ErrorCode::KEYMASTER_NOT_CONFIGURED दिखाते रहते हैं. अगर जानकारी मेल खाती है, तो configure ErrorCode::OK दिखाता है. साथ ही, Keymaster के अन्य तरीके सामान्य तरीके से काम करने लगते हैं.

configure को बाद में किए गए कॉल, पहले कॉल से मिली वैल्यू को ही दिखाते हैं. साथ ही, Keymaster की स्थिति में कोई बदलाव नहीं करते.

configure को उस सिस्टम से कॉल किया जाता है जिसके कॉन्टेंट की पुष्टि करनी होती है. इसलिए, हमलावर के पास सिस्टम इमेज को नुकसान पहुंचाने और उसे बूट इमेज से मेल खाने वाली वर्शन की जानकारी देने के लिए मजबूर करने का सीमित समय होता है. हालांकि, यह सिस्टम का असल वर्शन नहीं होता है. बूट इमेज की पुष्टि करने की सुविधा, सिस्टम इमेज के कॉन्टेंट की dm-verity पुष्टि करने की सुविधा, और सिस्टम बूट होने के दौरान configure को बहुत पहले कॉल किया जाता है. इन सभी सुविधाओं की वजह से, इस विंडो का फ़ायदा उठाना मुश्किल हो जाता है.