diff --git a/deps/verifier/src/se/ibmse.rs b/deps/verifier/src/se/ibmse.rs index 7a99a57d11..515f3eabd5 100644 --- a/deps/verifier/src/se/ibmse.rs +++ b/deps/verifier/src/se/ibmse.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use crate::{ReportData, TeeEvidence, TeeEvidenceParsedClaim, ToHex}; +use crate::{regularize_data, ReportData, TeeEvidence, TeeEvidenceParsedClaim, ToHex}; use anyhow::{anyhow, Context, Result}; use core::result::Result::Ok; use openssl::encrypt::{Decrypter, Encrypter}; @@ -24,6 +24,9 @@ use tracing::{debug, info, warn}; const DEFAULT_CERTS_OFFLINE_VERIFICATION: &str = "false"; +/// Size of report data in IBM SE attestation (64 bytes) +const SE_REPORT_DATA_SIZE: usize = 64; + const DEFAULT_SE_HOST_KEY_DOCUMENTS_ROOT: &str = "/run/confidential-containers/ibmse/hkds"; const DEFAULT_SE_CERTIFICATES_ROOT: &str = "/run/confidential-containers/ibmse/certs"; @@ -230,13 +233,19 @@ impl SeVerifierImpl { // Validate runtime_data_digest if provided if let ReportData::Value(expected_report_data) = expected_report_data { + let expected_report_data = regularize_data( + expected_report_data, + SE_REPORT_DATA_SIZE, + "USER_DATA", + "IBM SE", + ); let report_data = se_response .user_data - .get(..48) + .get(..expected_report_data.len()) .context("Failed to get report_data section from USER_DATA")?; - if report_data != *expected_report_data { + if report_data != expected_report_data { return Err(SeError::UserDataMismatch { - expected: expected_report_data.to_vec(), + expected: expected_report_data, actual: report_data.to_vec(), } .into()); @@ -438,8 +447,8 @@ mod tests { fn test_user_data_validation_success() { let verifier = create_test_verifier(); - // Create test data - SHA-384 is 48 bytes - let report_data = vec![0x05; 48]; + // Create test data - SHA-512 is 64 bytes + let report_data = vec![0x05; SE_REPORT_DATA_SIZE]; // Build user_data: first 48 bytes are report_data, rest can be anything let mut user_data = report_data.clone(); @@ -486,11 +495,11 @@ mod tests { fn test_user_data_validation_mismatch() { let verifier = create_test_verifier(); - // Create test data - SHA-384 is 48 bytes - let report_data = vec![0x05; 48]; + // Create test data - SE report data is 64 bytes + let report_data = vec![0x05; SE_REPORT_DATA_SIZE]; - // Build user_data with WRONG report_data in first 48 bytes - let mut user_data = vec![0xFF; 48]; // Wrong report data + // Build user_data with WRONG report_data + let mut user_data = vec![0xFF; SE_REPORT_DATA_SIZE]; // Wrong report data user_data.extend_from_slice(&[0xAA; 16]); // Add some extra data let nonce = vec![0x09; 16]; @@ -534,7 +543,7 @@ mod tests { let verifier = create_test_verifier(); // Build user_data with some report_data - let report_data = vec![0x05; 48]; + let report_data = vec![0x05; SE_REPORT_DATA_SIZE]; let mut user_data = report_data.clone(); user_data.extend_from_slice(&[0xBB; 16]); diff --git a/kbs/src/attestation/coco/builtin.rs b/kbs/src/attestation/coco/builtin.rs index ae59921504..ed4bc13b4c 100644 --- a/kbs/src/attestation/coco/builtin.rs +++ b/kbs/src/attestation/coco/builtin.rs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 +use crate::attestation::generate_extra_params; use anyhow::*; use async_trait::async_trait; use attestation_service::{ @@ -62,11 +63,16 @@ impl Attest for BuiltInCoCoAs { let mut verification_requests = vec![]; for evidence in evidence_to_verify { + let runtime_data_hash_algorithm = match evidence.tee { + Tee::Se => HashAlgorithm::Sha512, + _ => HashAlgorithm::Sha384, + }; + let mut request = VerificationRequest { evidence: evidence.tee_evidence, tee: evidence.tee, runtime_data: Some(RuntimeData::Structured(evidence.runtime_data)), - runtime_data_hash_algorithm: HashAlgorithm::Sha384, + runtime_data_hash_algorithm, init_data: None, }; if let Some(init_data) = evidence.init_data { @@ -102,13 +108,12 @@ impl Attest for BuiltInCoCoAs { } _ => make_nonce().await?, }; + let extra_params = generate_extra_params(tee, &tee_parameters)?; - let challenge = Challenge { + Ok(Challenge { nonce, - extra_params: serde_json::Value::String(String::new()), - }; - - Ok(challenge) + extra_params, + }) } async fn register_reference_value(&self, message: &str) -> anyhow::Result<()> { diff --git a/kbs/src/attestation/coco/grpc.rs b/kbs/src/attestation/coco/grpc.rs index 6134fd2c67..8c66789ef8 100644 --- a/kbs/src/attestation/coco/grpc.rs +++ b/kbs/src/attestation/coco/grpc.rs @@ -9,7 +9,7 @@ use attestation::{ ReferenceValueQueryRequest, ReferenceValueQueryResponse, ReferenceValueRegisterRequest, }; use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; -use kbs_types::{Challenge, Tee}; +use kbs_types::{Challenge, HashAlgorithm, Tee}; use mobc::{Manager, Pool}; use serde::Deserialize; use std::collections::HashMap; @@ -32,8 +32,6 @@ mod attestation { pub const DEFAULT_AS_ADDR: &str = "http://127.0.0.1:50004"; pub const DEFAULT_POOL_SIZE: u64 = 100; -pub const COCO_AS_HASH_ALGORITHM: &str = "sha384"; - #[derive(Clone, Debug, Deserialize, PartialEq)] pub struct GrpcConfig { #[serde(default = "default_as_addr")] @@ -106,10 +104,15 @@ impl Attest for GrpcClientPool { .trim_start_matches('"') .to_string(); + let runtime_data_hash_algorithm = match evidence.tee { + Tee::Se => HashAlgorithm::Sha512.as_ref().to_string().to_lowercase(), + _ => HashAlgorithm::Sha384.as_ref().to_string().to_lowercase(), + }; + let mut request = IndividualAttestationRequest { tee, evidence: URL_SAFE_NO_PAD.encode(evidence.tee_evidence.to_string()), - runtime_data_hash_algorithm: COCO_AS_HASH_ALGORITHM.into(), + runtime_data_hash_algorithm, runtime_data: Some(RuntimeData::StructuredRuntimeData( evidence.runtime_data.to_string(), )), @@ -165,9 +168,11 @@ impl Attest for GrpcClientPool { _ => make_nonce().await?, }; + let extra_params = crate::attestation::generate_extra_params(tee, &tee_parameters)?; + let challenge = Challenge { nonce, - extra_params: serde_json::Value::String(String::new()), + extra_params, }; Ok(challenge) diff --git a/kbs/src/attestation/intel_trust_authority/mod.rs b/kbs/src/attestation/intel_trust_authority/mod.rs index fc62be69b6..e35afec9b1 100644 --- a/kbs/src/attestation/intel_trust_authority/mod.rs +++ b/kbs/src/attestation/intel_trust_authority/mod.rs @@ -3,7 +3,10 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - attestation::backend::{generic_generate_challenge, make_nonce, Attest, IndependentEvidence}, + attestation::{ + backend::{generic_generate_challenge, make_nonce, Attest, IndependentEvidence}, + SELECTED_HASH_ALGORITHM_JSON_KEY, SUPPORTED_HASH_ALGORITHMS_JSON_KEY, + }, token::{jwk::JwkAttestationTokenVerifier, AttestationTokenVerifierConfig}, }; use anyhow::*; @@ -21,9 +24,6 @@ use sha2::{Digest, Sha512}; use std::result::Result::Ok; use tracing::{debug, info, warn}; -const SUPPORTED_HASH_ALGORITHMS_JSON_KEY: &str = "supported-hash-algorithms"; -const SELECTED_HASH_ALGORITHM_JSON_KEY: &str = "selected-hash-algorithm"; - const ERR_NO_TEE_ALGOS: &str = "ITA: TEE does not support any hash algorithms"; const ERR_INVALID_TEE: &str = "ITA: Unknown TEE specified"; diff --git a/kbs/src/attestation/mod.rs b/kbs/src/attestation/mod.rs index 10d9ca88d2..8d1e1abbc7 100644 --- a/kbs/src/attestation/mod.rs +++ b/kbs/src/attestation/mod.rs @@ -14,5 +14,67 @@ pub mod session; pub use backend::AttestationService; +use anyhow::bail; +use kbs_types::{HashAlgorithm, Tee}; +use serde_json::json; +use tracing::info; + +/// JSON key for supported hash algorithms in TEE parameters +pub const SUPPORTED_HASH_ALGORITHMS_JSON_KEY: &str = "supported-hash-algorithms"; + +/// JSON key for selected hash algorithm in extra parameters +pub const SELECTED_HASH_ALGORITHM_JSON_KEY: &str = "selected-hash-algorithm"; + +/// Generate extra parameters for TEE hash algorithm negotiation. +/// +/// This function checks if the provided TEE parameters contain supported hash algorithms +/// and selects a hash algorithm based on the TEE type if available. +/// Returns a JSON value with the selected algorithm, +/// or an empty string if negotiation is not applicable. +/// +/// Currently only applies to SE (Secure Execution) TEE type. +/// +/// # Errors +/// +/// Returns an error if: +/// - The hash algorithms field is not an array +/// - The required hash algorithm is not supported by the TEE +pub fn generate_extra_params( + tee: Tee, + tee_parameters: &serde_json::Value, +) -> anyhow::Result { + let extra_params = match tee { + Tee::Se if !tee_parameters.is_null() => { + if let Some(hash_algorithms_found) = + tee_parameters.get(SUPPORTED_HASH_ALGORITHMS_JSON_KEY) + { + let Some(algorithms) = hash_algorithms_found.as_array() else { + bail!("SE expected hash algorithm array, found {hash_algorithms_found:?}"); + }; + + let supported_hash_algorithms: Vec = algorithms + .iter() + .filter_map(|value| Some(value.as_str()?.to_lowercase())) + .collect(); + + let needed_algorithm = HashAlgorithm::Sha512.as_ref().to_string().to_lowercase(); + + if !supported_hash_algorithms.contains(&needed_algorithm) { + bail!("SE TEE does not support {needed_algorithm}"); + } + + json!({ + SELECTED_HASH_ALGORITHM_JSON_KEY: needed_algorithm, + }) + } else { + info!("SE TEE parameters missing supported hash algorithms"); + serde_json::Value::String(String::new()) + } + } + _ => serde_json::Value::String(String::new()), + }; + + Ok(extra_params) +} pub mod error; pub use error::*;