APK署名v2・v3の違い:apksigner verify成功でも止まる理由

ネットワークを描いたアイキャッチ画像

APKの全体検証に通った成果物が、追加した検査項目ひとつで止まりました。署名済みAPKを配布する小規模な開発・ホームラボ運用では、「検査を増やせば安全になる」と考えたくなります。しかし、検査項目が保証したい仕様から離れると、正常な成果物を不合格にすることがあります。

今回の対象はminSdk 28のAPKです。apksigner verify による全体検証は成功していました。一方、追加のリリースゲートはAPK Signature Scheme v2だけを必須とし、v2=falseを理由に停止しました。

秘密鍵を開かずに署名済みAPKを再検査すると、v3=true、signer 1、RSA-4096、16 KiB alignment passを確認できました。成果物は壊れていません。止まっていたのは、検査側の前提です。

目次

v2だけを必須にすると何が起きるか

SDK同梱のhelpでは、APK Signature Scheme v3はAPI 28で導入され、各署名方式の既定はmin/max SDKに依存します。また verify は、manifestが宣言する対応platform全体を対象に検証する仕様です。

つまりminSdk 28の成果物に対して、v2が常に存在することを無条件の合格条件にする根拠はありません。今回のtoolchainはv3を既定で選択していました。v2がfalseであることは署名不良の証拠ではなく、個別ゲートが生んだfalse negativeでした。

確認の置き方 固定方式を必須にする設計 対応範囲を起点にする設計
一次判定 v2など一方式の有無 宣言したmin/max SDKでの全体検証
方式表示の扱い 不一致なら停止 互換性と結び付けた補助証跡
起こりやすい問題 正常な成果物のfalse negative 仕様外の成果物を検出しやすい
判断の説明 「この値がtrueか」 「対応範囲で成果物が検証できるか」

修復では、modern schemeの条件を「v2またはv3」としました。ただし、単にv2をv3へ置き換えたわけではありません。apksigner verify の成功を一次判定に戻し、signer 1と16 KiBの zipalign 成功も維持しています。

完了条件は、成果物の仕様から並べる

  1. 成果物の仕様を宣言する。ここではminSdk 28を含む対応範囲です。
  2. その対応範囲で成果物全体を検証する。APKでは apksigner verify の成功が中心になります。
  3. 署名方式、署名者数、鍵種別、alignmentのような補助証跡を照合する。
  4. 一次判定と補助証跡がそろって初めて、公開判定へ進める。

「v2かv3か」は重要な観測値です。ただし、それだけで完了を決める絶対基準ではありません。対応範囲と検証仕様に結び付けて初めて意味を持ちます。

監視や自動化の判定そのものを観測対象にする考え方は、先行記事誤検知も監視のバグであるともつながります。

false negativeの後、秘密を触らずに再開する

図解: 秘密を触らずに再開(誤判定の時点 / APK公開 / 復旧経路 / 既存の署名済みAPK / 再検証 / 既存の認証内download page)
図解: 秘密を触らずに再開(AI生成)

今回、fail-safeは機能しました。誤判定の時点でAPK公開、certificate pin、owner-device installには進みませんでした。

復旧経路では、primaryと2 backupsの暗号化bytes hash、backup readback pin、別filesystem、file owner/mode、root-owned signing checkpointを照合してから、既存の署名済みAPKだけを扱いました。復旧後は同一の署名済みAPKを再検証し、転送hashとcertificate pinを確認してから、既存の認証内download pageへ公開しました。未認証の応答は401であること、serviceがactiveであること、restart countが0であることも確認しています。

ここでの完了条件は「一度成功した工程をもう一度実行する」ことではありません。「秘密を増やして触らずとも、検証済みの同一artifactに安全に戻れる」ことです。

修復は停止解除だけで終わっていない

修復後、script testは68/68を通過しました。確認対象には、既存の検証済みartifactのcheckpoint移行、hardened resume、署名済みAPK hash、download copy hash、certificate pin、HTML link、未認証401、service active、restart count 0が含まれます。

ただし、端末所有者による初回installとrelease-build acceptanceは未完了です。署名・転送・公開前後の検証が通っても、実端末での受け入れ確認までは別の完了条件として残ります。

リリースゲートを見直す3項目

  • 完了条件は、宣言した対応範囲で成果物全体を検証していますか。
  • 個別の方式・属性チェックは、一次判定を補強する証跡に留まっていますか。
  • false negativeの後、秘密を再操作せず、同一artifactで検証と公開を再開できますか。

個別の検査項目は、上位の仕様を代替しません。完了判定はまず「宣言した対応範囲で成果物全体が検証できるか」に置くべきです。apksigner verify の成功とminSdk互換性を一次判定に戻し、v2またはv3の観測を仕様に従属させる。その順序なら、検査は公開してよい理由を積み上げるために働きます。

この検証を回している環境

この検証は、自宅の常設ラボ(使い捨てVM/LXCを回す母艦+GPU+VLAN分離ネットワーク)で動かしています。使っている機材と選定理由、全体構成は1本にまとめています。

ラボ構成のまとめを見る →
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次