GithubHelp home page GithubHelp logo

Comments (14)

amarochk avatar amarochk commented on July 24, 2024

The decrypted salt value is never returned from the TPM. It is used to generate session's symmetric key and then discarded. The salt itself is encrypted with an asymmetric key. Thus a MIM has no way to get access to the salt value.

from ms-tpm-20-ref.

mateoconlechuga avatar mateoconlechuga commented on July 24, 2024

Ah, I guess I completely misunderstood then. Thanks for the clarification!

from ms-tpm-20-ref.

mateoconlechuga avatar mateoconlechuga commented on July 24, 2024

Actually, I still think I am missing something. The encrypted salt has to be decrypted somehow on the CPU side. How does that happen?

from ms-tpm-20-ref.

amarochk avatar amarochk commented on July 24, 2024

It is the CPU that generates and asymmetrically encrypts the salt and sends it to the TPM. The CPU uses the salt on its side to produce the session key, and so does the TPM after decrypting it.

from ms-tpm-20-ref.

mateoconlechuga avatar mateoconlechuga commented on July 24, 2024

Okay, perhaps I need to be a little clearer with my concerns:

The CPU uses the salt on its side to produce the session key

Technically this is correct. However, the implementation obtains the salt value from the encrypted salt rather than using the actual salt value. This leads to a potential leak of the salt value across the bus because only the TPM contains the private information needed to decrypt the salt.

This is the issue that I am trying to point out.

In other implementations I have seen, there is a specific parameter TPM2B_MAX_BUFFER salt; in the StartAuthSession_In structure for just this reason.

from ms-tpm-20-ref.

amarochk avatar amarochk commented on July 24, 2024

If an adversary can get access to data read/written by the CPU from/to memory/coprocessors, then all bets are off, and the TPM session encryption cannot help anything, because the adversary will get access to any data returned by the TPM after they are eventually decrypted, or to any data sent to the TPM before they are encrypted.

If a local device hosting the TPM cannot be trusted at the point of time when a TPM communication needs to occur, then a remote entity has to establish a session and communicate with the TPM remotely. The only way to overcome the problem of a compromised CPU is to completely exclude it from the TPM command generation and TPM response interpretation - such compromised CPU can only be used as a transport means.

What do you mean when you mention "other implementations"? There is only one TPM 2.0 specification, and all implementations must be compliant with it. And what would be the use of sending an unencrypted salt value to/from the TPM anyway? The whole point is having a secret shared by both ends of the communication so that those two ends could generate identical symmetric key.

P.S.
The name 'salt' used by the TPM 2.0 spec is probably somewhat misguiding, because its most widely known usage is with symmetric block ciphers, where it is a public value. With TPM sessions it rather plays a role of a seed (that is a secret value). On the other hand a seed is often a sort of a root value for a key derivation process, while in StartAuthSession() it is more like a mix-in to a basic session key derivation process that works without this seed, too.

from ms-tpm-20-ref.

mateoconlechuga avatar mateoconlechuga commented on July 24, 2024

If an adversary can get access to data read/written by the CPU from/to memory/coprocessors, then all bets are off, and the TPM session encryption cannot help anything, because the adversary will get access to any data returned by the TPM after they are eventually decrypted, or to any data sent to the TPM before they are encrypted.

Even if they can access the memory interface, it is theoretically more difficult especially if the memory and related buses are embedded as part of an FPGA. I'm not saying there are other attack vectors, but I am currently just trying to minimize the vectors related to the TPM. Other issues can be solved through inline memory encryption or similar.

What do you mean when you mention "other implementations"? There is only one TPM 2.0 specification, and all implementations must be compliant with it. And what would be the use of sending an unencrypted salt value to/from the TPM anyway?

Here's an example: https://github.com/tpm2-software/tpm2-tss/blob/master/test/integration/session-util.h#L20

I understand that I may be describing this poorly, but in order to secure the bus from an interposer, a decrypt/encrypt session is started using TPM2_StartAuthSession. The session key is derived in part from this salt, and if bound includes the respective authValue. The session's HMAC and
session encryption command/response keys are derived directly from the session key.

