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

Add Trusted Platform Module 2.0 (TPM2) pin support #17

Closed
wants to merge 1 commit into
base: master
from

Conversation

Projects
None yet
5 participants
@martinezjavier
Contributor

martinezjavier commented Jul 12, 2017

This adds support for a Trusted Platform Module 2.0 (TPM2) clevis pin.
It encrypts the JWK using a TPM2 chip, and then at decryption time the
JWK is decrypted using the same TPM2 chip to allow clevis to decrypt
the secret stored in the JWE. That way the ciphertext is bound to a TPM
so it can only be decripted in a particular machine.

Encrypting data using the tpm2 pin works the same than with other pins:

$ clevis encrypt tpm2 '{}' < PT > JWE

The pin has reasonable defaults for its configuration, but a different
hierarchy, hash, and key algorithms can be choosen if the defaults are
not suitable.

Decryption also works the same than with other pins, only needs the JWE:

$ clevis decrypt tpm2 < JWE > PT

The public and private key pair of the encrypted JWK are stored in the
JWE object, so those can be fetched at decryption time to unseal the
JWK using the TPM2 chip.

Signed-off-by: Javier Martinez Canillas javierm@redhat.com

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 26, 2017

Contributor

@npmccallum one thing pointing out is that the default algorithm used for the primary key is ECC (TPM_ALG_ECC).

A better option would be to use a symmetric algorithm (TPM_ALG_SYMCIPHER) instead. But unfortunately only asymmetric algorithms were supported for primary keys in previous version of the TCG TPM specification so using symcipher as default may not work on all TPM2 chips (please refer to this tpm2-tools project issue).

The TPM chips have properties that specify the implemented version of the spec, so you can query them, i.e:

$ tpm2_dump_capability -c properties-fixed | head -n8
TPM_PT_FAMILY_INDICATOR:
  as UINT32:                0x08322e3000
  as string:                "2.0"
TPM_PT_LEVEL:               0
TPM_PT_REVISION:            1.16
TPM_PT_DAY_OF_YEAR:         0x0000012f
TPM_PT_YEAR:                0x000007de
TPM_PT_MANUFACTURER:        0x494e5443

So we could query the specification version but as @webmeister mentioned, I also didn't find where exactly in the specification is mentioned which algorithms are supported for primary keys on each version of the spec. So I'm not sure if we can rely on something like that to choose which key algorithm use by default.

I also didn't have access to a TPM2 that implements a 01.38 revision to test if symmetric parent keys were working. That's why I left ECC as the default for now, which should work on all TPM2 chips.

Contributor

martinezjavier commented Sep 26, 2017

@npmccallum one thing pointing out is that the default algorithm used for the primary key is ECC (TPM_ALG_ECC).

A better option would be to use a symmetric algorithm (TPM_ALG_SYMCIPHER) instead. But unfortunately only asymmetric algorithms were supported for primary keys in previous version of the TCG TPM specification so using symcipher as default may not work on all TPM2 chips (please refer to this tpm2-tools project issue).

The TPM chips have properties that specify the implemented version of the spec, so you can query them, i.e:

$ tpm2_dump_capability -c properties-fixed | head -n8
TPM_PT_FAMILY_INDICATOR:
  as UINT32:                0x08322e3000
  as string:                "2.0"
TPM_PT_LEVEL:               0
TPM_PT_REVISION:            1.16
TPM_PT_DAY_OF_YEAR:         0x0000012f
TPM_PT_YEAR:                0x000007de
TPM_PT_MANUFACTURER:        0x494e5443

So we could query the specification version but as @webmeister mentioned, I also didn't find where exactly in the specification is mentioned which algorithms are supported for primary keys on each version of the spec. So I'm not sure if we can rely on something like that to choose which key algorithm use by default.

I also didn't have access to a TPM2 that implements a 01.38 revision to test if symmetric parent keys were working. That's why I left ECC as the default for now, which should work on all TPM2 chips.

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Sep 26, 2017

Member
$ sudo tpm2_dump_capability -c properties-fixed
Failed to initialize tcti context: 0x1

Any ideas?

Member

npmccallum commented Sep 26, 2017

$ sudo tpm2_dump_capability -c properties-fixed
Failed to initialize tcti context: 0x1

Any ideas?

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 26, 2017

Contributor

@npmccallum yes, the tpm2-tools support different TCTI modules (transport layers). By default it attempts to use the D-Bus based resource manager (tpm2-abrmd) but you can also access the TPM device directly. Could you please try the following command instead:

$ sudo tpm2_dump_capability -c properties-fixed -T device
Contributor

martinezjavier commented Sep 26, 2017

@npmccallum yes, the tpm2-tools support different TCTI modules (transport layers). By default it attempts to use the D-Bus based resource manager (tpm2-abrmd) but you can also access the TPM device directly. Could you please try the following command instead:

$ sudo tpm2_dump_capability -c properties-fixed -T device
@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Sep 26, 2017

Member

This is on a 6mo Dell XPS 13:

$ sudo tpm2_dump_capability -c properties-fixed -T device
TPM_PT_FAMILY_INDICATOR:
  as UINT32:                0x08322e3000
  as string:                "2.0"
TPM_PT_LEVEL:               0
TPM_PT_REVISION:            1.00
TPM_PT_DAY_OF_YEAR:         0x000000a7
TPM_PT_YEAR:                0x000007df
TPM_PT_MANUFACTURER:        0x4e544300
TPM_PT_VENDOR_STRING_1:
  as UINT32:                0x726c7300
  as string:                "rls"
TPM_PT_VENDOR_STRING_2:
  as UINT32:                0x4e504354
  as string:                "NPCT"
TPM_PT_VENDOR_STRING_3:
  as UINT32:                0x20000000
  as string:                " "
TPM_PT_VENDOR_STRING_4:
  as UINT32:                0x20000000
  as string:                " "
TPM_PT_VENDOR_TPM_TYPE:     0x00000001
TPM_PT_FIRMWARE_VERSION_1:  0x00010003
TPM_PT_FIRMWARE_VERSION_2:  0x00010000
TPM_PT_INPUT_BUFFER:        0x00000400
TPM_PT_HR_TRANSIENT_MIN:    0x00000003
TPM_PT_HR_PERSISTENT_MIN:   0x00000007
TPM_PT_HR_LOADED_MIN:       0x00000003
TPM_PT_ACTIVE_SESSIONS_MAX: 0x00000040
TPM_PT_PCR_COUNT:           0x00000018
TPM_PT_PCR_SELECT_MIN:      0x00000003
TPM_PT_CONTEXT_GAP_MAX:     0x0000ffff
TPM_PT_NV_COUNTERS_MAX:     0x00000010
TPM_PT_NV_INDEX_MAX:        0x00000800
TPM_PT_MEMORY:              0x00000006
TPM_PT_CLOCK_UPDATE:        0x00400000
TPM_PT_CONTEXT_HASH:        0x0000000b
TPM_PT_CONTEXT_SYM:         0x00000006
TPM_PT_CONTEXT_SYM_SIZE:    0x00000080
TPM_PT_ORDERLY_COUNT:       0x000000ff
TPM_PT_MAX_COMMAND_SIZE:    0x00000800
TPM_PT_MAX_RESPONSE_SIZE:   0x00000800
TPM_PT_MAX_DIGEST:          0x00000020
TPM_PT_MAX_OBJECT_CONTEXT:  0x00000392
TPM_PT_MAX_SESSION_CONTEXT: 0x000000e9
TPM_PT_PS_FAMILY_INDICATOR: 0x00000001
TPM_PT_PS_LEVEL:            0x00000000
TPM_PT_PS_REVISION:         0x00000100
TPM_PT_PS_DAY_OF_YEAR:      0x00000000
TPM_PT_PS_YEAR:             0x00000000
TPM_PT_SPLIT_MAX:           0x00000080
TPM_PT_TOTAL_COMMANDS:      0x0000006b
TPM_PT_LIBRARY_COMMANDS:    0x00000065
TPM_PT_VENDOR_COMMANDS:     0x00000006
TPM_PT_NV_BUFFER_MAX:       0x00000400

Thoughts?

Member

npmccallum commented Sep 26, 2017

This is on a 6mo Dell XPS 13:

$ sudo tpm2_dump_capability -c properties-fixed -T device
TPM_PT_FAMILY_INDICATOR:
  as UINT32:                0x08322e3000
  as string:                "2.0"
TPM_PT_LEVEL:               0
TPM_PT_REVISION:            1.00
TPM_PT_DAY_OF_YEAR:         0x000000a7
TPM_PT_YEAR:                0x000007df
TPM_PT_MANUFACTURER:        0x4e544300
TPM_PT_VENDOR_STRING_1:
  as UINT32:                0x726c7300
  as string:                "rls"
TPM_PT_VENDOR_STRING_2:
  as UINT32:                0x4e504354
  as string:                "NPCT"
TPM_PT_VENDOR_STRING_3:
  as UINT32:                0x20000000
  as string:                " "
TPM_PT_VENDOR_STRING_4:
  as UINT32:                0x20000000
  as string:                " "
