apache / incubator-teaclave-sgx-sdk

Apache Teaclave (incubating) SGX SDK helps developers to write Intel SGX applications in the Rust programming language, and also known as Rust SGX SDK.
https://teaclave.apache.org
Apache License 2.0
1.17k stars 263 forks source link

Sealing struct containing Vec<> #69

Closed matthias-g closed 5 years ago

matthias-g commented 5 years ago

How can I use seal_data for a struct containing a Vec? Starting from the sample sealeddata: If I add a field containing a Vec to RandData, I don't understand how to seal the struct then, because Vec does not implement Copy:

#[derive(Copy, Clone, Default, Debug)]
struct RandData {
    key: u32,
    rand: [u8; 16],
    vec: Vec<u8>,
}
error[E0204]: the trait `Copy` may not be implemented for this type
  --> src/lib.rs:48:10
   |
48 | #[derive(Copy, Clone, Default, Debug)]
   |          ^^^^
...
52 |     vec: Vec<u8>
   |     ------------ this field does not implement `Copy`

An idea was to use corepack to serialize the struct. But this results in a Vec<u8> which does not really help. There is an implementation of SgxSealedData for [T] where T is Copy + ContiguousMemory, but none for &[T] which I could get from vec.as_slice().

Generally I don't understand, why the Copy trait is required. Can someone help me here?

dingelish commented 5 years ago

SGXAPI sgx_seal_data only supports linear buffer (identified by ptr+len).

So the seal+unseal combination performs a bit-by-bit copy of a linear buffer, which is equivalent to the definition of Copy.

The memory object of a Vec structure contains a pointer field. And this is the reason why we cannot duplicate a Vec by simply memcpy it.

I would recommend you use the ported serde for serialization and use serde_cbor for encoding. This combination would generate a byte string which is dense and friendly to sgx_seal_data.

elichai commented 5 years ago

Can't you just do this?

#[derive(Clone, Copy)]
struct A<'a> (pub &'a [u8]);
unsafe impl sgx_types::marker::ContiguousMemory for A {};

Then you can put a vec in there using: v.as_slice()/ v.into_boxed_slice / slice::from_raw_parts(s.as_ptr(), v.len())

matthias-g commented 5 years ago

Thanks for your replies! That helped me to get a better understanding of what happens here. However I can't get it working yet. To show you the problem, I adapted the sealeddata sample using a combination of your replies.

The app is terminated by signal SIGILL (Illegal instruction). This is probably because the data read during verify_sealeddata differs from the data written in create_sealeddata. In my case the first 32 bytes are different and the remaining are the same. Do you see where this difference comes from? How can this be implemented correctly?

dingelish commented 5 years ago

Hmmmm I just find that the fixed-length array works fine with your EncodedData

let a: [u8;4] = [0x11,0x22,0x33,0x44]

But Vec<u8> like this not working:

let b: Vec<u8> = vec![0x11,0x22,0x33,0x44]

I think there's something wrong with sgx_tseal when dealing with fat pointers.

dingelish commented 5 years ago

Sorry for the wrong answer. I just deleted it.

dingelish commented 5 years ago

seal_data function uses mem::size_of_val to get the buffer length:

let len = mem::size_of_val(encrypt_text);

len of the EncodedData is always 16 no matter how long the data is. I think this may be the problem.

dingelish commented 5 years ago
use std::mem;

#[derive(Clone, Copy)]
struct EncodedData<'a> (pub &'a [u8]);

impl<'a> From<&'a[u8]> for EncodedData<'a> {
    fn from(data: &'a[u8]) -> Self {
        EncodedData(data)
    }
}

fn main() {
    let a:[u8;20] = [0x11,0x22,0x33,0x44,0x11,0x22,0x33,0x44,0x11,0x22,0x33,0x44,0x11,0x22,0x33,0x44,0x11,0x22,0x33,0x44];
    let enc_a = EncodedData::from(&a[..]);
    println!("size_of_val of a = {}", mem::size_of_val(&a));    // 20
    println!("size_of_val of enc_a = {}", mem::size_of_val(&enc_a));    // 16
}

The current sgx_tseal can seal a but not enc_a. Hmmmm.

dingelish commented 5 years ago

So I think you can just put the output of serde_cbor (data stored in [u8]) to the data sealing API. No need for additional data structure such as EncodedData, which only contains an immutable reference.

dingelish commented 5 years ago

EncodedData seems to be a FatPtr<FatPtr<...>> and the sealing API only supports FatPtr<T> where T: Copy + ContiguousMemory.

matthias-g commented 5 years ago

Ok, thanks for looking into it. I removed EncodedData in #70 so that we now pass a slice with the output of serde_cbor to seal_data. However this does not compile because the necessary traits are not implemented for &[u8]. In seal.rs there is an implementation of SgxSealedData for T where T: Copy + ContiguousMemory and an implementation for [T] where T: Copy + ContiguousMemory. Maybe an implementation for slices is needed there as well?

matthias-g commented 5 years ago

Closing since new code sample shows how to implement this. https://github.com/baidu/rust-sgx-sdk/pull/70#issuecomment-488071572