Skip to content

Added session functionality#169

Open
thomkopp wants to merge 3 commits intotpm2-software:masterfrom
thomkopp:add-session-functionality
Open

Added session functionality#169
thomkopp wants to merge 3 commits intotpm2-software:masterfrom
thomkopp:add-session-functionality

Conversation

@thomkopp
Copy link
Copy Markdown

@thomkopp thomkopp commented Mar 16, 2026

Auth sessions are used to protect sensitive data (e.g. key passwords / parameters) transferred between the TPM and the provider.

Salt key
The approach was to generate a salt key in the null hierarchy. The key is being loaded when the provider is being initialized and destroyed when the provider is being tear down.

The flow is as follows

  1. Generates a random salt
  2. Encrypts it with the tpmKey's public key (asymmetric encryption — only the TPM can decrypt it)
  3. Sends the encrypted salt to the TPM during StartAuthSession
  4. Both sides derive the session key from this shared salt
    This salt contributes entropy to the session key, which is then used as the symmetric key for AES-CFB parameter encryption/decryption. Without it, there's nothing to encrypt parameters with.

Session lifetime
Sessions are being created per operation. If an operation leads to multiple ESYS-API commands, the same session is being reused. This should lead to a good balance between performance and ease of use. In order to start and end the session I added helper functions to tpm2-provider-core.c

Affected commands
I modified all commands which used TR_PASSWORD as session handle in order to use an auth session.

Testing
Regarding the current testing infrastructure, writing unit tests is difficult. This isn't anything which can be tested explicitly when using openssl cli. We'd need to mock the ESYS-API to verify if the corresponding methods are called.

Hint
I developed the idea as well as the implementation with the help of GitHub CoPilot and the Claude Opus 4.6 model. I did a manual review of the code (as well as I can do it) and did some manual adjustments. It compiles and it seems to work. I'm open to inputs regarding improvements.

Resolves: #65

The salt key is located in the null hierarchy and will later on be used
for session management.

By provideing a tpmKey, the ESAPI layer:
1. Generates a random salt.
2. Encrypts it with the tpmKey's public key (asymmetric encryption —
only the TPM can decrypt it)
3. Sends the encrypted salt to the TPM during StartAuthSession
4. Both sides derive the session key from this shared salt
This salt contributes entropy to the session key, which is then used
as the symmetric key for AES-CFB parameter encryption/decryption.
Without it, there's nothing to encrypt parameters with.

Signed-off-by: Thomas Kopp <thomas.kopp@securiton.ch>
An auth session is being used to secure the communication between the
provider and the TPM-chip itself.

Signed-off-by: Thomas Kopp <thomas.kopp@securiton.ch>
In order to make sure passwords are being encrypted when communicating
between the openssl provider and the TPM itself.

Signed-off-by: Thomas Kopp <thomas.kopp@securiton.ch>
@williamcroberts
Copy link
Copy Markdown
Member

Based on the description, you have to trust that the communication channel is not compromised when you generate the null key. So an attacker just has to feed back a key they control. You need a way to verify that it's a known good key, during a step when the tpm is in a trusted state or verify it to an EK. This doesn't thwart the attack you're attempting to prevent.

@thomkopp
Copy link
Copy Markdown
Author

Thanks for your feedback William. Thanks for pointing that out. I (unfortunately) haven't been thinking about this aspect.

It would be nice if we could find a solution which can be fully implemented in the provider itself. Without any requirements to the environment. But I don't really have an idea on how this can be achieved.

You mentioned two ideas:

  • Making sure the tpm is in a trusted state
    As far as my understanding is this is nothing which can be achieved in the provider itself. Then we would need to find a way on how such a salt key can be specified in openssl commands as additional parameter (could propquery be a possibility to do that?)

  • verify it to an ek
    From my undrestanding we can't assume that an ek is always present.

