blob: 9a5144c2c387c1cab0c547e4cd2c7c4f5949ce25 [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 Wang1ffff622022-09-16 13:45:47 +000019use anyhow::{ensure, Result};
Alice Wang0a293bb2022-09-19 08:41:40 +000020use num_derive::{FromPrimitive, ToPrimitive};
Alice Wang5d0f89a2022-09-15 15:06:10 +000021use openssl::hash::MessageDigest;
Alice Wanga66b5c02022-09-16 07:25:17 +000022use openssl::pkey::{self, PKey};
23use openssl::rsa::Padding;
24use openssl::sign::Verifier;
Alice Wang5d0f89a2022-09-15 15:06:10 +000025
26/// [Signature Algorithm IDs]: https://source.android.com/docs/security/apksigning/v2#signature-algorithm-ids
Alice Wang0a293bb2022-09-19 08:41:40 +000027/// [SignatureAlgorithm.java]: (tools/apksig/src/main/java/com/android/apksig/internal/apk/SignatureAlgorithm.java)
Alice Wang5d0f89a2022-09-15 15:06:10 +000028///
29/// Some of the algorithms are not implemented. See b/197052981.
Alice Wangb1e15ca2022-09-19 11:06:11 +000030#[derive(Clone, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
Alice Wang5d0f89a2022-09-15 15:06:10 +000031#[repr(u32)]
32pub enum SignatureAlgorithmID {
Alice Wang0a293bb2022-09-19 08:41:40 +000033 /// RSASSA-PSS with SHA2-256 digest, SHA2-256 MGF1, 32 bytes of salt, trailer: 0xbc, content
34 /// digested using SHA2-256 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000035 RsaPssWithSha256 = 0x0101,
Alice Wang0a293bb2022-09-19 08:41:40 +000036
37 /// RSASSA-PSS with SHA2-512 digest, SHA2-512 MGF1, 64 bytes of salt, trailer: 0xbc, content
38 /// digested using SHA2-512 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000039 RsaPssWithSha512 = 0x0102,
Alice Wang0a293bb2022-09-19 08:41:40 +000040
41 /// RSASSA-PKCS1-v1_5 with SHA2-256 digest, content digested using SHA2-256 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000042 RsaPkcs1V15WithSha256 = 0x0103,
Alice Wang0a293bb2022-09-19 08:41:40 +000043
44 /// RSASSA-PKCS1-v1_5 with SHA2-512 digest, content digested using SHA2-512 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000045 RsaPkcs1V15WithSha512 = 0x0104,
Alice Wang0a293bb2022-09-19 08:41:40 +000046
47 /// ECDSA with SHA2-256 digest, content digested using SHA2-256 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000048 EcdsaWithSha256 = 0x0201,
Alice Wang0a293bb2022-09-19 08:41:40 +000049
50 /// ECDSA with SHA2-512 digest, content digested using SHA2-512 in 1 MB chunks.
Alice Wang5d0f89a2022-09-15 15:06:10 +000051 EcdsaWithSha512 = 0x0202,
Alice Wang0a293bb2022-09-19 08:41:40 +000052
53 /// DSA with SHA2-256 digest, content digested using SHA2-256 in 1 MB chunks.
54 /// Signing is done deterministically according to RFC 6979.
Alice Wang5d0f89a2022-09-15 15:06:10 +000055 DsaWithSha256 = 0x0301,
Alice Wang0a293bb2022-09-19 08:41:40 +000056
57 /// RSASSA-PKCS1-v1_5 with SHA2-256 digest, content digested using SHA2-256 in 4 KB
58 /// chunks, in the same way fsverity operates. This digest and the content length
59 /// (before digestion, 8 bytes in little endian) construct the final digest.
Alice Wang5d0f89a2022-09-15 15:06:10 +000060 VerityRsaPkcs1V15WithSha256 = 0x0421,
Alice Wang0a293bb2022-09-19 08:41:40 +000061
62 /// ECDSA with SHA2-256 digest, content digested using SHA2-256 in 4 KB chunks, in the
63 /// same way fsverity operates. This digest and the content length (before digestion,
64 /// 8 bytes in little endian) construct the final digest.
Alice Wang5d0f89a2022-09-15 15:06:10 +000065 VerityEcdsaWithSha256 = 0x0423,
Alice Wang0a293bb2022-09-19 08:41:40 +000066
67 /// DSA with SHA2-256 digest, content digested using SHA2-256 in 4 KB chunks, in the
68 /// same way fsverity operates. This digest and the content length (before digestion,
69 /// 8 bytes in little endian) construct the final digest.
Alice Wang5d0f89a2022-09-15 15:06:10 +000070 VerityDsaWithSha256 = 0x0425,
71}
72
Alice Wang0a293bb2022-09-19 08:41:40 +000073impl Default for SignatureAlgorithmID {
74 fn default() -> Self {
75 SignatureAlgorithmID::DsaWithSha256
76 }
77}
78
Alice Wang5d0f89a2022-09-15 15:06:10 +000079impl SignatureAlgorithmID {
Alice Wanga66b5c02022-09-16 07:25:17 +000080 pub(crate) fn new_verifier<'a>(
81 &self,
82 public_key: &'a PKey<pkey::Public>,
83 ) -> Result<Verifier<'a>> {
84 ensure!(
85 !matches!(
86 self,
Alice Wang455b02b2022-09-16 13:32:13 +000087 SignatureAlgorithmID::DsaWithSha256 | SignatureAlgorithmID::VerityDsaWithSha256
Alice Wanga66b5c02022-09-16 07:25:17 +000088 ),
89 "TODO(b/197052981): Algorithm '{:#?}' is not implemented.",
90 self
91 );
92 ensure!(public_key.id() == self.pkey_id(), "Public key has the wrong ID");
93 let mut verifier = Verifier::new(self.new_message_digest(), public_key)?;
94 if public_key.id() == pkey::Id::RSA {
95 verifier.set_rsa_padding(self.rsa_padding())?;
96 }
97 Ok(verifier)
98 }
99
100 /// Returns the message digest corresponding to the signature algorithm
101 /// according to the spec [Signature Algorithm IDs].
Alice Wang1ffff622022-09-16 13:45:47 +0000102 pub(crate) fn new_message_digest(&self) -> MessageDigest {
Alice Wanga66b5c02022-09-16 07:25:17 +0000103 match self {
104 SignatureAlgorithmID::RsaPssWithSha256
105 | SignatureAlgorithmID::RsaPkcs1V15WithSha256
106 | SignatureAlgorithmID::EcdsaWithSha256
107 | SignatureAlgorithmID::DsaWithSha256
108 | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
109 | SignatureAlgorithmID::VerityEcdsaWithSha256
110 | SignatureAlgorithmID::VerityDsaWithSha256 => MessageDigest::sha256(),
111 SignatureAlgorithmID::RsaPssWithSha512
112 | SignatureAlgorithmID::RsaPkcs1V15WithSha512
113 | SignatureAlgorithmID::EcdsaWithSha512 => MessageDigest::sha512(),
114 }
115 }
116
117 fn pkey_id(&self) -> pkey::Id {
118 match self {
119 SignatureAlgorithmID::RsaPssWithSha256
120 | SignatureAlgorithmID::RsaPssWithSha512
121 | SignatureAlgorithmID::RsaPkcs1V15WithSha256
122 | SignatureAlgorithmID::RsaPkcs1V15WithSha512
123 | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256 => pkey::Id::RSA,
124 SignatureAlgorithmID::EcdsaWithSha256
125 | SignatureAlgorithmID::EcdsaWithSha512
126 | SignatureAlgorithmID::VerityEcdsaWithSha256 => pkey::Id::EC,
127 SignatureAlgorithmID::DsaWithSha256 | SignatureAlgorithmID::VerityDsaWithSha256 => {
128 pkey::Id::DSA
129 }
130 }
131 }
132
133 fn rsa_padding(&self) -> Padding {
134 match self {
135 SignatureAlgorithmID::RsaPssWithSha256 | SignatureAlgorithmID::RsaPssWithSha512 => {
136 Padding::PKCS1_PSS
137 }
138 SignatureAlgorithmID::RsaPkcs1V15WithSha256
139 | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
140 | SignatureAlgorithmID::RsaPkcs1V15WithSha512 => Padding::PKCS1,
141 SignatureAlgorithmID::EcdsaWithSha256
142 | SignatureAlgorithmID::EcdsaWithSha512
143 | SignatureAlgorithmID::VerityEcdsaWithSha256
144 | SignatureAlgorithmID::DsaWithSha256
145 | SignatureAlgorithmID::VerityDsaWithSha256 => Padding::NONE,
146 }
147 }
Alice Wang1ffff622022-09-16 13:45:47 +0000148
Alice Wangb1e15ca2022-09-19 11:06:11 +0000149 pub(crate) fn to_content_digest_algorithm(&self) -> ContentDigestAlgorithm {
Alice Wang1ffff622022-09-16 13:45:47 +0000150 match self {
151 SignatureAlgorithmID::RsaPssWithSha256
152 | SignatureAlgorithmID::RsaPkcs1V15WithSha256
153 | SignatureAlgorithmID::EcdsaWithSha256
154 | SignatureAlgorithmID::DsaWithSha256 => ContentDigestAlgorithm::ChunkedSha256,
155 SignatureAlgorithmID::RsaPssWithSha512
156 | SignatureAlgorithmID::RsaPkcs1V15WithSha512
157 | SignatureAlgorithmID::EcdsaWithSha512 => ContentDigestAlgorithm::ChunkedSha512,
158 SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
159 | SignatureAlgorithmID::VerityEcdsaWithSha256
160 | SignatureAlgorithmID::VerityDsaWithSha256 => {
161 ContentDigestAlgorithm::VerityChunkedSha256
162 }
163 }
164 }
Alice Wang5d0f89a2022-09-15 15:06:10 +0000165}
166
167/// The rank of the content digest algorithm in this enum is used to help pick
168/// v4 apk digest.
169/// According to APK Signature Scheme v4, [apk digest] is the first available
170/// content digest of the highest rank (rank N).
171///
172/// This rank was also used for step 3a of the v3 signature verification.
173///
174/// [apk digest]: https://source.android.com/docs/security/features/apksigning/v4#apk-digest
175/// [v3 verification]: https://source.android.com/docs/security/apksigning/v3#v3-verification
176#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
Alice Wangb1e15ca2022-09-19 11:06:11 +0000177pub(crate) enum ContentDigestAlgorithm {
Alice Wang5d0f89a2022-09-15 15:06:10 +0000178 ChunkedSha256 = 1,
179 VerityChunkedSha256,
180 ChunkedSha512,
181}