From dfbdcc0e81ee065a3dd2caeb8df00664d3dced2c Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Mon, 2 Dec 2024 11:48:24 +0800 Subject: [PATCH] AA/kbs_protocol: Update protocol version to 0.2.0 to fix JWE Per RFC7516, the AEAD's auth tag should be included inside the JWE body. Also, the AAD field should be calculated from the ProtectedHeader field of JWE. We fix this to align with trustee side. Signed-off-by: Xynnn007 --- Cargo.lock | 4 +-- Cargo.toml | 6 ++-- .../deps/crypto/src/native/aes256gcm.rs | 13 ++++++++ .../deps/crypto/src/rust/aes256gcm.rs | 21 +++++++++++-- .../deps/crypto/src/symmetric.rs | 11 +++++++ .../kbs_protocol/src/client/mod.rs | 2 +- .../kbs_protocol/src/client/rcar_client.rs | 2 +- attestation-agent/kbs_protocol/src/keypair.rs | 31 ++++++++----------- 8 files changed, 64 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 293429d0f..4dd5a6f9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3348,9 +3348,9 @@ dependencies = [ [[package]] name = "kbs-types" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6441ed73b0faa50707d4de41c6b45c76654b661b96aaf7b26a41331eedc0a5" +checksum = "fdbe8d94404c84323fda787c81975895740aeffb5cf9376ffacec4b1fd75b3e2" dependencies = [ "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 2d6a0b2f2..4caa30fcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,10 @@ ctr = "0.9.2" env_logger = "0.11.5" hex = "0.4.3" hmac = "0.12.1" -jwt-simple = { version = "0.12", default-features = false, features = ["pure-rust"] } -kbs-types = "0.7.0" +jwt-simple = { version = "0.12", default-features = false, features = [ + "pure-rust", +] } +kbs-types = "0.9.0" lazy_static = "1.5.0" log = "0.4.22" nix = "0.29" diff --git a/attestation-agent/deps/crypto/src/native/aes256gcm.rs b/attestation-agent/deps/crypto/src/native/aes256gcm.rs index 73a883a4e..3e1c11a8a 100644 --- a/attestation-agent/deps/crypto/src/native/aes256gcm.rs +++ b/attestation-agent/deps/crypto/src/native/aes256gcm.rs @@ -10,6 +10,19 @@ use openssl::symm::Cipher; const TAG_LENGTH: usize = 16; +pub fn decrypt_with_aad( + encrypted_data: &[u8], + key: &[u8], + iv: &[u8], + aad: &[u8], + tag: &[u8], +) -> Result> { + let cipher = Cipher::aes_256_gcm(); + + openssl::symm::decrypt_aead(cipher, key, Some(iv), aad, encrypted_data, tag) + .map_err(|e| anyhow!("{e:?}")) +} + pub fn decrypt(encrypted_data: &[u8], key: &[u8], iv: &[u8]) -> Result> { let cipher = Cipher::aes_256_gcm(); if encrypted_data.len() < TAG_LENGTH { diff --git a/attestation-agent/deps/crypto/src/rust/aes256gcm.rs b/attestation-agent/deps/crypto/src/rust/aes256gcm.rs index 00a4a0d55..d8dde91df 100644 --- a/attestation-agent/deps/crypto/src/rust/aes256gcm.rs +++ b/attestation-agent/deps/crypto/src/rust/aes256gcm.rs @@ -4,10 +4,27 @@ // //! This mod implements aes-256-gcm encryption & decryption. - -use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit, Nonce}; +use aes_gcm::{aead::Aead, AeadInPlace, Aes256Gcm, Key, KeyInit, Nonce}; use anyhow::*; +pub fn decrypt_with_aad( + encrypted_data: &[u8], + key: &[u8], + iv: &[u8], + aad: &[u8], + tag: &[u8], +) -> Result> { + let decrypting_key = Key::::from_slice(key); + let cipher = Aes256Gcm::new(decrypting_key); + let nonce = Nonce::from_slice(iv); + let mut plaintext = encrypted_data.to_vec(); + cipher + .decrypt_in_place_detached(nonce, aad, &mut plaintext, tag.into()) + .map_err(|e| anyhow!("aes-256-gcm decrypt failed: {:?}", e))?; + + Ok(plaintext) +} + pub fn decrypt(encrypted_data: &[u8], key: &[u8], iv: &[u8]) -> Result> { let decrypting_key = Key::::from_slice(key); let cipher = Aes256Gcm::new(decrypting_key); diff --git a/attestation-agent/deps/crypto/src/symmetric.rs b/attestation-agent/deps/crypto/src/symmetric.rs index 900c95f93..0f7f1c5e2 100644 --- a/attestation-agent/deps/crypto/src/symmetric.rs +++ b/attestation-agent/deps/crypto/src/symmetric.rs @@ -48,6 +48,17 @@ pub fn decrypt( } } +/// Decrypt the given `ciphertext` with AES256-GCM algorithm. +pub fn aes256gcm_decrypt( + key: Zeroizing>, + ciphertext: Vec, + iv: Vec, + aad: Vec, + tag: Vec, +) -> Result> { + aes256gcm::decrypt_with_aad(&ciphertext, &key, &iv, &aad, &tag) +} + /// Encrypt the given `plaintext`. /// Note: /// - IV length for A256GCM: 12 bytes diff --git a/attestation-agent/kbs_protocol/src/client/mod.rs b/attestation-agent/kbs_protocol/src/client/mod.rs index 5febb6911..fdb7f23db 100644 --- a/attestation-agent/kbs_protocol/src/client/mod.rs +++ b/attestation-agent/kbs_protocol/src/client/mod.rs @@ -48,7 +48,7 @@ pub struct KbsClient { pub(crate) token: Option, } -pub const KBS_PROTOCOL_VERSION: &str = "0.1.1"; +pub const KBS_PROTOCOL_VERSION: &str = "0.2.0"; pub const KBS_GET_RESOURCE_MAX_ATTEMPT: u64 = 3; diff --git a/attestation-agent/kbs_protocol/src/client/rcar_client.rs b/attestation-agent/kbs_protocol/src/client/rcar_client.rs index 45b194ebb..155aae339 100644 --- a/attestation-agent/kbs_protocol/src/client/rcar_client.rs +++ b/attestation-agent/kbs_protocol/src/client/rcar_client.rs @@ -450,7 +450,7 @@ mod test { assert!( e.to_string() .contains("KBS Client Protocol Version Mismatch"), - "Actual error: {e:#?}" + "{e:#?}" ); println!("NOTE: the test is skipped due to KBS protocol incompatibility."); return (); diff --git a/attestation-agent/kbs_protocol/src/keypair.rs b/attestation-agent/kbs_protocol/src/keypair.rs index 897724e3e..c4fad4d69 100644 --- a/attestation-agent/kbs_protocol/src/keypair.rs +++ b/attestation-agent/kbs_protocol/src/keypair.rs @@ -6,12 +6,8 @@ use anyhow::{Context, Result}; use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; -use crypto::{ - rsa::{PaddingMode, RSAKeyPair}, - WrapType, -}; +use crypto::rsa::{PaddingMode, RSAKeyPair}; use kbs_types::{Response, TeePubKey}; -use serde::Deserialize; use zeroize::Zeroizing; #[derive(Clone, Debug)] @@ -55,9 +51,7 @@ impl TeeKeyPair { } pub fn decrypt_response(&self, response: Response) -> Result> { - // deserialize the jose header and check that the key type matches - let protected: ProtectedHeader = serde_json::from_str(&response.protected)?; - let padding_mode = PaddingMode::try_from(&protected.alg[..]) + let padding_mode = PaddingMode::try_from(&response.protected.alg[..]) .context("Unsupported padding mode for wrapped key")?; // unwrap the wrapped key @@ -66,17 +60,18 @@ impl TeeKeyPair { let iv = URL_SAFE_NO_PAD.decode(&response.iv)?; let ciphertext = URL_SAFE_NO_PAD.decode(&response.ciphertext)?; - - let plaintext = crypto::decrypt(Zeroizing::new(symkey), ciphertext, iv, protected.enc)?; + let tag = URL_SAFE_NO_PAD.decode(&response.tag)?; + let protected_utf8 = serde_json::to_string(&response.protected) + .context("serialize protected header failed")?; + let aad = URL_SAFE_NO_PAD.encode(protected_utf8); + let plaintext = crypto::aes256gcm_decrypt( + Zeroizing::new(symkey), + ciphertext, + iv, + aad.into_bytes(), + tag, + )?; Ok(plaintext) } } - -#[derive(Deserialize)] -struct ProtectedHeader { - /// enryption algorithm for encrypted key - alg: String, - /// encryption algorithm for payload - enc: WrapType, -}