TPM_PT_VENDOR_TPM_TYPE:     0x00000001
TPM_PT_FIRMWARE_VERSION_1:  0x00010003
TPM_PT_FIRMWARE_VERSION_2:  0x00010000
TPM_PT_INPUT_BUFFER:        0x00000400
TPM_PT_HR_TRANSIENT_MIN:    0x00000003
TPM_PT_HR_PERSISTENT_MIN:   0x00000007
TPM_PT_HR_LOADED_MIN:       0x00000003
TPM_PT_ACTIVE_SESSIONS_MAX: 0x00000040
TPM_PT_PCR_COUNT:           0x00000018
TPM_PT_PCR_SELECT_MIN:      0x00000003
TPM_PT_CONTEXT_GAP_MAX:     0x0000ffff
TPM_PT_NV_COUNTERS_MAX:     0x00000010
TPM_PT_NV_INDEX_MAX:        0x00000800
TPM_PT_MEMORY:              0x00000006
TPM_PT_CLOCK_UPDATE:        0x00400000
TPM_PT_CONTEXT_HASH:        0x0000000b
TPM_PT_CONTEXT_SYM:         0x00000006
TPM_PT_CONTEXT_SYM_SIZE:    0x00000080
TPM_PT_ORDERLY_COUNT:       0x000000ff
TPM_PT_MAX_COMMAND_SIZE:    0x00000800
TPM_PT_MAX_RESPONSE_SIZE:   0x00000800
TPM_PT_MAX_DIGEST:          0x00000020
TPM_PT_MAX_OBJECT_CONTEXT:  0x00000392
TPM_PT_MAX_SESSION_CONTEXT: 0x000000e9
TPM_PT_PS_FAMILY_INDICATOR: 0x00000001
TPM_PT_PS_LEVEL:            0x00000000
TPM_PT_PS_REVISION:         0x00000100
TPM_PT_PS_DAY_OF_YEAR:      0x00000000
TPM_PT_PS_YEAR:             0x00000000
TPM_PT_SPLIT_MAX:           0x00000080
TPM_PT_TOTAL_COMMANDS:      0x0000006b
TPM_PT_LIBRARY_COMMANDS:    0x00000065
TPM_PT_VENDOR_COMMANDS:     0x00000006
TPM_PT_NV_BUFFER_MAX:       0x00000400

Thoughts?

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Sep 26, 2017

Member

I question whether or not we can predict algorithm support from TPM_PT_REVISION. I suspect vendors will implement the algorithms and forget to bump the revision. Is there a way to test for symcipher directly? What precisely are the drawbacks for using EC?

Member

npmccallum commented Sep 26, 2017

I question whether or not we can predict algorithm support from TPM_PT_REVISION. I suspect vendors will implement the algorithms and forget to bump the revision. Is there a way to test for symcipher directly? What precisely are the drawbacks for using EC?

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 26, 2017

Contributor

@npmccallum right, that's what I questioned too. I don't think there's a way to explicitly query the algorithms that are supported by a given TPM2 chip. AFAICT, the spec only defines the set of mandatory algorithms on each spec version. But even there, it doesn't specify if these are only for created objects or also for primary keys.

But even older versions of the spec mentions that asymmetric algorithms can be used for primary keys, and RSA and ECC are listed as mandatory asymmetric algorithms.

The reason I mentioned symcipher as possibly a better default option was performance. But since ECDH is used, I guess is less of a concern?

Contributor

martinezjavier commented Sep 26, 2017

@npmccallum right, that's what I questioned too. I don't think there's a way to explicitly query the algorithms that are supported by a given TPM2 chip. AFAICT, the spec only defines the set of mandatory algorithms on each spec version. But even there, it doesn't specify if these are only for created objects or also for primary keys.

But even older versions of the spec mentions that asymmetric algorithms can be used for primary keys, and RSA and ECC are listed as mandatory asymmetric algorithms.

The reason I mentioned symcipher as possibly a better default option was performance. But since ECDH is used, I guess is less of a concern?

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Sep 26, 2017

Member

What is the current performance impact of ECC? Can you help define this for me? Is there any way we can mitigate the performance hit?

Member

npmccallum commented Sep 26, 2017

What is the current performance impact of ECC? Can you help define this for me? Is there any way we can mitigate the performance hit?

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 26, 2017

Contributor

@npmccallum the problem is that I didn't have access to many TPMs to have a conclusive answer.

But a colleague tested the clevis tpm2 pin (which defaults to ECC) on his system and said that encryption/decryption took several seconds. Now, I don't know if the performance on those chips are really bad regardless of the used algorithm since I don't have access to test.

On my test system (Intel PTT firmware based TPM2) I get much faster times:

$ time echo hi | clevis encrypt tpm2 '{"pcr_ids":"7"}' > hi.jwe

real    0m0.500s
user    0m0.056s
sys     0m0.100s

$ time clevis decrypt < hi.jwe 
hi

real    0m0.959s
user    0m0.041s
sys     0m0.100s

I've also tested on a system with a hardware TPM2 and the times were similar than my test system. Neither system supports using symmetric primary keys so I couldn't compare the performance. So more than the default algorithm used, I'm worried about the performance variability between different TPM2 chips.

One optimization that I did compared with the previous PR is that the primary key isn't recalculated on each operation (which may be slow specially for RSA). But instead the pin only calculates the PK the first time and make it persistent in the TPM, so future operations don't have to.

Contributor

martinezjavier commented Sep 26, 2017

@npmccallum the problem is that I didn't have access to many TPMs to have a conclusive answer.

But a colleague tested the clevis tpm2 pin (which defaults to ECC) on his system and said that encryption/decryption took several seconds. Now, I don't know if the performance on those chips are really bad regardless of the used algorithm since I don't have access to test.

On my test system (Intel PTT firmware based TPM2) I get much faster times:

$ time echo hi | clevis encrypt tpm2 '{"pcr_ids":"7"}' > hi.jwe

real    0m0.500s
user    0m0.056s
sys     0m0.100s

$ time clevis decrypt < hi.jwe 
hi

real    0m0.959s
user    0m0.041s
sys     0m0.100s

I've also tested on a system with a hardware TPM2 and the times were similar than my test system. Neither system supports using symmetric primary keys so I couldn't compare the performance. So more than the default algorithm used, I'm worried about the performance variability between different TPM2 chips.

One optimization that I did compared with the previous PR is that the primary key isn't recalculated on each operation (which may be slow specially for RSA). But instead the pin only calculates the PK the first time and make it persistent in the TPM, so future operations don't have to.

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Sep 26, 2017

Member

This seems reasonable. Can you defined "make it persistent in the TPM" for me?

At the Linux Security Summit two weeks ago, I sat in a talk on TPM where the recommended advice was to export the primary key and load it during decryption. Are you persisting the PK on the NVRAM?

Member

npmccallum commented Sep 26, 2017

This seems reasonable. Can you defined "make it persistent in the TPM" for me?

At the Linux Security Summit two weeks ago, I sat in a talk on TPM where the recommended advice was to export the primary key and load it during decryption. Are you persisting the PK on the NVRAM?

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 26, 2017

Contributor

Yes, the objects in the TPM2 can either be transient or persistent. Transient objects are the ones that are only in the TPM RAM and can be removed by either a TPM2_FlushContext() command or a TPM2 reset.

Persistent objects are stored in the TPM NVRAM and there's a TPM2_EvictControl() command to either make a transient object persistent or to evict a persistent object.

I also read the same recommendation than you, and that's why the previous implementation didn't store the primary keys in the TPM and was recalculated on decryption (since the PK derivation function is deterministic).

But then someone found this TPM2 chip that's very slow and also I noticed that RSA primary key creation time took several seconds even on my test system.

Notice how the first operation takes a lot because the RSA PK is created and the second one is fast due the PK already being in the TPM2:

$ time echo foo | clevis encrypt tpm2 '{"key":"rsa","pcr_ids":"7"}' > foo.jwe

real    0m13.341s
user    0m0.071s
sys     0m0.127s

$ time echo bar | clevis encrypt tpm2 '{"key":"rsa","pcr_ids":"7"}' > bar.jwe

real    0m0.489s
user    0m0.050s
sys     0m0.086s

For ECC is faster, but still creating the PK increases the operation time:

$ time echo foo | clevis encrypt tpm2 '{"key":"ecc","pcr_ids":"7"}' > foo.jwe

real    0m1.083s
user    0m0.090s
sys     0m0.112s

$ time echo bar | clevis encrypt tpm2 '{"key":"ecc","pcr_ids":"7"}' > bar.jwe

real    0m0.486s
user    0m0.055s
sys     0m0.084s
Contributor

martinezjavier commented Sep 26, 2017

Yes, the objects in the TPM2 can either be transient or persistent. Transient objects are the ones that are only in the TPM RAM and can be removed by either a TPM2_FlushContext() command or a TPM2 reset.

Persistent objects are stored in the TPM NVRAM and there's a TPM2_EvictControl() command to either make a transient object persistent or to evict a persistent object.

I also read the same recommendation than you, and that's why the previous implementation didn't store the primary keys in the TPM and was recalculated on decryption (since the PK derivation function is deterministic).

But then someone found this TPM2 chip that's very slow and also I noticed that RSA primary key creation time took several seconds even on my test system.

Notice how the first operation takes a lot because the RSA PK is created and the second one is fast due the PK already being in the TPM2:

$ time echo foo | clevis encrypt tpm2 '{"key":"rsa","pcr_ids":"7"}' > foo.jwe

real    0m13.341s
user    0m0.071s
sys     0m0.127s

$ time echo bar | clevis encrypt tpm2 '{"key":"rsa","pcr_ids":"7"}' > bar.jwe

real    0m0.489s
user    0m0.050s
sys     0m0.086s

For ECC is faster, but still creating the PK increases the operation time:

$ time echo foo | clevis encrypt tpm2 '{"key":"ecc","pcr_ids":"7"}' > foo.jwe

real    0m1.083s
user    0m0.090s
sys     0m0.112s

$ time echo bar | clevis encrypt tpm2 '{"key":"ecc","pcr_ids":"7"}' > bar.jwe

real    0m0.486s
user    0m0.055s
sys     0m0.084s
@webmeister

This comment has been minimized.

Show comment
Hide comment
@webmeister

webmeister Sep 26, 2017

So we could query the specification version but as @webmeister mentioned, I also didn't find where exactly in the specification is mentioned which algorithms are supported for primary keys on each version of the spec. So I'm not sure if we can rely on something like that to choose which key algorithm use by default.

