mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
rust: Add EBC support to pv_core library
Add EBC (Early Boot Customization) utility functions to pv_core library for parsing and verifying Add-Secret-Request structures. Introduce the core library functionality needed for EBC: - Add ebc_utils module to pv_core with ASR parsing and verification - Export ebc_utils in pv_core lib.rs - Re-export ebc_utils in pv lib.rs for downstream consumers - Update pvsecret Cargo.toml dependencies The library provides the foundation for tools that work with integrity-protected ASR structures used in SEL guest customization. Assisted-by: IBM Bob:1.0.1 Acked-by: Holger Dengler <dengler@linux.ibm.com> Reviewed-by: Steffen Eiden <seiden@linux.ibm.com> Signed-off-by: Finn Callies <fcallies@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
20de1fce2a
commit
1741ecff96
@@ -104,7 +104,14 @@ pub mod request {
|
||||
|
||||
/// Reexports some useful OpenSSL symbols
|
||||
pub mod openssl {
|
||||
pub use openssl::{error::ErrorStack, hash::DigestBytes, nid::Nid, pkey, x509};
|
||||
pub use openssl::{
|
||||
error::ErrorStack,
|
||||
hash::DigestBytes,
|
||||
nid::Nid,
|
||||
pkey,
|
||||
sha::{Sha256, Sha512},
|
||||
x509,
|
||||
};
|
||||
// rust-OpenSSL does not define these NIDs
|
||||
#[allow(missing_docs)]
|
||||
pub const NID_ED25519: Nid = Nid::from_raw(openssl_sys::NID_ED25519);
|
||||
@@ -113,6 +120,8 @@ pub mod request {
|
||||
}
|
||||
|
||||
pub use pv_core::request::*;
|
||||
|
||||
pub use pv_core::PolicyReference;
|
||||
}
|
||||
|
||||
/// Functionalities for creating add-secret requests
|
||||
|
||||
@@ -23,6 +23,7 @@ zerocopy = {version = "0.8", features = ["derive"]}
|
||||
serde = { version = "1.0.217", features = ["derive"]}
|
||||
byteorder = "1.5"
|
||||
regex = "1.10"
|
||||
sha2 = "0.10.9"
|
||||
|
||||
[dev-dependencies]
|
||||
serde_test = "1.0.177"
|
||||
|
||||
@@ -6,6 +6,7 @@ mod apdevice;
|
||||
mod confidential;
|
||||
mod error;
|
||||
mod macros;
|
||||
mod policy;
|
||||
mod utils;
|
||||
mod uvattest;
|
||||
mod uvdevice;
|
||||
@@ -13,6 +14,13 @@ mod uvsecret;
|
||||
|
||||
pub use error::{Error, FileAccessErrorType, FileIoErrorType, Result};
|
||||
|
||||
/// Early Boot Customization (EBC) utilities.
|
||||
///
|
||||
/// This module provides types and functions for working with Early Boot
|
||||
/// Customization. The integrity and completeness of ASRs are ensured through
|
||||
/// cryptographically protected table of contents files.
|
||||
pub use policy::PolicyReference;
|
||||
|
||||
/// Functionalities for reading attestation requests
|
||||
pub mod attest {
|
||||
pub use crate::uvattest::{AttestationMagic, AttestationMeasAlg};
|
||||
|
||||
112
rust/pv_core/src/policy.rs
Normal file
112
rust/pv_core/src/policy.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp.
|
||||
|
||||
use crate::misc::encode_hex;
|
||||
use crate::utils::open_file;
|
||||
use crate::{Error, Result};
|
||||
use std::{
|
||||
fmt::{Display, Formatter, Result as Resfmt},
|
||||
fs::File,
|
||||
os::unix::ffi::OsStrExt,
|
||||
path::{Path, PathBuf},
|
||||
str::from_utf8,
|
||||
};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes};
|
||||
|
||||
const HASH_LEN: usize = 32;
|
||||
// UserDataType::Unsigned.max() returns 512
|
||||
const USER_DATA_MAX_SIZE: usize = 512;
|
||||
|
||||
/// A reference to a policy file containing its SHA-256 hash and file path.
|
||||
///
|
||||
/// This structure is used in Early Boot Customization (EBC) to store
|
||||
/// a reference to a policy file. It contains the SHA-256 hash of the policy
|
||||
/// file content and the file path as a fixed-size byte array.
|
||||
///
|
||||
/// The total size is constrained by `USER_DATA_MAX_SIZE` (512 bytes), with
|
||||
/// 32 bytes allocated for the hash and the remaining bytes for the file path.
|
||||
#[derive(Debug, FromBytes, IntoBytes, Immutable, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct PolicyReference {
|
||||
/// SHA-256 hash of the policy file content (32 bytes)
|
||||
pub hash: [u8; HASH_LEN],
|
||||
/// File path stored as a null-terminated byte array
|
||||
pub name: [u8; USER_DATA_MAX_SIZE - HASH_LEN],
|
||||
}
|
||||
|
||||
impl PolicyReference {
|
||||
/// Creates a new `PolicyReference` from a file path.
|
||||
///
|
||||
/// Opens the file, reads its content, and computes the SHA-256 hash.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `src` - The path to the policy file
|
||||
/// * `sha256` - A function that computes the SHA-256 hash of the content
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a `PolicyReference` containing the SHA-256 hash and the file path,
|
||||
/// or an error if the file cannot be opened or the hash computation fails.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The file path is truncated if it exceeds the available space in the `name` field.
|
||||
pub fn new<P, H>(src: P, sha256: H) -> Result<Self>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
H: Fn(File) -> Result<Vec<u8>>,
|
||||
{
|
||||
let mut ret = Self {
|
||||
hash: [0; HASH_LEN],
|
||||
name: [0; USER_DATA_MAX_SIZE - HASH_LEN],
|
||||
};
|
||||
|
||||
let file = open_file(src.as_ref())?;
|
||||
ret.hash.copy_from_slice(sha256(file)?.as_bytes());
|
||||
let strbytes = src.as_ref().as_os_str().as_bytes();
|
||||
let nbytes = strbytes.len().min(ret.name.len());
|
||||
ret.name[..nbytes].copy_from_slice(&strbytes[..nbytes]);
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Converts the stored file path back to a `PathBuf`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns the file path as a `PathBuf`, or an error if the stored name
|
||||
/// is not valid UTF-8.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// * `Error::ParseError` - If the name contains invalid UTF-8
|
||||
pub fn to_path(&self) -> Result<PathBuf> {
|
||||
// Extract bytes until the first null byte (null-terminated string)
|
||||
let name_bytes: Vec<u8> = self
|
||||
.name
|
||||
.iter()
|
||||
.copied()
|
||||
.take_while(|&byte| byte != 0)
|
||||
.collect();
|
||||
|
||||
let rust_string = String::from_utf8(name_bytes).map_err(|e| Error::ParseError {
|
||||
subject: "PolicyReference name".to_string(),
|
||||
content: format!("Invalid UTF-8 in name: {}", e),
|
||||
})?;
|
||||
|
||||
Ok(Path::new(&rust_string).to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PolicyReference {
|
||||
fn fmt(&self, f: &mut Formatter) -> Resfmt {
|
||||
write!(
|
||||
f,
|
||||
"{} {}",
|
||||
encode_hex(self.hash),
|
||||
from_utf8(&self.name).expect("unable to convert name")
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user