I also had a look at the tpm2-pkcs11 where you implemented the session handling (if I'm not mistaken). From my understanding you're using the primary key as tpm-key as well as bind parameter when calling Esys_StartAuthSession. That's a solution I've seen in multiple implementations. Also in this example here: https://gitlab.com/opensecuritytraining/TC1102_TPM_Intermediate_code_for_class/-/blob/main/solutions/lab4/lab4.c?ref_type=heads

The problem I'm seeing is that the password for the owner hierarchy (when creating a primary key) or the password for the primary key (when creating a key below the primary) is being sent unencrypted. Therefore this approach isn't water-proof as well.....

Do you have any other ideas?

@williamcroberts
Copy link
Copy Markdown
Member

Thanks for your feedback William. Thanks for pointing that out. I (unfortunately) haven't been thinking about this aspect.

It would be nice if we could find a solution which can be fully implemented in the provider itself. Without any requirements to the environment. But I don't really have an idea on how this can be achieved.

You mentioned two ideas:

  • Making sure the tpm is in a trusted state
    As far as my understanding is this is nothing which can be achieved in the provider itself. Then we would need to find a way on how such a salt key can be specified in openssl commands as additional parameter (could propquery be a possibility to do that?)
  • verify it to an ek
    From my undrestanding we can't assume that an ek is always present.

In the PKCS11 code, we make the following assumption:

  1. When you enroll the primary key, we assume that you have a system in a known good state.
  2. When you create and use subsequent keys, we assume that the system could be potentially tampered with and we use the previously enrolled primary key to establish a secure channel.

I would use this model again here. We can store the parent key information in the PEM file, and use that to verify the key . I would just serialize the key name into the pem file, and then verify the names in the code. This model would work for both transient and persistent parent keys.

I also had a look at the tpm2-pkcs11 where you implemented the session handling (if I'm not mistaken). From my understanding you're using the primary key as tpm-key as well as bind parameter when calling Esys_StartAuthSession. That's a solution I've seen in multiple implementations. Also in this example here: https://gitlab.com/opensecuritytraining/TC1102_TPM_Intermediate_code_for_class/-/blob/main/solutions/lab4/lab4.c?ref_type=heads

The problem I'm seeing is that the password for the owner hierarchy (when creating a primary key) or the password for the primary key (when creating a key below the primary) is being sent unencrypted. Therefore this approach isn't water-proof as well.....

See above, in the threat model, we say when the primary key is being generated, the system must be in a known good state. One thing I wanted to add was a name option to the enrollment commands, so you can verify that the key you created is what you expected.

Do you have any other ideas?

@tpm2-software tpm2-software deleted a comment from billatarm Mar 18, 2026
@thomkopp
Copy link
Copy Markdown
Author

thomkopp commented Mar 18, 2026

Thanks for your inputs. I see your point. What you assume in your threat model makes totally sense.

You're talking about adding parent information to the pem file. I assume you're referring to the TSS2 PRIVATE KEY according to: https://github.com/tpm2-software/tpm2-openssl/blob/master/docs/keys.md#loading-a-private-key?

You'd need to handle compatibility as earlier versions of the provider (or keys created by the tpm-tss-engine) wouldn't have that key name information. Additionally silently dropping session support in such cases doesn't feel like a good approach.

Furthermore I don't see how the proposed approach would work for keys specified as handles or serialized objects. Serialized objects are created using tpm2-evictcontrol (which is not part of the provider-ecosystem and therefore would not be able to add any specific information used by the provider solely). Having session support exclusively for keys specified in PEM format unfortunately isn't a full solution, as keys stored as handles or serialized objects can be password protected too - therefore sessions are needed in these cases as well.

@williamcroberts
Copy link
Copy Markdown
Member

Thanks for your inputs. I see your point. What you assume in your threat model makes totally sense.

You're talking about adding parent information to the pem file. I assume you're referring to the TSS2 PRIVATE KEY according to: https://github.com/tpm2-software/tpm2-openssl/blob/master/docs/keys.md#loading-a-private-key?

You'd need to handle compatibility as earlier versions of the provider (or keys created by the tpm-tss-engine) wouldn't have that key name information. Additionally silently dropping session support in such cases doesn't feel like a good approach.

I would just warn, this will preserve backwards compatibility behavior.

Furthermore I don't see how the proposed approach would work for keys specified as handles or serialized objects. Serialized objects are created using tpm2-evictcontrol (which is not part of the provider-ecosystem and therefore would not be able to add any specific information used by the provider solely). Having session support exclusively for keys specified in PEM format unfortunately isn't a full solution, as keys stored as handles or serialized objects can be password protected too - therefore sessions are needed in these cases as well.

I think this is only for parent objects, which could be persistent objects. In this case, the parent information would be serialized to the child keys pem format IIUC.

@thomkopp
Copy link
Copy Markdown
Author

thomkopp commented Apr 7, 2026

I think this is only for parent objects, which could be persistent objects. In this case, the parent information would be serialized to the child keys pem format IIUC.

I see your point. Our primary is persistent as well as our derived keys. The problem is, that we're not using PEM files for the keys.
Reason: A key stored in a PEM file is loaded into the TPM during runtime. Loading is an operation that needs the password of the primary key. According to our threat model we don't have access to the primary key's password, when simply using keys.
Therefore we decided to persist our keys within the TPM and access them by serialized objects.
As these keys live inside the TPM no load operation is needed an therefore no primary key password is needed when accessing the keys (only the password of the key itself).

Serialized objects are being created using the tpm2-tools. So it wouldn't be possible to add any additional parent information that the provider could use to start an auth session.

Meaning: Adding information to a PEM file, isn't a solution for our use - case. Can't we find a solution that works for PEM-files, serialized objects as well as key-handles?

@williamcroberts
Copy link
Copy Markdown
Member

williamcroberts commented Apr 8, 2026

I think this is only for parent objects, which could be persistent objects. In this case, the parent information would be serialized to the child keys pem format IIUC.

I see your point. Our primary is persistent as well as our derived keys. The problem is, that we're not using PEM files for the keys. Reason: A key stored in a PEM file is loaded into the TPM during runtime. Loading is an operation that needs the password of the primary key.

The parent key should be the SRK (Storage Root Key) which has no password and is at a known fixed address. If this is not the case, then it would have made sense to make a passwordless parent key below the current parent key that has a password, this key could then serve as the parent to the actual keys.

According to our threat model we don't have access to the primary key's password, when simply using keys. Therefore we decided to persist our keys within the TPM and access them by serialized objects. As these keys live inside the TPM no load operation is needed an therefore no primary key password is needed when accessing the keys (only the password of the key itself).

The problem here is, the TPM has very limited amounts of persistent storage, so in shared systems, this can lead to an issue.

Serialized objects are being created using the tpm2-tools. So it wouldn't be possible to add any additional parent information that the provider could use to start an auth session.

Meaning: Adding information to a PEM file, isn't a solution for our use - case. Can't we find a solution that works for PEM-files, serialized objects as well as key-handles?

There could be a lookup a table in a config file somewhere, but this seems more like a hack job to make it work rather than a clean design on key management. Maybe support persistent keys in the PEM file. Something like, if key is marked persistent, and found and at that address, verify it to the details in the PEM file (Key should match) and use it. Perhaps, the else clause would be to load it and persist it, maybe... that's something that could be discussed.

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.

Enable Session Support

2 participants