I'd be pretty certain that if your TPM claims to implement 01.38 (or newer), you can also rely on it supporting symmetric storage keys. But this version of the specification is just a year old now, so it will probably take a long time before the majority of TPMs implements it.

I don't think there's a way to explicitly query the algorithms that are supported by a given TPM2 chip.

You can query the supported algorithms, but only in a generic "is this algorithm supported at all" kind of way (TPM_CAP_ALGS). You cannot determine whether a specific command will accept a certain parameter. Of course, if symmetric keys are fast enough to create, you could just always start with one, and only when your command fails, fall back to slower keys.

Or another wild idea: Why do you need a storage key at all in your scenario? Can't you just use a symmetric primary key and do all your operations with it? There is no need for you to be able to move keys between TPMs, is there?

I sat in a talk on TPM where the recommended advice was to export the primary key and load it during decryption.

Exporting the primary key sounds like TPM2_ContextSave, right? This should indeed be a fast operation, but your exported copy is only valid for that power cycle, so you need to recreate it after each reboot (or store it in NVM using TPM2_EvictControl).

webmeister commented Sep 26, 2017

So we could query the specification version but as @webmeister mentioned, I also didn't find where exactly in the specification is mentioned which algorithms are supported for primary keys on each version of the spec. So I'm not sure if we can rely on something like that to choose which key algorithm use by default.

I'd be pretty certain that if your TPM claims to implement 01.38 (or newer), you can also rely on it supporting symmetric storage keys. But this version of the specification is just a year old now, so it will probably take a long time before the majority of TPMs implements it.

I don't think there's a way to explicitly query the algorithms that are supported by a given TPM2 chip.

You can query the supported algorithms, but only in a generic "is this algorithm supported at all" kind of way (TPM_CAP_ALGS). You cannot determine whether a specific command will accept a certain parameter. Of course, if symmetric keys are fast enough to create, you could just always start with one, and only when your command fails, fall back to slower keys.

Or another wild idea: Why do you need a storage key at all in your scenario? Can't you just use a symmetric primary key and do all your operations with it? There is no need for you to be able to move keys between TPMs, is there?

I sat in a talk on TPM where the recommended advice was to export the primary key and load it during decryption.

Exporting the primary key sounds like TPM2_ContextSave, right? This should indeed be a fast operation, but your exported copy is only valid for that power cycle, so you need to recreate it after each reboot (or store it in NVM using TPM2_EvictControl).

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Sep 26, 2017

Member

The talk didn't break it down into TSS functions, so I don't know. I'm still pretty knew at TPM structures/operations.

Member

npmccallum commented Sep 26, 2017

The talk didn't break it down into TSS functions, so I don't know. I'm still pretty knew at TPM structures/operations.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 27, 2017

Contributor

You can query the supported algorithms, but only in a generic "is this algorithm supported at all" kind of way (TPM_CAP_ALGS). You cannot determine whether a specific command will accept a certain parameter. Of

Yes, I know about TPM_CAP_ALGS. I meant to query if are supported as primary key.

course, if symmetric keys are fast enough to create, you could just always start with one, and only when your command fails, fall back to slower keys.

That's an option indeed. I would prefer to have as default algorithm one that's known to work on most TPM2 and let users decide (via the JSON config) if they want to use a different one.

Or another wild idea: Why do you need a storage key at all in your scenario? Can't you just use a symmetric primary key and do all your operations with it? There is no need for you to be able to move keys between TPMs, is there?

Not sure I understood this comment, could you please elaborate?

Exporting the primary key sounds like TPM2_ContextSave, right? This should indeed be a fast operation, but your exported copy is only valid for that power cycle, so you need to recreate it after each reboot (or store it in NVM using TPM2_EvictControl).

Indeed.

Contributor

martinezjavier commented Sep 27, 2017

You can query the supported algorithms, but only in a generic "is this algorithm supported at all" kind of way (TPM_CAP_ALGS). You cannot determine whether a specific command will accept a certain parameter. Of

Yes, I know about TPM_CAP_ALGS. I meant to query if are supported as primary key.

course, if symmetric keys are fast enough to create, you could just always start with one, and only when your command fails, fall back to slower keys.

That's an option indeed. I would prefer to have as default algorithm one that's known to work on most TPM2 and let users decide (via the JSON config) if they want to use a different one.

Or another wild idea: Why do you need a storage key at all in your scenario? Can't you just use a symmetric primary key and do all your operations with it? There is no need for you to be able to move keys between TPMs, is there?

Not sure I understood this comment, could you please elaborate?

Exporting the primary key sounds like TPM2_ContextSave, right? This should indeed be a fast operation, but your exported copy is only valid for that power cycle, so you need to recreate it after each reboot (or store it in NVM using TPM2_EvictControl).

Indeed.

@webmeister

This comment has been minimized.

Show comment
Hide comment
@webmeister

webmeister Sep 27, 2017

But instead the pin only calculates the PK the first time and make it persistent in the TPM, so future operations don't have to.

As far as I can see from the code, you do not handle the case that the call to TPM2_EvictControl fails, for example because there is no space left in the TPM. Wouldn't it be better then to recreate the temporary key every time instead of refusing to work at all? Also, have you thought about how this works when more than one application uses the TPM? How do you recognize your persistent key in the TPM and not confuse it with a key that belongs to a different application? What is the lifetime of your persistent key in the TPM? If every application tries to store its keys there indefinitely, then it will certainly run out of space at some point.

@martinezjavier: Could you document somewhere what your solution is meant to protect against? Then I might review it with a focus on security. At the moment all I can say is that yes, it uses a TPM, but whether that makes it secure or not depends a lot on what you assume your attacker to be able to do.

webmeister commented Sep 27, 2017

But instead the pin only calculates the PK the first time and make it persistent in the TPM, so future operations don't have to.

As far as I can see from the code, you do not handle the case that the call to TPM2_EvictControl fails, for example because there is no space left in the TPM. Wouldn't it be better then to recreate the temporary key every time instead of refusing to work at all? Also, have you thought about how this works when more than one application uses the TPM? How do you recognize your persistent key in the TPM and not confuse it with a key that belongs to a different application? What is the lifetime of your persistent key in the TPM? If every application tries to store its keys there indefinitely, then it will certainly run out of space at some point.

@martinezjavier: Could you document somewhere what your solution is meant to protect against? Then I might review it with a focus on security. At the moment all I can say is that yes, it uses a TPM, but whether that makes it secure or not depends a lot on what you assume your attacker to be able to do.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 27, 2017

Contributor

@webmeister I've sent you a document I wrote that should better explain the goal of the solution, what we want to protect against and what security threats are not meant to protect.

Good point about handling the TPM2_EvictControl failure and recognizing the PK and not confusing it with an object stored by another application with the same associated key and hash algorithm.

I looked if there's information about a persistent object being a hierarchy root key or not but didn't find it. It seem that storing the PK makes it more fragile indeed, maybe we should only do it for RSA or only support algorithms whose PK recalculation is fast so don't need to be stored.

For the clevis tpm2 pin, only the PK keys are stored. The sealed objects created under the PK are stored outside of the TPM2.

I haven't considered other untrusted applications having access to the TPM2, otherwise they could do more destructive operations than just storing a lot of objects, for example clearing the TPM2 and making all the created objects unusable.

Contributor

martinezjavier commented Sep 27, 2017

@webmeister I've sent you a document I wrote that should better explain the goal of the solution, what we want to protect against and what security threats are not meant to protect.

Good point about handling the TPM2_EvictControl failure and recognizing the PK and not confusing it with an object stored by another application with the same associated key and hash algorithm.

I looked if there's information about a persistent object being a hierarchy root key or not but didn't find it. It seem that storing the PK makes it more fragile indeed, maybe we should only do it for RSA or only support algorithms whose PK recalculation is fast so don't need to be stored.

For the clevis tpm2 pin, only the PK keys are stored. The sealed objects created under the PK are stored outside of the TPM2.

I haven't considered other untrusted applications having access to the TPM2, otherwise they could do more destructive operations than just storing a lot of objects, for example clearing the TPM2 and making all the created objects unusable.

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Sep 27, 2017

Member

Can the document including the threat model please be included in the pull request?

Member

npmccallum commented Sep 27, 2017

Can the document including the threat model please be included in the pull request?

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 27, 2017

Contributor

@npmccallum for now I've added the mentioned document (not sure what should be a good place for these kind of docs and if are suitable) that explains the goal of binding a LUKS volume to a tpm2 pin, what is meant to protect and its limitations.

I should work on a more formal threat modelling but I think that doc could be a starting point for people to review the approach.

Contributor

martinezjavier commented Sep 27, 2017

@npmccallum for now I've added the mentioned document (not sure what should be a good place for these kind of docs and if are suitable) that explains the goal of binding a LUKS volume to a tpm2 pin, what is meant to protect and its limitations.

I should work on a more formal threat modelling but I think that doc could be a starting point for people to review the approach.

@webmeister

This comment has been minimized.

Show comment
Hide comment
@webmeister

webmeister Sep 27, 2017

@webmeister I've sent you a document I wrote that should better explain the goal of the solution, what we want to protect against and what security threats are not meant to protect.

Thanks, that was helpful to understand more of the details. Can your security model be summarized as "If and only if you can communicate with the TPM, you can decrypt the data"? So, on its own (without SSS) this solution can cover scenarios like "if the disk is broken, just throw it away, without the TPM nobody can get the key" (which also means that if the TPM is broken, the key is gone), but it does not help if the whole machine gets stolen and an attacker that can execute code on the machine might also be able to get the key?

I'm not sure though if the PCR restriction that you've implemented as an option brings a real benefit, at least as long as it is only used to bind the key to the current PCR values, instead of providing the expected PCR digests. If you just blindly use it to bind the key to the current state, then you risk not knowing what data has been extended into the PCRs, so that you'll be surprised when some of it changes at some point and you lose access to your key.

