diff --git a/attestation-agent/attester/src/se/mod.rs b/attestation-agent/attester/src/se/mod.rs index 648a11640..1f7394f0d 100644 --- a/attestation-agent/attester/src/se/mod.rs +++ b/attestation-agent/attester/src/se/mod.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use super::{Attester, TeeEvidence}; +use super::{utils::validate_and_pad_data, Attester, TeeEvidence}; use anyhow::*; use pv::{ misc, @@ -14,7 +14,10 @@ use serde::{Deserialize, Serialize}; use serde_with::{base64::Base64, serde_as}; use tracing::debug; -const RUNTIME_DIGEST_SIZE: usize = 48; // SHA-384 digest size in bytes +/// The size for SE attestation report data (SHA-512 digest size in bytes). +/// Only the first `SE_REPORT_DATA_SIZE` bytes of the `runtime_data_digest` field +/// from `SeAttestationRequest` are used in the attestation command. +const SE_REPORT_DATA_SIZE: usize = 64; /// Structured user data for IBM SEL attestation /// Currently, only contains runtime data digest bound to the attestation measurement @@ -105,25 +108,7 @@ impl Attester for SeAttester { runtime_digest ); - let runtime_digest = match runtime_digest.len() { - len if len > RUNTIME_DIGEST_SIZE => { - bail!( - "Invalid runtime_data_digest length: expected {} bytes (SHA-384), got {} (too large)", - RUNTIME_DIGEST_SIZE, - len - ); - } - len if len < RUNTIME_DIGEST_SIZE => { - debug!( - "Padding runtime_data_digest from {} to {} bytes with zeros", - len, RUNTIME_DIGEST_SIZE - ); - let mut padded = runtime_digest; - padded.resize(RUNTIME_DIGEST_SIZE, 0); - padded - } - _ => runtime_digest, // Exact match, use as-is - }; + let runtime_digest = validate_and_pad_data(runtime_digest, SE_REPORT_DATA_SIZE)?; let user_data = UserData { runtime_data_digest: runtime_digest, @@ -165,9 +150,9 @@ impl Attester for SeAttester { mod tests { use super::*; - // Mock runtime digest (SHA-384 size: 48 bytes) for tests + // Mock runtime digest (SHA-512 size: 64 bytes) for tests // This simulates the digest computed from runtime data in production - const MOCK_RUNTIME_DIGEST: [u8; 48] = [0xBB; 48]; + const MOCK_RUNTIME_DIGEST: [u8; 64] = [0xBB; 64]; // Helper to create a dummy BootHdrTags for testing fn create_dummy_boot_hdr_tags() -> BootHdrTags { @@ -224,64 +209,44 @@ mod tests { #[tokio::test] async fn test_runtime_data_digest_with_various_sizes() { - // Helper function that mimics the validation/padding logic from lines 110-129 - fn process_runtime_digest(runtime_digest: Vec) -> Result> { - match runtime_digest.len() { - len if len > RUNTIME_DIGEST_SIZE => { - bail!( - "Invalid runtime_data_digest length: expected {} bytes (SHA-384), got {} (too large)", - RUNTIME_DIGEST_SIZE, - len - ) - } - len if len < RUNTIME_DIGEST_SIZE => { - let mut padded = runtime_digest; - padded.resize(RUNTIME_DIGEST_SIZE, 0); - Ok(padded) - } - _ => Ok(runtime_digest), // Exact match, use as-is - } - } - // Case 1: Exact size (48 bytes) - should use as-is - let exact_digest = vec![0xAA; RUNTIME_DIGEST_SIZE]; - let result = process_runtime_digest(exact_digest.clone()).unwrap(); - assert_eq!(result.len(), RUNTIME_DIGEST_SIZE); + let exact_digest = vec![0xAA; SE_REPORT_DATA_SIZE]; + let result = validate_and_pad_data(exact_digest.clone(), SE_REPORT_DATA_SIZE).unwrap(); + assert_eq!(result.len(), SE_REPORT_DATA_SIZE); assert_eq!(result, exact_digest); - // Case 2: Too small (< 48 bytes) - should be padded with zeros + // Case 2: Small size (< 64 bytes) - should be padded with zeros let small_test_cases = vec![ (vec![], 0), // Empty digest (vec![0xAA], 1), // Single byte (vec![0xAA, 0xBB, 0xCC, 0xDD], 4), // 4 bytes (vec![0xFF; 32], 32), // 32 bytes (SHA-256 size) - (vec![0x11; 47], 47), // 47 bytes (just under limit) + (vec![0x11; 63], 63), // 63 bytes (just under limit) ]; for (small_digest, original_len) in small_test_cases { - let result = process_runtime_digest(small_digest.clone()).unwrap(); + let result = validate_and_pad_data(small_digest.clone(), SE_REPORT_DATA_SIZE).unwrap(); - // Verify result is padded to 48 bytes - assert_eq!(result.len(), RUNTIME_DIGEST_SIZE); + // Verify result is padded to 64 bytes + assert_eq!(result.len(), SE_REPORT_DATA_SIZE); // Verify original data is preserved at the beginning assert_eq!(&result[..original_len], &small_digest[..]); // Verify zeros are padded at the end - for i in original_len..RUNTIME_DIGEST_SIZE { + for i in original_len..SE_REPORT_DATA_SIZE { assert_eq!(result[i], 0, "Byte at index {} should be 0 (padded)", i); } } - // Case 3: Too large (> 48 bytes) - should return error + // Case 3: Large size (> 64 bytes) - should return error let large_test_cases = vec![ - (vec![0xFF; 49], 49), // 49 bytes (just over limit) - (vec![0xFF; 64], 64), // 64 bytes (SHA-512 size) + (vec![0xFF; 65], 65), // 65 bytes (just over limit) (vec![0xFF; 100], 100), // 100 bytes (way over limit) ]; for (large_digest, len) in large_test_cases { - let result = process_runtime_digest(large_digest); + let result = validate_and_pad_data(large_digest, SE_REPORT_DATA_SIZE); // Verify error is returned assert!( diff --git a/attestation-agent/attester/src/utils.rs b/attestation-agent/attester/src/utils.rs index 8cb9059b2..956860295 100644 --- a/attestation-agent/attester/src/utils.rs +++ b/attestation-agent/attester/src/utils.rs @@ -8,6 +8,7 @@ use std::{env, path::Path}; use anyhow::{bail, Result}; use base64::{engine::general_purpose::STANDARD, Engine}; use tokio::{fs::File, io::AsyncReadExt}; +use tracing::debug; pub fn pad(input: &[u8]) -> [u8; T] { let mut output = [0; T]; @@ -20,6 +21,42 @@ pub fn pad(input: &[u8]) -> [u8; T] { output } +/// Validates and pads data to a specified size. +/// +/// This function ensures that the input data does not exceed the expected size, +/// and pads it with zeros if it's smaller than the expected size. +/// +/// # Arguments +/// +/// * `data` - The input data to validate and pad +/// * `expected_size` - The target size for the data +/// +/// # Returns +/// +/// * `Ok(Vec)` - The validated and padded data +/// * `Err(anyhow::Error)` - If the data exceeds the expected size +pub fn validate_and_pad_data(data: Vec, expected_size: usize) -> Result> { + match data.len() { + len if len > expected_size => { + bail!( + "Invalid data length: expected {} bytes, got {} (too large)", + expected_size, + len + ) + } + len if len < expected_size => { + debug!( + "Padding data from {} to {} bytes with zeros", + len, expected_size + ); + let mut padded = data; + padded.resize(expected_size, 0); + Ok(padded) + } + _ => Ok(data), // Exact match, use as-is + } +} + /// This is a fixed eventlog header. If no CCEL is found, we will use this header ahead /// of aael eventlog. ///