Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions packages/stack-kms-azure/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ pub fn issued_at() -> SystemTime {
}

/// The TEST-ONLY 256-bit AES key of the fixture `oct-HSM` key version: the
/// RFC 3394 example key-encryption key (`00 01 .. 1F`). It is no one's key.
pub const TEST_ONLY_KEK: [u8; 32] = [
/// RFC 3394 example key (`00 01 .. 1F`). It is no one's key.
pub const TEST_ONLY_VENDOR_KEY: [u8; 32] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31,
];
Expand All @@ -76,9 +76,9 @@ const KW_IV: [u8; 8] = [0xA6; 8];

/// AES key wrap (RFC 3394) under a 256-bit key: an implementation for the
/// emulator, pinned by the RFC's own example in `tests/fixtures.rs`.
pub fn kw_wrap(kek: &[u8; 32], plaintext: &[u8]) -> Vec<u8> {
pub fn kw_wrap(vendor_key: &[u8; 32], plaintext: &[u8]) -> Vec<u8> {
assert!(plaintext.len().is_multiple_of(8) && plaintext.len() >= 16);
let cipher = Aes256::new(GenericArray::from_slice(kek));
let cipher = Aes256::new(GenericArray::from_slice(vendor_key));
let n = plaintext.len() / 8;
let mut a = KW_IV;
let mut r: Vec<[u8; 8]> = plaintext.chunks(8).map(|c| c.try_into().unwrap()).collect();
Expand All @@ -99,11 +99,11 @@ pub fn kw_wrap(kek: &[u8; 32], plaintext: &[u8]) -> Vec<u8> {
}

/// AES key unwrap (RFC 3394). `None` when the integrity check fails.
pub fn kw_unwrap(kek: &[u8; 32], ciphertext: &[u8]) -> Option<Vec<u8>> {
pub fn kw_unwrap(vendor_key: &[u8; 32], ciphertext: &[u8]) -> Option<Vec<u8>> {
if !ciphertext.len().is_multiple_of(8) || ciphertext.len() < 24 {
return None;
}
let cipher = Aes256::new(GenericArray::from_slice(kek));
let cipher = Aes256::new(GenericArray::from_slice(vendor_key));
let n = ciphertext.len() / 8 - 1;
let mut a: [u8; 8] = ciphertext[..8].try_into().unwrap();
let mut r: Vec<[u8; 8]> = ciphertext[8..]
Expand Down Expand Up @@ -544,10 +544,10 @@ impl KeyVaultEmulator {
.unwrap(),
),
("unwrapkey", Material::Rsa) => self.rsa.decrypt(Oaep::new::<Sha256>(), &value).ok(),
("wrapkey", Material::Aes(kek)) => {
(value.len().is_multiple_of(8) && value.len() >= 16).then(|| kw_wrap(kek, &value))
}
("unwrapkey", Material::Aes(kek)) => kw_unwrap(kek, &value),
("wrapkey", Material::Aes(vendor_key)) => (value.len().is_multiple_of(8)
&& value.len() >= 16)
.then(|| kw_wrap(vendor_key, &value)),
("unwrapkey", Material::Aes(vendor_key)) => kw_unwrap(vendor_key, &value),
_ => None,
};
match result {
Expand Down
18 changes: 12 additions & 6 deletions packages/stack-kms-azure/tests/fixtures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use base64ct::{Base64UrlUnpadded, Encoding};
use common::{
fixture_client, issued_at, kw_unwrap, kw_wrap, load, replay, test_only_rsa_key, Fixture,
FixtureResponse, KeyVaultEmulator, Replay, CLIENT_ID, CLIENT_SECRET, OCT_KEY, OCT_VERSION,
RSA_KEY, RSA_OLD_VERSION, RSA_VERSION, TENANT, TEST_ONLY_KEK, TOKEN,
RSA_KEY, RSA_OLD_VERSION, RSA_VERSION, TENANT, TEST_ONLY_VENDOR_KEY, TOKEN,
};
use rsa::sha2::Sha256;
use rsa::Oaep;
Expand Down Expand Up @@ -186,10 +186,13 @@ fn the_fixture_ciphertexts_open_under_the_test_only_keys() {
let fixtures: Vec<Fixture> = load("hsm_wrap.json");
let plaintext = b64(&fixtures[1].request.body["value"]);
let ciphertext = b64(&fixtures[1].response.body["value"]);
assert_eq!(kw_unwrap(&TEST_ONLY_KEK, &ciphertext).unwrap(), plaintext);
assert_eq!(kw_wrap(&TEST_ONLY_KEK, &plaintext), ciphertext);
assert_eq!(
kw_unwrap(&TEST_ONLY_VENDOR_KEY, &ciphertext).unwrap(),
plaintext
);
assert_eq!(kw_wrap(&TEST_ONLY_VENDOR_KEY, &plaintext), ciphertext);

// RFC 3394, 4.6: 256 bits of key data with a 256-bit KEK.
// RFC 3394, 4.6: 256 bits of key data with a 256-bit key (the vendor key).
let key_data: Vec<u8> = (0..16u8)
.map(|i| i * 0x11)
.chain(0..16u8)
Expand All @@ -199,8 +202,11 @@ fn the_fixture_ciphertexts_open_under_the_test_only_keys() {
0x26, 0x3F, 0x57, 0x86, 0xE2, 0xD8, 0x0E, 0xD3, 0x26, 0xCB, 0xC7, 0xF0, 0xE7, 0x1A, 0x99,
0xF4, 0x3B, 0xFB, 0x98, 0x8B, 0x9B, 0x7A, 0x02, 0xDD, 0x21,
];
assert_eq!(kw_wrap(&TEST_ONLY_KEK, &key_data), expected);
assert_eq!(kw_unwrap(&TEST_ONLY_KEK, &expected).unwrap(), key_data);
assert_eq!(kw_wrap(&TEST_ONLY_VENDOR_KEY, &key_data), expected);
assert_eq!(
kw_unwrap(&TEST_ONLY_VENDOR_KEY, &expected).unwrap(),
key_data
);
}

fn fixed_clock() -> stack_kms_azure::Clock {
Expand Down
Loading