APK imza şeması v2, APK'nın korunan bölümlerindeki değişiklikleri tespit ederek doğrulama hızını artıran ve bütünlük garantilerini güçlendiren bir bütün dosya imza şemasıdır.
APK imza şeması v2 kullanılarak imzalama işlemi, ZIP Merkezi Dizin bölümünden hemen önce APK dosyasına bir APK imzalama bloğu ekler. APK imzalama bloğunda, v2 imzaları ve imzalayan kimlik bilgileri APK imza şeması v2 bloğunda saklanır.
Şekil 1. İmzalanmadan önce ve sonra APK
APK imza şeması v2, Android 7.0 (Nougat) ile kullanıma sunulmuştur. Bir APK'nın Android 6.0 (Marshmallow) ve daha eski cihazlarda yüklenebilmesi için v2 şemasıyla imzalanmadan önce JAR imzalama kullanılarak imzalanması gerekir.
APK imzalama bloğu
V1 APK biçimiyle geriye dönük uyumluluğu korumak için v2 ve sonraki APK imzaları, APK imza şeması v2'yi desteklemek amacıyla kullanıma sunulan yeni bir kapsayıcı olan APK imza bloğu içinde saklanır. APK dosyasında APK imzalama bloğu, dosyanın sonunda bulunan ZIP Merkezi Dizin'den hemen önce yer alır.
Blok, APK'da bloğun bulunmasını kolaylaştıracak şekilde sarmalanmış kimlik-değer çiftleri içerir. APK'nın v2 imzası, 0x7109871a kimliğine sahip bir kimlik-değer çifti olarak saklanır.
Biçim
APK imzalama bloğunun biçimi aşağıdaki gibidir (tüm sayısal alanlar küçük endiandır):
- Bayt cinsinden
size of block
(bu alan hariç) (uint64) - uint64 uzunluğunda ön ek eklenmiş kimlik-değer çiftleri dizisi:
ID
(uint32)value
(değişken uzunluk: çiftin uzunluğu - 4 bayt)
- Bayt cinsinden
size of block
(ilk alanla (uint64) aynı) magic
"APK Sig Block 42" (16 bayt)
APK, önce ZIP Merkezi Dizin'in başlangıcı bulunarak (dosyanın sonunda ZIP Merkezi Dizin'in sonu kaydını bulup kayıttan Merkezi Dizin'in başlangıç ofsetini okuyarak) ayrıştırılır. magic
değeri, Merkezi Dizin'den önce gelen öğenin büyük olasılıkla APK imzalama bloğu olduğunu belirlemenin hızlı bir yolunu sağlar. size of
block
değeri, dosyada bloğun başlangıcını etkili bir şekilde gösterir.
Bilinmeyen kimliklere sahip kimlik-değer çiftleri, blok yorumlanırken yoksayılmalıdır.
APK imza şeması v2 bloğu
APK, her biri bir imzalama anahtarıyla temsil edilen bir veya daha fazla imzalayan/kimlik tarafından imzalanır. Bu bilgiler APK imza şeması v2 bloğu olarak saklanır. Her imzacı için aşağıdaki bilgiler saklanır:
- (imza algoritması, özet, imza) tuple'leri. Özet, imza doğrulamasını APK'nın içeriğinin bütünlük kontrolünden ayırmak için depolanır.
- İmzalayanın kimliğini temsil eden X.509 sertifika zinciri.
- Anahtar/değer çiftleri olarak ek özellikler.
Her imzalayan için APK, sağlanan listedeki desteklenen bir imza kullanılarak doğrulanır. Bilinmeyen imza algoritmalarına sahip imzalar yoksayılır. Birden çok desteklenen imzayla karşılaşıldığında hangi imzanın kullanılacağını seçmek her uygulamaya bağlıdır. Bu sayede, gelecekte geriye dönük uyumlu bir şekilde daha güçlü imzalama yöntemlerinin kullanıma sunulması mümkün olur. Önerilen yaklaşım, en güçlü imzayı doğrulamaktır.
Biçim
APK imza şeması v2 bloğu, APK imzalama bloğunun içinde 0x7109871a
kimliği altında depolanır.
APK imza şeması v2 bloğunun biçimi aşağıdaki gibidir (tüm sayısal değerler küçük endiandır, ön ek uzunluğu olan tüm alanlar uzunluk için uint32 kullanır):
- Uzunluk ön ekiyle başlayan
signer
'nin uzunluk ön ekiyle başlayan dizisi:- uzunluk ön ekiyle
signed data
:- Uzunluk ön ekiyle başlayan
digests
'nin uzunluk ön ekiyle başlayan dizisi:signature algorithm ID
(uint32)- (uzunluk ön ekiyle)
digest
: Bütünlüğü Korunan İçerik bölümüne bakın.
- X.509
certificates
uzunluğuna öncelikli sıra:- uzunluk ön ekiyle X.509
certificate
(ASN.1 DER formu)
- uzunluk ön ekiyle X.509
- Uzunluk ön ekiyle başlayan
additional attributes
'nin uzunluk ön ekiyle başlayan dizisi:ID
(uint32)value
(değişken uzunluk: ek özelliğin uzunluğu - 4 bayt)
- Uzunluk ön ekiyle başlayan
- Uzunluk ön ekiyle başlayan
signatures
'nin uzunluk ön ekiyle başlayan dizisi:signature algorithm ID
(uint32)- length-prefixed
signature
oversigned data
- uzunluk ön ekiyle
public key
(SubjectPublicKeyInfo, ASN.1 DER biçimi)
- uzunluk ön ekiyle
İmza algoritması kimlikleri
- 0x0101: SHA2-256 özetiyle RSASSA-PSS, SHA2-256 MGF1, 32 bayt tuz, son ek: 0xbc
- 0x0102: SHA2-512 özetiyle RSASSA-PSS, SHA2-512 MGF1, 64 bayt tuz, ek: 0xbc
- 0x0103: SHA2-256 özetiyle RSASSA-PKCS1-v1_5. Bu, zorunlu imzalar gerektiren derleme sistemleri içindir.
- 0x0104: SHA2-512 özetiyle RSASSA-PKCS1-v1_5. Bu, zorunlu imzalar gerektiren derleme sistemleri içindir.
- 0x0201: SHA2-256 özetine sahip ECDSA
- 0x0202: SHA2-512 özetiyle ECDSA
- 0x0301: SHA2-256 özetiyle DSA
Yukarıdaki imza algoritmalarının tümü Android platformu tarafından desteklenir. İmzalama araçları, algoritmaların bir alt kümesini destekleyebilir.
Desteklenen anahtar boyutları ve EC eğrileri:
- RSA: 1024, 2048, 4096, 8192, 16384
- EC: NIST P-256, P-384, P-521
- DSA: 1024, 2048, 3072
Bütünlük korumalı içerikler
APK'lar, APK içeriklerini korumak amacıyla dört bölümden oluşur:
- ZIP girişlerinin içeriği (0 ofsetinden APK imzalama bloğunun başına kadar)
- APK imzalama bloğu
- ZIP Merkezi Dizini
- ZIP Merkezi Dizin Sonu
Şekil 2. İmzalanmış APK bölümleri
APK imza şeması v2, 1., 3. ve 4. bölümlerin yanı sıra 2. bölümde bulunan APK imza şeması v2 bloğunun signed data
bloklarının bütünlüğünü korur.
1, 3 ve 4 numaralı bölümlerin bütünlüğü, içeriklerinin signed data
bloklarında depolanan bir veya daha fazla özetiyle korunur. Bu özetler de bir veya daha fazla imzayla korunur.
1, 3 ve 4 numaralı bölümlerin özeti, iki düzeyli bir Merkle ağacına benzer şekilde aşağıdaki gibi hesaplanır.
Her bölüm, art arda gelen 1 MB'lık (220 bayt) parçalara ayrılır. Her bölümün son parçası daha kısa olabilir. Her bir parçanın özeti, 0xa5
baytının, parçanın bayt cinsinden uzunluğunun (az bayttan büyük uint32) ve parçanın içeriğinin birleştirilmesi üzerinden hesaplanır. Üst düzey özet, 0x5a
baytının, parça sayısının (az bayttan büyük uint32) ve parçaların APK'da göründüğü sırayla parçaların özetlerinin birleştirilmesi üzerinden hesaplanır. Özet, paralelleştirerek hesaplamayı hızlandırmak için parçalara ayrılmış şekilde hesaplanır.
Şekil 3. APK özeti
4. bölümün (ZIP Merkezi Dizininin Sonu) korunması, ZIP Merkezi Dizininin ofsetini içeren bölüm nedeniyle karmaşıktır. APK imzalama bloğunun boyutu değiştiğinde (ör. yeni bir imza eklendiğinde) ofset değişir. Bu nedenle, ZIP Merkezi Dizin Sonu üzerinde özet hesaplanırken ZIP Merkezi Dizin'in ofsetini içeren alan, APK imzalama bloğunun ofsetini içeren alan olarak değerlendirilmelidir.
Geri alma korumaları
Bir saldırgan, v2 imzalı APK'nın doğrulanmasını destekleyen Android platformlarında v2 imzalı APK'yı v1 imzalı APK olarak doğrulamaya çalışabilir. Bu saldırıyı azaltmak için, v1 ile de imzalanmış olan v2 ile imzalanmış APK'lar, META-INF/*.SF dosyalarının ana bölümünde bir X-Android-APK-Signed özelliği içermelidir. Özelliğin değeri, virgülle ayrılmış bir APK imza şeması kimliği grubudur (bu şemanın kimliği 2'dir). APK doğrulayıcının, v1 imzasını doğrularken bu gruptaki doğrulayıcının tercih ettiği APK imza şeması (ör. v2 şeması) için imzası olmayan APK'ları reddetmesi gerekir. Bu koruma, META-INF/*.SF dosyalarının içeriklerinin v1 imzalarıyla korunmasına dayanır. JAR imzalı APK doğrulaması bölümüne bakın.
Saldırganlar, APK İmza Şeması v2 bloğundan daha güçlü imzaları kaldırmayı deneyebilir. Bu saldırıyı azaltmak için APK'nın imzalandığı imza algoritması kimliklerinin listesi, her imza tarafından korunan signed data
bloğunda saklanır.
Doğrulama
Android 7.0 ve sonraki sürümlerde APK'lar APK imza şeması v2 veya sonraki sürümlere ya da JAR imzalamaya (v1 şeması) göre doğrulanabilir. Eski platformlar v2 imzalarını yoksayar ve yalnızca v1 imzalarını doğrular.
Şekil 4. APK imza doğrulama süreci (yeni adımlar kırmızıyla gösterilmiştir)
APK İmza Şeması v2 doğrulaması
- APK imzalama bloğunu bulun ve şunları doğrulayın:
- APK imzalama bloğunun iki boyut alanı aynı değeri içeriyor.
- ZIP Merkezi Dizin'in hemen ardından ZIP Merkezi Dizin Sonu kaydı gelir.
- ZIP End of Central Directory'nin (Merkezi Dizinin Sonu) ardından daha fazla veri gelmez.
- APK imzalama bloğunun içindeki ilk APK imza şeması v2 bloğunu bulun. v2 bloğu varsa 3. adıma geçin. Aksi takdirde, APK'yı v1 şemasını kullanarak doğrulamaya geçin.
- APK imza şeması v2 bloğundaki her
signer
için:signatures
arasından en güçlü desteklenensignature algorithm ID
'yi seçin. Güç sıralaması her uygulama/platform sürümüne bağlıdır.public key
kullanaraksignatures
'daki ilgilisignature
'yisigned data
ile karşılaştırın. (signed data
artık ayrıştırılabilir.)digests
vesignatures
'daki imza algoritması kimliklerinin sıralı listesinin aynı olduğundan emin olun. (Bu, imzanın kaldırılmasını/eklenmesini önlemek içindir.)- İmza algoritması tarafından kullanılan özet algoritmasıyla aynı özet algoritmasını kullanarak APK içeriğinin özetini hesaplayın.
- Hesaplanan özetin,
digests
'daki ilgilidigest
ile aynı olduğundan emin olun. certificates
'un ilkcertificate
öğesinin SubjectPublicKeyInfo değerininpublic key
ile aynı olduğunu doğrulayın.
- En az bir
signer
bulunursa ve bulunan hersigner
için 3. adım başarılı olursa doğrulama başarılı olur.
Not: 3. veya 4. adımda hata oluşursa APK, v1 şeması kullanılarak doğrulanmamalıdır.
JAR imzalı APK doğrulaması (v1 şeması)
JAR imzalı APK, META-INF/MANIFEST.MF'de listelenen girişleri tam olarak içermesi ve tüm girişlerin aynı imzalar tarafından imzalanması gereken bir standart imzalı JAR dosyasıdır. Bütünlüğü aşağıdaki şekilde doğrulanır:
- Her imzalayan, META-INF/<signer>.SF ve META-INF/<signer>.(RSA|DSA|EC) JAR girişiyle temsil edilir.
- <signer>.(RSA|DSA|EC), imzasının <signer>.SF dosyası üzerinden doğrulandığı SignedData yapısına sahip bir PKCS #7 CMS ContentInfo dosyasıdır.
- <signer>.SF dosyası, META-INF/MANIFEST.MF dosyasının tamamını ve META-INF/MANIFEST.MF dosyasının her bölümünün özetini içerir. MANIFEST.MF dosyasının tümünü içeren özet doğrulanır. Bu işlem başarısız olursa bunun yerine her MANIFEST.MF bölümünün özeti doğrulanır.
- META-INF/MANIFEST.MF, bütünlük korumalı her JAR girişi için girişin sıkıştırılmamış içeriğinin özetini içeren, uygun şekilde adlandırılmış bir bölüm içerir. Bu özetlerin tümü doğrulanır.
- APK, MANIFEST.MF dosyasında listelenmeyen ve JAR imzasının parçası olmayan JAR girişleri içeriyorsa APK doğrulaması başarısız olur.
Bu nedenle koruma zinciri <signer>.(RSA|DSA|EC) -> <signer>.SF -> MANIFEST.MF -> her bir bütünlük korumalı JAR girişinin içeriği şeklindedir.