// SPDX-License-Identifier: MIT // // Copyright IBM Corp. 2024 use std::io::Write; use anyhow::{Context, Result}; use log::{info, warn}; use pv::misc::{open_file, read_file}; use pv::request::SymKey; use pvimg::error::{Error, OwnExitCode}; use pvimg::uvdata::{EnvelopeSeHdrV1, KeyExchangeTrait, SeH, SeHdr, UvDataTrait}; use crate::cli::{InfoArgs, OutputFormatKind, OutputFormatSpec, OutputFormatVariant}; pub const INFO_V1_JSON_SCHEMA: &str = include_str!("../../schema/info-v1.schema.json"); pub fn info(opt: &InfoArgs) -> Result { let mut output = std::io::stdout(); if let Some(format_kind) = opt.print_schema { match format_kind { OutputFormatKind::Text => { writeln!(output, "No schema for {format_kind} format available!")? } OutputFormatKind::Json => write!(output, "{INFO_V1_JSON_SCHEMA}")?, } return Ok(OwnExitCode::Success); } let input_path = opt.input.as_ref().unwrap().path.clone(); info!("Reading Secure Execution header {}", input_path.display(),); let mut img = open_file(&input_path)?; SeHdr::seek_sehdr(&mut img, None)?; let hdr = SeHdr::try_from_io(&mut img)?; let se_hdr = if let Some(key_path) = &opt.hdr_key { let key = SymKey::try_from_data( hdr.key_type(), read_file(key_path, "Reading header protection key")?.into(), ) .map_err(|err| Error::InvalidSeHdrProtectionKey { source: Box::new(Error::Pv(err)), })?; let decrypted_hdr = hdr .decrypt(&key) .context("Failed to authenticate and decrypt the Secure Execution header")?; if opt.show_secrets { SeH::DecryptedSeHdr { se_hdr: decrypted_hdr, verified: true, } } else { SeH::SeHdr { se_hdr: hdr, verified: true, } } } else { warn!("WARNING: The Secure Execution header integrity and authenticity was not verified. Specify '--hdr-key' to authenticate it. Do not trust the data without verification."); SeH::SeHdr { se_hdr: hdr, verified: false, } }; match opt.format.unwrap_or_else(OutputFormatSpec::detect) { OutputFormatSpec { kind: OutputFormatKind::Text, variant: OutputFormatVariant::Default, } => write!(output, "{se_hdr}").context("Cannot generate the human readable output")?, OutputFormatSpec { kind: OutputFormatKind::Text, variant: OutputFormatVariant::Full, } => write!(output, "{se_hdr:#}").context("Cannot generate the human readable output")?, OutputFormatSpec { kind: OutputFormatKind::Json, variant, } => { let doc = EnvelopeSeHdrV1::new(se_hdr); match variant { OutputFormatVariant::Minify => { serde_json::to_writer(&mut output, &doc)?; } OutputFormatVariant::Default | OutputFormatVariant::Pretty => { serde_json::to_writer_pretty(&mut output, &doc)?; } OutputFormatVariant::Full => { unreachable!("we already validate the variant in the outer match") } } // Make sure the output ends with a new line writeln!(&mut output)? } _ => unreachable!(), } output.flush()?; Ok(OwnExitCode::Success) }