It seem that storing the PK makes it more fragile indeed, maybe we should only do it for RSA or only support algorithms whose PK recalculation is fast so don't need to be stored.

Yes, not storing the PK would be the simplest solution. From what I understand from the code, what you want ideally is this: Let the TPM generate a symmetric primary key and encrypt/decrypt some data with it (this is also the idea I had mentioned above). For a symmetric primary key the TPM just needs to run the KDF to generate a small amount of key material, so it is the fastest way to get a key. Since it is a primary key, you do not need to store it anywhere, but can simply recreate it every time you need it. And because it is derived from the TPM's internal seed values, the key is bound to that single TPM and cannot be generated by another TPM.

Unfortunately, the specification authors seem to be against such a simple solution. For symmetric encryption with the TPM you need the TPM2_EncryptDecrypt(2) command, but that is optional, not mandatory, according to PTP, so you cannot rely on it being present anywhere. And you cannot use the current approach with TPM2_Unseal and TPM-external encryption either, because that command is not allowed for keys that have been generated by the TPM internally.

RSA keys are too slow to use for direct encryption with TPM2_RSA_Encrypt and ECC keys do not really provide that feature. So, if it needs to run on most TPMs, it seems you can hardly do better than the current approach with an ECC storage key and unsealing a subkey.

I haven't considered other untrusted applications having access to the TPM2, otherwise they could do more destructive operations than just storing a lot of objects, for example clearing the TPM2 and making all the created objects unusable.

Clearing the TPM and other destructive operations should require separate authentication (at least, if it is configured). But just storing an object in NVM is more of an unprivileged operation that most applications should be able to do, isn't it? So if multiple applications have to share the same space, how do they cooperate to avoid conflicts? Maybe some kind of default storage key (as suggested in https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf, chapter 7.5.1 Storage Primary Key (SRK) Templates), that can be used by many applications, so that you can usually rely on it being present?

webmeister commented Sep 27, 2017

@webmeister I've sent you a document I wrote that should better explain the goal of the solution, what we want to protect against and what security threats are not meant to protect.

Thanks, that was helpful to understand more of the details. Can your security model be summarized as "If and only if you can communicate with the TPM, you can decrypt the data"? So, on its own (without SSS) this solution can cover scenarios like "if the disk is broken, just throw it away, without the TPM nobody can get the key" (which also means that if the TPM is broken, the key is gone), but it does not help if the whole machine gets stolen and an attacker that can execute code on the machine might also be able to get the key?

I'm not sure though if the PCR restriction that you've implemented as an option brings a real benefit, at least as long as it is only used to bind the key to the current PCR values, instead of providing the expected PCR digests. If you just blindly use it to bind the key to the current state, then you risk not knowing what data has been extended into the PCRs, so that you'll be surprised when some of it changes at some point and you lose access to your key.

It seem that storing the PK makes it more fragile indeed, maybe we should only do it for RSA or only support algorithms whose PK recalculation is fast so don't need to be stored.

Yes, not storing the PK would be the simplest solution. From what I understand from the code, what you want ideally is this: Let the TPM generate a symmetric primary key and encrypt/decrypt some data with it (this is also the idea I had mentioned above). For a symmetric primary key the TPM just needs to run the KDF to generate a small amount of key material, so it is the fastest way to get a key. Since it is a primary key, you do not need to store it anywhere, but can simply recreate it every time you need it. And because it is derived from the TPM's internal seed values, the key is bound to that single TPM and cannot be generated by another TPM.

Unfortunately, the specification authors seem to be against such a simple solution. For symmetric encryption with the TPM you need the TPM2_EncryptDecrypt(2) command, but that is optional, not mandatory, according to PTP, so you cannot rely on it being present anywhere. And you cannot use the current approach with TPM2_Unseal and TPM-external encryption either, because that command is not allowed for keys that have been generated by the TPM internally.

RSA keys are too slow to use for direct encryption with TPM2_RSA_Encrypt and ECC keys do not really provide that feature. So, if it needs to run on most TPMs, it seems you can hardly do better than the current approach with an ECC storage key and unsealing a subkey.

I haven't considered other untrusted applications having access to the TPM2, otherwise they could do more destructive operations than just storing a lot of objects, for example clearing the TPM2 and making all the created objects unusable.

Clearing the TPM and other destructive operations should require separate authentication (at least, if it is configured). But just storing an object in NVM is more of an unprivileged operation that most applications should be able to do, isn't it? So if multiple applications have to share the same space, how do they cooperate to avoid conflicts? Maybe some kind of default storage key (as suggested in https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf, chapter 7.5.1 Storage Primary Key (SRK) Templates), that can be used by many applications, so that you can usually rely on it being present?

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 27, 2017

Contributor

Thanks, that was helpful to understand more of the details. Can your security model be summarized as "If and only if you can communicate with the TPM, you can decrypt the data"? So, on its own (without SSS) this solution can cover scenarios like "if the disk is broken, just throw it away, without the TPM nobody can get the key" (which also means that if the TPM is broken, the key is gone), but it does not help if the whole machine gets stolen and an attacker that can execute code on the machine might also be able to get the key?

Your summary is correct, and also cover cases like if someone is able to get a VM image but has no access to the host.

'm not sure though if the PCR restriction that you've implemented as an option brings a real benefit, at least as long as it is only used to bind the key to the current PCR values, instead of providing the expected PCR digests. If you just blindly use it to bind the key to the current state, then you risk not knowing what data has been extended into the PCRs, so that you'll be surprised when some of it changes at some point and you lose access to your key.

There's an option to pass an expected PCR digest:

clevis encrypt tpm2 '{"pcr_ids":"7","pcr_digest":"xy7J5svCtqlfM03d1lE5gdoA8MI"}' < foo > bar.jwe

But you are right that people should know against what state they are sealing the data. The reason I added was mostly to not allow unlocking the disk if Secure Boot was disabled or the key modified. Since only the UEFI firmware and shim extends the PCR7.

Now, it doesn't protect against someone replacing the initramfs with a custom one, that just unlocks the disk and replaces the LUKS key for one that doesn't have this restriction.

As a second step, we should also have an encrypted /boot, that way this attack vector is mitigated since grub2 will be signed and so you know that no one was able to tamper with. But first we will need support in grub2 to be able to unseal the LUKS master key of the encrypted boot partition.

Unfortunately, the specification authors seem to be against such a simple solution. For symmetric encryption with the TPM you need the TPM2_EncryptDecrypt(2) command, but that is optional, not mandatory, according to PTP, so you cannot rely on it being present anywhere. And you cannot use the current approach with TPM2_Unseal and TPM-external encryption either, because that command is not allowed for keys that have been generated by the TPM internally.

And also you can't encrypt things with TPM2_EncryptDecrypt that will only be decrypted with a specific PCR state, right? Or at least I didn't find that information in the specification.

RSA keys are too slow to use for direct encryption with TPM2_RSA_Encrypt and ECC keys do not really provide that feature. So, if it needs to run on most TPMs, it seems you can hardly do better than the current approach with an ECC storage key and unsealing a subkey.

Indeed.

Clearing the TPM and other destructive operations should require separate authentication (at least, if it is configured). But just storing an object in NVM is more of an unprivileged operation that most applications

That's a very good point.

So if multiple applications have to share the same space, how do they cooperate to avoid conflicts? Maybe some kind of default storage key (as suggested in https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf, chapter 7.5.1 Storage Primary Key (SRK) Templates), that can be used by many applications, so that you can usually rely on it being present?

I was not aware of this document, I'll explore this. Thanks a lot for all your feedback.

Contributor

martinezjavier commented Sep 27, 2017

Thanks, that was helpful to understand more of the details. Can your security model be summarized as "If and only if you can communicate with the TPM, you can decrypt the data"? So, on its own (without SSS) this solution can cover scenarios like "if the disk is broken, just throw it away, without the TPM nobody can get the key" (which also means that if the TPM is broken, the key is gone), but it does not help if the whole machine gets stolen and an attacker that can execute code on the machine might also be able to get the key?

Your summary is correct, and also cover cases like if someone is able to get a VM image but has no access to the host.

'm not sure though if the PCR restriction that you've implemented as an option brings a real benefit, at least as long as it is only used to bind the key to the current PCR values, instead of providing the expected PCR digests. If you just blindly use it to bind the key to the current state, then you risk not knowing what data has been extended into the PCRs, so that you'll be surprised when some of it changes at some point and you lose access to your key.

There's an option to pass an expected PCR digest:

clevis encrypt tpm2 '{"pcr_ids":"7","pcr_digest":"xy7J5svCtqlfM03d1lE5gdoA8MI"}' < foo > bar.jwe

But you are right that people should know against what state they are sealing the data. The reason I added was mostly to not allow unlocking the disk if Secure Boot was disabled or the key modified. Since only the UEFI firmware and shim extends the PCR7.

Now, it doesn't protect against someone replacing the initramfs with a custom one, that just unlocks the disk and replaces the LUKS key for one that doesn't have this restriction.

As a second step, we should also have an encrypted /boot, that way this attack vector is mitigated since grub2 will be signed and so you know that no one was able to tamper with. But first we will need support in grub2 to be able to unseal the LUKS master key of the encrypted boot partition.

Unfortunately, the specification authors seem to be against such a simple solution. For symmetric encryption with the TPM you need the TPM2_EncryptDecrypt(2) command, but that is optional, not mandatory, according to PTP, so you cannot rely on it being present anywhere. And you cannot use the current approach with TPM2_Unseal and TPM-external encryption either, because that command is not allowed for keys that have been generated by the TPM internally.

And also you can't encrypt things with TPM2_EncryptDecrypt that will only be decrypted with a specific PCR state, right? Or at least I didn't find that information in the specification.

