blob: edfa946939b190847733ca9f213a3ca7b737f0f8 [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 Wang5d0f89a2022-09-15 15:06:10 +000020use num_derive::FromPrimitive;
21use 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 +000025use std::cmp::Ordering;
26
27/// [Signature Algorithm IDs]: https://source.android.com/docs/security/apksigning/v2#signature-algorithm-ids
28///
29/// Some of the algorithms are not implemented. See b/197052981.
30#[derive(Clone, Debug, Eq, FromPrimitive)]
31#[repr(u32)]
32pub enum SignatureAlgorithmID {
33 RsaPssWithSha256 = 0x0101,
34 RsaPssWithSha512 = 0x0102,
35 RsaPkcs1V15WithSha256 = 0x0103,
36 RsaPkcs1V15WithSha512 = 0x0104,
37 EcdsaWithSha256 = 0x0201,
38 EcdsaWithSha512 = 0x0202,
39 DsaWithSha256 = 0x0301,
40 VerityRsaPkcs1V15WithSha256 = 0x0421,
41 VerityEcdsaWithSha256 = 0x0423,
42 VerityDsaWithSha256 = 0x0425,
43}
44
45impl Ord for SignatureAlgorithmID {
46 /// Ranks the signature algorithm according to the corresponding content
47 /// digest algorithm's rank.
48 fn cmp(&self, other: &Self) -> Ordering {
49 self.to_content_digest_algorithm().cmp(&other.to_content_digest_algorithm())
50 }
51}
52
53impl PartialOrd for SignatureAlgorithmID {
54 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
55 Some(self.cmp(other))
56 }
57}
58
59impl PartialEq for SignatureAlgorithmID {
60 fn eq(&self, other: &Self) -> bool {
61 self.cmp(other) == Ordering::Equal
62 }
63}
64
65impl SignatureAlgorithmID {
Alice Wanga66b5c02022-09-16 07:25:17 +000066 pub(crate) fn new_verifier<'a>(
67 &self,
68 public_key: &'a PKey<pkey::Public>,
69 ) -> Result<Verifier<'a>> {
70 ensure!(
71 !matches!(
72 self,
Alice Wang455b02b2022-09-16 13:32:13 +000073 SignatureAlgorithmID::DsaWithSha256 | SignatureAlgorithmID::VerityDsaWithSha256
Alice Wanga66b5c02022-09-16 07:25:17 +000074 ),
75 "TODO(b/197052981): Algorithm '{:#?}' is not implemented.",
76 self
77 );
78 ensure!(public_key.id() == self.pkey_id(), "Public key has the wrong ID");
79 let mut verifier = Verifier::new(self.new_message_digest(), public_key)?;
80 if public_key.id() == pkey::Id::RSA {
81 verifier.set_rsa_padding(self.rsa_padding())?;
82 }
83 Ok(verifier)
84 }
85
86 /// Returns the message digest corresponding to the signature algorithm
87 /// according to the spec [Signature Algorithm IDs].
Alice Wang1ffff622022-09-16 13:45:47 +000088 pub(crate) fn new_message_digest(&self) -> MessageDigest {
Alice Wanga66b5c02022-09-16 07:25:17 +000089 match self {
90 SignatureAlgorithmID::RsaPssWithSha256
91 | SignatureAlgorithmID::RsaPkcs1V15WithSha256
92 | SignatureAlgorithmID::EcdsaWithSha256
93 | SignatureAlgorithmID::DsaWithSha256
94 | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
95 | SignatureAlgorithmID::VerityEcdsaWithSha256
96 | SignatureAlgorithmID::VerityDsaWithSha256 => MessageDigest::sha256(),
97 SignatureAlgorithmID::RsaPssWithSha512
98 | SignatureAlgorithmID::RsaPkcs1V15WithSha512
99 | SignatureAlgorithmID::EcdsaWithSha512 => MessageDigest::sha512(),
100 }
101 }
102
103 fn pkey_id(&self) -> pkey::Id {
104 match self {
105 SignatureAlgorithmID::RsaPssWithSha256
106 | SignatureAlgorithmID::RsaPssWithSha512
107 | SignatureAlgorithmID::RsaPkcs1V15WithSha256
108 | SignatureAlgorithmID::RsaPkcs1V15WithSha512
109 | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256 => pkey::Id::RSA,
110 SignatureAlgorithmID::EcdsaWithSha256
111 | SignatureAlgorithmID::EcdsaWithSha512
112 | SignatureAlgorithmID::VerityEcdsaWithSha256 => pkey::Id::EC,
113 SignatureAlgorithmID::DsaWithSha256 | SignatureAlgorithmID::VerityDsaWithSha256 => {
114 pkey::Id::DSA
115 }
116 }
117 }
118
119 fn rsa_padding(&self) -> Padding {
120 match self {
121 SignatureAlgorithmID::RsaPssWithSha256 | SignatureAlgorithmID::RsaPssWithSha512 => {
122 Padding::PKCS1_PSS
123 }
124 SignatureAlgorithmID::RsaPkcs1V15WithSha256
125 | SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
126 | SignatureAlgorithmID::RsaPkcs1V15WithSha512 => Padding::PKCS1,
127 SignatureAlgorithmID::EcdsaWithSha256
128 | SignatureAlgorithmID::EcdsaWithSha512
129 | SignatureAlgorithmID::VerityEcdsaWithSha256
130 | SignatureAlgorithmID::DsaWithSha256
131 | SignatureAlgorithmID::VerityDsaWithSha256 => Padding::NONE,
132 }
133 }
Alice Wang1ffff622022-09-16 13:45:47 +0000134
135 fn to_content_digest_algorithm(&self) -> ContentDigestAlgorithm {
136 match self {
137 SignatureAlgorithmID::RsaPssWithSha256
138 | SignatureAlgorithmID::RsaPkcs1V15WithSha256
139 | SignatureAlgorithmID::EcdsaWithSha256
140 | SignatureAlgorithmID::DsaWithSha256 => ContentDigestAlgorithm::ChunkedSha256,
141 SignatureAlgorithmID::RsaPssWithSha512
142 | SignatureAlgorithmID::RsaPkcs1V15WithSha512
143 | SignatureAlgorithmID::EcdsaWithSha512 => ContentDigestAlgorithm::ChunkedSha512,
144 SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
145 | SignatureAlgorithmID::VerityEcdsaWithSha256
146 | SignatureAlgorithmID::VerityDsaWithSha256 => {
147 ContentDigestAlgorithm::VerityChunkedSha256
148 }
149 }
150 }
Alice Wang5d0f89a2022-09-15 15:06:10 +0000151}
152
153/// The rank of the content digest algorithm in this enum is used to help pick
154/// v4 apk digest.
155/// According to APK Signature Scheme v4, [apk digest] is the first available
156/// content digest of the highest rank (rank N).
157///
158/// This rank was also used for step 3a of the v3 signature verification.
159///
160/// [apk digest]: https://source.android.com/docs/security/features/apksigning/v4#apk-digest
161/// [v3 verification]: https://source.android.com/docs/security/apksigning/v3#v3-verification
162#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
Alice Wang1ffff622022-09-16 13:45:47 +0000163enum ContentDigestAlgorithm {
Alice Wang5d0f89a2022-09-15 15:06:10 +0000164 ChunkedSha256 = 1,
165 VerityChunkedSha256,
166 ChunkedSha512,
167}