Skip to content

Commit

Permalink
KBS: Update KBS protocol to 0.2.0 to fix JWE
Browse files Browse the repository at this point in the history
Fixes #583.

Due to RFC 7516, the JWE AEAD Auth Tag should be expcilitly be included
inside the `tag` part. Before this commit, the tag is actually included
as the suffix of the `ciphertext`.

We fix this by expcilitly extract the tag and include it into the jwe
body.

Also, we fix the AAD calculation logic, s.t. derived from
ProtectedHeader which is also specifiled by RFC7516. This should be
align with the guest-components side.

This change will make the kbs_client not able to connect to the KBS.
Thus we update the KBS protocol version from 0.1.1 to 0.2.0.

Signed-off-by: Xynnn007 <xynnn@linux.alibaba.com>
  • Loading branch information
Xynnn007 committed Dec 2, 2024
1 parent db2c246 commit 7fb7897
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 34 deletions.
23 changes: 16 additions & 7 deletions Cargo.lock

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

19 changes: 13 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,21 @@ ear = "0.3.0"
env_logger = "0.10.0"
hex = "0.4.3"
jwt-simple = "0.11"
kbs_protocol = { git = "https://github.com/confidential-containers/guest-components.git", rev="e6999a3c0fd877dae9e68ea78b8b483062db32b8", default-features = false }
kbs-types = "0.7.0"
kms = { git = "https://github.com/confidential-containers/guest-components.git", rev="e6999a3c0fd877dae9e68ea78b8b483062db32b8", default-features = false }
kbs_protocol = { git = "https://github.com/confidential-containers/guest-components.git", rev = "e6999a3c0fd877dae9e68ea78b8b483062db32b8", default-features = false }
kbs-types = { git = "https://github.com/virtee/kbs-types.git", rev = "f47881f" }
kms = { git = "https://github.com/confidential-containers/guest-components.git", rev = "e6999a3c0fd877dae9e68ea78b8b483062db32b8", default-features = false }
jsonwebtoken = { version = "9", default-features = false }
log = "0.4.17"
prost = "0.12"
regorus = { version = "0.2.6", default-features = false, features = ["regex", "base64", "time", "std" ] }
reqwest = { version = "0.12", default-features = false, features = ["default-tls"] }
regorus = { version = "0.2.6", default-features = false, features = [
"regex",
"base64",
"time",
"std",
] }
reqwest = { version = "0.12", default-features = false, features = [
"default-tls",
] }
rstest = "0.18.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.132"
Expand All @@ -47,7 +54,7 @@ sha2 = "0.10"
shadow-rs = "0.19.0"
strum = { version = "0.25", features = ["derive"] }
thiserror = "1.0"
tokio = { version = "1", features = ["full"], default-features = false }
tokio = { version = "1", features = ["full"], default-features = false }
tempfile = "3.14.0"
tonic = "0.11"
tonic-build = "0.11"
6 changes: 4 additions & 2 deletions deps/verifier/src/snp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const LOADER_SPL_OID: Oid<'static> = oid!(1.3.6 .1 .4 .1 .3704 .1 .3 .1);
const KDS_CERT_SITE: &str = "https://kdsintf.amd.com";
const KDS_VCEK: &str = "/vcek/v1";

/// Attestation report versions supported
/// Attestation report versions supported
const REPORT_VERSION_MIN: u32 = 2;
const REPORT_VERSION_MAX: u32 = 3;