RSA keys are too slow to use for direct encryption with TPM2_RSA_Encrypt and ECC keys do not really provide that feature. So, if it needs to run on most TPMs, it seems you can hardly do better than the current approach with an ECC storage key and unsealing a subkey.

Indeed.

Clearing the TPM and other destructive operations should require separate authentication (at least, if it is configured). But just storing an object in NVM is more of an unprivileged operation that most applications

That's a very good point.

So if multiple applications have to share the same space, how do they cooperate to avoid conflicts? Maybe some kind of default storage key (as suggested in https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf, chapter 7.5.1 Storage Primary Key (SRK) Templates), that can be used by many applications, so that you can usually rely on it being present?

I was not aware of this document, I'll explore this. Thanks a lot for all your feedback.

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Sep 27, 2017

Member

To be clear, I'd strongly prefer that we not store anything in NVRAM. We have metadata storage built into our API. We should use this to store whatever key state we need to load into the TPM at recovery time. If we depend on keys being in NVRAM and they disappear for some reason, we're sunk.

Member

npmccallum commented Sep 27, 2017

To be clear, I'd strongly prefer that we not store anything in NVRAM. We have metadata storage built into our API. We should use this to store whatever key state we need to load into the TPM at recovery time. If we depend on keys being in NVRAM and they disappear for some reason, we're sunk.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 27, 2017

Contributor

@npmccallum agreed, I also don't like to store the primary key and that's why my first implementation didn't do it. I just added it latter due the high creation time for RSA keys.

But this is not an issue for ECC or SYMCIPHER so I could go back to the old implementation and we could maybe just not support RSA? The performance gain for not creating the primary keys for the other algorithms is really not worth the fragility of storing them in the TPM NVRAM.

Contributor

martinezjavier commented Sep 27, 2017

@npmccallum agreed, I also don't like to store the primary key and that's why my first implementation didn't do it. I just added it latter due the high creation time for RSA keys.

But this is not an issue for ECC or SYMCIPHER so I could go back to the old implementation and we could maybe just not support RSA? The performance gain for not creating the primary keys for the other algorithms is really not worth the fragility of storing them in the TPM NVRAM.

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Sep 27, 2017

Member

If RSA has to be slow, so be it. We can support it with this known trade-off.

However, I still don't understand why we can't create the RSA primary key during provisioning and then export it. Then, during recovery, we would load the primary key into the TPM and perform the operation. This should result in a huge speed-up since you don't have to find large primes.

Member

npmccallum commented Sep 27, 2017

If RSA has to be slow, so be it. We can support it with this known trade-off.

However, I still don't understand why we can't create the RSA primary key during provisioning and then export it. Then, during recovery, we would load the primary key into the TPM and perform the operation. This should result in a huge speed-up since you don't have to find large primes.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 28, 2017

Contributor

@npmccallum it's due a limitation imposed by the TPM specification. Primary keys can't be stored off the TPM, they have to either be regenerated from the internal primary seed values each time that are needed (with TPM2_CreatePrimary) or they can be made persistent in the TPM NVRAM (with TPM2_EvictControl).

The specification says that primary objects are not allowed to be stored off the TPM to prevent certain types of power analysis attacks on the primary seed values (which are the cryptographic root for the TPM hierarchies).

Other objects in the hierarchy are allowed to be stored off the TPM, by wrapping the sensitive part of the object with the parent object key. That's what we do for the actual sealed JWK and that's why we can include the public and sensitive part of the sealed object in the JWE, stored in the LUKSMeta header.

Contributor

martinezjavier commented Sep 28, 2017

@npmccallum it's due a limitation imposed by the TPM specification. Primary keys can't be stored off the TPM, they have to either be regenerated from the internal primary seed values each time that are needed (with TPM2_CreatePrimary) or they can be made persistent in the TPM NVRAM (with TPM2_EvictControl).

The specification says that primary objects are not allowed to be stored off the TPM to prevent certain types of power analysis attacks on the primary seed values (which are the cryptographic root for the TPM hierarchies).

Other objects in the hierarchy are allowed to be stored off the TPM, by wrapping the sensitive part of the object with the parent object key. That's what we do for the actual sealed JWK and that's why we can include the public and sensitive part of the sealed object in the JWE, stored in the LUKSMeta header.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Sep 29, 2017

Contributor

FYI, I've updated the branch yesterday going back to the version that didn't store the primary keys in the TPM NVRAM.

Contributor

martinezjavier commented Sep 29, 2017

FYI, I've updated the branch yesterday going back to the version that didn't store the primary keys in the TPM NVRAM.

@webmeister

This comment has been minimized.

Show comment
Hide comment
@webmeister

webmeister Oct 2, 2017

But you are right that people should know against what state they are sealing the data. The reason I added was mostly to not allow unlocking the disk if Secure Boot was disabled or the key modified. Since only the UEFI firmware and shim extends the PCR7.

Then what interface do you want to provide for that? The generic one that you have at the moment, where your users need to know exactly what they do, or they might lock themselves out of their system? Or a more limited interface, that maybe only has a single yes/no parameter "seal-against-current-secure-boot-state" that internally does the right thing?

Now, it doesn't protect against someone replacing the initramfs with a custom one, that just unlocks the disk and replaces the LUKS key for one that doesn't have this restriction.

