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

ek, ak abstractions: allow to specficy exact key type #546

Conversation

Superhepper
Copy link
Collaborator

@Superhepper Superhepper commented Sep 22, 2024

This adds support other keys than RSA2048 and ECC Nist P256.

This takes the following PRs and from the main
branch and adapts them so that they can be merged
into the 7.x.y branch:

#464 (By @ionut-arm )
#414 (By @THS-on )
#552 (By @THS-on )

@Superhepper
Copy link
Collaborator Author

I need to rebase it on #547
before it will pass all CI tests.

wiktor-k
wiktor-k previously approved these changes Sep 23, 2024
Copy link
Collaborator

@wiktor-k wiktor-k left a comment

Choose a reason for hiding this comment

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

Looks good. 👍

@THS-on could you review if this solves your use case reported in #414 (comment) ? 👋

@Superhepper Superhepper force-pushed the 7.x.y-allow-to-specify-exact-key-type branch from 9c5eea2 to b51ce33 Compare September 25, 2024 07:47
@Superhepper Superhepper marked this pull request as ready for review September 25, 2024 07:48
@Superhepper Superhepper force-pushed the 7.x.y-allow-to-specify-exact-key-type branch from b51ce33 to b4cdbda Compare September 25, 2024 07:55
@THS-on
Copy link
Contributor

THS-on commented Sep 27, 2024

@Superhepper I'll develop try to develop the fix for this issue against this branch and will report back. Thanks for backporting it!

@THS-on
Copy link
Contributor

THS-on commented Oct 1, 2024

When using create_ak(), I get:

ECC unique identifier have not been set in the Public Builder even though the ECC algorithm have been selected. Consider using: .with_ecc_unique_identifier(&EccPoint::default())

Can we just add this to the create_ak_public() function or does this need to be customizable?

@Superhepper
Copy link
Collaborator Author

