diff --git a/Cargo.lock b/Cargo.lock index 6937e1a..b12450a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -291,6 +291,7 @@ dependencies = [ "cfg-if", "cipher", "cpufeatures", + "zeroize", ] [[package]] @@ -305,6 +306,7 @@ dependencies = [ "ctr", "ghash", "subtle", + "zeroize", ] [[package]] @@ -1281,11 +1283,12 @@ checksum = "2f8a2ca5ac02d09563609681103aada9e1777d54fc57a5acd7a41404f9c93b6e" [[package]] name = "const_format" -version = "0.2.34" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" dependencies = [ "const_format_proc_macros", + "konst", ] [[package]] @@ -3405,6 +3408,7 @@ dependencies = [ "actix", "actix-web", "actix-web-httpauth", + "aes", "aes-gcm", "aes-kw", "anyhow", @@ -3431,6 +3435,7 @@ dependencies = [ "mobc", "openssl", "p256", + "polyval", "prost", "rand", "reference-value-provider-service", @@ -3513,6 +3518,21 @@ dependencies = [ "yasna 0.5.2", ] +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + [[package]] name = "language-tags" version = "0.3.2" @@ -4610,6 +4630,7 @@ dependencies = [ "cpufeatures", "opaque-debug", "universal-hash", + "zeroize", ] [[package]] diff --git a/kbs/Cargo.toml b/kbs/Cargo.toml index b34d1ba..52707b8 100644 --- a/kbs/Cargo.toml +++ b/kbs/Cargo.toml @@ -13,7 +13,7 @@ default = ["coco-as-builtin", "coco-as-grpc"] encrypted-local-fs = [] # Enable encrypted DB-backed resource backend (multi-replica wrap-key sharing) -encrypted-db = ["sqlx", "argon2", "zeroize", "chrono"] +encrypted-db = ["sqlx", "argon2", "chrono"] # Support a backend attestation service for KBS as = [] @@ -47,7 +47,11 @@ tpm-pca = [] actix = "0.13.5" actix-web = { workspace = true, features = ["openssl"] } actix-web-httpauth.workspace = true -aes-gcm = "0.10.1" +aes-gcm = { version = "0.10.1", features = ["zeroize"] } +# Direct deps to activate their `zeroize` feature: `aes-gcm`'s own `zeroize` +# feature does not propagate down to `aes` or `polyval`. Do not remove. +aes = { version = "0.8", features = ["zeroize"] } +polyval = { version = "0.6", features = ["zeroize"] } aes-kw = "0.2.1" anyhow.workspace = true argon2 = { workspace = true, optional = true } @@ -93,7 +97,7 @@ derivative = "2.2.0" rustls-pki-types = "1.14.0" rustls-webpki = { version = "0.103.9", features = ["ring"] } x509-cert = "0.2.5" -zeroize = { workspace = true, optional = true } +zeroize.workspace = true [target.'cfg(not(any(target_arch = "s390x", target_arch = "aarch64")))'.dependencies] attestation-service = { path = "../attestation-service", default-features = false, features = [ diff --git a/kbs/src/jwe.rs b/kbs/src/jwe.rs index 27b4863..134a012 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 zeroize::Zeroizing; /// RSA PKCS#1 v1.5 const RSA1_5_ALGORITHM: &str = "RSA1_5"; @@ -49,7 +50,7 @@ fn rsa_1v15(k_mod: String, k_exp: String, mut payload_data: Vec) -> Result(); let nonce = Nonce::from_slice(&iv); @@ -94,7 +95,7 @@ fn rsa_1v15(k_mod: String, k_exp: String, mut payload_data: Vec) -> Result) -> Result { let mut rng = rand::thread_rng(); - let aes_sym_key = Aes256Gcm::generate_key(&mut OsRng); + let aes_sym_key = Zeroizing::new(Aes256Gcm::generate_key(&mut OsRng)); let mut cipher = Aes256Gcm::new(&aes_sym_key); let iv = rng.gen::<[u8; 12]>(); let nonce = Nonce::from_slice(&iv); @@ -141,7 +142,7 @@ fn ecdh_es_a256kw_p256(x: String, y: String, mut payload_data: Vec) -> Resul let mut rng = rand::thread_rng(); // 1. Generate a random CEK - let cek = Aes256Gcm::generate_key(&mut rng); + let cek = Zeroizing::new(Aes256Gcm::generate_key(&mut rng)); // 2. Wrap the CEK and generate ProtectedHeader let x: [u8; 32] = URL_SAFE_NO_PAD @@ -163,32 +164,29 @@ fn ecdh_es_a256kw_p256(x: String, y: String, mut payload_data: Vec) -> Resul .into_option() .ok_or(anyhow!("invalid TEE public key"))?; let encrypter_secret = EphemeralSecret::random(&mut rng); - let z = encrypter_secret - .diffie_hellman(&public_key) - .raw_secret_bytes() - .to_vec(); + let z = Zeroizing::new( + encrypter_secret + .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]; + let mut wrapping_key = Zeroizing::new(vec![0u8; 32]); concat_kdf::derive_key_into::( &z, &key_derivation_materials, &mut wrapping_key, ) .map_err(|e| anyhow!("failed to do concat KDF: {e:?}"))?; - let wrapping_key: [u8; 32] = wrapping_key - .try_into() - .map_err(|_| anyhow!("invalid bytes length of AES wrapping key"))?; - let wrapping_key: KekAes256 = Kek::new(&GenericArray::from(wrapping_key)); + let wrapping_kek: KekAes256 = Kek::new(GenericArray::from_slice(&wrapping_key)); let mut encrypted_key = vec![0; 40]; - encrypted_key.resize(40, 0); - let cek = cek.to_vec(); - wrapping_key - .wrap(&cek, &mut encrypted_key) + wrapping_kek + .wrap(cek.as_slice(), &mut encrypted_key) .map_err(|e| anyhow!("failed to do AES wrapping: {e:?}"))?; let point = EncodedPoint::from(encrypter_secret.public_key()); @@ -217,7 +215,7 @@ fn ecdh_es_a256kw_p256(x: String, y: String, mut payload_data: Vec) -> Resul }; // 3. Encrypt content with CEK - let mut cek_cipher = Aes256Gcm::new(GenericArray::from_slice(&cek)); + let mut cek_cipher = Aes256Gcm::new(&cek); let iv = rand::thread_rng().gen::<[u8; 12]>(); let nonce = Nonce::from_slice(&iv);