blob: 63156069bf1648777e2ac7b5024c2ce640a0be83 [file] [log] [blame]
Alice Wang5d0f89a2022-09-15 15:06:10 +00001/*
2 * Copyright (C) 2022 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//! Algorithms used for APK Signature Scheme.
18
Alice Wangab5231f2022-09-28 12:36:48 +000019use anyhow::{ensure, Context, Result};
20use byteorder::{LittleEndian, ReadBytesExt};
Alice Wangd73d0ff2022-09-20 11:33:30 +000021use bytes::{Buf, Bytes};
Alice Wang0a293bb2022-09-19 08:41:40 +000022use num_derive::{FromPrimitive, ToPrimitive};
Alice Wangd73d0ff2022-09-20 11:33:30 +000023use num_traits::{FromPrimitive, ToPrimitive};
Alice Wang5d0f89a2022-09-15 15:06:10 +000024use openssl::hash::MessageDigest;
Alice Wanga66b5c02022-09-16 07:25:17 +000025use openssl::pkey::{self, PKey};
26use openssl::rsa::Padding;
27use openssl::sign::Verifier;
Alice Wang2ef30742022-09-19 11:59:17 +000028use serde::{Deserialize, Serialize};
Alice Wangab5231f2022-09-28 12:36:48 +000029use std::io::Read;
Alice Wang5d0f89a2022-09-15 15:06:10 +000030
Alice Wangd73d0ff2022-09-20 11:33:30 +000031use crate::bytes_ext::ReadFromBytes;
32
Alice Wang5d0f89a2022-09-15 15:06:10 +000033/// [Signature Algorithm IDs]: https://source.android.com/docs/security/apksigning/v2#signature-algorithm-ids
Alice Wang0a293bb2022-09-19 08:41:40 +000034/// [SignatureAlgorithm.java]: (tools/apksig/src/main/java/com/android/apksig/internal/apk/SignatureAlgorithm.java)
Alice Wang5d0f89a2022-09-15 15:06:10 +000035///
36/// Some of the algorithms are not implemented. See b/197052981.
Alice Wangd73d0ff2022-09-20 11:33:30 +000037#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
Alice Wang5d0f89a2022-09-15 15:06:10 +000038#[repr(u32)]
39pub enum SignatureAlgorithmID {
Alice Wang0a293bb2022-09-19 08:41:40 +000040 /// RSASSA-PSS with SHA2-256 digest, SHA2-256 MGF1, 32 bytes of salt, trailer: 0xbc, content
41 /// digested using SHA2-256 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000042 RsaPssWithSha256 = 0x0101,
Alice Wang0a293bb2022-09-19 08:41:40 +000043
44 /// RSASSA-PSS with SHA2-512 digest, SHA2-512 MGF1, 64 bytes of salt, trailer: 0xbc, content
45 /// digested using SHA2-512 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000046 RsaPssWithSha512 = 0x0102,
Alice Wang0a293bb2022-09-19 08:41:40 +000047
48 /// RSASSA-PKCS1-v1_5 with SHA2-256 digest, content digested using SHA2-256 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000049 RsaPkcs1V15WithSha256 = 0x0103,
Alice Wang0a293bb2022-09-19 08:41:40 +000050
51 /// RSASSA-PKCS1-v1_5 with SHA2-512 digest, content digested using SHA2-512 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000052 RsaPkcs1V15WithSha512 = 0x0104,
Alice Wang0a293bb2022-09-19 08:41:40 +000053
54 /// ECDSA with SHA2-256 digest, content digested using SHA2-256 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000055 EcdsaWithSha256 = 0x0201,
Alice Wang0a293bb2022-09-19 08:41:40 +000056
57 /// ECDSA with SHA2-512 digest, content digested using SHA2-512 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000058 EcdsaWithSha512 = 0x0202,
Alice Wang0a293bb2022-09-19 08:41:40 +000059
60 /// DSA with SHA2-256 digest, content digested using SHA2-256 in 1 MB chunks.
61 /// Signing is done deterministically according to RFC 6979.
Alice Wang5d0f89a2022-09-15 15:06:10 +000062 DsaWithSha256 = 0x0301,
Alice Wang0a293bb2022-09-19 08:41:40 +000063
64 /// RSASSA-PKCS1-v1_5 with SHA2-256 digest, content digested using SHA2-256 in 4 KB
65 /// chunks, in the same way fsverity operates. This digest and the content length
66 /// (before digestion, 8 bytes in little endian) construct the final digest.
Alice Wang5d0f89a2022-09-15 15:06:10 +000067 VerityRsaPkcs1V15WithSha256 = 0x0421,
Alice Wang0a293bb2022-09-19 08:41:40 +000068
69 /// ECDSA with SHA2-256 digest, content digested using SHA2-256 in 4 KB chunks, in the
70 /// same way fsverity operates. This digest and the content length (before digestion,
71 /// 8 bytes in little endian) construct the final digest.
Alice Wang5d0f89a2022-09-15 15:06:10 +000072 VerityEcdsaWithSha256 = 0x0423,
Alice Wang0a293bb2022-09-19 08:41:40 +000073
74 /// DSA with SHA2-256 digest, content digested using SHA2-256 in 4 KB chunks, in the
75 /// same way fsverity operates. This digest and the content length (before digestion,
76 /// 8 bytes in little endian) construct the final digest.
Alice Wang5d0f89a2022-09-15 15:06:10 +000077 VerityDsaWithSha256 = 0x0425,
78}
79
Alice Wang0a293bb2022-09-19 08:41:40 +000080impl Default for SignatureAlgorithmID {
81 fn default() -> Self {
Alice Wanga09156e2022-09-22 09:09:49 +000082 SignatureAlgorithmID::RsaPssWithSha256
Alice Wang0a293bb2022-09-19 08:41:40 +000083 }
84}
85
Alice Wangd73d0ff2022-09-20 11:33:30 +000086impl ReadFromBytes for Option<SignatureAlgorithmID> {
87 fn read_from_bytes(buf: &mut Bytes) -> Result<Self> {
88 Ok(SignatureAlgorithmID::from_u32(buf.get_u32_le()))
89 }
90}
91
Alice Wang5d0f89a2022-09-15 15:06:10 +000092impl SignatureAlgorithmID {
Alice Wang2ef30742022-09-19 11:59:17 +000093 /// Converts the signature algorithm ID to the corresponding u32.
94 pub fn to_u32(&self) -> u32 {
95 ToPrimitive::to_u32(self).expect("Unsupported algorithm for to_u32.")
96 }
97
Alice Wanga66b5c02022-09-16 07:25:17 +000098 pub(crate) fn new_verifier<'a>(
99 &self,
100 public_key: &'a PKey<pkey::Public>,
101 ) -> Result<Verifier<'a>> {
Andrew Scull3bae36c2022-09-21 21:55:42 +0000102 ensure!(
103 !matches!(
104 self,
105 SignatureAlgorithmID::DsaWithSha256 | SignatureAlgorithmID::VerityDsaWithSha256
106 ),
Alice Wang50701022022-09-21 08:51:38 +0000107 "Algorithm '{:?}' is not supported in openssl to build this verifier (b/197052981).",
Andrew Scull3bae36c2022-09-21 21:55:42 +0000108 self
109 );
Alice Wanga66b5c02022-09-16 07:25:17 +0000110 ensure!(public_key.id() == self.pkey_id(), "Public key has the wrong ID");
111 let mut verifier = Verifier::new(self.new_message_digest(), public_key)?;
112 if public_key.id() == pkey::Id::RSA {
113 verifier.set_rsa_padding(self.rsa_padding())?;
114 }
115 Ok(verifier)
116 }
117
118 /// Returns the message digest corresponding to the signature algorithm
119 /// according to the spec [Signature Algorithm IDs].
Alice Wang1ffff622022-09-16 13:45:47 +0000120 pub(crate) fn new_message_digest(&self) -> MessageDigest {
Alice Wanga66b5c02022-09-16 07:25:17 +0000121 match self {
122 SignatureAlgorithmID::RsaPssWithSha256
123 | SignatureAlgorithmID::RsaPkcs1V15WithSha256
124 | SignatureAlgorithmID::EcdsaWithSha256
125 | SignatureAlgorithmID::DsaWithSha256
126 | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
127 | SignatureAlgorithmID::VerityEcdsaWithSha256
128 | SignatureAlgorithmID::VerityDsaWithSha256 => MessageDigest::sha256(),
129 SignatureAlgorithmID::RsaPssWithSha512
130 | SignatureAlgorithmID::RsaPkcs1V15WithSha512
131 | SignatureAlgorithmID::EcdsaWithSha512 => MessageDigest::sha512(),
132 }
133 }
134
Alice Wang50701022022-09-21 08:51:38 +0000135 /// DSA is not directly supported in openssl today. See b/197052981.
136 pub(crate) fn is_supported(&self) -> bool {
137 !matches!(
138 self,
139 SignatureAlgorithmID::DsaWithSha256 | SignatureAlgorithmID::VerityDsaWithSha256,
140 )
141 }
142
Alice Wanga66b5c02022-09-16 07:25:17 +0000143 fn pkey_id(&self) -> pkey::Id {
144 match self {
145 SignatureAlgorithmID::RsaPssWithSha256
146 | SignatureAlgorithmID::RsaPssWithSha512
147 | SignatureAlgorithmID::RsaPkcs1V15WithSha256
148 | SignatureAlgorithmID::RsaPkcs1V15WithSha512
149 | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256 => pkey::Id::RSA,
150 SignatureAlgorithmID::EcdsaWithSha256
151 | SignatureAlgorithmID::EcdsaWithSha512
152 | SignatureAlgorithmID::VerityEcdsaWithSha256 => pkey::Id::EC,
153 SignatureAlgorithmID::DsaWithSha256 | SignatureAlgorithmID::VerityDsaWithSha256 => {
154 pkey::Id::DSA
155 }
156 }
157 }
158
159 fn rsa_padding(&self) -> Padding {
160 match self {
161 SignatureAlgorithmID::RsaPssWithSha256 | SignatureAlgorithmID::RsaPssWithSha512 => {
162 Padding::PKCS1_PSS
163 }
164 SignatureAlgorithmID::RsaPkcs1V15WithSha256
165 | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
166 | SignatureAlgorithmID::RsaPkcs1V15WithSha512 => Padding::PKCS1,
167 SignatureAlgorithmID::EcdsaWithSha256
168 | SignatureAlgorithmID::EcdsaWithSha512
169 | SignatureAlgorithmID::VerityEcdsaWithSha256
170 | SignatureAlgorithmID::DsaWithSha256
171 | SignatureAlgorithmID::VerityDsaWithSha256 => Padding::NONE,
172 }
173 }
Alice Wang1ffff622022-09-16 13:45:47 +0000174
Alice Wangd73d0ff2022-09-20 11:33:30 +0000175 pub(crate) fn content_digest_algorithm(&self) -> ContentDigestAlgorithm {
Alice Wang1ffff622022-09-16 13:45:47 +0000176 match self {
177 SignatureAlgorithmID::RsaPssWithSha256
178 | SignatureAlgorithmID::RsaPkcs1V15WithSha256
179 | SignatureAlgorithmID::EcdsaWithSha256
180 | SignatureAlgorithmID::DsaWithSha256 => ContentDigestAlgorithm::ChunkedSha256,
181 SignatureAlgorithmID::RsaPssWithSha512
182 | SignatureAlgorithmID::RsaPkcs1V15WithSha512
183 | SignatureAlgorithmID::EcdsaWithSha512 => ContentDigestAlgorithm::ChunkedSha512,
184 SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
185 | SignatureAlgorithmID::VerityEcdsaWithSha256
186 | SignatureAlgorithmID::VerityDsaWithSha256 => {
187 ContentDigestAlgorithm::VerityChunkedSha256
188 }
189 }
190 }
Alice Wang5d0f89a2022-09-15 15:06:10 +0000191}
192
193/// The rank of the content digest algorithm in this enum is used to help pick
194/// v4 apk digest.
195/// According to APK Signature Scheme v4, [apk digest] is the first available
196/// content digest of the highest rank (rank N).
197///
198/// This rank was also used for step 3a of the v3 signature verification.
199///
200/// [apk digest]: https://source.android.com/docs/security/features/apksigning/v4#apk-digest
201/// [v3 verification]: https://source.android.com/docs/security/apksigning/v3#v3-verification
202#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
Alice Wangb1e15ca2022-09-19 11:06:11 +0000203pub(crate) enum ContentDigestAlgorithm {
Alice Wang5d0f89a2022-09-15 15:06:10 +0000204 ChunkedSha256 = 1,
205 VerityChunkedSha256,
206 ChunkedSha512,
207}
Alice Wangab5231f2022-09-28 12:36:48 +0000208
209/// Hash algorithms.
210#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
211#[repr(u32)]
212pub enum HashAlgorithm {
213 /// SHA-256
214 SHA256 = 1,
215}
216
217impl HashAlgorithm {
218 pub(crate) fn from_read<R: Read>(read: &mut R) -> Result<Self> {
219 let val = read.read_u32::<LittleEndian>()?;
220 Self::from_u32(val).context(format!("Unsupported hash algorithm: {}", val))
221 }
222}
223
224impl Default for HashAlgorithm {
225 fn default() -> Self {
226 HashAlgorithm::SHA256
227 }
228}