//! This module wraps the certificate validation functions intended for BccEntry.

use super::{cose_error, get_label_value};
use crate::dice;
use crate::publickey;
use crate::valueas::ValueAs;
use anyhow::{anyhow, bail, ensure, Context, Result};
use coset::AsCborValue;
use coset::{
    cbor::value::Value,
    iana::{self, EnumI64},
    Algorithm, CborSerializable,
    CoseError::{self, EncodeFailed, UnexpectedItem},
    CoseKey, CoseSign1, Header, RegisteredLabel,
};
use std::fmt::{self, Display, Formatter, Write};
use std::io::Read;

/// Read a series of bcc file certificates and verify that the public key of
/// any given cert's payload in the series correctly signs the next cose
/// sign1 cert.
pub fn check_sign1_cert_chain(certs: &[&str]) -> Result<()> {
    ensure!(!certs.is_empty());
    let mut payload = Payload::from_sign1(&read(certs[0])?)
        .context("Failed to read the first bccEntry payload")?;
    for item in certs.iter().skip(1) {
        payload.check().context("Validation of BccPayload entries failed.")?;
        payload =
            payload.check_sign1(&read(item).context("Failed to read the bccEntry payload")?)?;
    }
    Ok(())
}

/// Read a given cbor array containing bcc entries and verify that the public key
/// of any given cert's payload in the series correctly signs the next cose sign1
/// cert.
pub fn check_sign1_chain_array(cbor_arr: &[Value]) -> Result<()> {
    ensure!(!cbor_arr.is_empty());

    let mut writeme: Vec<u8> = Vec::new();
    ciborium::ser::into_writer(&cbor_arr[0], &mut writeme)?;
    let mut payload = Payload::from_sign1(&CoseSign1::from_slice(&writeme).map_err(cose_error)?)
        .context("Failed to read bccEntry payload")?;
    for item in cbor_arr.iter().skip(1) {
        payload.check().context("Validation of BccPayload entries failed")?;
        writeme = Vec::new();
        ciborium::ser::into_writer(item, &mut writeme)?;
        let next_sign1 = &CoseSign1::from_slice(&writeme).map_err(cose_error)?;
        payload = payload.check_sign1(next_sign1).context("Failed to read bccEntry payload")?;
    }
    Ok(())
}

/// Read a file name as string and create the BccEntry as COSE_sign1 structure.
pub fn read(fname: &str) -> Result<CoseSign1> {
    let mut f = std::fs::File::open(fname)?;
    let mut content = Vec::new();
    f.read_to_end(&mut content)?;
    CoseSign1::from_slice(&content).map_err(cose_error)
}

/// Validate the protected header of a bcc entry with respect to the provided
/// alg (typically originating from the subject public key of the payload).
pub fn check_protected_header(alg: &Option<Algorithm>, header: &Header) -> Result<()> {
    ensure!(&header.alg == alg);
    ensure!(header
        .crit
        .iter()
        .all(|l| l == &RegisteredLabel::Assigned(iana::HeaderParameter::Alg)));
    Ok(())
}
/// Struct describing BccPayload cbor of the BccEntry.
#[derive(Debug)]
pub struct Payload(Value);
impl Payload {
    /// Construct the Payload from the parent BccEntry COSE_sign1 structure.
    pub fn from_sign1(sign1: &CoseSign1) -> Result<Payload> {
        Self::from_slice(sign1.payload.as_ref().ok_or_else(|| anyhow!("no payload"))?)
    }

    /// Validate entries in the Payload to be correct.
    pub fn check(&self) -> Result<()> {
        // Validate required fields.
        self.map_lookup(dice::ISS)?.as_string()?;
        self.map_lookup(dice::SUB)?.as_string()?;
        SubjectPublicKey::from_payload(self)?.check().context("Public key failed checking")?;
        self.map_lookup(dice::KEY_USAGE)?
            .as_bytes()
            .ok_or_else(|| anyhow!("Payload Key usage not bytes"))?;

        // Validate required and optional fields. The required fields are those defined
        // to be present for CDI_Certificates in the open-DICE profile.
        // TODO: Check if the optional fields are present, and if so, ensure that
        //       the operations applied to the mandatory fields actually reproduce the
        //       values in the optional fields as specified in open-DICE.
        self.0.map_lookup(dice::CODE_HASH).context("Code hash must be present.")?;
        self.0.map_lookup(dice::CONFIG_DESC).context("Config descriptor must be present.")?;
        self.0.map_lookup(dice::AUTHORITY_HASH).context("Authority hash must be present.")?;
        self.0.map_lookup(dice::MODE).context("Mode must be present.")?;

        // Verify that each key that does exist has the expected type.
        self.0
            .check_bytes_val_if_key_in_map(dice::CODE_HASH)
            .context("Code Hash value not bytes.")?;
        self.0
            .check_bytes_val_if_key_in_map(dice::CODE_DESC)
            .context("Code Descriptor value not bytes.")?;
        self.0
            .check_bytes_val_if_key_in_map(dice::CONFIG_HASH)
            .context("Configuration Hash value not bytes.")?;
        self.0
            .check_bytes_val_if_key_in_map(dice::CONFIG_DESC)
            .context("Configuration descriptor value not bytes.")?;
        self.0
            .check_bytes_val_if_key_in_map(dice::AUTHORITY_HASH)
            .context("Authority Hash value not bytes.")?;
        self.0
            .check_bytes_val_if_key_in_map(dice::AUTHORITY_DESC)
            .context("Authority descriptor value not bytes.")?;
        self.0.check_bytes_val_if_key_in_map(dice::MODE).context("Mode value not bytes.")?;
        Ok(())
    }

    /// Verify that the public key of this payload correctly signs the provided
    /// BccEntry sign1 object.
    pub fn check_sign1(&self, sign1: &CoseSign1) -> Result<Payload> {
        let pkey = SubjectPublicKey::from_payload(self)
            .context("Failed to construct Public key from the Bcc payload.")?;
        let new_payload = Self::check_sign1_signature(&pkey, sign1)?;
        ensure!(
            self.map_lookup(dice::SUB)? == new_payload.map_lookup(dice::ISS)?,
            "Subject/Issuer mismatch"
        );
        Ok(new_payload)
    }

    pub(super) fn check_sign1_signature(
        pkey: &SubjectPublicKey,
        sign1: &CoseSign1,
    ) -> Result<Payload> {
        check_protected_header(&pkey.0.alg, &sign1.protected.header)
            .context("Validation of bcc entry protected header failed.")?;
        let v = publickey::PublicKey::from_cose_key(&pkey.0)
            .context("Extracting the Public key from coseKey failed.")?;
        sign1
            .verify_signature(b"", |s, m| v.verify(s, m, &pkey.0.alg))
            .context("public key incorrectly signs the given cose_sign1 cert.")?;
        let new_payload =
            Payload::from_sign1(sign1).context("Failed to extract bcc payload from cose_sign1")?;
        Ok(new_payload)
    }

    fn from_slice(b: &[u8]) -> Result<Self> {
        Ok(Payload(coset::cbor::de::from_reader(b).map_err(|e| anyhow!("CborError: {}", e))?))
    }

    fn map_lookup(&self, key: i64) -> Result<&Value> {
        Ok(&self
            .0
            .as_map()
            .ok_or_else(|| anyhow!("not a map"))?
            .iter()
            .find(|(k, _v)| k == &Value::from(key))
            .ok_or_else(|| anyhow!("missing key {}", key))?
            .1)
    }
}

/// Struct wrapping the CoseKey for BccEntry.BccPayload.SubjectPublicKey
/// and the methods used for its validation.
pub struct SubjectPublicKey(CoseKey);
impl SubjectPublicKey {
    pub(super) fn from_cose_key(cose_key: CoseKey) -> Self {
        Self(cose_key)
    }