At the moment, it is even easier than that, because as long as you do not change the PCR values after unlocking the disk, you can just repeat the TPM command after the machine has booted (and you may or may not need to be root for that, depending on how you've configured your /dev/tpm* and resource manager).

But once something changes the PCRs after unlocking I wonder how you'd then implement the "seal-against-current-state" option. Only change the PCR value if you really did unseal the LUKS key from the TPM, but leave it unchanged otherwise? How does this work in a multi-application environment, i.e. can you rely on no other application changing that PCR and on no other application requiring that PCR to be unchanged (or at a known value)? And what if you want to configure TPM-unlocking for a second disk in your machine, when the current system has already booted with a changed PCR? This all seems to be easy in a test environment, but rather fragile in the real world...

And also you can't encrypt things with TPM2_EncryptDecrypt that will only be decrypted with a specific PCR state, right? Or at least I didn't find that information in the specification.

You should be able to configure an authPolicy for the key that allows it to be used only with TPM2_EncryptDecrypt when the PCRs have a specific value. TPM2_PolicyCpHash additionally allows you to restrict the parameters that may be used with that TPM2_EncryptDecrypt call (encrypt or decrypt operation?), but as far as I can tell from the specification this restriction must include all parameters (which makes it pointless to use with TPM2_EncryptDecrypt since you do not want your data to be part of the policy).

Interesting, how easy it is to find things that are not covered by the specification, despite it being so huge and flexible, once you start working on real-world implementations...

If we depend on keys being in NVRAM and they disappear for some reason, we're sunk.

As long as those are primary keys, you can simply tell the TPM to recreate that key, and the decryption will still work. This is the advantage of primary keys, where the NVM acts only as a kind of cache, so that you do not have to wait that long for the key to be recreated.

But I can imagine some pitfalls that you would need to take care of, to ensure that this works in all cases. Therefore, if ECC key generation is fast enough without NVM caching, that makes it easier for now. Should performance become an issue, such optimizations can still be added in the future.

If RSA has to be slow, so be it. We can support it with this known trade-off.

Yes, and RSA-only TPMs should be rare, so there is no need for anybody to use it.

webmeister commented Oct 2, 2017

But you are right that people should know against what state they are sealing the data. The reason I added was mostly to not allow unlocking the disk if Secure Boot was disabled or the key modified. Since only the UEFI firmware and shim extends the PCR7.

Then what interface do you want to provide for that? The generic one that you have at the moment, where your users need to know exactly what they do, or they might lock themselves out of their system? Or a more limited interface, that maybe only has a single yes/no parameter "seal-against-current-secure-boot-state" that internally does the right thing?

Now, it doesn't protect against someone replacing the initramfs with a custom one, that just unlocks the disk and replaces the LUKS key for one that doesn't have this restriction.

At the moment, it is even easier than that, because as long as you do not change the PCR values after unlocking the disk, you can just repeat the TPM command after the machine has booted (and you may or may not need to be root for that, depending on how you've configured your /dev/tpm* and resource manager).

But once something changes the PCRs after unlocking I wonder how you'd then implement the "seal-against-current-state" option. Only change the PCR value if you really did unseal the LUKS key from the TPM, but leave it unchanged otherwise? How does this work in a multi-application environment, i.e. can you rely on no other application changing that PCR and on no other application requiring that PCR to be unchanged (or at a known value)? And what if you want to configure TPM-unlocking for a second disk in your machine, when the current system has already booted with a changed PCR? This all seems to be easy in a test environment, but rather fragile in the real world...

And also you can't encrypt things with TPM2_EncryptDecrypt that will only be decrypted with a specific PCR state, right? Or at least I didn't find that information in the specification.

You should be able to configure an authPolicy for the key that allows it to be used only with TPM2_EncryptDecrypt when the PCRs have a specific value. TPM2_PolicyCpHash additionally allows you to restrict the parameters that may be used with that TPM2_EncryptDecrypt call (encrypt or decrypt operation?), but as far as I can tell from the specification this restriction must include all parameters (which makes it pointless to use with TPM2_EncryptDecrypt since you do not want your data to be part of the policy).

Interesting, how easy it is to find things that are not covered by the specification, despite it being so huge and flexible, once you start working on real-world implementations...

If we depend on keys being in NVRAM and they disappear for some reason, we're sunk.

As long as those are primary keys, you can simply tell the TPM to recreate that key, and the decryption will still work. This is the advantage of primary keys, where the NVM acts only as a kind of cache, so that you do not have to wait that long for the key to be recreated.

But I can imagine some pitfalls that you would need to take care of, to ensure that this works in all cases. Therefore, if ECC key generation is fast enough without NVM caching, that makes it easier for now. Should performance become an issue, such optimizations can still be added in the future.

If RSA has to be slow, so be it. We can support it with this known trade-off.

Yes, and RSA-only TPMs should be rare, so there is no need for anybody to use it.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Oct 2, 2017

Contributor

Then what interface do you want to provide for that? The generic one that you have at the moment, where your users need to know exactly what they do, or they might lock themselves out of their system? Or a more limited interface, that maybe only has a single yes/no parameter "seal-against-current-secure-boot-state" that internally does the right thing?

@webmeister That's a very good question. The way I see it, is that clevis is more of a tool for a system administrators than for regular users. In my example, it's likely that another program (i.e: the Anaconda installer) will use clevis to bind a LUKS volume against a tpm2 pin and not expect users to do this using the CLI after the installation. The user should just check a "Use TPM2 to unlock" box or something in the installer along the current "Encrypt my data" one.

At the moment, it is even easier than that, because as long as you do not change the PCR values after unlocking the disk, you can just repeat the TPM command after the machine has booted (and you may or may not need to be root for that, depending on how you've configured your /dev/tpm* and resource manager).

You mean with some sort of man-in-the-middle in the device TCTI library (the clevis tpm2 pin explicitly use the device TCTI) that stores the command and sends it back to the TPM?

Because someone that doesn't have access to either the public and sensitive parts of the sealed objects (that are in the LUKSMeta header) to load it into the TPM or the used load context (which is temporary and deleted after unsealing) shouldn't be able to perform this kind of attack, right?

Probably I should suggest a change to the tpm2-tools folks to allow tpm2_load to print the load context to the standard output, so it never is stored as a temp file.

If someone has access to both the TPM2 and the LUKS device, then yes it can decrypt the data but then it can just use clevis for that, no need to send a cached command.

This all seems to be easy in a test environment, but rather fragile in the real world...

As mentioned, for the root partition I expect anaconda to do the binding and dracut to do the unlocking in the initramfs. If someone messes with the initramfs and has an application that extends the PCR7 before clevis is able to unlock, then it will fail indeed. But that's why I said that it's not meant to protect from someone with root access after the volume has been unlocked.

nteresting, how easy it is to find things that are not covered by the specification, despite it being so huge and flexible, once you start working on real-world implementations...

Indeed.

But I can imagine some pitfalls that you would need to take care of, to ensure that this works in all cases. Therefore, if ECC key generation is fast enough without NVM caching, that makes it easier for now. Should performance become an issue, such optimizations can still be added in the future.

Agreed.

Thanks a lot for your feedback and explanations!

Contributor

martinezjavier commented Oct 2, 2017

Then what interface do you want to provide for that? The generic one that you have at the moment, where your users need to know exactly what they do, or they might lock themselves out of their system? Or a more limited interface, that maybe only has a single yes/no parameter "seal-against-current-secure-boot-state" that internally does the right thing?

@webmeister That's a very good question. The way I see it, is that clevis is more of a tool for a system administrators than for regular users. In my example, it's likely that another program (i.e: the Anaconda installer) will use clevis to bind a LUKS volume against a tpm2 pin and not expect users to do this using the CLI after the installation. The user should just check a "Use TPM2 to unlock" box or something in the installer along the current "Encrypt my data" one.

At the moment, it is even easier than that, because as long as you do not change the PCR values after unlocking the disk, you can just repeat the TPM command after the machine has booted (and you may or may not need to be root for that, depending on how you've configured your /dev/tpm* and resource manager).

You mean with some sort of man-in-the-middle in the device TCTI library (the clevis tpm2 pin explicitly use the device TCTI) that stores the command and sends it back to the TPM?

Because someone that doesn't have access to either the public and sensitive parts of the sealed objects (that are in the LUKSMeta header) to load it into the TPM or the used load context (which is temporary and deleted after unsealing) shouldn't be able to perform this kind of attack, right?

Probably I should suggest a change to the tpm2-tools folks to allow tpm2_load to print the load context to the standard output, so it never is stored as a temp file.

If someone has access to both the TPM2 and the LUKS device, then yes it can decrypt the data but then it can just use clevis for that, no need to send a cached command.

This all seems to be easy in a test environment, but rather fragile in the real world...

As mentioned, for the root partition I expect anaconda to do the binding and dracut to do the unlocking in the initramfs. If someone messes with the initramfs and has an application that extends the PCR7 before clevis is able to unlock, then it will fail indeed. But that's why I said that it's not meant to protect from someone with root access after the volume has been unlocked.

nteresting, how easy it is to find things that are not covered by the specification, despite it being so huge and flexible, once you start working on real-world implementations...

Indeed.

But I can imagine some pitfalls that you would need to take care of, to ensure that this works in all cases. Therefore, if ECC key generation is fast enough without NVM caching, that makes it easier for now. Should performance become an issue, such optimizations can still be added in the future.

Agreed.

Thanks a lot for your feedback and explanations!

@webmeister

This comment has been minimized.

Show comment
Hide comment
@webmeister

webmeister Oct 2, 2017

In my example, it's likely that another program (i.e: the Anaconda installer) will use clevis to bind a LUKS volume against a tpm2 pin and not expect users to do this using the CLI after the installation.

Then Anaconda needs to know that PCR7 is connected to the secure boot state. If it is only Anaconda that needs this knowledge, this is fine. But if you expect other applications to have the same need, then it would make sense to encode this TPM-specific knowledge somewhere on a lower layer (clevis in this case?), so that not every application author has to read the obscure TPM specifications (or blindly copy the algorithm from another application).

You mean with some sort of man-in-the-middle in the device TCTI library (the clevis tpm2 pin explicitly use the device TCTI) that stores the command and sends it back to the TPM?

No, my assumption was that the attacker can access the sealed object that is stored on the disk (encrypted with a TPM-internal secret). Because if your assumption is that an attacker cannot access that data, there would be no need for you to use a TPM at all, you could just store your key in plain at the same location.

From the "the disk alone cannot be decrypted" scenario I guess that what you really assume is that the attacker can access the sealed object (e.g. because they have physical access to the disk) or perhaps the TPM (e.g. because they can execute code as a non-root user on the machine), but never both. But that scenario would also work with an inexpensive USB flash drive as key storage, no need for a fancy TPM. So to really get an advantage from the TPM, you need to use it for more than just a very complicated data storage ;-)

Because someone that doesn't have access to either the public and sensitive parts of the sealed objects (that are in the LUKSMeta header) to load it into the TPM or the used load context (which is temporary and deleted after unsealing) shouldn't be able to perform this kind of attack, right?

Correct.

If someone messes with the initramfs and has an application that extends the PCR7 before clevis is able to unlock, then it will fail indeed. But that's why I said that it's not meant to protect from someone with root access after the volume has been unlocked.

This is not so much about attacks, but again rather about cooperation between multiple applications. You are probably the first/only application at the moment, so there is nobody else to cooperate with. But that only means that you will not notice now, if you violate the expectations of other authors (that might be encoded in some specification). Do you know whether there is a specification that describes what you can and cannot do with PCR7?

I'll be on vacation for the rest of the week, so further discussion probably has to be moved to next week.

webmeister commented Oct 2, 2017

In my example, it's likely that another program (i.e: the Anaconda installer) will use clevis to bind a LUKS volume against a tpm2 pin and not expect users to do this using the CLI after the installation.

Then Anaconda needs to know that PCR7 is connected to the secure boot state. If it is only Anaconda that needs this knowledge, this is fine. But if you expect other applications to have the same need, then it would make sense to encode this TPM-specific knowledge somewhere on a lower layer (clevis in this case?), so that not every application author has to read the obscure TPM specifications (or blindly copy the algorithm from another application).

You mean with some sort of man-in-the-middle in the device TCTI library (the clevis tpm2 pin explicitly use the device TCTI) that stores the command and sends it back to the TPM?

No, my assumption was that the attacker can access the sealed object that is stored on the disk (encrypted with a TPM-internal secret). Because if your assumption is that an attacker cannot access that data, there would be no need for you to use a TPM at all, you could just store your key in plain at the same location.

From the "the disk alone cannot be decrypted" scenario I guess that what you really assume is that the attacker can access the sealed object (e.g. because they have physical access to the disk) or perhaps the TPM (e.g. because they can execute code as a non-root user on the machine), but never both. But that scenario would also work with an inexpensive USB flash drive as key storage, no need for a fancy TPM. So to really get an advantage from the TPM, you need to use it for more than just a very complicated data storage ;-)

Because someone that doesn't have access to either the public and sensitive parts of the sealed objects (that are in the LUKSMeta header) to load it into the TPM or the used load context (which is temporary and deleted after unsealing) shouldn't be able to perform this kind of attack, right?

Correct.

If someone messes with the initramfs and has an application that extends the PCR7 before clevis is able to unlock, then it will fail indeed. But that's why I said that it's not meant to protect from someone with root access after the volume has been unlocked.

This is not so much about attacks, but again rather about cooperation between multiple applications. You are probably the first/only application at the moment, so there is nobody else to cooperate with. But that only means that you will not notice now, if you violate the expectations of other authors (that might be encoded in some specification). Do you know whether there is a specification that describes what you can and cannot do with PCR7?

I'll be on vacation for the rest of the week, so further discussion probably has to be moved to next week.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Oct 2, 2017

Contributor

But if you expect other applications to have the same need, then it would make sense to encode this

TPM-specific knowledge somewhere on a lower layer (clevis in this case?), so that not every application author has to read the obscure TPM specifications (or blindly copy the algorithm from another application).

Yes, I get your point and I don't say that I disagree with you. I'm just not sure if clevis is supposed to only provide mechanisms and let users define the policies or also have some built-in policies, like your "seal-against-current-secure-boot-state" example. I'll let @npmccallum comment on this.

No, my assumption was that the attacker can access the sealed object that is stored on the disk (encrypted with a TPM-internal secret). Because if your assumption is that an attacker cannot access that data, there

I was talking about the "user with access to both the disk and TPM2 after boot" case. One option I can think of is to extend the PCR7 with a pre-defined hash (i.e: all 0) after the LUKS volume is unlocked.

That way someone who gets access to both the sealed data and the TPM2, won't be able to unseal the secret after the system was booted. But users will still be able to seal other data against that current PCR state, since the PCR7 digest will always be extended with the same value (hash on boot + 0s).

would be no need for you to use a TPM at all, you could just store your key in plain at the same location.

Well, the point of having the key sealed against the TPM2 and not in plain text is to bind the disk to the machine. If it was in plain text, then someone that steals the disk (or VM image) could just unlock it.

From the "the disk alone cannot be decrypted" scenario I guess that what you really assume is that the attacker can access the sealed object (e.g. because they have physical access to the disk) or perhaps the TPM (e.g. because they can execute code as a non-root user on the machine), but never both. But that

Correct, I assume that either one can access the TPM2 (because not only root can execute commands) or the sealed key (because the disk is stolen) but never both.

scenario would also work with an inexpensive USB flash drive as key storage, no need for a fancy TPM. So to really get an advantage from the TPM, you need to use it for more than just a very complicated data storage ;-)

That's true. But the advantage of the TPM2 is that it will already be present in most machines and also users don't have to plug it on boot. If a security mechanism depends on user to plug a device each time they need to boot a machine, most likely will fail due being hard to use. I think the TPM2 is a good trade off between security and easy of use.

This is not so much about attacks, but again rather about cooperation between multiple applications. You are probably the first/only application at the moment, so there is nobody else to cooperate with. But that only means that you will not notice now, if you violate the expectations of other authors (that might

I see, you are making a very good point and I've to admit that I haven't given a lot of thinking to this yet. But I think that the TPM2 being a sensitive shared resource, most applications using it should be trusted.

be encoded in some specification). Do you know whether there is a specification that describes what you can and cannot do with PCR7?

The most official documentation that I know of is this from Microsoft and is what follows shim.

I'll be on vacation for the rest of the week, so further discussion probably has to be moved to next week.

No worries, enjoy your vacation. This is blocked on a new release of the tpm2-tools anyways, so we have time to discuss these issues and further refine the implementation if needed.

I should also go on paternity leave soon (depending on when the baby decides to arrive), so I may become less active for a couple of weeks. Thanks, again!

Contributor

martinezjavier commented Oct 2, 2017

But if you expect other applications to have the same need, then it would make sense to encode this

TPM-specific knowledge somewhere on a lower layer (clevis in this case?), so that not every application author has to read the obscure TPM specifications (or blindly copy the algorithm from another application).

Yes, I get your point and I don't say that I disagree with you. I'm just not sure if clevis is supposed to only provide mechanisms and let users define the policies or also have some built-in policies, like your "seal-against-current-secure-boot-state" example. I'll let @npmccallum comment on this.

No, my assumption was that the attacker can access the sealed object that is stored on the disk (encrypted with a TPM-internal secret). Because if your assumption is that an attacker cannot access that data, there

I was talking about the "user with access to both the disk and TPM2 after boot" case. One option I can think of is to extend the PCR7 with a pre-defined hash (i.e: all 0) after the LUKS volume is unlocked.

That way someone who gets access to both the sealed data and the TPM2, won't be able to unseal the secret after the system was booted. But users will still be able to seal other data against that current PCR state, since the PCR7 digest will always be extended with the same value (hash on boot + 0s).

would be no need for you to use a TPM at all, you could just store your key in plain at the same location.

Well, the point of having the key sealed against the TPM2 and not in plain text is to bind the disk to the machine. If it was in plain text, then someone that steals the disk (or VM image) could just unlock it.

From the "the disk alone cannot be decrypted" scenario I guess that what you really assume is that the attacker can access the sealed object (e.g. because they have physical access to the disk) or perhaps the TPM (e.g. because they can execute code as a non-root user on the machine), but never both. But that

Correct, I assume that either one can access the TPM2 (because not only root can execute commands) or the sealed key (because the disk is stolen) but never both.

scenario would also work with an inexpensive USB flash drive as key storage, no need for a fancy TPM. So to really get an advantage from the TPM, you need to use it for more than just a very complicated data storage ;-)

