1mod 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#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
32pub enum Scheme {
33 V1,
35 V2,
37 V3,
39}
40
41impl Scheme {
42 const ALL: [Self; 3] = [Self::V1, Self::V2, Self::V3];
43
44 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 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 #[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 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 pub fn iter_schemes(self) -> impl Iterator<Item = Scheme> {
112 Scheme::ALL.into_iter().filter(move |s| self.contains(s.flag()))
113 }
114
115 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#[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}