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

Implements TPM vendor check function #113

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
13 changes: 11 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,17 @@ static NOTFOUND: &[u8] = b"Not Found";

fn main() {
pretty_env_logger::init();
// Get a context to work with the TPM
let mut ctx = tpm::get_tpm2_ctx();
// Retreive the TPM Vendor, this allows us to warn if someone is using a
// Software TPM ("SW")
let tpm_vendor = match tpm::get_tpm_vendor() {
Ok(content) => content,
Err(e) => panic!("{:?}", e),
};
if tpm_vendor.contains("SW") {
warn!("INSECURE: Keylime is using a software TPM emulator rather than a real hardware TPM.");
warn!("INSECURE: The security of Keylime is NOT linked to a hardware root of trust.");
warn!("INSECURE: Only use Keylime in this mode for testing or debugging purposes.");
};

let cloudagent_ip =
config_get("/etc/keylime.conf", "cloud_agent", "cloudagent_ip");
Expand Down
73 changes: 71 additions & 2 deletions src/tpm.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
use std::collections::HashMap;
use std::str::FromStr;

use tss_esapi::constants::algorithm::HashingAlgorithm;
use tss_esapi::constants::tss as tss_constants;
use tss_esapi::constants::tss::*;
use tss_esapi::tss2_esys::{ESYS_TR, ESYS_TR_NONE, ESYS_TR_RH_OWNER};
use tss_esapi::Context;
use tss_esapi::Tcti;

fn int_to_str(num: u32) -> String {
Copy link
Contributor

Choose a reason for hiding this comment

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

Function name

This is really moving to a String rather than str

Suggested change
fn int_to_str(num: u32) -> String {
fn int_to_string(num: u32) -> String {

Possibly simpler implementation

fn int_to_string(num: u32) -> String {
    num.to_string()
}

Or directly using to_string() 😄

Copy link
Member

@puiterwijk puiterwijk Oct 6, 2020

Choose a reason for hiding this comment

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

Well, it's not really a standard integer-to-string operation. It's basically parsing every byte in a u32 (i.e. up to 4 bytes) as a different ascii character. Because that's how TPM does strings.

Copy link
Member

Choose a reason for hiding this comment

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

(Renaming to int_to_string is reasonable though)

let mut num = num;
let mut result = String::new();

loop {
let chr: u8 = (num & 0xFF) as u8;
num >>= 8;
if chr == 0 {
continue;
}
let chr = char::from(chr);
result.insert(0, chr);
if num == 0 {
break;
}
}
result
}

/*
* Input: None
* Return: Connection context
Expand All @@ -23,3 +42,53 @@ pub(crate) fn get_tpm2_ctx() -> Result<tss_esapi::Context, tss_esapi::Error> {
let tcti = Tcti::from_str(tcti_path)?;
unsafe { Context::new(tcti) }
}

/*
* Input: None
* Return:
* TPM Vendor Type
* tss_esapi::Error
*
* get_tpm_vendor will retrieve the type of TPM. This allows us
* to perform opertions, such as understand the host is using a
* software TPM as opposed to hardware TPM.
*/
pub fn get_tpm_vendor() -> Result<String, tss_esapi::Error> {
let mut ctx = get_tpm2_ctx()?;
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 you want to get the context in main() and pass that one through to here as &mut Context.


let mut allprops = HashMap::new();
let (capabs, more) = ctx.get_capabilities(
TPM2_CAP_TPM_PROPERTIES,
TPM2_PT_MANUFACTURER,
80,
)?;

if capabs.capability != TPM2_CAP_TPM_PROPERTIES {
panic!("Invalid property returned");
ashcrow marked this conversation as resolved.
Show resolved Hide resolved
}

// SAFETY: This is a C union, and Rust wants us to make sure we're using the correct one.
// We checked the returned capability type just above, so this should be fine.
unsafe {
for i in 0..capabs.data.tpmProperties.count {
let capab = capabs.data.tpmProperties.tpmProperty[i as usize];
allprops.insert(capab.property, capab.value);
}
}

let mut vend_strs: String = [
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: My brain turns to mush when I see many map/filter/etc.. statements on something. Consider adding a comment explaining what's going on here for folks like me 😆.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, sorry. Let me explain what's going on, so Luke can add comments.

This basically first uses a set of constants (TPM2_PT_VENDOR_STRING_{1,2,3,4}) as lookup indexes into allprops, to get all the values from there where they're set. After that, it removes the values that don't exist (is_some), removes the Option<_> wrappers (unwrap()), removes the items that are actually a value (i.e. != && 0), then puts the individual parts to a different through int_to_str to get a Vec<String> with the parts, and then makes a single string from them (.join("")).

Copy link
Member Author

Choose a reason for hiding this comment

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

I added comments. in time we can move this into a helper function (if they all need the some manipulation)

TPM2_PT_VENDOR_STRING_1,
TPM2_PT_VENDOR_STRING_2,
TPM2_PT_VENDOR_STRING_3,
TPM2_PT_VENDOR_STRING_4,
]
.iter()
.map(|propid| allprops.get(&propid))
.filter(|x| x.is_some())
.map(|x| x.unwrap())
.filter(|x| x != &&0)
.map(|x| int_to_str(*x))
.collect::<Vec<String>>()
.join("");
Ok(vend_strs.split_whitespace().collect())
}