Skip to content

Commit

Permalink
AA/kbs_protocol: Update protocol version to 0.2.0 to fix JWE
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Xynnn007 committed Dec 2, 2024
1 parent c01a615 commit dfbdcc0
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 26 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

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

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
13 changes: 13 additions & 0 deletions attestation-agent/deps/crypto/src/native/aes256gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>> {
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<Vec<u8>> {
let cipher = Cipher::aes_256_gcm();
if encrypted_data.len() < TAG_LENGTH {
Expand Down
21 changes: 19 additions & 2 deletions attestation-agent/deps/crypto/src/rust/aes256gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>> {
let decrypting_key = Key::<Aes256Gcm>::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<Vec<u8>> {
let decrypting_key = Key::<Aes256Gcm>::from_slice(key);
let cipher = Aes256Gcm::new(decrypting_key);
Expand Down
11 changes: 11 additions & 0 deletions attestation-agent/deps/crypto/src/symmetric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@ pub fn decrypt(
}
}

/// Decrypt the given `ciphertext` with AES256-GCM algorithm.
pub fn aes256gcm_decrypt(
key: Zeroizing<Vec<u8>>,
ciphertext: Vec<u8>,
iv: Vec<u8>,
aad: Vec<u8>,
tag: Vec<u8>,
) -> Result<Vec<u8>> {
aes256gcm::decrypt_with_aad(&ciphertext, &key, &iv, &aad, &tag)
}

/// Encrypt the given `plaintext`.
/// Note:
/// - IV length for A256GCM: 12 bytes
Expand Down
2 changes: 1 addition & 1 deletion attestation-agent/kbs_protocol/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub struct KbsClient<T> {
pub(crate) token: Option<Token>,
}

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;

Expand Down
2 changes: 1 addition & 1 deletion attestation-agent/kbs_protocol/src/client/rcar_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ();
Expand Down
31 changes: 13 additions & 18 deletions attestation-agent/kbs_protocol/src/keypair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -55,9 +51,7 @@ impl TeeKeyPair {
}

pub fn decrypt_response(&self, response: Response) -> Result<Vec<u8>> {
// 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
Expand All @@ -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,
}

0 comments on commit dfbdcc0

Please sign in to comment.