trustee/0003-kbs-replace-concat-kdf-dependency-with-internal-impl.patch
Cropi 012874b70a Initial commit on c10s
Resolves: RHEL-143742
2026-02-10 08:50:00 +01:00

106 lines
4.0 KiB
Diff

From 933b57d8e8915280d671e4796c8919a06bcbb2fb Mon Sep 17 00:00:00 2001
From: Cropi <alakatos@redhat.com>
Date: Wed, 21 Jan 2026 11:00:08 +0100
Subject: [PATCH] kbs: replace concat-kdf dependency with internal
implementation
Remove the 'concat-kdf' crate dependency and replace it with a local
implementation of the Single-Step Concatenation Key Derivation Function
(Concat KDF), using standard 'openssl' primitives.
This change reduces the external dependency footprint while maintaining
compatibility with the algorithm used by other guest components (based
on NIST SP 800-56A).
Inspired by attestation-agent/deps/crypto/src/native/ec.rs
---
kbs/Cargo.toml | 1 -
kbs/src/jwe.rs | 46 +++++++++++++++++++++++++++++++++-------------
2 files changed, 33 insertions(+), 14 deletions(-)
diff --git a/kbs/Cargo.toml b/kbs/Cargo.toml
index 52968e2..1bd4adf 100644
--- a/kbs/Cargo.toml
+++ b/kbs/Cargo.toml
@@ -52,7 +52,6 @@ base64.workspace = true
cfg-if.workspace = true
clap = { workspace = true, features = ["derive", "env"] }
config.workspace = true
-concat-kdf = "0.1.0"
cryptoki = { version = "0.10.0", optional = true }
env_logger.workspace = true
hex.workspace = true
diff --git a/kbs/src/jwe.rs b/kbs/src/jwe.rs
index 27b4863..6eb25a2 100644
--- a/kbs/src/jwe.rs
+++ b/kbs/src/jwe.rs
@@ -19,6 +19,7 @@ use p256::{
use rand::{rngs::OsRng, Rng};
use rsa::{sha2::Sha256, BigUint, Oaep, Pkcs1v15Encrypt, RsaPublicKey};
use serde_json::{json, Map};
+use openssl::hash::{Hasher, MessageDigest};
/// RSA PKCS#1 v1.5
const RSA1_5_ALGORITHM: &str = "RSA1_5";
@@ -41,6 +42,36 @@ const AES_GCM_256_ALGORITHM: &str = "A256GCM";
/// AES 256 GCM Key length in bits
const AES_GCM_256_KEY_BITS: u32 = 256;
+// Concat KDF as per NIST SP 800-56A
+// Based on the implementation from attestation-agent/deps/crypto/src/native/ec.rs
+fn concat_kdf(alg: &str, target_length: usize, z: &[u8]) -> Result<Vec<u8>> {
+ let target_length_bytes = ((target_length * 8) as u32).to_be_bytes();
+ let alg_len_bytes = (alg.len() as u32).to_be_bytes();
+
+ let mut output = Vec::new();
+ let md = MessageDigest::sha256();
+ let count = target_length.div_ceil(md.size());
+ for i in 0..count {
+ let mut hasher = Hasher::new(md)?;
+ hasher.update(&((i + 1) as u32).to_be_bytes())?;
+ hasher.update(z)?;
+ hasher.update(&alg_len_bytes)?;
+ hasher.update(alg.as_bytes())?;
+ hasher.update(&0_u32.to_be_bytes())?;
+ hasher.update(&0_u32.to_be_bytes())?;
+ hasher.update(&target_length_bytes)?;
+
+ let digest = hasher.finish()?;
+ output.extend(digest.to_vec());
+ }
+
+ if output.len() > target_length {
+ output.truncate(target_length);
+ }
+
+ Ok(output)
+}
+
/// Use RSAv1.5 to encrypt the payload data.
/// Warning: This algorithm is deprecated per
/// <https://www.ietf.org/archive/id/draft-madden-jose-deprecate-none-rsa15-00.html#section-1.2>
@@ -167,19 +198,8 @@ fn ecdh_es_a256kw_p256(x: String, y: String, mut payload_data: Vec<u8>) -> Resul
.diffie_hellman(&public_key)
.raw_secret_bytes()
.to_vec();
- let mut key_derivation_materials = Vec::new();
- key_derivation_materials.extend_from_slice(&(ECDH_ES_A256KW.len() as u32).to_be_bytes());
- key_derivation_materials.extend_from_slice(ECDH_ES_A256KW.as_bytes());
- key_derivation_materials.extend_from_slice(&(0_u32).to_be_bytes());
- key_derivation_materials.extend_from_slice(&(0_u32).to_be_bytes());
- key_derivation_materials.extend_from_slice(&AES_GCM_256_KEY_BITS.to_be_bytes());
- let mut wrapping_key = vec![0; 32];
- concat_kdf::derive_key_into::<rsa::sha2::Sha256>(
- &z,
- &key_derivation_materials,
- &mut wrapping_key,
- )
- .map_err(|e| anyhow!("failed to do concat KDF: {e:?}"))?;
+
+ let wrapping_key = concat_kdf(ECDH_ES_A256KW, 32, &z).context("failed to do concat KDF")?;
let wrapping_key: [u8; 32] = wrapping_key
.try_into()
.map_err(|_| anyhow!("invalid bytes length of AES wrapping key"))?;
--
2.52.0