Skip to content

Commit

Permalink
AA: kbs: Add supported hash algorithms to Request
Browse files Browse the repository at this point in the history
Add a `supported-hash-algorithms` list to the `Request` to allow the
returned `Challenge` to select an appropriate TEE-specific algorithm
from the list.

Signed-off-by: James O. D. Hunt <[email protected]>
  • Loading branch information
jodh-intel committed Sep 10, 2024
1 parent f3ecec6 commit a2f4428
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 23 deletions.
10 changes: 0 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

139 changes: 126 additions & 13 deletions attestation-agent/kbs_protocol/src/client/rcar_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use std::time::Duration;

use anyhow::{bail, Context};
use async_trait::async_trait;
use crypto::HashAlgorithm;
use kbs_types::{Attestation, Challenge, ErrorInformation, Request, Response, Tee};
use log::{debug, warn};
use resource_uri::ResourceUri;
use serde::Deserialize;
use serde_json::json;
use sha2::{Digest, Sha384};

use crate::{
api::KbsClientCapabilities,
Expand All @@ -32,15 +32,36 @@ const RCAR_MAX_ATTEMPT: i32 = 5;
/// The interval (seconds) between RCAR handshake retries.
const RCAR_RETRY_TIMEOUT_SECOND: u64 = 1;

/// JSON object added to a 'Request's extra parameters.
const SUPPORTED_HASH_ALGORITHMS_JSON_KEY: &str = "supported-hash-algorithms";

/// JSON object returned in the Challenge whose value is based on
/// SUPPORTED_HASH_ALGORITHMS_JSON_KEY and the TEE.
const SELECTED_HASH_ALGORITHM_JSON_KEY: &str = "selected-hash-algorithm";

/// Hash algorithm to use by default.
const DEFAULT_HASH_ALGORITHM: HashAlgorithm = HashAlgorithm::Sha384;

#[derive(Deserialize, Debug, Clone)]
struct AttestationResponseData {
// Attestation token in JWT format
token: String,
}

async fn get_request_extra_params() -> serde_json::Value {
let supported_hash_algorithms = HashAlgorithm::list_all();

let extra_params = json!({SUPPORTED_HASH_ALGORITHMS_JSON_KEY: supported_hash_algorithms});

extra_params
}

async fn build_request(tee: Tee) -> Request {
let extra_params = serde_json::Value::String(String::new());
let extra_params = get_request_extra_params().await;

// Note that the Request includes the list of supported hash algorithms.
// The Challenge response will return which TEE-specific algorithm should
// be used for future communications.
Request {
version: String::from(KBS_PROTOCOL_VERSION),
tee,
Expand Down Expand Up @@ -113,7 +134,7 @@ impl KbsClient<Box<dyn EvidenceProvider>> {

let request = build_request(tee).await;

debug!("send auth request to {auth_endpoint}");
debug!("send auth request {request:?} to {auth_endpoint}");

let resp = self
.http_client
Expand Down Expand Up @@ -144,6 +165,23 @@ impl KbsClient<Box<dyn EvidenceProvider>> {

let challenge = resp.json::<Challenge>().await?;
debug!("get challenge: {challenge:#?}");

let extra_params = challenge.extra_params;

let algorithm = match extra_params.get(SELECTED_HASH_ALGORITHM_JSON_KEY) {
Some(selected_hash_algorithm) => {
// Note the blank string which will be handled as an error when parsed.
let name = selected_hash_algorithm
.as_str()
.unwrap_or("")
.to_lowercase();

name.parse::<HashAlgorithm>()
.map_err(|_| Error::InvalidHashAlgorithm(name))?
}
None => DEFAULT_HASH_ALGORITHM,
};

let tee_pubkey = self.tee_key.export_pubkey()?;
let runtime_data = json!({
"tee-pubkey": tee_pubkey,
Expand All @@ -152,7 +190,7 @@ impl KbsClient<Box<dyn EvidenceProvider>> {
let runtime_data =
serde_json::to_string(&runtime_data).context("serialize runtime data failed")?;
let evidence = self
.generate_evidence(tee, runtime_data, challenge.nonce)
.generate_evidence(tee, runtime_data, challenge.nonce, algorithm)
.await?;
debug!("get evidence with challenge: {evidence}");

Expand Down Expand Up @@ -192,25 +230,42 @@ impl KbsClient<Box<dyn EvidenceProvider>> {
Ok(())
}

async fn generate_evidence(
/// Convert the runtime data and the nonce into a hashed representation using the
/// specified hash algorithm.
async fn hash_runtime_data(
&self,
tee: Tee,
runtime_data: String,
nonce: String,
) -> Result<String> {
debug!("Challenge nonce: {nonce}");
let mut hasher = Sha384::new();
hasher.update(runtime_data);
tee: Tee,
algorithm: HashAlgorithm,
) -> Result<Vec<u8>> {
debug!("Hashing {tee:?} runtime data using nonce {nonce} and algorithm {algorithm:?}");

let ehd = match tee {
let hashed_data = match tee {
// IBM SE uses nonce as runtime_data to pass attestation_request
Tee::Se => nonce.into_bytes(),
_ => hasher.finalize().to_vec(),
_ => algorithm.digest(runtime_data.as_bytes()),
};

Ok(hashed_data)
}

async fn generate_evidence(
&self,
tee: Tee,
runtime_data: String,
nonce: String,
algorithm: HashAlgorithm,
) -> Result<String> {
debug!("Challenge nonce: {nonce}, algorithm: {algorithm:?}");

let hashed_data = self
.hash_runtime_data(runtime_data, nonce, tee, algorithm)
.await?;

let tee_evidence = self
.provider
.get_evidence(ehd)
.get_evidence(hashed_data)
.await
.context("Get TEE evidence failed")
.map_err(|e| Error::GetEvidence(e.to_string()))?;
Expand Down Expand Up @@ -302,6 +357,12 @@ mod test {
evidence_provider::NativeEvidenceProvider, KbsClientBuilder, KbsClientCapabilities,
};

use crate::client::rcar_client::{
build_request, get_request_extra_params, KBS_PROTOCOL_VERSION,
SUPPORTED_HASH_ALGORITHMS_JSON_KEY,
};
use kbs_types::Tee;

const CONTENT: &[u8] = b"test content";

#[tokio::test]
Expand Down Expand Up @@ -388,4 +449,56 @@ mod test {
println!("Get token : {token:?}");
println!("Get key: {key:?}");
}

#[tokio::test]
#[serial_test::serial]
async fn test_get_request_extra_params() {
let extra_params = get_request_extra_params().await;

assert!(extra_params.is_object());

let algos_json = extra_params
.get(SUPPORTED_HASH_ALGORITHMS_JSON_KEY)
.unwrap();
assert!(algos_json.is_array());

let algos = algos_json.as_array().unwrap();

let expected_algos = HashAlgorithm::list_all();

Check failure on line 467 in attestation-agent/kbs_protocol/src/client/rcar_client.rs

View workflow job for this annotation

GitHub Actions / Check (stable, ubuntu-22.04)

failed to resolve: use of undeclared type `HashAlgorithm`
let expected_length: usize = expected_algos.len();

assert!(expected_length > 0);

for algo in algos {
let result = algos.contains(algo);
assert!(result);
}
}

#[tokio::test]
#[serial_test::serial]
async fn test_build_request() {
let tees = vec![
Tee::AzSnpVtpm,
Tee::AzTdxVtpm,
Tee::Cca,
Tee::Csv,
Tee::Se,
Tee::Sev,
Tee::Sgx,
Tee::Snp,
Tee::Tdx,
];

let expected_version = String::from(KBS_PROTOCOL_VERSION);
let expected_extra_params = get_request_extra_params().await;

for tee in tees {
let request = build_request(tee).await;

assert_eq!(request.version, expected_version);
assert_eq!(request.tee, tee);
assert_eq!(request.extra_params, expected_extra_params);
}
}
}
3 changes: 3 additions & 0 deletions attestation-agent/kbs_protocol/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,7 @@ pub enum Error {

#[error("request unauthorized")]
UnAuthorized,

#[error("invalid hash algorithm: {0}")]
InvalidHashAlgorithm(String),
}

0 comments on commit a2f4428

Please sign in to comment.