Android 12 से, Android रनटाइम (ART) मॉड्यूल एक Mainline मॉड्यूल है. मॉड्यूल को अपडेट करने के लिए, बूटक्लाथपाथ जार और सिस्टम सर्वर के कंपाइल किए गए आर्टफ़ैक्ट को फिर से बनाना पड़ सकता है. ये आर्टफ़ैक्ट सुरक्षा के लिहाज़ से संवेदनशील होते हैं. इसलिए, Android 12 में डिवाइस पर साइन करने की सुविधा का इस्तेमाल किया जाता है. इससे इन आर्टफ़ैक्ट में छेड़छाड़ नहीं की जा सकती. इस पेज पर, डिवाइस पर हस्ताक्षर करने की सुविधा के आर्किटेक्चर और Android की अन्य सुरक्षा सुविधाओं के साथ इसके इंटरैक्शन के बारे में बताया गया है.
हाई-लेवल डिज़ाइन
डिवाइस पर साइन इन करने की सुविधा के दो मुख्य कॉम्पोनेंट होते हैं:
odrefresh, एआरटी मेनलाइन मॉड्यूल का हिस्सा है. यह रनटाइम आर्टफ़ैक्ट जनरेट करने के लिए ज़िम्मेदार है. यह मौजूदा आर्टफ़ैक्ट की तुलना, ART मॉड्यूल के इंस्टॉल किए गए वर्शन, बूटक्लाथपाथ जार, और सिस्टम सर्वर जार से करता है. इससे यह पता चलता है कि ये अप-टू-डेट हैं या इन्हें फिर से जनरेट करने की ज़रूरत है. अगर उन्हें फिर से जनरेट करने की ज़रूरत होती है, तोodrefreshउन्हें जनरेट करके सेव करता है.odsignएक बाइनरी है, जो Android प्लैटफ़ॉर्म का हिस्सा है. यह/dataपार्टीशन के माउंट होने के तुरंत बाद, बूटिंग की शुरुआती प्रोसेस के दौरान चलता है. इसकी मुख्य ज़िम्मेदारी,odrefreshको शुरू करना है. इससे यह पता चलता है कि किसी आर्टफ़ैक्ट को जनरेट या अपडेट करने की ज़रूरत है या नहीं.odrefreshजनरेट किए गए किसी भी नए या अपडेट किए गए आर्टफ़ैक्ट के लिए,odsignहैश फ़ंक्शन का हिसाब लगाता है. इस तरह की हैश कंप्यूटेशन के नतीजे को फ़ाइल डाइजेस्ट कहा जाता है. पहले से मौजूद किसी भी आर्टफ़ैक्ट के लिए,odsignपुष्टि करता है कि मौजूदा आर्टफ़ैक्ट के डाइजेस्ट, उन डाइजेस्ट से मेल खाते हैं जिन्हेंodsignने पहले कैलकुलेट किया था. इससे यह पक्का होता है कि आर्टफ़ैक्ट में कोई बदलाव नहीं किया गया है.
गड़बड़ी की स्थितियों में, जैसे कि जब किसी फ़ाइल का डाइजेस्ट मैच नहीं करता है, तो odrefresh और odsign, /data पर मौजूद सभी मौजूदा आर्टफ़ैक्ट मिटा देते हैं और उन्हें फिर से जनरेट करने की कोशिश करते हैं. अगर ऐसा नहीं हो पाता है, तो सिस्टम JIT मोड पर वापस आ जाता है.
odrefresh और odsign को dm-verity की मदद से सुरक्षित किया जाता है. साथ ही, ये Android की वेरिफ़ाइड बूट चेन का हिस्सा हैं.
fs-verity की मदद से फ़ाइल डाइजेस्ट की गणना
fs-verity, Linux कर्नेल की एक सुविधा है. यह फ़ाइल के डेटा की पुष्टि करने के लिए, मर्कल ट्री का इस्तेमाल करती है. किसी फ़ाइल पर fs-verity चालू करने से, फ़ाइल सिस्टम SHA-256 हैश का इस्तेमाल करके, फ़ाइल के डेटा पर एक Merkle ट्री बनाता है. साथ ही, इसे फ़ाइल के साथ छिपी हुई जगह पर सेव करता है और फ़ाइल को सिर्फ़ पढ़ने के लिए मार्क करता है. fs-verity, फ़ाइल के डेटा की पुष्टि अपने-आप करता है. इसके लिए, वह Merkle ट्री का इस्तेमाल करता है. ऐसा तब होता है, जब फ़ाइल को पढ़ा जाता है. fs-verity, Merkle ट्री के रूट हैश को fs-verity फ़ाइल डाइजेस्ट के तौर पर उपलब्ध कराता है. साथ ही, यह पक्का करता है कि फ़ाइल से पढ़ा गया कोई भी डेटा, इस फ़ाइल डाइजेस्ट के मुताबिक हो.
odsign fs-verity का इस्तेमाल करता है. इससे बूट होने के समय, उपयोगकर्ता के डिवाइस पर कंपाइल किए गए आर्टफ़ैक्ट की क्रिप्टोग्राफ़िक पुष्टि को ऑप्टिमाइज़ करके, बूट होने की परफ़ॉर्मेंस को बेहतर बनाया जाता है. आर्टफ़ैक्ट जनरेट होने पर, odsign उस पर fs-verity चालू करता है. जब odsign किसी आर्टफ़ैक्ट की पुष्टि करता है, तो वह पूरी फ़ाइल के हैश के बजाय, fs-verity फ़ाइल डाइजेस्ट की पुष्टि करता है. इससे बूट के समय, आर्टफ़ैक्ट के पूरे डेटा को पढ़ने और हैश करने की ज़रूरत नहीं पड़ती. इसके बजाय, fs-verity, आर्टफ़ैक्ट डेटा को ज़रूरत के हिसाब से हैश करता है. ऐसा तब होता है, जब डेटा का इस्तेमाल किया जाता है. यह काम ब्लॉक-दर-ब्लॉक के हिसाब से होता है.
जिन डिवाइसों के कर्नल में fs-verity काम नहीं करता उन पर odsign, उपयोगकर्ताओं के स्पेस में फ़ाइल डाइजेस्ट का हिसाब लगाता है. odsign, fs-verity की तरह ही Merkle ट्री पर आधारित हैश एल्गोरिदम का इस्तेमाल करता है. इसलिए, दोनों मामलों में डाइजेस्ट एक जैसे होते हैं. Android 11 और इसके बाद के वर्शन के साथ लॉन्च किए गए सभी डिवाइसों पर fs-verity की सुविधा होना ज़रूरी है.
फ़ाइल डाइजेस्ट का स्टोरेज
odsign, आर्टफ़ैक्ट के फ़ाइल डाइजेस्ट को odsign.info नाम की अलग फ़ाइल में सेव करता है. यह पक्का करने के लिए कि odsign.info में कोई छेड़छाड़ न की गई हो, odsign.info पर हस्ताक्षर करने वाली ऐसी कुंजी से हस्ताक्षर किया जाता है जिसमें सुरक्षा से जुड़ी अहम प्रॉपर्टी होती हैं. खास तौर पर, इस कुंजी को सिर्फ़ शुरुआती बूट के दौरान जनरेट और इस्तेमाल किया जा सकता है. इस दौरान, सिर्फ़ भरोसेमंद कोड चलता है. ज़्यादा जानकारी के लिए, भरोसेमंद हस्ताक्षर करने वाली कुंजियां देखें.
फ़ाइल डाइजेस्ट की पुष्टि करना
हर बार बूट होने पर, अगर odrefresh को लगता है कि मौजूदा आर्टफ़ैक्ट अप-टू-डेट हैं, तो odsign यह पक्का करता है कि फ़ाइलें जनरेट होने के बाद से उनमें कोई छेड़छाड़ नहीं की गई है. odsign, फ़ाइल डाइजेस्ट की पुष्टि करके ऐसा करता है. सबसे पहले, यह odsign.info के हस्ताक्षर की पुष्टि करता है. अगर हस्ताक्षर मान्य है, तो odsign यह पुष्टि करता है कि हर फ़ाइल का डाइजेस्ट, odsign.info में मौजूद डाइजेस्ट से मेल खाता है.
भरोसेमंद साइनिंग पासकोड
Android 12 में, Keystore की नई सुविधा जोड़ी गई है. इसे बूट स्टेज कीज़ कहा जाता है. इससे सुरक्षा से जुड़ी इन समस्याओं को हल किया जा सकता है:
- हमारा ऐप्लिकेशन साइन करने की कुंजी का इस्तेमाल करके, हमलावर को
odsign.infoके अपने वर्शन को साइन करने से कौन रोकता है? - हमले करने वाला व्यक्ति, खुद का साइनिंग पासकोड जनरेट करके उसका इस्तेमाल
odsign.infoके अपने वर्शन को साइन करने के लिए क्यों नहीं कर सकता?
बूट स्टेज की कुंजियां, Android के बूट साइकल को लेवल में बांटती हैं. साथ ही, किसी कुंजी को बनाने और उसके इस्तेमाल को क्रिप्टोग्राफ़िक तरीके से किसी तय लेवल से जोड़ती हैं. odsign शुरुआती लेवल पर अपनी
हस्ताक्षर करने वाली कुंजी बनाता है. ऐसा तब होता है, जब सिर्फ़ भरोसेमंद कोड चल रहा हो. इसे dm-verity की मदद से सुरक्षित किया जाता है.
बूट स्टेज के लेवल को 0 से लेकर मैजिक नंबर 1000000000 तक नंबर दिया जाता है. Android के बूट होने की प्रोसेस के दौरान, init.rc से सिस्टम प्रॉपर्टी सेट करके, बूट लेवल को बढ़ाया जा सकता है. उदाहरण के लिए, यहां दिया गया कोड बूट लेवल को 10 पर सेट करता है:
setprop keystore.boot_level 10
Keystore के क्लाइंट, ऐसी कुंजियां बना सकते हैं जो किसी बूट लेवल से जुड़ी हों. उदाहरण के लिए, अगर आपने बूट लेवल 10 के लिए कोई कुंजी बनाई है, तो उस कुंजी का इस्तेमाल सिर्फ़ तब किया जा सकता है, जब डिवाइस बूट लेवल 10 पर हो.
odsign बूट लेवल 30 का इस्तेमाल करता है. साथ ही, यह जिस साइनिंग कुंजी को बनाता है वह उस बूट लेवल से जुड़ी होती है. आर्टफ़ैक्ट पर साइन करने के लिए किसी कुंजी का इस्तेमाल करने से पहले, odsign यह पुष्टि करता है कि कुंजी, बूट लेवल 30 से जुड़ी है.
इससे इस सेक्शन में बताए गए दो हमलों को रोका जा सकता है:
- हमलावर जनरेट की गई कुंजी का इस्तेमाल नहीं कर सकते. ऐसा इसलिए, क्योंकि जब तक हमलावर को दुर्भावनापूर्ण कोड चलाने का मौका मिलता है, तब तक बूट लेवल 30 से ज़्यादा हो जाता है. साथ ही, Keystore उन कार्रवाइयों को अस्वीकार कर देता है जिनमें कुंजी का इस्तेमाल किया जाता है.
- हमलावर नई कुंजी नहीं बना सकते, क्योंकि जब तक हमलावर को दुर्भावनापूर्ण कोड चलाने का मौका मिलता है, तब तक बूट लेवल 30 से ज़्यादा हो जाता है. साथ ही, Keystore उस बूट लेवल के साथ नई कुंजी बनाने से मना कर देता है. अगर कोई हमलावर ऐसी नई कुंजी बनाता है जो बूट लेवल 30 से नहीं जुड़ी है, तो
odsignउसे अस्वीकार कर देता है.
कीस्टोर यह पक्का करता है कि बूट लेवल को सही तरीके से लागू किया गया हो. यहां दिए गए सेक्शन में, अलग-अलग KeyMint (पहले Keymaster) वर्शन के लिए, इस प्रोसेस को पूरा करने के तरीके के बारे में ज़्यादा जानकारी दी गई है.
Keymaster 4.0 लागू करना
Keymaster के अलग-अलग वर्शन, बूट स्टेज की कुंजियों को अलग-अलग तरीके से लागू करते हैं. Keymaster 4.0 TEE/StrongBox वाले डिवाइसों पर, Keymaster इस सुविधा को इस तरह लागू करता है:
- पहली बार बूट करने पर, Keystore एक सिमेट्रिक की K0 बनाता है. इसमें
MAX_USES_PER_BOOTटैग को1पर सेट किया जाता है. इसका मतलब है कि हर बूट के लिए, इस कुंजी का इस्तेमाल सिर्फ़ एक बार किया जा सकता है. - बूट के दौरान, अगर बूट लेवल बढ़ जाता है, तो उस बूट लेवल के लिए नई कुंजी, K0 से जनरेट की जा सकती है. इसके लिए, HKDF फ़ंक्शन:
Ki+i=HKDF(Ki, "some_fixed_string")का इस्तेमाल किया जाता है. उदाहरण के लिए, अगर बूट लेवल 0 से बूट लेवल 10 पर स्विच किया जाता है, तो K0 से K10 पाने के लिए HKDF को 10 बार लागू किया जाता है. बूट लेवल बदलने पर, पिछले बूट लेवल की कुंजी को मेमोरी से मिटा दिया जाता है. साथ ही, पिछले बूट लेवल से जुड़ी कुंजियां अब उपलब्ध नहीं होती हैं.
कुंजी K0,
MAX_USES_PER_BOOT=1कुंजी है. इसका मतलब है कि बाद में बूट के दौरान उस कुंजी का इस्तेमाल नहीं किया जा सकता, क्योंकि कम से कम एक बूट लेवल ट्रांज़िशन (फ़ाइनल बूट लेवल पर) हमेशा होता है.
जब odsign जैसा कोई Keystore क्लाइंट, बूट लेवल i में कोई कुंजी बनाने का अनुरोध करता है, तो उसके ब्लब को कुंजी Ki से एन्क्रिप्ट (सुरक्षित) किया जाता है. Ki, बूट लेवल i के बाद उपलब्ध नहीं होता. इसलिए, इस कुंजी को बाद के बूट चरणों में न तो बनाया जा सकता है और न ही डिक्रिप्ट किया जा सकता है.
Keymaster 4.1 और KeyMint 1.0 को लागू करने का तरीका
Keymaster 4.1 और KeyMint 1.0 को लागू करने का तरीका, Keymaster 4.0 को लागू करने के तरीके से काफ़ी हद तक मिलता-जुलता है. इनमें मुख्य अंतर यह है कि K0, MAX_USES_PER_BOOT कुंजी नहीं है, बल्कि EARLY_BOOT_ONLY कुंजी है. इसे Keymaster 4.1 में पेश किया गया था. EARLY_BOOT_ONLY कुंजी का इस्तेमाल सिर्फ़ बूटिंग के शुरुआती चरणों में किया जा सकता है. ऐसा तब होता है, जब कोई अविश्वसनीय कोड नहीं चल रहा होता है. इससे सुरक्षा का एक और लेवल मिलता है: Keymaster 4.0 को लागू करने के दौरान, फ़ाइल सिस्टम और SELinux से समझौता करने वाला हमलावर, Keystore डेटाबेस में बदलाव कर सकता है. इससे वह अपने MAX_USES_PER_BOOT=1 कुंजी बना सकता है, ताकि वह आर्टफ़ैक्ट पर हस्ताक्षर कर सके. Keymaster 4.1 और KeyMint 1.0 को लागू करने पर, इस तरह का हमला नहीं किया जा सकता. इसकी वजह यह है कि EARLY_BOOT_ONLY कुंजियां सिर्फ़ शुरुआती बूट के दौरान बनाई जा सकती हैं.
भरोसेमंद साइनिंग कुंजियों का सार्वजनिक कॉम्पोनेंट
odsign, Keystore से साइनिंग कुंजी का सार्वजनिक पासकोड कॉम्पोनेंट वापस पाता है.
हालांकि, Keystore उस सार्वजनिक कुंजी को TEE/SE से वापस नहीं पाता है जिसमें निजी कुंजी होती है. इसके बजाय, यह सार्वजनिक पासकोड को अपने ऑन-डिस्क डेटाबेस से वापस पाता है. इसका मतलब है कि फ़ाइल सिस्टम को नुकसान पहुंचाने वाला कोई हमलावर, Keystore डेटाबेस में बदलाव कर सकता है. ऐसा करके, वह ऐसी सार्वजनिक कुंजी शामिल कर सकता है जो उसके कंट्रोल में मौजूद सार्वजनिक/निजी कुंजी के जोड़े का हिस्सा हो.
इस तरह के हमले को रोकने के लिए, odsign एक और एचएमएसी कुंजी बनाता है. इसका बूट लेवल, साइनिंग कुंजी के बूट लेवल के बराबर होता है. इसके बाद, साइनिंग कुंजी बनाते समय, odsign
इस एचएमएसी कुंजी का इस्तेमाल करके, सार्वजनिक कुंजी का हस्ताक्षर बनाता है और उसे डिस्क पर सेव करता है. इसके बाद, जब साइनिंग पासकोड की सार्वजनिक कुंजी को वापस लाया जाता है, तब बूट होने पर यह एचएमएसी पासकोड का इस्तेमाल करके यह पुष्टि करता है कि डिस्क पर मौजूद सिग्नेचर, वापस लाई गई सार्वजनिक कुंजी के सिग्नेचर से मेल खाता है. अगर ये दोनों वैल्यू मेल खाती हैं, तो सार्वजनिक पासकोड भरोसेमंद है. ऐसा इसलिए, क्योंकि एचएमएसी पासकोड का इस्तेमाल सिर्फ़ शुरुआती बूट लेवल में किया जा सकता है. इसलिए, इसे हमलावर ने नहीं बनाया होगा.