Skip to content
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

Add U and V key handlers, and decrypt + run payload #197

Merged
merged 6 commits into from
Jul 13, 2021

Conversation

lkatalin
Copy link
Contributor

@lkatalin lkatalin commented Jun 7, 2021

  • I'll need to figure out how to avoid using
#![feature(string_remove_matches)]
#![feature(mutex_unlock)]

in order for CI to pass as these are unstable features. The former should be easy, the latter maybe not so much.

  • There are a few details still to fill in re: running the decrypted payload, checking if it's a zip file, etc.
    The decrypted payload appears to be the excludes list; there is no autorun.sh sent.

Resolves #97
Resolves #203
Resolves #221
Resolves #226
Resolves #202
Resolves #99

let (iv, rest) = payload.split_at(AES_BLOCK_SIZE);
let (ciphertext, tag) = rest.split_at(rest.len() - AES_BLOCK_SIZE);

// note: it's unclear in the python codebase whether this is AES 128, but 128 seems
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, you could just automatically derive the Cipher value.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I'm pretty sure that for cryptography, the default depends on the length of the key.

Copy link
Member

@puiterwijk puiterwijk Jun 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Also, given the fact that ukey, vkey and sym_key are 32 bytes, that means that this is 256 bit AES.)

// to be the default
// https://cryptography.io/en/latest/hazmat/primitives/symmetric-encryption/#symmetric-encryption-modes
decrypt_aead(
Cipher::aes_128_gcm(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Cipher::aes_128_gcm(),
match symm_key.len() {
16 => Cipher::aes_128_gcm(),
32 => Cipher::aes_256_gcm(),
_ => return Err(....),
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Terrific idea.


use crate::{error::Error, QuoteData};

// This value comes from and must match the Python codebase
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a better reference for this constant could be FIPS 197, Introduction: This standard specifies the Rijndael algorithm ([3] and [4]), a symmetric block cipher that can process data blocks of 128 bits, .... (128 bits / 8 bits-per-byte gives you 16)

This comment was marked as outdated.

Cipher::aes_128_gcm(),
symm_key,
Some(iv),
&[0u8], // todo: check that we don't need additional auth data here?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no additional data: that would be a call like encryptor.authenticate_additional_data(associated_data) in the encrypt function, or decryptor.authenticate_additional_data(authenticated_data) in decrypt.

)
}

pub(crate) unsafe fn try_combine_keys() -> bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the unsafe stuff makes me feel a bit worried. Would it be a possibility to put this data as a fully locked struct field in the overall HTTP state?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I've put this in the app_data now.

@lkatalin lkatalin force-pushed the keyshandler branch 3 times, most recently from a22749d to 44cd92c Compare July 5, 2021 04:00
@lkatalin lkatalin marked this pull request as ready for review July 5, 2021 05:06
@lkatalin lkatalin requested a review from puiterwijk July 5, 2021 05:20
@lkatalin lkatalin changed the title Add U and V key handlers Add U and V key handlers, and decrypt + run payload Jul 5, 2021
@lkatalin lkatalin force-pushed the keyshandler branch 5 times, most recently from 46b48d4 to 121185c Compare July 8, 2021 22:12
@lkatalin
Copy link
Contributor Author

lkatalin commented Jul 8, 2021

@puiterwijk @lukehinds @ashcrow This is updated, I'm able to run a small script with it. Still having the problem referenced in #202 but that is the fail point right now after the payload script runs.

@lkatalin lkatalin force-pushed the keyshandler branch 3 times, most recently from dbe7019 to e6af73a Compare July 9, 2021 20:07
@lkatalin
Copy link
Contributor Author

lkatalin commented Jul 9, 2021

I can also split these commits out into their own PRs if that makes it easier to review; just let me know.

@lkatalin lkatalin added the critical must fix for rust agent release label Jul 9, 2021
@lkatalin lkatalin force-pushed the keyshandler branch 2 times, most recently from 3ab0bb5 to 56a32bd Compare July 12, 2021 14:09
@lkatalin
Copy link
Contributor Author

lkatalin commented Jul 12, 2021

@puiterwijk @lukehinds @ashcrow This is updated, I'm able to run a small script with it. Still having the problem referenced in #202 but that is the fail point right now after the payload script runs.

Happy to say #202 is fixed now in this PR. To use the revocation feature and ensure that the revocation certificate is sent correctly, you must run the tenant with the following command (example directory and script shown here):

[root@localhost ~]# ls /root/senddir/
autorun.sh

[root@localhost ~]# keylime_tenant -v 127.0.0.1 -t 127.0.0.1 --uuid d432fbb3-d2f1-4a97-9ef7-75bd81c00000 
--allowlist /root/allowlist.txt --include /root/senddir --cert /root/ca --exclude /root/excludes.txt -c add

... where autorun.sh is any script you want for testing. You must also ensure that the following values are set in /etc/keylime.conf:

[cloud_agent]
...
extract_payload_zip = True
...
listen_notfications = True
...
payload_script=autorun.sh

I'll include this in some documentation.

lkatalin and others added 3 commits July 12, 2021 11:09
The Python code manually forces the IMA PCR (PCR 10) to be added from the SHA1 bank,
even when that is not the bank used for the other PCRs. Because of the way it builds
up the list of PCRs to check, we must also do this the same way.

Signed-off-by: Lily Sturmann <[email protected]>
Co-authored-by: Patrick Uiterwijk <[email protected]>
src/main.rs Outdated
let zipped_payload = config_get("cloud_agent", "dec_payload_file")?;
info!("Unzipping payload {} to {}", zipped_payload, unzipped);

let mut status = Command::new("unzip")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is nothing wrong with this, though I do want to ask: Why use the system command instead of a library?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ashcrow I tried a library, but it was a bit more fiddly than I expected and this just worked. I suppose we could always update it on a second pass if we want to make some enhancements.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The zip_rs is not nice I agree, check out compress tools, I find it a lot simpler https://crates.io/crates/compress-tools

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lukehinds Sure will do, I can push a new version of that commit if I get that working.

Copy link
Contributor Author

@lkatalin lkatalin Jul 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The library seems straightforward, but I keep getting

 INFO  keylime_agent > Unzipping payload decrypted_payload.zip to /tmp/secure/unzipped
Error: Io(Os { code: 2, kind: NotFound, message: "No such file or directory" })

Despite

[keylime-ima@localhost rust-keylime]$ ls /tmp/secure/unzipped/
decrypted_payload.zip  derived_tci_key
[keylime-ima@localhost rust-keylime]$ file /tmp/secure/unzipped/decrypted_payload.zip 
/tmp/secure/unzipped/decrypted_payload.zip: Zip archive data, at least v2.0 to extract
[keylime-ima@localhost rust-keylime]$ ls -la /tmp/secure/unzipped/decrypted_payload.zip 
-rw-r--r--. 1 root root 8738 Jul 12 14:02 /tmp/secure/unzipped/decrypted_payload.zip

The code:

let zipped_payload = config_get("cloud_agent", "dec_payload_file")?;
        info!("Unzipping payload {} to {}", &zipped_payload, &unzipped);

        let mut source = fs::File::open(&zipped_payload)?;    
        assert!(Path::new(&zipped_payload).exists());

        let dest = Path::new(&unzipped);
        assert!(Path::new(&dest).exists());

        let file_list = list_archive_files(&mut source).expect("failed to list files");
        info!("File list: {:?}", file_list);

        uncompress_archive(&mut source, &dest, Ownership::Ignore).expect("failed to unzip");

Still debugging...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, it worked with a test example so it should be doable here shortly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It says it succeeds, but then the unzipped files aren't there. All I can think of is maybe it isn't opening with the correct permissions, as it's apparently r only. This should be easy to update but for some reason is not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured out the error... apparently compress_tools::list_archive_files mutates the src archive you give it so that there are no files left afterwards. Bizarre!

Copy link
Contributor

@ashcrow ashcrow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question but overall 👍

@lukehinds
Copy link
Member

This LGTM, would you like me to test again first thing tomorrow @lkatalin ?

@lkatalin
Copy link
Contributor Author

Thanks @ashcrow and @lukehinds !

@lukehinds Thanks for the offer - if you test again with this branch, you will get the same intermittent quote error we saw at the end of last week. I bypassed that to test the U/V key handling behavior by setting the Python tpm2_checkquote function to return true so that I could at least build out the rest of the code following the quote check. So if you want to test the code in this branch, I could send you a branch of the Python code that I use for testing the interaction. If you want to test the whole system, we will need to fix the intermittent quote error first. I am about to give that a go, but could use help, as it seems to be esoteric TPM behavior.

@lkatalin lkatalin force-pushed the keyshandler branch 3 times, most recently from 996683c to 3f97775 Compare July 13, 2021 13:32
@lkatalin lkatalin requested a review from ashcrow July 13, 2021 13:45
@lkatalin
Copy link
Contributor Author

@ashcrow @lukehinds Updated to use a zip library!

@lkatalin lkatalin merged commit 4bb5ba8 into keylime:master Jul 13, 2021
@lkatalin lkatalin deleted the keyshandler branch July 16, 2021 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
critical must fix for rust agent release
Projects
None yet
4 participants