Therefore, if the interposer is able to get the salt value, they can act as a man in the middle and modify the HMAC, decrypt commands and responses sent across the bus, and other nefarious things. (assuming, as I said in the first post, that authValue is empty or known)

What I am trying to say is that the implementation is susceptible because the standard just says that salt is used in the session key derivation function. It does not say that it is okay to decrypt the salt using the TPM before the session has started.

from ms-tpm-20-ref.

DavidWooten avatar DavidWooten commented on July 24, 2024

from ms-tpm-20-ref.

mateoconlechuga avatar mateoconlechuga commented on July 24, 2024

Yes, CPU encrypts salt and sends it to the TPM, where the TPM decrypts and produces the session key.

My issue is the code I highlighted in the first section. This is where the CPU computes the identical session key. It uses the TPM to decrypt the encrypted salt! This is where an attacker can use the information sent across the bus to compute the session key, and as I've said before if the authValue is known or empty (as the spec says to use a salt if authValue is weak), then the attacker can compute the session key and thereby the HMAC and bus encryption keys.

imho, the salt value is already known on the CPU side. There is no point in encrypting it with the TPM public key, and then proceeding to decrypt it with the private key. In fact it's just weird.

from ms-tpm-20-ref.

DavidWooten avatar DavidWooten commented on July 24, 2024

from ms-tpm-20-ref.

mateoconlechuga avatar mateoconlechuga commented on July 24, 2024

@DavidWooten:

I don’t know what code you highlighted in the “first section.”

The very first comment of this issue, relevant code here:

if(in->tpmKey != TPM_RH_NULL)
{
// Get pointer to loaded decrypt key
tpmKey = HandleToObject(in->tpmKey);
// key must be asymmetric with its sensitive area loaded. Since this
// command does not require authorization, the presence of the sensitive
// area was not already checked as it is with most other commands that
// use the sensitive are so check it here
if(!CryptIsAsymAlgorithm(tpmKey->publicArea.type))
return TPM_RCS_KEY + RC_StartAuthSession_tpmKey;
// secret size cannot be 0
if(in->encryptedSalt.t.size == 0)
return TPM_RCS_VALUE + RC_StartAuthSession_encryptedSalt;
// Decrypting salt requires accessing the private portion of a key.
// Therefore, tmpKey can not be a key with only public portion loaded
if(tpmKey->attributes.publicOnly)
return TPM_RCS_HANDLE + RC_StartAuthSession_tpmKey;
// HMAC session input handle check.
// tpmKey should be a decryption key
if(!IS_ATTRIBUTE(tpmKey->publicArea.objectAttributes, TPMA_OBJECT, decrypt))
return TPM_RCS_ATTRIBUTES + RC_StartAuthSession_tpmKey;
// Secret Decryption. A TPM_RC_VALUE, TPM_RC_KEY or Unmarshal errors
// may be returned at this point
result = CryptSecretDecrypt(tpmKey, &in->nonceCaller, SECRET_KEY,
&in->encryptedSalt, &salt);
if(result != TPM_RC_SUCCESS)
return TPM_RCS_VALUE + RC_StartAuthSession_encryptedSalt;
}

However, the point of salting a session is to allow confidentiality and integrity when using a TPM object with low entropy authValues

I am well aware of this, hence why I am trying to point out a critical implementation flaw.

Are you asking for more warning to people about the nature of tpmKey used to encrypt salt?

No, I am specifically saying that someone with access to the bus can obtain the salt just from the traffic across the bus in this repository's implementation of the TPM2_StartAuthSession function. The function should be fixed to use the salt value, not deriving the salt value from the encrypted salt value using the TPM. This would eliminate the ability for an attacker to snoop or modify transactions on the bus.

from ms-tpm-20-ref.

amarochk avatar amarochk commented on July 24, 2024

OK, David, I think I've understood what Matt's problem is. Matt, I believe you are misunderstanding the TPM architecture and usage model. In particular, the link in your reply to my question points not to a TPM implementation but rather to a TSS - a utility library used by TPM client applications to prepare and marshal TPM command buffers and unmarshal TPM responses.

