• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 use anyhow::{anyhow, bail, Context, Result};
18 use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
19 use num_derive::{FromPrimitive, ToPrimitive};
20 use num_traits::{FromPrimitive, ToPrimitive};
21 use std::io::{copy, Cursor, Read, Seek, SeekFrom, Write};
22 
23 use crate::hashtree::*;
24 
25 // `apksigv4` module provides routines to decode and encode the idsig file as defined in [APK
26 // signature scheme v4] (https://source.android.com/security/apksigning/v4).
27 
28 /// `V4Signature` provides access to the various fields in an idsig file.
29 #[derive(Default)]
30 pub struct V4Signature<R: Read + Seek> {
31     /// Version of the header. Should be 2.
32     pub version: Version,
33     /// Provides access to the information about how the APK is hashed.
34     pub hashing_info: HashingInfo,
35     /// Provides access to the information that can be used to verify this file
36     pub signing_info: SigningInfo,
37     /// Total size of the merkle tree
38     pub merkle_tree_size: u32,
39     /// Offset of the merkle tree in the idsig file
40     pub merkle_tree_offset: u64,
41 
42     // Provides access to the underlying data
43     data: R,
44 }
45 
46 /// `HashingInfo` provides information about how the APK is hashed.
47 #[derive(Default)]
48 pub struct HashingInfo {
49     /// Hash algorithm used when creating the merkle tree for the APK.
50     pub hash_algorithm: HashAlgorithm,
51     /// The log size of a block used when creating the merkle tree. 12 if 4k block was used.
52     pub log2_blocksize: u8,
53     /// The salt used when creating the merkle tree. 32 bytes max.
54     pub salt: Box<[u8]>,
55     /// The root hash of the merkle tree created.
56     pub raw_root_hash: Box<[u8]>,
57 }
58 
59 /// `SigningInfo` provides information that can be used to verify the idsig file.
60 #[derive(Default)]
61 pub struct SigningInfo {
62     /// Digest of the APK that this idsig file is for.
63     pub apk_digest: Box<[u8]>,
64     /// Certificate of the signer that signed this idsig file. ASN.1 DER form.
65     pub x509_certificate: Box<[u8]>,
66     /// A free-form binary data
67     pub additional_data: Box<[u8]>,
68     /// Public key of the signer in ASN.1 DER form. This must match the `x509_certificate` field.
69     pub public_key: Box<[u8]>,
70     /// Signature algorithm used to sign this file.
71     pub signature_algorithm_id: SignatureAlgorithmId,
72     /// The signature of this file.
73     pub signature: Box<[u8]>,
74 }
75 
76 /// Version of the idsig file format
77 #[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
78 #[repr(u32)]
79 pub enum Version {
80     /// Version 2, the only supported version.
81     V2 = 2,
82 }
83 
84 impl Version {
from(val: u32) -> Result<Version>85     fn from(val: u32) -> Result<Version> {
86         Self::from_u32(val).ok_or_else(|| anyhow!("{} is an unsupported version", val))
87     }
88 }
89 
90 impl Default for Version {
default() -> Self91     fn default() -> Self {
92         Version::V2
93     }
94 }
95 
96 /// Hash algorithm that can be used for idsig file.
97 #[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
98 #[repr(u32)]
99 pub enum HashAlgorithm {
100     /// SHA2-256
101     SHA256 = 1,
102 }
103 
104 impl HashAlgorithm {
from(val: u32) -> Result<HashAlgorithm>105     fn from(val: u32) -> Result<HashAlgorithm> {
106         Self::from_u32(val).ok_or_else(|| anyhow!("{} is an unsupported hash algorithm", val))
107     }
108 }
109 
110 impl Default for HashAlgorithm {
default() -> Self111     fn default() -> Self {
112         HashAlgorithm::SHA256
113     }
114 }
115 
116 /// Signature algorithm that can be used for idsig file
117 #[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
118 #[allow(non_camel_case_types)]
119 #[repr(u32)]
120 pub enum SignatureAlgorithmId {
121     /// RSASSA-PSS with SHA2-256 digest, SHA2-256 MGF1, 32 bytes of salt, trailer: 0xbc
122     RSASSA_PSS_SHA2_256 = 0x0101,
123     /// RSASSA-PSS with SHA2-512 digest, SHA2-512 MGF1, 64 bytes of salt, trailer: 0xbc
124     RSASSA_PSS_SHA2_512 = 0x0102,
125     /// RSASSA-PKCS1-v1_5 with SHA2-256 digest.
126     RSASSA_PKCS1_SHA2_256 = 0x0103,
127     /// RSASSA-PKCS1-v1_5 with SHA2-512 digest.
128     RSASSA_PKCS1_SHA2_512 = 0x0104,
129     /// ECDSA with SHA2-256 digest.
130     ECDSA_SHA2_256 = 0x0201,
131     /// ECDSA with SHA2-512 digest.
132     ECDSA_SHA2_512 = 0x0202,
133     /// DSA with SHA2-256 digest
134     DSA_SHA2_256 = 0x0301,
135 }
136 
137 impl SignatureAlgorithmId {
from(val: u32) -> Result<SignatureAlgorithmId>138     fn from(val: u32) -> Result<SignatureAlgorithmId> {
139         Self::from_u32(val)
140             .with_context(|| format!("{:#06x} is an unsupported signature algorithm", val))
141     }
142 }
143 
144 impl Default for SignatureAlgorithmId {
default() -> Self145     fn default() -> Self {
146         SignatureAlgorithmId::DSA_SHA2_256
147     }
148 }
149 
150 impl<R: Read + Seek> V4Signature<R> {
151     /// Consumes a stream for an idsig file into a `V4Signature` struct.
from(mut r: R) -> Result<V4Signature<R>>152     pub fn from(mut r: R) -> Result<V4Signature<R>> {
153         Ok(V4Signature {
154             version: Version::from(r.read_u32::<LittleEndian>()?)?,
155             hashing_info: HashingInfo::from(&mut r)?,
156             signing_info: SigningInfo::from(&mut r)?,
157             merkle_tree_size: r.read_u32::<LittleEndian>()?,
158             merkle_tree_offset: r.stream_position()?,
159             data: r,
160         })
161     }
162 
163     /// Read a stream for an APK file and creates a corresponding `V4Signature` struct that digests
164     /// the APK file. Note that the signing is not done.
create( mut apk: &mut R, block_size: usize, salt: &[u8], algorithm: HashAlgorithm, ) -> Result<V4Signature<Cursor<Vec<u8>>>>165     pub fn create(
166         mut apk: &mut R,
167         block_size: usize,
168         salt: &[u8],
169         algorithm: HashAlgorithm,
170     ) -> Result<V4Signature<Cursor<Vec<u8>>>> {
171         // Determine the size of the apk
172         let start = apk.stream_position()?;
173         let size = apk.seek(SeekFrom::End(0))? as usize;
174         apk.seek(SeekFrom::Start(start))?;
175 
176         // Create hash tree (and root hash)
177         let algorithm = match algorithm {
178             HashAlgorithm::SHA256 => &ring::digest::SHA256,
179         };
180         let hash_tree = HashTree::from(&mut apk, size, salt, block_size, algorithm)?;
181 
182         let mut ret = V4Signature {
183             version: Version::default(),
184             hashing_info: HashingInfo::default(),
185             signing_info: SigningInfo::default(),
186             merkle_tree_size: hash_tree.tree.len() as u32,
187             merkle_tree_offset: 0, // merkle tree starts from the beginning of `data`
188             data: Cursor::new(hash_tree.tree),
189         };
190         ret.hashing_info.raw_root_hash = hash_tree.root_hash.into_boxed_slice();
191         ret.hashing_info.log2_blocksize = log2(block_size);
192 
193         // TODO(jiyong): fill the signing_info struct by reading the APK file. The information,
194         // especially `apk_digest` is needed to check if `V4Signature` is outdated, in which case
195         // it needs to be created from the updated APK.
196 
197         Ok(ret)
198     }
199 
200     /// Writes the data into a writer
write_into<W: Write + Seek>(&mut self, mut w: &mut W) -> Result<()>201     pub fn write_into<W: Write + Seek>(&mut self, mut w: &mut W) -> Result<()> {
202         // Writes the header part
203         w.write_u32::<LittleEndian>(self.version.to_u32().unwrap())?;
204         self.hashing_info.write_into(&mut w)?;
205         self.signing_info.write_into(&mut w)?;
206         w.write_u32::<LittleEndian>(self.merkle_tree_size)?;
207 
208         // Writes the merkle tree
209         self.data.seek(SeekFrom::Start(self.merkle_tree_offset))?;
210         let copied_size = copy(&mut self.data, &mut w)?;
211         if copied_size != self.merkle_tree_size as u64 {
212             bail!(
213                 "merkle tree is {} bytes, but only {} bytes are written.",
214                 self.merkle_tree_size,
215                 copied_size
216             );
217         }
218         Ok(())
219     }
220 
221     /// Returns the bytes that represents the merkle tree
merkle_tree(&mut self) -> Result<Vec<u8>>222     pub fn merkle_tree(&mut self) -> Result<Vec<u8>> {
223         self.data.seek(SeekFrom::Start(self.merkle_tree_offset))?;
224         let mut out = Vec::new();
225         self.data.read_to_end(&mut out)?;
226         Ok(out)
227     }
228 }
229 
230 impl HashingInfo {
from(mut r: &mut dyn Read) -> Result<HashingInfo>231     fn from(mut r: &mut dyn Read) -> Result<HashingInfo> {
232         // Size of the entire hashing_info struct. We don't need this because each variable-sized
233         // fields in the struct are also length encoded.
234         r.read_u32::<LittleEndian>()?;
235         Ok(HashingInfo {
236             hash_algorithm: HashAlgorithm::from(r.read_u32::<LittleEndian>()?)?,
237             log2_blocksize: r.read_u8()?,
238             salt: read_sized_array(&mut r)?,
239             raw_root_hash: read_sized_array(&mut r)?,
240         })
241     }
242 
write_into<W: Write + Seek>(&self, mut w: &mut W) -> Result<()>243     fn write_into<W: Write + Seek>(&self, mut w: &mut W) -> Result<()> {
244         let start = w.stream_position()?;
245         // Size of the entire hashing_info struct. Since we don't know the size yet, fill the place
246         // with 0. The exact size will then be written below.
247         w.write_u32::<LittleEndian>(0)?;
248 
249         w.write_u32::<LittleEndian>(self.hash_algorithm.to_u32().unwrap())?;
250         w.write_u8(self.log2_blocksize)?;
251         write_sized_array(&mut w, &self.salt)?;
252         write_sized_array(&mut w, &self.raw_root_hash)?;
253 
254         // Determine the size of hashing_info, and write it in front of the struct where the value
255         // was initialized to zero.
256         let end = w.stream_position()?;
257         let size = end - start - std::mem::size_of::<u32>() as u64;
258         w.seek(SeekFrom::Start(start))?;
259         w.write_u32::<LittleEndian>(size as u32)?;
260         w.seek(SeekFrom::Start(end))?;
261         Ok(())
262     }
263 }
264 
265 impl SigningInfo {
from(mut r: &mut dyn Read) -> Result<SigningInfo>266     fn from(mut r: &mut dyn Read) -> Result<SigningInfo> {
267         // Size of the entire signing_info struct. We don't need this because each variable-sized
268         // fields in the struct are also length encoded.
269         r.read_u32::<LittleEndian>()?;
270         Ok(SigningInfo {
271             apk_digest: read_sized_array(&mut r)?,
272             x509_certificate: read_sized_array(&mut r)?,
273             additional_data: read_sized_array(&mut r)?,
274             public_key: read_sized_array(&mut r)?,
275             signature_algorithm_id: SignatureAlgorithmId::from(r.read_u32::<LittleEndian>()?)?,
276             signature: read_sized_array(&mut r)?,
277         })
278     }
279 
write_into<W: Write + Seek>(&self, mut w: &mut W) -> Result<()>280     fn write_into<W: Write + Seek>(&self, mut w: &mut W) -> Result<()> {
281         let start = w.stream_position()?;
282         // Size of the entire signing_info struct. Since we don't know the size yet, fill the place
283         // with 0. The exact size will then be written below.
284         w.write_u32::<LittleEndian>(0)?;
285 
286         write_sized_array(&mut w, &self.apk_digest)?;
287         write_sized_array(&mut w, &self.x509_certificate)?;
288         write_sized_array(&mut w, &self.additional_data)?;
289         write_sized_array(&mut w, &self.public_key)?;
290         w.write_u32::<LittleEndian>(self.signature_algorithm_id.to_u32().unwrap())?;
291         write_sized_array(&mut w, &self.signature)?;
292 
293         // Determine the size of signing_info, and write it in front of the struct where the value
294         // was initialized to zero.
295         let end = w.stream_position()?;
296         let size = end - start - std::mem::size_of::<u32>() as u64;
297         w.seek(SeekFrom::Start(start))?;
298         w.write_u32::<LittleEndian>(size as u32)?;
299         w.seek(SeekFrom::Start(end))?;
300         Ok(())
301     }
302 }
303 
read_sized_array(r: &mut dyn Read) -> Result<Box<[u8]>>304 fn read_sized_array(r: &mut dyn Read) -> Result<Box<[u8]>> {
305     let size = r.read_u32::<LittleEndian>()?;
306     let mut data = vec![0; size as usize];
307     r.read_exact(&mut data)?;
308     Ok(data.into_boxed_slice())
309 }
310 
write_sized_array(w: &mut dyn Write, data: &[u8]) -> Result<()>311 fn write_sized_array(w: &mut dyn Write, data: &[u8]) -> Result<()> {
312     w.write_u32::<LittleEndian>(data.len() as u32)?;
313     Ok(w.write_all(data)?)
314 }
315 
log2(n: usize) -> u8316 fn log2(n: usize) -> u8 {
317     let num_bits = std::mem::size_of::<usize>() * 8;
318     (num_bits as u32 - n.leading_zeros() - 1) as u8
319 }
320 
321 #[cfg(test)]
322 mod tests {
323     use super::*;
324     use std::io::Cursor;
325 
hexstring_from(s: &[u8]) -> String326     fn hexstring_from(s: &[u8]) -> String {
327         s.iter().map(|byte| format!("{:02x}", byte)).reduce(|i, j| i + &j).unwrap_or_default()
328     }
329 
330     #[test]
parse_idsig_file()331     fn parse_idsig_file() {
332         let idsig = Cursor::new(include_bytes!("../testdata/test.apk.idsig"));
333         let parsed = V4Signature::from(idsig).unwrap();
334 
335         assert_eq!(Version::V2, parsed.version);
336 
337         let hi = parsed.hashing_info;
338         assert_eq!(HashAlgorithm::SHA256, hi.hash_algorithm);
339         assert_eq!(12, hi.log2_blocksize);
340         assert_eq!("", hexstring_from(hi.salt.as_ref()));
341         assert_eq!(
342             "ce1194fdb3cb2537daf0ac8cdf4926754adcbce5abeece7945fe25d204a0df6a",
343             hexstring_from(hi.raw_root_hash.as_ref())
344         );
345 
346         let si = parsed.signing_info;
347         assert_eq!(
348             "b5225523a813fb84ed599dd649698c080bcfed4fb19ddb00283a662a2683bc15",
349             hexstring_from(si.apk_digest.as_ref())
350         );
351         assert_eq!("", hexstring_from(si.additional_data.as_ref()));
352         assert_eq!(
353             "303d021c77304d0f4732a90372bbfce095223e4ba82427ceb381f69bc6762d78021d008b99924\
354                    a8585c38d7f654835eb219ae9e176b44e86dcb23153e3d9d6",
355             hexstring_from(si.signature.as_ref())
356         );
357         assert_eq!(SignatureAlgorithmId::DSA_SHA2_256, si.signature_algorithm_id);
358 
359         assert_eq!(36864, parsed.merkle_tree_size);
360         assert_eq!(2251, parsed.merkle_tree_offset);
361     }
362 
363     /// Parse an idsig file into V4Signature and write it. The written date must be the same as
364     /// the input file.
365     #[test]
parse_and_compose()366     fn parse_and_compose() {
367         let input = Cursor::new(include_bytes!("../testdata/test.apk.idsig"));
368         let mut parsed = V4Signature::from(input.clone()).unwrap();
369 
370         let mut output = Cursor::new(Vec::new());
371         parsed.write_into(&mut output).unwrap();
372 
373         assert_eq!(input.get_ref().as_ref(), output.get_ref().as_slice());
374     }
375 
376     /// Create V4Signature by hashing an APK. Merkle tree and the root hash should be the same
377     /// as those in the idsig file created by the signapk tool.
378     #[test]
digest_from_apk()379     fn digest_from_apk() {
380         let mut input = Cursor::new(include_bytes!("../testdata/test.apk"));
381         let mut created =
382             V4Signature::create(&mut input, 4096, &[], HashAlgorithm::SHA256).unwrap();
383 
384         let golden = Cursor::new(include_bytes!("../testdata/test.apk.idsig"));
385         let mut golden = V4Signature::from(golden).unwrap();
386 
387         // Compare the root hash
388         assert_eq!(
389             created.hashing_info.raw_root_hash.as_ref(),
390             golden.hashing_info.raw_root_hash.as_ref()
391         );
392 
393         // Compare the merkle tree
394         assert_eq!(
395             created.merkle_tree().unwrap().as_slice(),
396             golden.merkle_tree().unwrap().as_slice()
397         );
398     }
399 }
400