From c0a0a43d91a53b30300b3c847e9befbae624de8f Mon Sep 17 00:00:00 2001 From: Pi Delport Date: Wed, 16 Jun 2021 14:24:47 +0200 Subject: [PATCH 1/7] feat(rtc_types::enclave_messages): derive Debug for EncryptedEnclaveMessage --- rtc_types/src/enclave_messages/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rtc_types/src/enclave_messages/mod.rs b/rtc_types/src/enclave_messages/mod.rs index 2e00ab49..bcb33074 100644 --- a/rtc_types/src/enclave_messages/mod.rs +++ b/rtc_types/src/enclave_messages/mod.rs @@ -10,6 +10,7 @@ pub const ARCHIVED_ENCLAVE_ID_SIZE: usize = // NIST AES-GCM recommended IV size pub type RecommendedAesGcmIv = [u8; 12]; +#[derive(Debug)] #[repr(C)] pub struct EncryptedEnclaveMessage { pub tag: sgx_aes_gcm_128bit_tag_t, From 2c68e78820af4972200a6af5e8adabee4de8ca03 Mon Sep 17 00:00:00 2001 From: Pi Delport Date: Wed, 9 Jun 2021 19:05:32 +0200 Subject: [PATCH 2/7] chore(rtc_tenclave::dh): expose pub ProtectedChannel The enclave code references this. --- rtc_tenclave/src/dh/sessions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtc_tenclave/src/dh/sessions.rs b/rtc_tenclave/src/dh/sessions.rs index 660b2e9f..94ce335a 100644 --- a/rtc_tenclave/src/dh/sessions.rs +++ b/rtc_tenclave/src/dh/sessions.rs @@ -8,7 +8,7 @@ use rtc_types::dh::{ExchangeReportResult, SessionRequestResult}; use secrecy::Secret; use sgx_types::*; -use super::protected_channel::ProtectedChannel; +pub use super::protected_channel::ProtectedChannel; use super::types::{AlignedKey, RtcDhInitiator, RtcDhResponder}; #[cfg(not(test))] From 49b092c576104c2f580b4ae273ef52a98279aeab Mon Sep 17 00:00:00 2001 From: Pi Delport Date: Tue, 15 Jun 2021 18:02:42 +0200 Subject: [PATCH 3/7] refactor(rtc_tenclave::dh::protected_channel): return AAD from decrypt_message This makes it the inverse of encrypt_message, and avoids the caller having to copy it. --- rtc_tenclave/src/dh/protected_channel.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtc_tenclave/src/dh/protected_channel.rs b/rtc_tenclave/src/dh/protected_channel.rs index c41f69c8..33fe8769 100644 --- a/rtc_tenclave/src/dh/protected_channel.rs +++ b/rtc_tenclave/src/dh/protected_channel.rs @@ -55,7 +55,7 @@ impl ProtectedChannel { pub fn decrypt_message( &self, message: EncryptedEnclaveMessage, - ) -> Result<[u8; MESSAGE_SIZE], sgx_status_t> { + ) -> Result<([u8; MESSAGE_SIZE], [u8; AAD_SIZE]), sgx_status_t> { let mut dst = [0_u8; MESSAGE_SIZE]; rsgx_rijndael128GCM_decrypt( self.key.expose_secret().key(), @@ -65,7 +65,7 @@ impl ProtectedChannel { &message.tag, &mut dst, )?; - Ok(dst) + Ok((dst, message.aad)) } } From 307b55daee4d3c770cb372ebe109708ab258e627 Mon Sep 17 00:00:00 2001 From: Pi Delport Date: Wed, 9 Jun 2021 20:53:53 +0200 Subject: [PATCH 4/7] deps(rtc_tenclave): add rkyv --- rtc_auth_enclave/Cargo.lock | 1 + rtc_data_enclave/Cargo.lock | 1 + rtc_exec_enclave/Cargo.lock | 1 + rtc_tenclave/Cargo.lock | 1 + rtc_tenclave/Cargo.toml | 1 + 5 files changed, 5 insertions(+) diff --git a/rtc_auth_enclave/Cargo.lock b/rtc_auth_enclave/Cargo.lock index 9657d3e1..9089805f 100644 --- a/rtc_auth_enclave/Cargo.lock +++ b/rtc_auth_enclave/Cargo.lock @@ -427,6 +427,7 @@ dependencies = [ "once_cell 1.4.0", "rand 0.7.3", "ring", + "rkyv", "rtc_types", "secrecy", "serde 1.0.118", diff --git a/rtc_data_enclave/Cargo.lock b/rtc_data_enclave/Cargo.lock index d9b8446f..a5632d55 100644 --- a/rtc_data_enclave/Cargo.lock +++ b/rtc_data_enclave/Cargo.lock @@ -524,6 +524,7 @@ dependencies = [ "once_cell 1.4.0", "rand 0.7.3", "ring", + "rkyv", "rtc_types", "secrecy", "serde 1.0.118", diff --git a/rtc_exec_enclave/Cargo.lock b/rtc_exec_enclave/Cargo.lock index 00dd1285..508be0d6 100644 --- a/rtc_exec_enclave/Cargo.lock +++ b/rtc_exec_enclave/Cargo.lock @@ -428,6 +428,7 @@ dependencies = [ "once_cell 1.4.0", "rand 0.7.3", "ring", + "rkyv", "rtc_types", "secrecy", "serde 1.0.118", diff --git a/rtc_tenclave/Cargo.lock b/rtc_tenclave/Cargo.lock index 298da866..4b279979 100644 --- a/rtc_tenclave/Cargo.lock +++ b/rtc_tenclave/Cargo.lock @@ -605,6 +605,7 @@ dependencies = [ "rand 0.7.3 (git+https://github.com/mesalock-linux/rand-sgx?tag=v0.7.3_sgx1.1.3)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "ring", + "rkyv", "rtc_types", "secrecy", "serde 1.0.118", diff --git a/rtc_tenclave/Cargo.toml b/rtc_tenclave/Cargo.toml index cbfa8e4c..4f2889f4 100644 --- a/rtc_tenclave/Cargo.toml +++ b/rtc_tenclave/Cargo.toml @@ -63,6 +63,7 @@ ring = { version = "0.17.0-alpha.8", default-features = false } sodalite = { version = "0.4.0", default-features = false } cfg-if = "1.0.0" hex = { version = "0.4.3", default-features = false, features = ["alloc"] } +rkyv = { version = "0.6.6", default_features = false, features = ["const_generics", "strict"] } [dev-dependencies] thiserror_std = { package = "thiserror", version = "1.0.9" } From 8bbddf831f176cc6b997d021bc5b5419b35d89da Mon Sep 17 00:00:00 2001 From: Pi Delport Date: Tue, 15 Jun 2021 19:02:08 +0200 Subject: [PATCH 5/7] deps(rtc_tenclave): add proptest-derive (dev) --- rtc_tenclave/Cargo.lock | 101 +++++++++++++++++++++++++++++----------- rtc_tenclave/Cargo.toml | 1 + 2 files changed, 75 insertions(+), 27 deletions(-) diff --git a/rtc_tenclave/Cargo.lock b/rtc_tenclave/Cargo.lock index 4b279979..fe998479 100644 --- a/rtc_tenclave/Cargo.lock +++ b/rtc_tenclave/Cargo.lock @@ -232,9 +232,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dd4234635bca06fc96c7368d038061e0aae1b00a764dc817e900dc974e3deea" dependencies = [ "cfg-if 1.0.0", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.72", ] [[package]] @@ -306,13 +306,22 @@ dependencies = [ "treeline", ] +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + [[package]] name = "proc-macro2" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ - "unicode-xid", + "unicode-xid 0.2.2", ] [[package]] @@ -335,6 +344,17 @@ dependencies = [ "tempfile", ] +[[package]] +name = "proptest-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90b46295382dc76166cb7cf2bb4a97952464e4b7ed5a43e6cd34e1fec3349ddc" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + [[package]] name = "ptr_meta" version = "0.1.3" @@ -350,9 +370,9 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53005b9863728f508d3f23ae37e03d60986a01b65f7ae8397dcebaa1d5e54e10" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.72", ] [[package]] @@ -367,13 +387,22 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + [[package]] name = "quote" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.26", ] [[package]] @@ -587,9 +616,9 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e3fccbf52ee0b76a29417794226e225798dd6bd32e40debd9e284cecc20dd76" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.72", ] [[package]] @@ -602,6 +631,7 @@ dependencies = [ "once_cell 1.4.0", "once_cell 1.7.2", "proptest", + "proptest-derive", "rand 0.7.3 (git+https://github.com/mesalock-linux/rand-sgx?tag=v0.7.3_sgx1.1.3)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "ring", @@ -832,15 +862,26 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + [[package]] name = "syn" version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "proc-macro2 1.0.26", + "quote 1.0.9", + "unicode-xid 0.2.2", ] [[package]] @@ -880,9 +921,9 @@ name = "thiserror-impl" version = "1.0.9" source = "git+https://github.com/mesalock-linux/thiserror-sgx.git#c2f806b88616e06aab0af770366a76885d974fdc" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.72", ] [[package]] @@ -891,9 +932,9 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.72", ] [[package]] @@ -902,6 +943,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "unicode-xid" version = "0.2.2" @@ -954,9 +1001,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.72", "wasm-bindgen-shared", ] @@ -966,7 +1013,7 @@ version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" dependencies = [ - "quote", + "quote 1.0.9", "wasm-bindgen-macro-support", ] @@ -976,9 +1023,9 @@ version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.72", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/rtc_tenclave/Cargo.toml b/rtc_tenclave/Cargo.toml index 4f2889f4..c265ece4 100644 --- a/rtc_tenclave/Cargo.toml +++ b/rtc_tenclave/Cargo.toml @@ -75,6 +75,7 @@ once_cell_std = { package = "once_cell", version="1.7.2" } # Test-only dependencies proptest = "1.0.0" +proptest-derive = "0.3.0" tempfile = "3.2.0" mockall = { version = "0.9.1", features = ["nightly"] } From 62439f80fa098cefee3bb25f9a2abecc6f71ab91 Mon Sep 17 00:00:00 2001 From: Pi Delport Date: Thu, 10 Jun 2021 13:44:44 +0200 Subject: [PATCH 6/7] feat(rtc_tenclave::dh::sealing): add helpers to seal and unseal enclave messages --- rtc_tenclave/src/dh/mod.rs | 1 + rtc_tenclave/src/dh/sealing.rs | 370 +++++++++++++++++++++++++++++++++ 2 files changed, 371 insertions(+) create mode 100644 rtc_tenclave/src/dh/sealing.rs diff --git a/rtc_tenclave/src/dh/mod.rs b/rtc_tenclave/src/dh/mod.rs index 5e481e8f..ebc2e23c 100644 --- a/rtc_tenclave/src/dh/mod.rs +++ b/rtc_tenclave/src/dh/mod.rs @@ -1,6 +1,7 @@ //! Support for establishing secure local inter-enclave sessions using [`sgx_tdh`]. mod protected_channel; +pub mod sealing; mod sessions; mod types; diff --git a/rtc_tenclave/src/dh/sealing.rs b/rtc_tenclave/src/dh/sealing.rs new file mode 100644 index 00000000..7ee522f9 --- /dev/null +++ b/rtc_tenclave/src/dh/sealing.rs @@ -0,0 +1,370 @@ +//! Helpers to seal and unseal enclave messages. + +use core::mem::size_of; + +use rkyv::ser::serializers::{BufferSerializer, BufferSerializerError}; +use rkyv::{Aligned, Archive, Deserialize, Infallible, Serialize}; +use rtc_types::byte_formats::rkyv_format; +use rtc_types::enclave_messages::EncryptedEnclaveMessage; +use sgx_types::sgx_status_t; + +use crate::dh::ProtectedChannel; + +/// Seal with associated data. +pub fn rkyv_seal_associated( + channel: &mut ProtectedChannel, + unsealed: &T, + associated: &A, +) -> Result< + EncryptedEnclaveMessage<{ size_of::() }, { size_of::() }>, + SealingError, +> +where + T: Serialize()]>>>, + A: Serialize()]>>>, +{ + let plaintext = rkyv_format::write_array(unsealed)?; + let aad = rkyv_format::write_array(associated)?; + let sealed = channel.encrypt_message(plaintext, aad)?; + Ok(sealed) +} + +/// Unseal with associated data. +/// +/// # Safety +/// +/// Callers must ensure that the sealed message contains valid serialized data, +/// to avoid undefined behaviour during deserialization. +/// +/// See [`rkyv_format::read_array`] and [`rkyv_format::view_array`]. +pub unsafe fn rkyv_unseal_associated( + channel: &ProtectedChannel, + sealed: EncryptedEnclaveMessage<{ size_of::() }, { size_of::() }>, +) -> Result<(T, A), SealingError> +where + T: Archive, + T::Archived: Deserialize, + A: Archive, + A::Archived: Deserialize, +{ + let (plaintext, aad) = &channel.decrypt_message(sealed)?; + let unsealed = unsafe { rkyv_format::read_array(plaintext) }; + let associated = unsafe { rkyv_format::read_array(aad) }; + Ok((unsealed, associated)) +} + +/// Seal without associated data. +pub fn rkyv_seal( + channel: &mut ProtectedChannel, + unsealed: &T, +) -> Result() }, 0>, SealingError> +where + T: Serialize()]>>>, +{ + let plaintext = rkyv_format::write_array(unsealed)?; + let sealed = channel.encrypt_message(plaintext, [])?; + Ok(sealed) +} + +/// Unseal without associated data. +/// +/// # Safety +/// +/// Callers must ensure that the sealed message contains valid serialized data, +/// to avoid undefined behaviour during deserialization. +/// +/// See [`rkyv_format::read_array`] and [`rkyv_format::view_array`]. +pub unsafe fn rkyv_unseal( + channel: &ProtectedChannel, + sealed: EncryptedEnclaveMessage<{ size_of::() }, 0>, +) -> Result +where + T: Archive, + T::Archived: Deserialize, +{ + let (plaintext, []) = &channel.decrypt_message(sealed)?; + let unsealed = unsafe { rkyv_format::read_array(plaintext) }; + Ok(unsealed) +} + +#[derive(Debug)] +pub enum SealingError { + Rkyv(BufferSerializerError), + Sgx(sgx_status_t), +} + +impl From for SealingError { + fn from(error: BufferSerializerError) -> Self { + SealingError::Rkyv(error) + } +} + +impl From for SealingError { + fn from(status: sgx_status_t) -> Self { + SealingError::Sgx(status) + } +} + +#[cfg(test)] +mod tests { + use proptest::prelude::*; + use rtc_types::enclave_messages::RecommendedAesGcmIv; + use sgx_types::sgx_aes_gcm_128bit_tag_t; + + use super::test_helpers::*; + use super::*; + + /// Roundtrip [`rkyv_seal_associated`] / [`rkyv_unseal_associated`] + #[test] + fn test_seal_unseal_associated_roundtrip() { + let test = |key: [u8; 16], message: &DummyMessage, associated: &DummyAssociated| { + let channel = &mut make_channel(key); + + let sealed = rkyv_seal_associated(channel, message, associated).unwrap(); + let (message2, associated2) = + &unsafe { rkyv_unseal_associated(channel, sealed) }.unwrap(); + assert_eq!(message, message2); + assert_eq!(associated, associated2); + }; + proptest!(|(key: [u8; 16], message: DummyMessage, associated: DummyAssociated)| test(key, &message, &associated)); + } + + /// Roundtrip [`rkyv_seal`] / [`rkyv_unseal`] + #[test] + fn test_seal_unseal_roundtrip() { + let test = |key: [u8; 16], message: &DummyMessage| { + let channel = &mut make_channel(key); + + let sealed = rkyv_seal(channel, message).unwrap(); + let message2 = &unsafe { rkyv_unseal(channel, sealed) }.unwrap(); + assert_eq!(message, message2); + }; + proptest!(|(key: [u8; 16], message: DummyMessage)| test(key, &message)); + } + + /// [`rkyv_seal_associated`] fails with zero-length message & associated data + #[test] + fn test_seal_associated_zero_length() { + let test = |key: [u8; 16]| { + let channel = &mut make_channel(key); + let message = &DummyEmpty; + let associated = &DummyEmpty; + + let err = rkyv_seal_associated::(channel, message, associated) + .unwrap_err(); + assert_eq!(format!("{:?}", err), "Sgx(SGX_ERROR_INVALID_PARAMETER)"); + }; + proptest!(|(key: [u8; 16])| test(key)); + } + + /// [`rkyv_seal`] fails with zero-length message + #[test] + fn test_seal_zero_length() { + let test = |key: [u8; 16]| { + let channel = &mut make_channel(key); + let message = &DummyEmpty; + + let err = rkyv_seal::(channel, message).unwrap_err(); + assert_eq!(format!("{:?}", err), "Sgx(SGX_ERROR_INVALID_PARAMETER)"); + }; + proptest!(|(key: [u8; 16])| test(key)); + } + + /// [`rkyv_unseal_associated`] fails with wrong channel + #[test] + fn test_unseal_associated_wrong_channel() { + let test = |key1: [u8; 16], + key2: [u8; 16], + message: &DummyMessage, + associated: &DummyAssociated| { + let channel1 = &mut make_channel(key1); + let channel2 = &mut make_channel(key2); + + let sealed = rkyv_seal_associated(channel1, message, associated).unwrap(); + let err = unsafe { + rkyv_unseal_associated::(channel2, sealed) + } + .unwrap_err(); + assert_eq!(format!("{:?}", err), "Sgx(SGX_ERROR_MAC_MISMATCH)"); + }; + proptest!(|(key1: [u8; 16], key2: [u8; 16], message: DummyMessage, associated: DummyAssociated)| { + prop_assume!(key1 != key2); + test(key1, key2, &message, &associated); + }); + } + + /// [`rkyv_unseal`] fails with wrong channel + #[test] + fn test_unseal_wrong_channel() { + let test = |key1: [u8; 16], key2: [u8; 16], message: &DummyMessage| { + let channel1 = &mut make_channel(key1); + let channel2 = &mut make_channel(key2); + + let sealed = rkyv_seal(channel1, message).unwrap(); + let err = unsafe { rkyv_unseal::(channel2, sealed) }.unwrap_err(); + assert_eq!(format!("{:?}", err), "Sgx(SGX_ERROR_MAC_MISMATCH)"); + }; + proptest!(|(key1: [u8; 16], key2: [u8; 16], message: DummyMessage)| { + prop_assume!(key1 != key2); + test(key1, key2, &message); + }); + } + + /// [`rkyv_unseal_associated`] fails with a tampered MAC tag + #[test] + fn test_unseal_associated_tampered_tag() { + let test = |key: [u8; 16], + tampered_tag: sgx_aes_gcm_128bit_tag_t, + message: &DummyMessage, + associated: &DummyAssociated| + -> Result<_, _> { + let channel = &mut make_channel(key); + + let mut sealed = rkyv_seal_associated(channel, message, associated).unwrap(); + prop_assume!(sealed.tag != tampered_tag); + sealed.tag = tampered_tag; + + let err = + unsafe { rkyv_unseal_associated::(channel, sealed) } + .unwrap_err(); + assert_eq!(format!("{:?}", err), "Sgx(SGX_ERROR_MAC_MISMATCH)"); + Ok(()) + }; + proptest!(|(key: [u8; 16], tampered_tag: sgx_aes_gcm_128bit_tag_t, message: DummyMessage, associated: DummyAssociated)| { + test(key, tampered_tag, &message, &associated)?; + }); + } + + /// [`rkyv_unseal`] fails with a tampered MAC tag + #[test] + fn test_unseal_tampered_tag() { + let test = |key: [u8; 16], + tampered_tag: sgx_aes_gcm_128bit_tag_t, + message: &DummyMessage| + -> Result<_, _> { + let channel = &mut make_channel(key); + + let mut sealed = rkyv_seal(channel, message).unwrap(); + prop_assume!(sealed.tag != tampered_tag); + sealed.tag = tampered_tag; + + let err = unsafe { rkyv_unseal::(channel, sealed) }.unwrap_err(); + assert_eq!(format!("{:?}", err), "Sgx(SGX_ERROR_MAC_MISMATCH)"); + Ok(()) + }; + proptest!(|(key: [u8; 16], tampered_tag: sgx_aes_gcm_128bit_tag_t, message: DummyMessage)| { + test(key, tampered_tag, &message)?; + }); + } + + /// [`rkyv_unseal_associated`] fails with a tampered nonce + #[test] + fn test_unseal_associated_tampered_nonce() { + let test = |key: [u8; 16], + tampered_nonce: RecommendedAesGcmIv, + message: &DummyMessage, + associated: &DummyAssociated| + -> Result<_, _> { + let channel = &mut make_channel(key); + + let mut sealed = rkyv_seal_associated(channel, message, associated).unwrap(); + prop_assume!(sealed.nonce != tampered_nonce); + sealed.nonce = tampered_nonce; + + let err = + unsafe { rkyv_unseal_associated::(channel, sealed) } + .unwrap_err(); + assert_eq!(format!("{:?}", err), "Sgx(SGX_ERROR_MAC_MISMATCH)"); + Ok(()) + }; + proptest!(|(key: [u8; 16], tampered_nonce: RecommendedAesGcmIv, message: DummyMessage, associated: DummyAssociated)| { + test(key, tampered_nonce, &message, &associated)?; + }); + } + + /// [`rkyv_unseal`] fails with a tampered nonce + #[test] + fn test_unseal_tampered_nonce() { + let test = |key: [u8; 16], + tampered_nonce: RecommendedAesGcmIv, + message: &DummyMessage| + -> Result<_, _> { + let channel = &mut make_channel(key); + + let mut sealed = rkyv_seal(channel, message).unwrap(); + prop_assume!(sealed.nonce != tampered_nonce); + sealed.nonce = tampered_nonce; + + let err = unsafe { rkyv_unseal::(channel, sealed) }.unwrap_err(); + assert_eq!(format!("{:?}", err), "Sgx(SGX_ERROR_MAC_MISMATCH)"); + Ok(()) + }; + proptest!(|(key: [u8; 16], tampered_nonce: RecommendedAesGcmIv, message: DummyMessage)| { + test(key, tampered_nonce, &message)?; + }); + } + + /// [`rkyv_unseal_associated`] fails with tampered associated data + #[test] + fn test_unseal_associated_tampered_aad() { + const AAD_SIZE: usize = size_of::(); + + let test = |key: [u8; 16], + tampered_aad: [u8; AAD_SIZE], + message: &DummyMessage, + associated: &DummyAssociated| { + let channel = &mut make_channel(key); + + let mut sealed = rkyv_seal_associated(channel, message, associated).unwrap(); + sealed.aad = tampered_aad; + + let err = + unsafe { rkyv_unseal_associated::(channel, sealed) } + .unwrap_err(); + assert_eq!(format!("{:?}", err), "Sgx(SGX_ERROR_MAC_MISMATCH)"); + }; + proptest!(|(key: [u8; 16], tampered_aad: [u8; AAD_SIZE], message: DummyMessage, associated: DummyAssociated)| { + let expected_aad = rkyv_format::write_array(&associated).unwrap(); + prop_assume!(expected_aad != tampered_aad); + test(key, tampered_aad, &message, &associated); + }); + } +} + +/// Supporting structs and code for the tests. +#[cfg(test)] +pub(crate) mod test_helpers { + use proptest_derive::Arbitrary; + use rkyv::{Archive, Deserialize, Serialize}; + use sgx_types::sgx_align_key_128bit_t; + + use crate::dh::types::AlignedKey; + use crate::dh::ProtectedChannel; + + #[derive(Clone, Debug, PartialEq)] // core + #[derive(Archive, Deserialize, Serialize)] // rkyv + #[derive(Arbitrary)] // proptest + pub struct DummyMessage { + code: u32, + message: [u8; 16], + } + + #[derive(Clone, Debug, PartialEq)] // core + #[derive(Archive, Deserialize, Serialize)] // rkyv + #[derive(Arbitrary)] // proptest + pub struct DummyAssociated { + flags: u8, + data: [u8; 8], + } + + #[derive(Clone, Debug, PartialEq)] // core + #[derive(Archive, Deserialize, Serialize)] // rkyv + pub struct DummyEmpty; + + /// Helper: Make a channel with the given key. + pub fn make_channel(key: [u8; 16]) -> ProtectedChannel { + let mut aligned_key = sgx_align_key_128bit_t::default(); + aligned_key.key = key; + ProtectedChannel::init(AlignedKey::new(aligned_key)) + } +} From 11124e129b7edf4f52ac4dcc59ca74aef0821f4f Mon Sep 17 00:00:00 2001 From: Pi Delport Date: Wed, 16 Jun 2021 17:09:43 +0200 Subject: [PATCH 7/7] feat(rtc_tenclave::dh::sealing): add rkyv_peek_associated helper --- rtc_tenclave/src/dh/sealing.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/rtc_tenclave/src/dh/sealing.rs b/rtc_tenclave/src/dh/sealing.rs index 7ee522f9..2e5ec6c4 100644 --- a/rtc_tenclave/src/dh/sealing.rs +++ b/rtc_tenclave/src/dh/sealing.rs @@ -87,6 +87,26 @@ where Ok(unsealed) } +/// Peek at a sealed message's associated data, without authenticating it. +/// +/// # Safety +/// +/// Callers must ensure that the sealed message contains valid serialized data, +/// to avoid undefined behaviour during deserialization. +/// +/// See: [`rkyv_format::view_array`] +pub unsafe fn rkyv_peek_associated( + sealed: &EncryptedEnclaveMessage<{ size_of::() }, { size_of::() }>, +) -> &A::Archived +where + T: Archive, + T::Archived: Deserialize, + A: Archive, + A::Archived: Deserialize, +{ + unsafe { rkyv_format::view_array::(&sealed.aad) } +} + #[derive(Debug)] pub enum SealingError { Rkyv(BufferSerializerError),