That's true. But the advantage of the TPM2 is that it will already be present in most machines and also users don't have to plug it on boot. If a security mechanism depends on user to plug a device each time they need to boot a machine, most likely will fail due being hard to use. I think the TPM2 is a good trade off between security and easy of use.

This is not so much about attacks, but again rather about cooperation between multiple applications. You are probably the first/only application at the moment, so there is nobody else to cooperate with. But that only means that you will not notice now, if you violate the expectations of other authors (that might

I see, you are making a very good point and I've to admit that I haven't given a lot of thinking to this yet. But I think that the TPM2 being a sensitive shared resource, most applications using it should be trusted.

be encoded in some specification). Do you know whether there is a specification that describes what you can and cannot do with PCR7?

The most official documentation that I know of is this from Microsoft and is what follows shim.

I'll be on vacation for the rest of the week, so further discussion probably has to be moved to next week.

No worries, enjoy your vacation. This is blocked on a new release of the tpm2-tools anyways, so we have time to discuss these issues and further refine the implementation if needed.

I should also go on paternity leave soon (depending on when the baby decides to arrive), so I may become less active for a couple of weeks. Thanks, again!

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Oct 6, 2017

Member

One thing we need to do in this patch is clearly define the threat model and what attacks we cannot protect against. This needs to be meticulously documented in the man page.

Member

npmccallum commented Oct 6, 2017

One thing we need to do in this patch is clearly define the threat model and what attacks we cannot protect against. This needs to be meticulously documented in the man page.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Oct 6, 2017

Contributor

@npmccallum yes, I've been thinking about this. I was wrongly focused on the LUKS volume unlock case, but that's just a particular case of a more general one. Basically, what clevis assumes is that the attacker doesn't have access to the TPM2.

On encryption, a JWK is created, the data is encrypted with the JWK and the JWK is encrypted with the TPM2. Both the ciphertext and the wrapped JWK are stored in the JWE.

On decryption, both the ciphertext and the wrapped JWK are taken from the JWE and the TPM2 is used to decrypt the JWK which in turn is used to decrypt the ciphertext.

So the assumption is that the attacker won't have access to both the JWE and the TPM2. This assumption is not only true for the clevis tpm2 pin but for all pins AFAICT.

For example, in the tang and HTTP pins an attacker only needs access to both the JWE and the network service to decrypt the ciphertext. The assumption is that it won't have access to both.

The only difference between these pins and the tpm2 one, is that the {en,de}cryption backend is local to the machine. So it must be protected from the attackers.

And additional protection that the TPM2 has, is that the encrypted data could be "sealed" to a specific TPM2 PCR state. So if the current PCR state doesn't match the one specified on encryption, the data can't de decrypted even if the attacker has access to the TPM2.

Contributor

martinezjavier commented Oct 6, 2017

@npmccallum yes, I've been thinking about this. I was wrongly focused on the LUKS volume unlock case, but that's just a particular case of a more general one. Basically, what clevis assumes is that the attacker doesn't have access to the TPM2.

On encryption, a JWK is created, the data is encrypted with the JWK and the JWK is encrypted with the TPM2. Both the ciphertext and the wrapped JWK are stored in the JWE.

On decryption, both the ciphertext and the wrapped JWK are taken from the JWE and the TPM2 is used to decrypt the JWK which in turn is used to decrypt the ciphertext.

So the assumption is that the attacker won't have access to both the JWE and the TPM2. This assumption is not only true for the clevis tpm2 pin but for all pins AFAICT.

For example, in the tang and HTTP pins an attacker only needs access to both the JWE and the network service to decrypt the ciphertext. The assumption is that it won't have access to both.

The only difference between these pins and the tpm2 one, is that the {en,de}cryption backend is local to the machine. So it must be protected from the attackers.

And additional protection that the TPM2 has, is that the encrypted data could be "sealed" to a specific TPM2 PCR state. So if the current PCR state doesn't match the one specified on encryption, the data can't de decrypted even if the attacker has access to the TPM2.

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Oct 6, 2017

Member

This is correct so far. The question for me is clearly delineating if/how the TPM2 can be protected. For network services this is pretty obvious (firewall, authentication, etc.). But it is much less clear for TPM.

Binding against PCRs only helps if the PCRs are extended with the relevant measurements. On Linux, they aren't (yet). Further, if the measurements are all stock executables (kernel, initramfs, init, etc.) then an attacker can reproduce these measurements by booting an alternate stock OS that has different root credentials. Thus, for example, this might be useful for a root volume in initramfs since, after initramfs, recovery would be impossible. But this can't be used for non-root volumes which are unlocked after boot because an attacker would then always have access to the TPM.

We need to think carefully about these cases and document the possible attacks.

Member

npmccallum commented Oct 6, 2017

This is correct so far. The question for me is clearly delineating if/how the TPM2 can be protected. For network services this is pretty obvious (firewall, authentication, etc.). But it is much less clear for TPM.

Binding against PCRs only helps if the PCRs are extended with the relevant measurements. On Linux, they aren't (yet). Further, if the measurements are all stock executables (kernel, initramfs, init, etc.) then an attacker can reproduce these measurements by booting an alternate stock OS that has different root credentials. Thus, for example, this might be useful for a root volume in initramfs since, after initramfs, recovery would be impossible. But this can't be used for non-root volumes which are unlocked after boot because an attacker would then always have access to the TPM.

We need to think carefully about these cases and document the possible attacks.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Nov 13, 2017

Contributor

We need to think carefully about these cases and document the possible attacks.

