microsoft / ms-tpm-20-ref

Reference implementation of the TCG Trusted Platform Module 2.0 specification.
Other
333 stars 133 forks source link

Potential leakage of salt value #31

Closed mateoconlechuga closed 5 years ago

mateoconlechuga commented 5 years ago

Based on my interpretation of this code block: https://github.com/microsoft/ms-tpm-20-ref/blob/5847c02ff793114343dc18e92e60e2919fadc0b8/TPMCmd/tpm/src/command/Session/StartAuthSession.c#L80-L108

An interposer sitting on the bus between the CPU and the TPM could extract the decrypted salt value from the TPM decryption. Assuming the authValue is empty or known, an interposer on the bus could decrypt any encrypted traffic during an encrypted session, as the symmetric encryption key is derived from the KDFa of the sessionKey.

amarochk commented 5 years ago

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.

mateoconlechuga commented 5 years ago

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

mateoconlechuga commented 5 years ago

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

amarochk commented 5 years ago

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.

mateoconlechuga commented 5 years ago

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.

amarochk commented 5 years ago

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.

mateoconlechuga commented 5 years ago

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.

DavidWooten commented 5 years ago

Matt,

“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.”

I’m not understanding your issue. I think that Part 1 is fairly clear that the user encrypts the salt and sends it to the TPM as encryptedSalt in TPM2_StartAuthSession(). The TPM then decrypts salt and uses it to derived the protection values for the session. Clearly, any entity that knows salt would be able to observe the communications between the user and the TPM including decrypting parameters. This does not, necessarily, let them mount a MiM attack unless they also know the authorization values used in the HMAC computations.

A salted session only provides partial confidentiality for the command (first TPM2B parameter in command or response). Command integrity is still provided by the HMAC and that is only susceptible to MiM if the auth values are known by the attacker.

David Wooten

From: Matt Waltz [mailto:notifications@github.com] Sent: Monday, May 13, 2019 7:27 PM To: microsoft/ms-tpm-20-ref Cc: Subscribed Subject: Re: [microsoft/ms-tpm-20-ref] Potential leakage of salt value (#31)

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.

I am under the impression that this is solved by allowing for decrypt/encrypt sessions, using either XOR or CFB encryption of commands and parameters, essentially "hiding" transmissions across the bus. At least, this is what the linux kernel proposes.

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.

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.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/microsoft/ms-tpm-20-ref/issues/31?email_source=notifications&email_token=ACQTPGAYROLRWCKX4USH76TPVH2M3A5CNFSM4HL6LWW2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODVJ2VFA#issuecomment-492022420 , or mute the thread https://github.com/notifications/unsubscribe-auth/ACQTPGFCVLYVWFBLC67MYZDPVH2M3ANCNFSM4HL6LWWQ . https://github.com/notifications/beacon/ACQTPGBW22CHEF7MJGXHLHTPVH2M3A5CNFSM4HL6LWW2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODVJ2VFA.gif

mateoconlechuga commented 5 years ago

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.

DavidWooten commented 5 years ago

Matt,

I don’t know what code you highlighted in the “first section.” However, the point of salting a session is to allow confidentiality and integrity when using a TPM object with low entropy authValues. (P1.19.6.14). The intent is that the user will pick some high-entropy value for salt making it unlikely (nearly impossible) for an attacker to be able to determine the value of salt so that the attacker can’t “break in” to the session.

Are you asking for more warning to people about the nature of tpmKey used to encrypt salt? Clearly, if someone uses an unrestricted asymmetric key for encryption of salt then they aren’t getting much protection (unless that key has a really strong authValue). Same for a symmetric key. Are you asking that some kind of disclaimer be added to cover this case?

David Wooten

From: Matt Waltz [mailto:notifications@github.com] Sent: Monday, May 13, 2019 8:56 PM To: microsoft/ms-tpm-20-ref Cc: DavidWooten; Comment Subject: Re: [microsoft/ms-tpm-20-ref] Potential leakage of salt value (#31)

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.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/microsoft/ms-tpm-20-ref/issues/31?email_source=notifications&email_token=ACQTPGH6DGEZYRORQNCKS4LPVIE3ZA5CNFSM4HL6LWW2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODVJ6R5Y#issuecomment-492038391 , or mute the thread https://github.com/notifications/unsubscribe-auth/ACQTPGHO6RG3IFPYL2PUTJ3PVIE3ZANCNFSM4HL6LWWQ . https://github.com/notifications/beacon/ACQTPGHRRCSJ4EMPFQ4IKQDPVIE3ZA5CNFSM4HL6LWW2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODVJ6R5Y.gif

mateoconlechuga commented 5 years ago

@DavidWooten:

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

The very first comment of this issue, relevant code here: https://github.com/microsoft/ms-tpm-20-ref/blob/5847c02ff793114343dc18e92e60e2919fadc0b8/TPMCmd/tpm/src/command/Session/StartAuthSession.c#L80-L108

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.

amarochk commented 5 years ago

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.

mateoconlechuga commented 5 years ago

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: https://github.com/microsoft/ms-tpm-20-ref/blob/5847c02ff793114343dc18e92e60e2919fadc0b8/TPMCmd/tpm/src/command/Session/StartAuthSession.c#L80-L108

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.

DavidWooten commented 5 years ago

My last post on this. The referenced code is in the TPM. It is NOT true that “the necessary secret is retrieved from the TPM.” The “necessary secret” (salt) is decrypted within the TPM and used by it to decrypt the seed. It is not visible outside of the TPM.

From: Matt Waltz [mailto:notifications@github.com] Sent: Tuesday, May 14, 2019 10:07 AM To: microsoft/ms-tpm-20-ref Cc: DavidWooten; Mention Subject: Re: [microsoft/ms-tpm-20-ref] Potential leakage of salt value (#31)

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: https://github.com/microsoft/ms-tpm-20-ref/blob/5847c02ff793114343dc18e92e60e2919fadc0b8/TPMCmd/tpm/src/command/Session/StartAuthSession.c#L80-L108

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.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/microsoft/ms-tpm-20-ref/issues/31?email_source=notifications&email_token=ACQTPGDAPEQZRQF5TNXY2RDPVLBOZA5CNFSM4HL6LWW2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODVLSZXI#issuecomment-492252381 , or mute the thread https://github.com/notifications/unsubscribe-auth/ACQTPGF33ENPNOUABLEPQ7TPVLBOZANCNFSM4HL6LWWQ . https://github.com/notifications/beacon/ACQTPGGXLNFVO6GIL72YBZLPVLBOZA5CNFSM4HL6LWW2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODVLSZXI.gif