Skip to main content

apk/sign/
mod.rs

1//! APK v1/v2/v3 signing, verification, and identity loading.
2
3mod block;
4mod certificate;
5mod error;
6mod identity;
7mod jar;
8mod key;
9#[cfg(feature = "keystore")]
10mod keystore;
11mod scheme;
12mod signer;
13mod verify;
14
15pub use crate::digest::DigestAlgorithm;
16pub use certificate::Certificate;
17pub use error::{KeyError, SignError, VerifyError};
18pub use identity::SigningIdentity;
19pub use jar::JarError;
20pub use key::{KeyKind, MIN_RSA_SIGNING_BITS, PrivateKey, PublicKey, SignatureAlgorithm, SignatureError};
21#[cfg(feature = "keystore")]
22pub use keystore::Keystore;
23pub use signer::Signer;
24pub use verify::{Verification, VerifiedSigner, verify, verify_bytes};
25
26use crate::types::ApiLevel;
27use bitflags::bitflags;
28pub use block::{BlockId, SigningBlock};
29use std::fmt;
30/// One APK signature scheme.
31#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
32pub enum Scheme {
33    /// JAR signing, verified by every Android release.
34    V1,
35    /// APK Signature Scheme v2, verified from Android 7.0 (API 24).
36    V2,
37    /// APK Signature Scheme v3, verified from Android 9 (API 28).
38    V3,
39}
40
41impl Scheme {
42    const ALL: [Self; 3] = [Self::V1, Self::V2, Self::V3];
43
44    /// The scheme number used by stripping protection markers.
45    pub const fn number(self) -> u32 {
46        match self {
47            Self::V1 => 1,
48            Self::V2 => 2,
49            Self::V3 => 3,
50        }
51    }
52
53    /// The first API level that verifies this scheme.
54    pub const fn min_sdk(self) -> ApiLevel {
55        match self {
56            Self::V1 => ApiLevel::BASE,
57            Self::V2 => ApiLevel::N,
58            Self::V3 => ApiLevel::P,
59        }
60    }
61
62    fn from_number(number: u32) -> Option<Self> {
63        Self::ALL.into_iter().find(|s| s.number() == number)
64    }
65
66    fn block_id(self) -> Option<BlockId> {
67        match self {
68            Self::V1 => None,
69            Self::V2 => Some(BlockId::V2),
70            Self::V3 => Some(BlockId::V3),
71        }
72    }
73
74    fn flag(self) -> Schemes {
75        match self {
76            Self::V1 => Schemes::V1,
77            Self::V2 => Schemes::V2,
78            Self::V3 => Schemes::V3,
79        }
80    }
81}
82
83impl fmt::Display for Scheme {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        f.write_str(match self {
86            Self::V1 => "JAR signature (v1)",
87            Self::V2 => "APK Signature Scheme v2",
88            Self::V3 => "APK Signature Scheme v3",
89        })
90    }
91}
92
93bitflags! {
94    /// A set of signature schemes.
95    #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
96    pub struct Schemes: u8 {
97        const V1 = 1 << 0;
98        const V2 = 1 << 1;
99        const V3 = 1 << 2;
100    }
101}
102
103impl Schemes {
104    /// The schemes `apksigner` uses by default: v2 and v3, plus v1 when the
105    /// app supports releases older than Android 7.0.
106    pub fn for_min_sdk(min_sdk: ApiLevel) -> Self {
107        if min_sdk < ApiLevel::N { Self::V1 | Self::V2 | Self::V3 } else { Self::V2 | Self::V3 }
108    }
109
110    /// The schemes in this set, weakest first.
111    pub fn iter_schemes(self) -> impl Iterator<Item = Scheme> {
112        Scheme::ALL.into_iter().filter(move |s| self.contains(s.flag()))
113    }
114
115    /// Checks that an app with `min_sdk` and `target_sdk` can rely on these
116    /// schemes: every release it supports verifies at least one, and modern
117    /// targets have a v2 or v3 signature.
118    pub fn check_coverage(self, min_sdk: ApiLevel, target_sdk: ApiLevel) -> Result<(), CoverageError> {
119        let covered_from = self.iter_schemes().map(Scheme::min_sdk).min().ok_or(CoverageError::NoSchemes)?;
120        if covered_from > min_sdk {
121            let needed = if min_sdk < ApiLevel::N { Scheme::V1 } else { Scheme::V2 };
122            return Err(CoverageError::UnverifiableOnMinSdk { schemes: self, min_sdk, needed });
123        }
124        if target_sdk >= ApiLevel::R && !self.intersects(Self::V2 | Self::V3) {
125            return Err(CoverageError::TargetRequiresV2 { target_sdk });
126        }
127        Ok(())
128    }
129}
130
131/// Why a set of signature schemes does not cover an app.
132#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
133#[non_exhaustive]
134pub enum CoverageError {
135    #[error("no signature schemes were selected")]
136    NoSchemes,
137    #[error("{schemes:?} cannot be verified by Android {min_sdk}; add {needed}")]
138    UnverifiableOnMinSdk { schemes: Schemes, min_sdk: ApiLevel, needed: Scheme },
139    #[error("targetSdkVersion {target_sdk} requires APK Signature Scheme v2 or v3")]
140    TargetRequiresV2 { target_sdk: ApiLevel },
141}