I think that rather than documenting all the possible attacks, what we should explain clearly is the fact that the Clevis security model relies on the fact that an attacker would not get access to both the encrypted secret and the decryption key.

And that in the case of the tpm2 pin, the key es encrypted using a TPM2 chip that's always present in the machine. While for other pins, the decryption key is located externally (a remove server, a pluggable authentication device, etc).

That way people can understand the limitations of the tpm2 pin an assess the risk and how to protect the TPM2 depending on their particular use case.

I've rebased the commit on top of latest master and also added some comments on this line to the clevis-encrypt-tpm2 man page:

# Threat model

The Clevis security model relies in the fact that an attacker will not be able to
access both the encrypted data and the decryption key.

For most Clevis pins, the decryption key is not locally stored, so the decryption
policy is only satisfied if the decryption key can be remotely accessed. It could
for example be stored in a remote server or in a hardware authentication device
that has to be plugged into the machine.

The tpm2 pin is different in this regard, since a key is wrapped by a TPM2 chip
that is always present in the machine. This does not mean that there are not use
cases for this pin, but it is important to understand the fact that an attacker
that has access to both the encrypted data and the local TPM2 chip will be able
to decrypt the data.

@npmccallum please let me know what you think.

Contributor

martinezjavier commented Nov 13, 2017

We need to think carefully about these cases and document the possible attacks.

I think that rather than documenting all the possible attacks, what we should explain clearly is the fact that the Clevis security model relies on the fact that an attacker would not get access to both the encrypted secret and the decryption key.

And that in the case of the tpm2 pin, the key es encrypted using a TPM2 chip that's always present in the machine. While for other pins, the decryption key is located externally (a remove server, a pluggable authentication device, etc).

That way people can understand the limitations of the tpm2 pin an assess the risk and how to protect the TPM2 depending on their particular use case.

I've rebased the commit on top of latest master and also added some comments on this line to the clevis-encrypt-tpm2 man page:

# Threat model

The Clevis security model relies in the fact that an attacker will not be able to
access both the encrypted data and the decryption key.

For most Clevis pins, the decryption key is not locally stored, so the decryption
policy is only satisfied if the decryption key can be remotely accessed. It could
for example be stored in a remote server or in a hardware authentication device
that has to be plugged into the machine.

The tpm2 pin is different in this regard, since a key is wrapped by a TPM2 chip
that is always present in the machine. This does not mean that there are not use
cases for this pin, but it is important to understand the fact that an attacker
that has access to both the encrypted data and the local TPM2 chip will be able
to decrypt the data.

@npmccallum please let me know what you think.

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Nov 13, 2017

Member

I think that is good. Perhaps we should also have a separate man page that discusses the security implications of automated decryption at a high level and then overviews the unlocking methods and their specific security properties?

Member

npmccallum commented Nov 13, 2017

I think that is good. Perhaps we should also have a separate man page that discusses the security implications of automated decryption at a high level and then overviews the unlocking methods and their specific security properties?

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Nov 14, 2017

Contributor

@npmccallum agreed. That will be a more general man page so I think that will belong to a separate pull request as a follow-up.

Contributor

martinezjavier commented Nov 14, 2017

@npmccallum agreed. That will be a more general man page so I think that will belong to a separate pull request as a follow-up.

@RashmicaG

This comment has been minimized.

Show comment
Hide comment
@RashmicaG

RashmicaG Nov 28, 2017

Hi @martinezjavier,
I'm interested in this pull request but unfortunately don't yet have access to a TPM to try it out :(

I like the idea of extending PCR7 once you've got the secret from the TPM. Have you read this article?

This is blocked on a new release of the tpm2-tools anyways

Do you have any idea on when the tpm2-tools release might come out?

RashmicaG commented Nov 28, 2017

Hi @martinezjavier,
I'm interested in this pull request but unfortunately don't yet have access to a TPM to try it out :(

I like the idea of extending PCR7 once you've got the secret from the TPM. Have you read this article?

This is blocked on a new release of the tpm2-tools anyways

Do you have any idea on when the tpm2-tools release might come out?

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Nov 28, 2017

Contributor

@RashmicaG great, thanks for your interest.

I like the idea of extending PCR7 once you've got the secret from the TPM. Have you read this article?

Yes, I read Matthew's article. In fact, that's from where I got the idea of extending PCR7.

Do you have any idea on when the tpm2-tools release might come out?

The second release candidate (-rc1) of the tpm2-tools 3.0.0 was released yesterday. Hopefully the final version should be in a week or so.

Contributor

martinezjavier commented Nov 28, 2017

@RashmicaG great, thanks for your interest.

I like the idea of extending PCR7 once you've got the secret from the TPM. Have you read this article?

Yes, I read Matthew's article. In fact, that's from where I got the idea of extending PCR7.

Do you have any idea on when the tpm2-tools release might come out?

The second release candidate (-rc1) of the tpm2-tools 3.0.0 was released yesterday. Hopefully the final version should be in a week or so.

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Nov 28, 2017

Member

@martinezjavier Can we land -rc1 in rawhide ASAP?

Member

npmccallum commented Nov 28, 2017

@martinezjavier Can we land -rc1 in rawhide ASAP?

Add Trusted Platform Module 2.0 (TPM2) pin support
This adds support for a Trusted Platform Module 2.0 (TPM2) clevis pin.
It encrypts the JWK using a TPM2 chip, and then at decryption time the
JWK is decrypted using the same TPM2 chip to allow clevis to decrypt
the secret stored in the JWE. That way the ciphertext is bound to a TPM
so it can only be decripted in a particular machine.

Encrypting data using the tpm2 pin works the same than with other pins:

$ clevis encrypt tpm2 '{}' < PT > JWE

The pin has reasonable defaults for its configuration, but a different
hierarchy, hash, and key algorithms can be choosen if the defaults are
not suitable.

Decryption also works the same than with other pins, only needs the JWE:

$ clevis decrypt tpm2 < JWE > PT

The public and private key pair of the encrypted JWK are stored in the
JWE object, so those can be fetched at decryption time to unseal the
JWK using the TPM2 chip.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Nov 30, 2017

Member

Excellent! I will try to get this tested next week.

Member

npmccallum commented Nov 30, 2017

Excellent! I will try to get this tested next week.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Nov 30, 2017

Contributor

@npmccallum perfect, thanks a lot for your help!

Please let me know if have any issues or something isn't clear to you.

Contributor

martinezjavier commented Nov 30, 2017

@npmccallum perfect, thanks a lot for your help!

Please let me know if have any issues or something isn't clear to you.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Jan 2, 2018

Contributor

@npmccallum did you have time to test this?

Contributor

martinezjavier commented Jan 2, 2018

@npmccallum did you have time to test this?

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Jan 2, 2018

Member

Not yet. I'm out of the office until Jan 8th. I'll make it a priority when I get back.

Member

npmccallum commented Jan 2, 2018

Not yet. I'm out of the office until Jan 8th. I'll make it a priority when I get back.

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Jan 2, 2018

Contributor

@npmccallum great, thanks a lot!

And also happy new year 😃

Contributor

martinezjavier commented Jan 2, 2018

@npmccallum great, thanks a lot!

And also happy new year 😃

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Feb 9, 2018

Contributor

@npmccallum another gentle ping on this.

Contributor

martinezjavier commented Feb 9, 2018

@npmccallum another gentle ping on this.

@npmccallum

I am testing this now.

curl \
jose \
nc
dracut_need_initqueue
}
installkernel() {
hostonly='' instmods =drivers/char/tpm

This comment has been minimized.

@npmccallum

npmccallum Feb 13, 2018

Member

The space after instmods looks strange. Is it correct?

@npmccallum

npmccallum Feb 13, 2018

Member

The space after instmods looks strange. Is it correct?

This comment has been minimized.

@circhioz

circhioz Feb 13, 2018

I think it is.
From dracut's man page:

instmods installs one or more kernel modules in the initramfs.
can also be a whole subsystem, if prefixed with a
"="

@circhioz

circhioz Feb 13, 2018

I think it is.
From dracut's man page:

instmods installs one or more kernel modules in the initramfs.
can also be a whole subsystem, if prefixed with a
"="

This comment has been minimized.

@martinezjavier

martinezjavier Feb 13, 2018

Contributor

@npmccallum yes, as @circhioz said I took that from dracut's man page.

You can also look that other dracut modules are using it, i.e: $ grep "instmods =" /usr/lib/dracut/modules.d/ -R

@martinezjavier

martinezjavier Feb 13, 2018

Contributor

@npmccallum yes, as @circhioz said I took that from dracut's man page.

You can also look that other dracut modules are using it, i.e: $ grep "instmods =" /usr/lib/dracut/modules.d/ -R

This comment has been minimized.

@npmccallum

npmccallum Feb 13, 2018

Member

Perfect! Thanks!

@npmccallum

npmccallum Feb 13, 2018

Member

Perfect! Thanks!

@npmccallum

This comment has been minimized.

Show comment
Hide comment
@npmccallum

npmccallum Feb 13, 2018

Member

I tested this in the boot and non-root cases. Both work. The code looks clean. It is merged. Congratulations to everyone!

Also, I've release v9, which contains primarily this change along with some minor other fixes.

Member

npmccallum commented Feb 13, 2018

I tested this in the boot and non-root cases. Both work. The code looks clean. It is merged. Congratulations to everyone!

Also, I've release v9, which contains primarily this change along with some minor other fixes.

@npmccallum npmccallum closed this Feb 13, 2018

@martinezjavier

This comment has been minimized.

Show comment
Hide comment
@martinezjavier

martinezjavier Feb 13, 2018

Contributor

@npmccallum great, thanks a lot for your help!

Contributor

martinezjavier commented Feb 13, 2018

@npmccallum great, thanks a lot for your help!

@martinezjavier martinezjavier deleted the martinezjavier:tpm2-pin branch Mar 22, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment