الإصدار 4 من مخطّط توقيع حزمة APK

يتوافق الإصدار 11 من Android مع مخطّط توقيع متوافق مع البث باستخدام الإصدار 4 من مخطّط توقيع حِزم APK. يستند توقيع الإصدار 4 إلى شجرة تجزئة Merkle التي يتم احتسابها على جميع وحدات البايت في حزمة APK. وتتّبع بنية شجرة التجزئة fs-verity تمامًا (على سبيل المثال، تتم إضافة حشوة من الأصفار إلى الملح وإضافة حشوة من الأصفار إلى الكتلة الأخيرة). يخزِّن نظام التشغيل Android 11 التوقيع في ملف منفصل، <apk name>.apk.idsigويتطلّب توقيع الإصدار 4 توقيعًا تكميليًا من الإصدار 2 أو الإصدار 3.

تنسيق الملف

جميع الحقول الرقمية بالتنسيق little endian تشغل جميع الحقول عددًا متطابقًا بالضبط من البايتات مثل sizeof()، ولا تتم إضافة أيّ تعبئة أو ALIGNED ضمني.

في ما يلي بنية مساعدة لتبسيط التعريفات.

template <class SizeT>
struct sized_bytes {
        SizeT size;
        byte bytes[size];
};

محتوى الملف الرئيسي:

struct V4Signature {
        int32 version; // only version 2 is supported as of now
        sized_bytes<int32> hashing_info;
        sized_bytes<int32> signing_info;
        sized_bytes<int32> merkle_tree;  // optional
};

hashing_info هي المَعلمات المستخدَمة لإنشاء شجرة التجزئة بالإضافة إلى التجزئة الجذرية:

struct hashing_info.bytes {
    int32 hash_algorithm;    // only 1 == SHA256 supported
    int8 log2_blocksize;     // only 12 (block size 4096) supported now
    sized_bytes<int32> salt; // used exactly as in fs-verity, 32 bytes max
    sized_bytes<int32> raw_root_hash; // salted digest of the first Merkle tree page
};

signing_info هي البنية التالية:

struct signing_info.bytes {
    sized_bytes<int32> apk_digest;  // used to match with the corresponding APK
    sized_bytes<int32> x509_certificate; // ASN.1 DER form
    sized_bytes<int32> additional_data; // a free-form binary data blob
    sized_bytes<int32> public_key; // ASN.1 DER, must match the x509_certificate
    int32 signature_algorithm_id; // see the APK v2 doc for the list
    sized_bytes<int32> signature;
};
  • يتم الحصول على apk_digest من حزمة توقيع الإصدار 3 من حزمة APK، أو من حزمة الإصدار 2 في حال عدم توفّرها (راجِع apk_digest).

لإنشاء رمز signature وإثبات صحته، يجب تسلسل البيانات التالية في ملف نصي ثنائي وتحويله إلى البيانات الموقَّعة وإرساله إلى خوارزمية التوقيع / التحقّق:

struct V4DataForSigning {
        int32 size;
        int64 file_size; // the size of the file that's been hashed.
        hashing_info.hash_algorithm;
        hashing_info.log2_blocksize;
        hashing_info.salt;
        hashing_info.raw_root_hash;
        signing_info.apk_digest;
        signing_info.x509_certificate;
        signing_info.additional_data;
};
  1. merkle_tree هي شجرة Merkle الكاملة لحزمة APK، ويتم احتسابها على النحو الموضّح في مستندات fs-verity.

المنتجون والمستهلكون

apksigner تُنشئ أداة حزمة تطوير البرامج (SDK) لنظام التشغيل Android الآن ملف التوقيع بالإصدار 4 في حال تشغيلها باستخدام المَعلمات التلقائية. ويمكن إيقاف التوقيع بالإصدار 4 بالطريقة نفسها المُستخدَمة مع مخطّطات التوقيع الأخرى. ويمكنه أيضًا التحقّق مما إذا كان توقيع الإصدار 4 صالحًا.

يتوقّع adb أن يكون ملف ‎.apk.idsig متوفّرًا بجانب ملف ‎.apk عند تنفيذ الأمر adb install --incremental.
سيستخدم أيضًا ملف ‎.idsig لمحاولة التثبيت المتزايد تلقائيًا، وسيعود إلى التثبيت العادي إذا كان غير متوفّر أو غير صالح.

عند إنشاء جلسة تثبيت، تقبل واجهة برمجة التطبيقات الجديدة لتثبيت البث في PackageInstaller توقيع الإصدار 4الذي تمّت إزالة البيانات غير الضرورية منه كوسيطة منفصلة عند إضافة ملف إلى الجلسة. في هذه المرحلة، يتم تمرير signing_info إلى incfs كملف ملف شخصي كامل. يستخرج Incfs تجزئة الجذر من العنصر المصغّر.

عند تنفيذ عملية التثبيت، تُجري خدمة PackageManagerService طلب ioctl لاسترداد signing_info blob من incfs، ثم تفكّكه وتتحقّق من التوقيع.

من المتوقّع أن يُرسِل مكوّن "أداة تحميل البيانات المتزايدة" جزءًا من شجرة Merkle للتوقيع من خلال واجهة برمجة التطبيقات الأصلية لأداة تحميل البيانات.
package يقبل الأمر shell في الخدمة install-incremental ملف توقيع الإصدار 4 الذي تمّت إزالة البيانات غير الضرورية منه والمشفَّر بترميز base64 كمَعلمة لكل ملف تمت إضافته. يجب إرسال شجرة Merkle المقابلة إلى stdin في الطلب.

apk_digest

apk_digest هو أول ملخّص محتوى متاح بالترتيب:

  1. الإصدار 3، كتلة بحجم 1 ميغابايت، SHA2-512 ‏ (CONTENT_DIGEST_CHUNKED_SHA512)،
  2. الإصدار 3، كتلة 4 كيلوبايت، SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256)،
  3. الإصدار 3، كتلة بحجم 1 ميغابايت، SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256)،
  4. الإصدار 2، SHA2-512،
  5. الإصدار 2، SHA2-256

اطّلِع على تسلسل التوقيعات التي تسبقها مدة في الإصدار 3 من مخطّط توقيع حِزم APK.

الإصدار 4 من عملية التحقّق من حِزم APK
الشكل 1: عملية التحقّق من حِزم APK‏ (الإصدار 4)

التحقّق والاختبار

تأكَّد من التنفيذ باستخدام اختبارات وحدات الميزات ومجموعة أدوات اختبار التوافق.

  • CtsIncrementalInstallHostTestCases
    • /android/cts/hostsidetests/incrementalinstall

اختبار تنسيق التوقيع

لاختبار تنسيق التوقيع، عليك إعداد بيئة تطوير وإجراء الاختبارات اليدوية التالية:

$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest

اختبار تنسيق التوقيع باستخدام حزمة تطوير البرامج (SDK) لنظام التشغيل Android (ADB وapksigner)

لاختبار تنسيق التوقيع باستخدام حزمة تطوير البرامج (SDK) لنظام التشغيل Android، عليك إعداد بيئة تطوير والتأكّد من إكمال تنفيذ IncFS. بعد ذلك، يمكنك فلاش الإصدار على جهاز أو محاكي فعلي مستهدف. عليك إنشاء حزمة APK حالية أو الحصول عليها ثم إنشاء مفتاح توقيع تصحيح الأخطاء. أخيرًا، عليك توقيع حزمة APK وتثبيتها باستخدام تنسيق التوقيع بالإصدار 4 من مجلد build-tools.

التوقيع

$ ./apksigner sign --ks debug.keystore game.apk

تثبيت

$ ./adb install game.apk

أين يمكن العثور على هذه الاختبارات؟

/android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java