been selected. Consider using: .with_ecc_unique_identifier(&EccPoint

Nah, I think it can be added. It has been added in the main branch probably just me who missed it. And the customization would work anyway. Because you can just overwrite it using the key customization.

@Superhepper Superhepper force-pushed the 7.x.y-allow-to-specify-exact-key-type branch 3 times, most recently from 9d306a0 to b5601bc Compare October 2, 2024 09:25
@Superhepper
Copy link
Collaborator Author

Now, I just need to figure out why these changes made the tests fail on Fedora ..

@Superhepper Superhepper force-pushed the 7.x.y-allow-to-specify-exact-key-type branch from b5601bc to 0984f34 Compare October 2, 2024 11:37
@THS-on
Copy link
Contributor

THS-on commented Oct 3, 2024

@Superhepper for reference, this is probably the change that we then also want to fully backport: #464

@Superhepper
Copy link
Collaborator Author

@Superhepper for reference, this is probably the change that we then also want to fully backport: #464

I will try to add that as well.

@Superhepper Superhepper force-pushed the 7.x.y-allow-to-specify-exact-key-type branch 3 times, most recently from 01ac482 to 1e8633f Compare October 4, 2024 18:56
@Superhepper
Copy link
Collaborator Author

@THS-on If you missed it this PR has now been updated with the requested changes so it should work better now I hope. Please try it out.

@THS-on
Copy link
Contributor

THS-on commented Oct 15, 2024

It now seems to work, but I get a miss match between the EK generated and in the EK cert on the Keylime verifier side. Still need to check where this actually goes wrong, somewhere between rust-tss-esapi, agent and verifier (which implements its own parser for TPM data structures). Once I checked that its not in rust-tss-esapi this PR can be merged 👍

@THS-on
Copy link
Contributor

THS-on commented Oct 16, 2024

I tried to write a simple example to compare the generated key with the one in the certificate, but I cannot figure out why it doesn't find the TryFrom for SubjectPublicKeyInfo. Which is kinda weird as in the Keylime codebase it just works.

use std::convert::TryFrom;
use picky_asn1_x509::SubjectPublicKeyInfo;
use tss_esapi::{abstraction::{ek, AsymmetricAlgorithmSelection, DefaultKey}, interface_types, Context, TctiNameConf};


fn main() {
    let tcti_name_conf = TctiNameConf::from_environment_variable().expect("Failed to get TCTI");
    let mut ctx = Context::new(tcti_name_conf).expect("Failed to init context");
    let ek = ek::create_ek_object(&mut ctx, AsymmetricAlgorithmSelection::Ecc(interface_types::ecc::EccCurve::NistP384), DefaultKey).unwrap(); 
    let (ekpub, _, _) = ctx.read_public(ek).unwrap();
    // Here it does not find the trait implementation
    let key = SubjectPublicKeyInfo::try_from(ekpub).unwrap();

    let res = ek::retrieve_ek_pubcert(&mut ctx, AsymmetricAlgorithmSelection::Ecc(interface_types::ecc::EccCurve::NistP384)).expect("Failed to get ECC Cert");
    print!("Data {:#?}", res);
}

@Superhepper
Copy link
Collaborator Author

I think you have jus

I tried to write a simple example to compare the generated key with the one in the certificate, but I cannot figure out why it doesn't find the TryFrom for SubjectPublicKeyInfo. Which is kinda weird as in the Keylime codebase it just works.

use std::convert::TryFrom;
use picky_asn1_x509::SubjectPublicKeyInfo;
use tss_esapi::{abstraction::{ek, AsymmetricAlgorithmSelection, DefaultKey}, interface_types, Context, TctiNameConf};


fn main() {
    let tcti_name_conf = TctiNameConf::from_environment_variable().expect("Failed to get TCTI");
    let mut ctx = Context::new(tcti_name_conf).expect("Failed to init context");
    let ek = ek::create_ek_object(&mut ctx, AsymmetricAlgorithmSelection::Ecc(interface_types::ecc::EccCurve::NistP384), DefaultKey).unwrap(); 
    let (ekpub, _, _) = ctx.read_public(ek).unwrap();
    // Here it does not find the trait implementation
    let key = SubjectPublicKeyInfo::try_from(ekpub).unwrap();

    let res = ek::retrieve_ek_pubcert(&mut ctx, AsymmetricAlgorithmSelection::Ecc(interface_types::ecc::EccCurve::NistP384)).expect("Failed to get ECC Cert");
    print!("Data {:#?}", res);
}

I just think you have forgotten to add picky-asn1-x509 = "0.12.0" as dependency in the Cargo.toml.

@THS-on
Copy link
Contributor

THS-on commented Oct 17, 2024

Edit: issue seems to be somewhere in tss-esapi

Old:

I just think you have forgotten to add picky-asn1-x509 = "0.12.0" as dependency in the Cargo.toml.

Thanks for the hint. I've added version "0.13.0", which then didn't work. I can confirm that the issue is somewhere on > the Keylime side, so this can be merged. Thank you for backporting this!

@THS-on
Copy link
Contributor

THS-on commented Oct 17, 2024

In my test script I only compared the bits and not the fully key. There seems to be still an issue in tss-esapi.

Reproducer

use openssl::pkey::PKey;
use picky_asn1_x509::SubjectPublicKeyInfo;
use tss_esapi::{abstraction::{ek, AsymmetricAlgorithmSelection, DefaultKey}, interface_types, Context, TctiNameConf};

use tss_esapi::structures::Public;

fn main() {
    let tcti_name_conf = TctiNameConf::from_environment_variable().expect("Failed to get TCTI");
    let mut ctx = Context::new(tcti_name_conf).expect("Failed to init context");
    let ek = ek::create_ek_object(&mut ctx, AsymmetricAlgorithmSelection::Ecc(interface_types::ecc::EccCurve::NistP384), DefaultKey).unwrap(); 
    let (ekpub, _, _): (Public, _, _ )= ctx.read_public(ek).unwrap();
    let key =  PKey::public_key_from_der(&picky_asn1_der::to_vec(&SubjectPublicKeyInfo::try_from(ekpub).unwrap()).unwrap()).unwrap();

    let nv_cert = ek::retrieve_ek_pubcert(&mut ctx, AsymmetricAlgorithmSelection::Ecc(interface_types::ecc::EccCurve::NistP384)).expect("Failed to get ECC Cert");
    let cert = openssl::x509::X509::from_der(&nv_cert).expect("Failed to parse EK cert");
    if key.public_eq(&cert.public_key().unwrap()){
        println!("Equal");
    }
}

Cargo.toml

[package]
name = "minimal-read-ek"
version = "0.1.0"
edition = "2021"


[dependencies]
picky-asn1-x509 = "0.12.0"
picky-asn1-der = "0.4"
openssl = "0.10.15"
tss-esapi = { git = "https://github.com/parallaxsecond/rust-tss-esapi.git", rev = "refs/pull/546/head" }

Tested with libvrit VM using swtpm version 0.8.2.

Validation that the EK and EK certificate actually match using tpm2-tools:

tpm2_nvread 0x1c00016 | openssl x509 -noout -pubkey | sha256sum
tpm2_createek -G ecc384 -u ek.pub -f pem -c ek.ctx
sha256sum ek.pub

@THS-on
Copy link
Contributor

THS-on commented Oct 17, 2024

Found the issue. The hashAlg and authPolicy are different for each ECC curve (e.g. section B.4.6 of https://trustedcomputinggroup.org/wp-content/uploads/TCG-EK-Credential-Profile-V-2.5-R2_published.pdf). We hard code them to sha256.

I'll create a PR probably next week that fixes this in the main branch that we then can backport.

@THS-on
Copy link
Contributor

THS-on commented Oct 21, 2024

Changes are implemented in #552

@Superhepper
Copy link
Collaborator Author

I will add the changes #552 to this PR when I got the time.

This takes the following PRs and from the main
branch and adapts them so that they can be merged
into the 7.x.y branch:

\parallaxsecond#464 (By Ionut Mihalcea <[email protected]>)
\parallaxsecond#414 (By Thore Sommer <[email protected]>)
\parallaxsecond#552 (By Thore Sommer <[email protected]>)

Co-authored-by: Jesper Brynolf <[email protected]>
Co-authored-by: Thore Sommer <[email protected]>
Co-authored-by: Ionut Mihalcea <[email protected]>
Signed-off-by: Jesper Brynolf <[email protected]>
@Superhepper Superhepper force-pushed the 7.x.y-allow-to-specify-exact-key-type branch from 1e8633f to 7c4dcee Compare November 7, 2024 20:08
@Superhepper
Copy link
Collaborator Author

@THS-on I have added your latest patch this one so please try it out again.

@THS-on
Copy link
Contributor

THS-on commented Nov 8, 2024

@Superhepper currently fails with the following in Keylime:

Nov 08 08:14:04 localhost.localdomain keylime_agent[6588]: WARNING:esys:src/tss2-esys/api/Esys_ActivateCredential.c:321:Esys_ActivateCredential_Finish() Received TPM Error
Nov 08 08:14:04 localhost.localdomain keylime_agent[6588]: ERROR:esys:src/tss2-esys/api/Esys_ActivateCredential.c:105:Esys_ActivateCredential() Esys Finish ErrorCode (0x00000a9d)
Nov 08 08:14:04 localhost.localdomain keylime_agent[6588]: Error: Tpm(Tss2 { err: Tss2Error(FormatOne(FormatOneResponseCode { .0: 2717, error_number: 29, parameter: false, format_selector: true, number: 10 })), kind: Some(PolicyFail), message: "a policy check failed (associated with session number 2)" })

I'll try to build a minimal reproducer.

@Superhepper
Copy link
Collaborator Author

I will make a more thorough check to see if I messed something up when I added the latest commit yesterday.

@ionut-arm
Copy link
Member

@THS-on - if you can share the code you used to get the above error, that would be good enough too.

@THS-on
Copy link
Contributor

THS-on commented Nov 9, 2024

@Superhepper @ionut-arm sorry for the noise regarding this one. It has nothing to do with the rust bindings itself.

Also for activate credential we need to set the policy accordingly for the upper profiles, we are currently are not: https://github.com/keylime/rust-keylime/blob/a3bfd5aa2c3ecea078ac0262821c3878cbdc8b94/keylime/src/tpm.rs#L1205

Copy link
Member

@ionut-arm ionut-arm left a comment

Choose a reason for hiding this comment

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

💯

Comment on lines +135 to +146
EccCurve::NistP256 => (
HashingAlgorithm::Sha256,
Digest::try_from(AUTH_POLICY_A_SHA256.as_slice())?,
SymmetricDefinitionObject::AES_128_CFB,
32,
),
EccCurve::NistP384 => (
HashingAlgorithm::Sha384,
Digest::try_from(AUTH_POLICY_B_SHA384.as_slice())?,
SymmetricDefinitionObject::AES_256_CFB,
0,
),
Copy link
Member

Choose a reason for hiding this comment

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

We seem to cover PolicyA for P256 and PolicyB for P384+. What about PolicyB for P256 (and also RSA 2048)?

cc @THS-on

Copy link
Contributor

Choose a reason for hiding this comment

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

P256 and RSA 2048 are the default algorithms in the lower profile which uses PolicyA. Technically also a higher profile exists for them using PolicyB, but we have no way knowing which to pick based on the key size/curve alone.

This mimics the behavior also found in tpm2-tools

Copy link
Contributor

@THS-on THS-on left a comment

Choose a reason for hiding this comment

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

Updated Keylime to set the correct policy for authorizing the EK (might make sense to put this also in as an abstraction in the future).

Now everything seems to work. LGTM! @Superhepper thanks for backporting it!

@Superhepper Superhepper merged commit 9c7d580 into parallaxsecond:7.x.y Nov 12, 2024
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants