blob: f15f0a48bff74f4896337aab2009f81efa3f6069 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! Algorithms used for APK Signature Scheme.
use anyhow::{bail, Result};
use num_derive::FromPrimitive;
use openssl::hash::MessageDigest;
use std::cmp::Ordering;
/// [Signature Algorithm IDs]: https://source.android.com/docs/security/apksigning/v2#signature-algorithm-ids
///
/// Some of the algorithms are not implemented. See b/197052981.
#[derive(Clone, Debug, Eq, FromPrimitive)]
#[repr(u32)]
pub enum SignatureAlgorithmID {
RsaPssWithSha256 = 0x0101,
RsaPssWithSha512 = 0x0102,
RsaPkcs1V15WithSha256 = 0x0103,
RsaPkcs1V15WithSha512 = 0x0104,
EcdsaWithSha256 = 0x0201,
EcdsaWithSha512 = 0x0202,
DsaWithSha256 = 0x0301,
VerityRsaPkcs1V15WithSha256 = 0x0421,
VerityEcdsaWithSha256 = 0x0423,
VerityDsaWithSha256 = 0x0425,
}
impl Ord for SignatureAlgorithmID {
/// Ranks the signature algorithm according to the corresponding content
/// digest algorithm's rank.
fn cmp(&self, other: &Self) -> Ordering {
self.to_content_digest_algorithm().cmp(&other.to_content_digest_algorithm())
}
}
impl PartialOrd for SignatureAlgorithmID {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for SignatureAlgorithmID {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl SignatureAlgorithmID {
pub(crate) fn to_content_digest_algorithm(&self) -> ContentDigestAlgorithm {
match self {
SignatureAlgorithmID::RsaPssWithSha256
| SignatureAlgorithmID::RsaPkcs1V15WithSha256
| SignatureAlgorithmID::EcdsaWithSha256
| SignatureAlgorithmID::DsaWithSha256 => ContentDigestAlgorithm::ChunkedSha256,
SignatureAlgorithmID::RsaPssWithSha512
| SignatureAlgorithmID::RsaPkcs1V15WithSha512
| SignatureAlgorithmID::EcdsaWithSha512 => ContentDigestAlgorithm::ChunkedSha512,
SignatureAlgorithmID::VerityRsaPkcs1V15WithSha256
| SignatureAlgorithmID::VerityEcdsaWithSha256
| SignatureAlgorithmID::VerityDsaWithSha256 => {
ContentDigestAlgorithm::VerityChunkedSha256
}
}
}
}
/// The rank of the content digest algorithm in this enum is used to help pick
/// v4 apk digest.
/// According to APK Signature Scheme v4, [apk digest] is the first available
/// content digest of the highest rank (rank N).
///
/// This rank was also used for step 3a of the v3 signature verification.
///
/// [apk digest]: https://source.android.com/docs/security/features/apksigning/v4#apk-digest
/// [v3 verification]: https://source.android.com/docs/security/apksigning/v3#v3-verification
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum ContentDigestAlgorithm {
ChunkedSha256 = 1,
VerityChunkedSha256,
ChunkedSha512,
}
impl ContentDigestAlgorithm {
pub(crate) fn new_message_digest(&self) -> Result<MessageDigest> {
match self {
ContentDigestAlgorithm::ChunkedSha256 => Ok(MessageDigest::sha256()),
ContentDigestAlgorithm::ChunkedSha512 => Ok(MessageDigest::sha512()),
ContentDigestAlgorithm::VerityChunkedSha256 => {
bail!("TODO(b/197052981): CONTENT_DIGEST_VERITY_CHUNKED_SHA256 is not implemented")
}
}
}
}