    /// Construct the SubjectPublicKey from the (bccEntry's) Payload.
    pub fn from_payload(payload: &Payload) -> Result<SubjectPublicKey> {
        let bytes = payload
            .map_lookup(dice::SUBJECT_PUBLIC_KEY)?
            .as_bytes()
            .ok_or_else(|| anyhow!("public key not bytes"))?;
        Self::from_slice(bytes)
    }

    fn from_slice(bytes: &[u8]) -> Result<SubjectPublicKey> {
        Ok(SubjectPublicKey(CoseKey::from_slice(bytes).map_err(cose_error)?))
    }

    /// Perform validation on the items in the public key.
    pub fn check(&self) -> Result<()> {
        let pkey = &self.0;
        if !pkey.key_ops.is_empty() {
            ensure!(pkey
                .key_ops
                .contains(&coset::KeyOperation::Assigned(iana::KeyOperation::Verify)));
        }
        match pkey.kty {
            coset::KeyType::Assigned(iana::KeyType::OKP) => {
                ensure!(pkey.alg == Some(coset::Algorithm::Assigned(iana::Algorithm::EdDSA)));
                let crv = get_label_value(pkey, iana::OkpKeyParameter::Crv as i64)?;
                ensure!(crv == &Value::from(iana::EllipticCurve::Ed25519 as i64));
            }
            coset::KeyType::Assigned(iana::KeyType::EC2) => {
                ensure!(pkey.alg == Some(coset::Algorithm::Assigned(iana::Algorithm::ES256)));
                let crv = get_label_value(pkey, iana::Ec2KeyParameter::Crv as i64)?;
                ensure!(crv == &Value::from(iana::EllipticCurve::P_256 as i64));
            }
            _ => bail!("Unexpected KeyType value: {:?}", pkey.kty),
        }
        Ok(())
    }
}

struct ConfigDesc(Vec<(Value, Value)>);

impl AsCborValue for ConfigDesc {
    /*
     * CDDL (from keymint/ProtectedData.aidl):
     *
     *  bstr .cbor {      // Configuration Descriptor
     *     ? -70002 : tstr,           // Component name
     *     ? -70003 : int,            // Firmware version
     *     ? -70004 : null,           // Resettable
     * },
     */

    fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
        match value {
            Value::Map(m) => Ok(Self(m)),
            _ => Err(UnexpectedItem("something", "a map")),
        }
    }

    fn to_cbor_value(self) -> Result<Value, CoseError> {
        // TODO: Implement when needed
        Err(EncodeFailed)
    }
}

impl CborSerializable for ConfigDesc {}

impl Display for ConfigDesc {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        write_payload_label(f, dice::CONFIG_DESC)?;
        f.write_str(":\n")?;
        for (label, value) in &self.0 {
            f.write_str("  ")?;
            if let Ok(i) = label.as_i64() {
                write_config_desc_label(f, i)?;
            } else {
                write_value(f, label)?;
            }
            f.write_str(": ")?;
            write_value(f, value)?;
            f.write_char('\n')?;
        }
        Ok(())
    }
}

fn write_config_desc_label(f: &mut Formatter, label: i64) -> Result<(), fmt::Error> {
    match label {
        dice::COMPONENT_NAME => f.write_str("Component Name"),
        dice::FIRMWARE_VERSION => f.write_str("Firmware Version"),
        dice::RESETTABLE => f.write_str("Resettable"),
        _ => write!(f, "{}", label),
    }
}

impl Display for SubjectPublicKey {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        let pkey = &self.0;
        if pkey.kty != coset::KeyType::Assigned(iana::KeyType::OKP)
            || pkey.alg != Some(coset::Algorithm::Assigned(iana::Algorithm::EdDSA))
        {
            return Err(fmt::Error);
        }