Expand Down Expand Up @@ -110,7 +110,9 @@ impl Verifier for Snp {

// See Trustee Issue#589 https://github.com/confidential-containers/trustee/issues/589
if report.version < REPORT_VERSION_MIN || report.version > REPORT_VERSION_MAX {
return Err(anyhow!("Unexpected attestation report version. Check SNP Firmware ABI specification"));
return Err(anyhow!(
"Unexpected attestation report version. Check SNP Firmware ABI specification"
));
}

if report.vmpl != 0 {
Expand Down
11 changes: 11 additions & 0 deletions kbs/docs/kbs_attestation_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ payload that follows the [JSON Web Encryption](https://www.rfc-editor.org/rfc/rf
{
"protected": "$jose_header",
"encrypted_key": "$encrypted_key",
"aad": "$aad",
"iv": "$iv",
"ciphertext": "$ciphertext",
"tag": "$tag"
Expand All @@ -204,6 +205,7 @@ The above JWE JSON fields are defined as follows:
let jose_header_string = format!(r#"{{"alg": "{}","enc": "{}"}}"#, alg, enc);
let jose_header = base64_url::encode(&jose_header_string);
let encrypted_key = base64_url::encode(enc_kbs_symkey);
let aad = base64_url::encode(additional_authenticated_data);
let iv = base64_url::encode(initialization_vector);
let ciphertext = base64_url::encode(response_output);

Expand All @@ -227,6 +229,10 @@ Encryption algorithm used to encrypt the output of the KBS service API.
The output of the KBS service API. It must be encrypted with the KBS-generated
ephemeral key.

- `aad` (Required if AEAD is used)

An input to an AEAD operation that is integrity protected but not encrypted.

- `iv`

The input to a cryptographic primitive is used to provide the initial state.
Expand All @@ -239,6 +245,11 @@ The encrypted symmetric key is used to encrypt `ciphertext`.
This key is encrypted with the HW-TEE's public key, using the algorithm defined
in `alg`.

- `tag`

The authentication tag is used to authenticate the ciphertext. If the algorithm
described by `enc` used does not need it, this field is left blank.

## Key Format

### Public Key
Expand Down
4 changes: 2 additions & 2 deletions kbs/src/attestation/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ use super::{
};

static KBS_MAJOR_VERSION: u64 = 0;
static KBS_MINOR_VERSION: u64 = 1;
static KBS_PATCH_VERSION: u64 = 1;
static KBS_MINOR_VERSION: u64 = 2;
static KBS_PATCH_VERSION: u64 = 0;

lazy_static! {
static ref VERSION_REQ: VersionReq = {
Expand Down
38 changes: 21 additions & 17 deletions kbs/src/jwe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
use std::collections::BTreeMap;

use aes_gcm::{aead::AeadMutInPlace, Aes256Gcm, KeyInit, Nonce};
use anyhow::{anyhow, bail, Context, Result};
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
use kbs_types::{Response, TeePubKey};
use kbs_types::{ProtectedHeader, Response, TeePubKey};
use rand::{rngs::OsRng, Rng};
use rsa::{BigUint, Pkcs1v15Encrypt, RsaPublicKey};
use serde_json::json;

const RSA_ALGORITHM: &str = "RSA1_5";
const AES_GCM_256_ALGORITHM: &str = "A256GCM";

pub fn jwe(tee_pub_key: TeePubKey, payload_data: Vec<u8>) -> Result<Response> {
pub fn jwe(tee_pub_key: TeePubKey, mut payload_data: Vec<u8>) -> Result<Response> {
let TeePubKey::RSA { alg, k_mod, k_exp } = tee_pub_key else {
bail!("Only RSA key is support for TEE pub key")
};
Expand All @@ -25,11 +26,20 @@ pub fn jwe(tee_pub_key: TeePubKey, payload_data: Vec<u8>) -> Result<Response> {
let mut rng = rand::thread_rng();

let aes_sym_key = Aes256Gcm::generate_key(&mut OsRng);
let cipher = Aes256Gcm::new(&aes_sym_key);
let mut cipher = Aes256Gcm::new(&aes_sym_key);
let iv = rng.gen::<[u8; 12]>();
let nonce = Nonce::from_slice(&iv);
let encrypted_payload_data = cipher
.encrypt(nonce, payload_data.as_slice())
let protected = ProtectedHeader {
alg: RSA_ALGORITHM.to_string(),
enc: AES_GCM_256_ALGORITHM.to_string(),
other_fields: BTreeMap::new(),
};
let protected_utf8 =
serde_json::to_string(&protected).context("serialize protected header failed")?;
let aad = URL_SAFE_NO_PAD.encode(protected_utf8);

let tag = cipher
.encrypt_in_place_detached(nonce, aad.as_bytes(), &mut payload_data)
.map_err(|e| anyhow!("AES encrypt Resource payload failed: {e}"))?;

let k_mod = URL_SAFE_NO_PAD
Expand All @@ -48,18 +58,12 @@ pub fn jwe(tee_pub_key: TeePubKey, payload_data: Vec<u8>) -> Result<Response> {
.encrypt(&mut rng, Pkcs1v15Encrypt, sym_key)
.context("RSA encrypt sym key failed")?;

let protected_header = json!(
{
"alg": RSA_ALGORITHM.to_string(),
"enc": AES_GCM_256_ALGORITHM.to_string(),
});

Ok(Response {
protected: serde_json::to_string(&protected_header)
.context("serde protected_header failed")?,
protected,
encrypted_key: URL_SAFE_NO_PAD.encode(wrapped_sym_key),
iv: URL_SAFE_NO_PAD.encode(iv),
ciphertext: URL_SAFE_NO_PAD.encode(encrypted_payload_data),
tag: "".to_string(),
ciphertext: URL_SAFE_NO_PAD.encode(payload_data),
aad: Some(aad),
tag: URL_SAFE_NO_PAD.encode(tag),
})
}

0 comments on commit 7fb7897

Please sign in to comment.