When saying "interposer sitting on the bus between the CPU and the TPM", what exactly do you mean? Do you think that the reference implementation just runs on the "main CPU" like an OS driver? This is not so.

In reality the reference code is supposed to run in a completely isolated environment - either on a separate chip with a CPU and memory of its own, or in a special CPU mode (e.g. TrustZone or hypervisor), where the access to the bus between the CPU and memory is protected. If someone could get access to the bus used by the TPM during its internal computations, none of TPM secrets would be safe, whatever implementation is used, and session salt value would've been the least of concerns.

The only way "main CPU" communicates with the TPM is via TPM command interface. This is why the salt value is sent encrypted (by the TPM client running on the main CPU), so that a MIM sitting between the CPU and the TPM could not get the salt value.

I'll repeat - no one must be able to get access to the data being produced and used inside the reference implementation. If this is possible - it means that the design of the platform hosting the TPM is deficient.

from ms-tpm-20-ref.

mateoconlechuga avatar mateoconlechuga commented on July 24, 2024

the link in your reply to my question points not to a TPM implementation but rather to a TSS - a utility library used by TPM client applications to prepare and marshal TPM command buffers and unmarshal TPM responses

It isn't supposed to be a TPM implementation. It's supposed to be the TSS. This is literally an issue with the TPM2_StartAuthSession in this "reference design".

In reality the reference code is supposed to run in a completely isolated environment

Yes, I am aware of this fact. However, in tamper situations there is always a possibility of a compromise of the hardware architecture. If it helps, this "reference design" is used as a template for this code as well, and many others: https://android.googlesource.com/platform/external/tpm2/+/master/StartAuthSession.c

The only way "main CPU" communicates with the TPM is via TPM command interface. This is why the salt value is sent encrypted (by the TPM client running on the main CPU), so that a MIM sitting between the CPU and the TPM could not get the salt value.

I'll say this again so everyone can actually look at the code I keep referencing in this repository:

if(in->tpmKey != TPM_RH_NULL)
{
// Get pointer to loaded decrypt key
tpmKey = HandleToObject(in->tpmKey);
// key must be asymmetric with its sensitive area loaded. Since this
// command does not require authorization, the presence of the sensitive
// area was not already checked as it is with most other commands that
// use the sensitive are so check it here
if(!CryptIsAsymAlgorithm(tpmKey->publicArea.type))
return TPM_RCS_KEY + RC_StartAuthSession_tpmKey;
// secret size cannot be 0
if(in->encryptedSalt.t.size == 0)
return TPM_RCS_VALUE + RC_StartAuthSession_encryptedSalt;
// Decrypting salt requires accessing the private portion of a key.
// Therefore, tmpKey can not be a key with only public portion loaded
if(tpmKey->attributes.publicOnly)
return TPM_RCS_HANDLE + RC_StartAuthSession_tpmKey;
// HMAC session input handle check.
// tpmKey should be a decryption key
if(!IS_ATTRIBUTE(tpmKey->publicArea.objectAttributes, TPMA_OBJECT, decrypt))
return TPM_RCS_ATTRIBUTES + RC_StartAuthSession_tpmKey;
// Secret Decryption. A TPM_RC_VALUE, TPM_RC_KEY or Unmarshal errors
// may be returned at this point
result = CryptSecretDecrypt(tpmKey, &in->nonceCaller, SECRET_KEY,
&in->encryptedSalt, &salt);
if(result != TPM_RC_SUCCESS)
return TPM_RCS_VALUE + RC_StartAuthSession_encryptedSalt;
}

A MIM sitting between the CPU and the TPM can get the salt value. This is because in the above code, the necessary secret is retrieved from the TPM before the bus is encrypted. A MIM can take this secret and decrypt the salt!

At this point I may just need to make a whole PoC.

If this is possible - it means that the design of the platform hosting the TPM is deficient.

No, it means the "reference design" implementation is inherently insecure. It would be secure if it didn't do what the code I linked does.

from ms-tpm-20-ref.

DavidWooten avatar DavidWooten commented on July 24, 2024

from ms-tpm-20-ref.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.