        let mut separator = "";
        for (label, value) in &pkey.params {
            use coset::Label;
            use iana::OkpKeyParameter;
            if let Label::Int(i) = label {
                match OkpKeyParameter::from_i64(*i) {
                    Some(OkpKeyParameter::Crv) => {
                        if let Some(crv) =
                            value.as_i64().ok().and_then(iana::EllipticCurve::from_i64)
                        {
                            f.write_str(separator)?;
                            write!(f, "Curve: {:?}", crv)?;
                            separator = " ";
                        }
                    }
                    Some(OkpKeyParameter::X) => {
                        if let Ok(x) = ValueAs::as_bytes(value) {
                            f.write_str(separator)?;
                            f.write_str("X: ")?;
                            write_bytes_in_hex(f, x)?;
                            separator = " ";
                        }
                    }
                    _ => (),
                }
            }
        }

        Ok(())
    }
}

impl Display for Payload {
    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        for (label, value) in self.0.as_map().ok_or(fmt::Error)? {
            if let Ok(i) = label.as_i64() {
                if i == dice::CONFIG_DESC {
                    write_config_desc(f, value)?;
                    continue;
                } else if i == dice::SUBJECT_PUBLIC_KEY {
                    write_payload_label(f, i)?;
                    f.write_str(": ")?;
                    write_subject_public_key(f, value)?;
                    continue;
                }
                write_payload_label(f, i)?;
            } else {
                write_value(f, label)?;
            }
            f.write_str(": ")?;
            write_value(f, value)?;
            f.write_char('\n')?;
        }
        Ok(())
    }
}

fn write_payload_label(f: &mut Formatter, label: i64) -> Result<(), fmt::Error> {
    match label {
        dice::ISS => f.write_str("Issuer"),
        dice::SUB => f.write_str("Subject"),
        dice::CODE_HASH => f.write_str("Code Hash"),
        dice::CODE_DESC => f.write_str("Code Desc"),
        dice::CONFIG_DESC => f.write_str("Config Desc"),
        dice::CONFIG_HASH => f.write_str("Config Hash"),
        dice::AUTHORITY_HASH => f.write_str("Authority Hash"),
        dice::AUTHORITY_DESC => f.write_str("Authority Desc"),
        dice::MODE => f.write_str("Mode"),
        dice::SUBJECT_PUBLIC_KEY => f.write_str("Subject Public Key"),
        dice::KEY_USAGE => f.write_str("Key Usage"),
        _ => write!(f, "{}", label),
    }
}

fn write_config_desc(f: &mut Formatter, value: &Value) -> Result<(), fmt::Error> {
    let bytes = value.as_bytes().ok_or(fmt::Error)?;
    let config_desc = ConfigDesc::from_slice(bytes).map_err(|_| fmt::Error)?;
    write!(f, "{}", config_desc)
}

fn write_subject_public_key(f: &mut Formatter, value: &Value) -> Result<(), fmt::Error> {
    let bytes = value.as_bytes().ok_or(fmt::Error)?;
    let subject_public_key = SubjectPublicKey::from_slice(bytes).map_err(|_| fmt::Error)?;
    write!(f, "{}", subject_public_key)
}

fn write_value(f: &mut Formatter, value: &Value) -> Result<(), fmt::Error> {
    if let Some(bytes) = value.as_bytes() {
        write_bytes_in_hex(f, bytes)
    } else if let Some(text) = value.as_text() {
        write!(f, "\"{}\"", text)
    } else if let Ok(integer) = value.as_i64() {
        write!(f, "{}", integer)
    } else {
        write!(f, "{:?}", value)
    }
}

fn write_bytes_in_hex(f: &mut Formatter, bytes: &[u8]) -> Result<(), fmt::Error> {
    for b in bytes {
        write!(f, "{:02x}", b)?
    }
    Ok(())
}
