mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-31 09:18:28 +00:00
* refactor(kms): share the DEK spec mapping and stop re-parsing opened envelopes
- generate_key_material is now the single spec->length mapping for every
backend that mints DEKs itself; the inline copies in the Static and Local
backends are gone, and ChaCha20 (32 bytes, same as AES_256) is accepted
uniformly instead of only by Static.
- The pub(crate) client decrypt of the Local, Vault KV2 and Vault Transit
backends returns (plaintext, master_key_id), so KmsBackend::decrypt no
longer re-parses the envelope it just opened (one JSON parse per SSE GET
instead of two, and unknown-field observability is no longer double-counted).
- Malformed-envelope parse failures now report CryptographicError("parse")
on all backends; Local was the last one mapping them to SerializationError.
- The four KmsBackend::generate_data_key adapters take fields out of
DataKeyInfo instead of cloning, dropping a redundant un-zeroized plaintext
DEK copy and a full ciphertext clone per call; a missing plaintext now
fails closed everywhere instead of returning an empty key on three of four
backends.
* test(kms): pin legacy header fallback, stored-AAD, and decrypt key-id contracts
- a_legacy_aws_kms_object_without_the_cipher_header_still_opens rebuilds the
true pre-internal-header shape (aws:kms mode + S3 key-id header, no
x-rustfs-* headers) and asserts the fallback normalizes the cipher and
re-projects it.
- a_rewritten_sse_c_context_header_fails_authentication is the SSE-C flank of
the stored-AAD tamper check; metadata_without_stored_context_bytes_still_opens
covers the derived-AAD path for both flavours and pins the seal side to the
canonical bytes (mutation-verified).
- data_key_spec_controls_the_length_of_the_generated_key requires every
backend in the matrix to honour all three specs, asserts the envelope
records the requested spec, and round-trips each blob.
- corrupt_ciphertext_fails_cleanly pins unparseable ciphertext to
CryptographicError instead of merely not-InternalError.
- Deleted the never-called assert_validation_error / assert_cryptographic_error
helpers.
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
|
||||
use crate::backends::{BackendCapabilities, KmsBackend, empty_key_page, list_keys_page_size};
|
||||
use crate::config::{BackendConfig, KmsConfig};
|
||||
use crate::encryption::{DataKeyEnvelope, context_aad};
|
||||
use crate::encryption::{DataKeyEnvelope, context_aad, generate_key_material};
|
||||
use crate::error::{KmsError, Result};
|
||||
use crate::types::*;
|
||||
use aes_gcm::{
|
||||
@@ -124,16 +124,7 @@ impl StaticKmsBackend {
|
||||
// The requested spec decides the DEK length; a caller that asked for
|
||||
// AES_128 and silently got 256 bits would build objects whose recorded
|
||||
// spec does not match their key material.
|
||||
// Lengths track `KeySpec::key_size`; the request carries the spec as a
|
||||
// string, so the mapping is repeated here rather than shared.
|
||||
let key_length = match request.key_spec.as_str() {
|
||||
"AES_256" | "ChaCha20" => 32,
|
||||
"AES_128" => 16,
|
||||
_ => return Err(KmsError::unsupported_algorithm(&request.key_spec)),
|
||||
};
|
||||
|
||||
let mut plaintext = vec![0u8; key_length];
|
||||
rand::rng().fill(&mut plaintext[..]);
|
||||
let plaintext = generate_key_material(&request.key_spec)?;
|
||||
|
||||
// Encrypt DEK with AES-256-GCM using the static key directly
|
||||
let key = Key::<Aes256Gcm>::from(*self.key);
|
||||
@@ -167,7 +158,7 @@ impl StaticKmsBackend {
|
||||
Ok(DataKeyInfo::new(
|
||||
self.key_id.clone(),
|
||||
0,
|
||||
Some(plaintext.to_vec()),
|
||||
Some(plaintext),
|
||||
ciphertext,
|
||||
request.key_spec.clone(),
|
||||
))
|
||||
@@ -360,17 +351,20 @@ impl KmsBackend for StaticKmsBackend {
|
||||
encryption_context: request.encryption_context,
|
||||
grant_tokens: Vec::new(),
|
||||
};
|
||||
let data_key = self.generate_data_key_envelope(&gen_req)?;
|
||||
let mut data_key = self.generate_data_key_envelope(&gen_req)?;
|
||||
|
||||
// Fields are taken, not destructured or cloned: `DataKeyInfo` has a
|
||||
// `Drop` impl, and a clone would leave a second un-zeroized plaintext
|
||||
// DEK on the heap.
|
||||
let plaintext_key = data_key
|
||||
.plaintext
|
||||
.clone()
|
||||
.take()
|
||||
.ok_or_else(|| KmsError::internal_error("Generated data key is missing plaintext"))?;
|
||||
|
||||
Ok(GenerateDataKeyResponse {
|
||||
key_id: data_key.key_id.clone(),
|
||||
key_id: std::mem::take(&mut data_key.key_id),
|
||||
plaintext_key,
|
||||
ciphertext_blob: data_key.ciphertext.clone(),
|
||||
ciphertext_blob: std::mem::take(&mut data_key.ciphertext),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user