-
Notifications
You must be signed in to change notification settings - Fork 209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The same MRENCLAVE for both trusted and protected files #513
Comments
I think the problem is that you have one server holding all PF keys, which then forwards those keys to different enclaves. If you do that, then it's also your job to make sure that the enclaves are valid. If all enclaves (i.e. the one holding all these keys and those that are running latter) are signed with the same key, then there is no problem - attacker doesn't have this signing key. If they are signed using different keys, then I think your scenario is insecure by design - you effectively allow running arbitrary code in enclaves which you then supply with secrets. Quoting your repo:
I definitely fail to see what the flaw is in Gramine. |
@AgentRX Let me see if I understand your attack scenario correctly.
Good run
Attack run
|
If the flows I outlined above are correct, then I think you need to harden the Secret Provisioning server. The main problem is that the Secret Provisioning server updates keys and sends keys as many times as it is asked to. In particular, the attacker uses the fact that he/she can request the key again and again, even if the key was changed in the meantime. So a simple defense against this attack would be a cryptographic nonce:
The attacker (Mallory) won't be able to guess the nonce at the pre-last step, where Alice sent her Of course, this needs some changes to Gramine's Secret Provisioning library. But changing this library is far better than changing Gramine's core source code. |
Instead of nonces I'd just require the application to sign the add-key request with the mrsigner key. This way only the owner of mrsigner key could modify the corresponding entries on the provisioning server. |
@dimakuv how does A and M have both the same |
@dimakuv Yep, your pipeline is right, but you missed some things:
In our architecture the server also reencrypt the applications and we have a solution idea:
|
Because M stole manifest file of A |
So I can send an arbitrary |
The main idea of malware is to get PFkey of A sending |
But why does your server allows anyone to change keys of other parties without verification? |
Unrelated to the current discussion of these attack scenarios: We had a meeting today where we discussed the idea of hashed + encrypted Protected Files. Gramine developers are fine with adding such a feature, with the following (preliminary) implementation details:
|
Our server like a task manager with upper level architecture. We simplified it just to show the problem. |
Good news. Will your team implement it or we can participate in developing? |
@dimakuv will Gramine support multikeys for different files in the new fs-mount scheme developed by Pawel (#358)? Because we reencrypt application and data with session key to avoid one of them to steal content of each other and also this allows them to work together. For example, we have NN speech recognition python in /run/index.py and speeches in /data/speechOne, /data/speechTwo etc. They all are encrypted by different keys but our server reencrypt them by session key. With the model of trusting/protected files that your suggested we can't reencrypt them and will need multiple PF keys supporting. But how we should combine it in manifest? Or mb new FS volumes will support different keys without changing manifest? |
But either it does accept, or it does not and M having enclave+signed manifest of A doesn't change anything. Besides manifest is assumed to be known to everyone (public), at least in our security model.
The support is already pending #504. Afaik it allows to set a key per mount (note you can just mount each file individually). |
Yes, manifest is opened and M can be run separately of the server (with PFKeyA) for example to make spoofing attack (it's not the replay attack).
Thank you |
Our team will implement it. Currently Pawel is working on the Protected Files rewrite (the new scheme that you mentioned), and Pawel will also add this feature as well. Our hope is that this feature will be useful for your scenarios. So if some design/implementation decisions are bad for your scenarios, please don't hesitate to ask. For example, please note that our current design is to hash the first 4KB of the encrypted file, and this hash is what is put in the manifest file. We hope this works for you.
Yes, as Borys mentioned, you can check #504. Each FS volume specifies a key name (e.g. |
@dimakuv sorry for the late reply
Of course, it's good feature but it won't update secret provisioning mechanism that we use, so it will need a time to implement this feature for secret provisioning (design and implement protocol, etc)
It could be great to allow use hash for unprotected files. Let me describe our logic:
If you allow to use unprotected hash for applications it will fit ideally for our solution. Otherwise in current situation we will need to regenerate manifest file with session MRSIGNER inside the trusted server. Of course when you support multiple protection keys with secret provisioning mechanism we'll simplify server solution just to return necessary keys and it will work correctly with your current decision. |
The main problem with this approach is that
This sounds like a reasonable solution. If I understand you correctly, your current implementation of the TEE server generates a new key and re-encrypts all Protected Files with this key, and then sends this key to the SGX enclave. But your future implementation of the TEE server will not generate the key but instead will get the key from the code/data provider and forward this key to the SGX enclave. Thus, there won't be any need to re-generate the manifest file, because |
Also this gives an oracle - given a plaintext (file) you can tell whether it matches the ciphertext. When hashing encrypted part, you wouldn't be able to tell if plaintext and ciphertext match. |
@dimakuv @boryspoplawski I got your point. So we're waiting you implement new mechanisms and integrate them in our solution. |
BTW thank you very much. We added some architecture features to increase whole solution protection. |
Hello. Is this feature not implemented yet? I couldn't find something similar in documentation and commits. |
@Villain88: Nope, it's not implemented yet (you can see that this issue is still open ;) ). |
Looking at this old thread again. I still don't think the scenario described by @AgentRX can only be solved by the encrypted-and-hashed files (i.e., the combination of Encrypted Files + Trusted Files, as we call them in Gramine). I'm missing the details of the proposed deployment and why e.g. hardening of the initial communication with the Secret Provisioning server is not enough. Nevertheless, I'd like to put here some of my notes. I still don't know if this is a good idea, and if this is actually helpful to anyone (possibly? the idea doesn't sound terrible to me)...
(What was meant by this is "calculate the hash over the decrypted file contents".) I think this part is actually trivial to implement:
I don't think it has any severe implications? We use AES in Encrypted/Protected Files in Gramine, and it's resistant to known-plaintext attacks: https://crypto.stackexchange.com/questions/1512/why-is-aes-resistant-to-known-plaintext-attacks/ |
Hardening of the initial communication with the Secret Provisioning server do not protect from TOCTOU attack. |
The main idea of our suggestion is to include critical protected files in the integrity checking. We thought a lot about possible vulnerabilities of our solution but haven't found it. May be your team could analyse it better.
Sha256 is a cryptographic hash and it's too hard to create dictionaries of "famous" files for it. I think the complexity of the task is not less then enumeration complexity but I could be wrong. |
But in that case the attacker won't know the key which the enclave uses, because it would only use the keys provisioned by a verified server? So, it won't be able to modify the encrypted file without being detected.
Being cryptographic or not is completely irrelevant here. You can create such directories as long as the function is deterministic and the output is big and +/- uniformly distributed, and the computation time is bearable.
In practice this whole "complexity" is just entering the hash into Google, which is exactly an example of such a dictionary. |
Quick note here: if we ask the user to add a unique salt, then we protect at least against rainbow tables. I envision it like this: To uniquify the file, the user will do smth like the Python script: import base64, hashlib, os
with open('my_file', 'rb') as f:
data = f.read()
salt = base64.b64encode(os.urandom(32))
hash = hashlib.sha256(salt + data).hexdigest()
print(f"salt: {salt}, hash: {hash}") |
No, please don't, this is just making the attack a bit slower/harder but doesn't really change anything. We just shouldn't hash the plaintext, it's a risky idea in general and I don't see a justification to implement it. |
Yes, after some additional thoughts and googling, I'm also leaning towards that this is simply unsafe and a broken crypto structure. I'm currently collecting opinions from other folks who are better at crypto then myself, but I also start to believe that The |
Encrypt-then-hash means changing the key will require a new manifest, right? If that's the case, the original problem may have an easier solution. Just use a "fingerprint" function and calculate fpA = fingerprint(pfkeyA). Write fpA to a text file and make it a protected file (which gets into MRENCLAVE). Then, after reading pfkeyA from the server, the common code always check fpA == fingerprint(pfkeyA). Then the attacker M won't be able to run his malicious script, because he doesn't have pfkeyA in the first place and the common code will refuse to decrypt his script. I'm no a crypto expert, so I'm not sure which fingerprint function is secure, but there are some options like sha512(key), KDF, etc. |
Can you really de-hash sha256? Is it really risk try to reverse crypto hash? PS. Just to remind - we speak about big files to run with different data |
In your specific case. But you want us to add this as a generic feature to Gramine, which various users will use differently on their data.
? See the discussion above, I think everything was explained there what exactly you can do when knowing the hash. |
I agree but encrypt-than-hash is not good solution too because you have to keep you encrypted data with the same key all time or you have to regenerate manifest. Also data couldn't be packed in this case.
I don't agree with the big dangerous of sha256 rainbow tables or brute forcing it but I have an idea to solve this problen: Can you use structure like this? So in this case you can use encryptedSalt and hash of plaintext XOR salt. |
What do you mean?
This doesn't change the amount of information leaked about the original file at all. Only makes the attack slower. |
You can't use compression for encrypted files. For example if you create tar.gz for the huge python solution it could be very useful to compress it. If you use protected files from the start they won't be compressed.
Also this case also doesn't fit for our solution because we generate session keys to re-encrypt files and will lose salt on this case. May be you can use sha512 but I think the rainbow tables is not about big files and it doesn't help in this cases. |
You always have to first compress and then encrypt, but how is this related to the discussion?
As said previously, rainbow tables are just speed optimization to reduce the cost of repeated attacks. |
Of course, you can first compress and then encrypt, but does the protected files mechanism support working from compressed files? If not, then it turns out that users will also need to come up with a solution to decompress files, am I right? Thats why this is relevant to the topic under discussion.
Could you describe the risk of attacking a configuration stored in a 256 byte long json file, for example? And how the rainbow tables will help in this case? |
"can" -> "have to". The other way just doesn't do anything.
No, why would it? It's a mechanism to encrypt application files, why would it compress them?
If you want your app to use compressed files, then just compress them and decompress in the app. If you want to propose a feature that Gramine compresses the mounted files and decompresses them on the fly then I'll be against this, it's the app role to do this, because it's the app which knows the file formats and how to compress them (e.g. if you work on images it's your app's role to pick the right image format and use it, making Gramine compress your BMPs into PNGs makes no sense). |
I created a PR that explores one way of encrypting-and-hashing files: #1390 |
Can you implement hash of source files as a separate option or think about how to bind the hash to the source file without being tied to encryption? I understand that it is not safe for very small files, but I have the following arguments:
|
@lejunzhu Could you expand on your comment:
In particular, what does it mean Also, if fpA would get into MRENCLAVE, then we are tied to this particular key ( |
Sorry, it should be "a trusted file" instead of protected.
Then my idea won't work. P.S. Later on this thread, the OP seems to want to decompress a tarball and its content as trusted files. IMO this won't work, because trusted files are read-only. |
Hello,
My name is Andrei Pogoreltsev,
I'm CTO of Super Protocol Team and we glad to use Gramine in our project. Thank you for the product you're developing!
So, we want to protect our clients application code which run inside TEE (enclave). The TEE hardware is not owned by application owners. To do it we want to use protected files mechanism by this way:
Prepare:
We separate "base image" with some entrypoint and the "application". For example we can use Python base image and run /entrypoint/start.py script at start. Base image is no need to be protected and can be reusable by different applications.
The application owner combine base image and the application together to create Gramine manifest and get mrenclave. Also the "/entrypoint/start.py" path is both trusted and protected file. The main idea - it allows to check application before run and be sure nobody replaced the code because Gramine can check trusted files based on manifest hashes.
After it we can protect (encrypt by pf files mechanism) application using some encryption key.
So the idea is simple:
Also, using the base image we can create different protected applications with different mrenclaves (see step 2)
To initialize Gramine PF encryption key we want to use Secret Provisioning mechanism which allows Gramine to get the key by connecting to our local server (which also runs inside enclave). The server attests enclave and send protection key matched to mrenclave.
One of using mechanism example:
The problem
The main problem is that Gramine doesn't check trusted file which also is protected:
https://github.com/gramineproject/gramine/blob/master/Pal/src/host/Linux-SGX/db_files.c#L112-L168
So in this case the intruder (for example hardware owner) can use his own malware to get other protected application encryption key by spoofing attack:
Prepare:
So now we have two protected applications with the same not encrypted base image and the same manifest but the applications are different
Using:
To solve the problem we suggest to check trusted files if they are also protected and prepared PR: https://github.com/Villain88/gramine/pull/1/files
Also you can get the attack example here: https://github.com/Villain88/gramine-pf-poc
The text was updated successfully, but these errors were encountered: