stefanberger / swtpm

Libtpms-based TPM emulator with socket, character device, and Linux CUSE interface.
Other
564 stars 136 forks source link

TPM 2.0 emulation silently fails on FIPS-enabled operating systems #703

Closed jean-edouard closed 2 years ago

jean-edouard commented 2 years ago

Describe the bug On a FIPS-enabled machines, emulated TPM 2.0 devices fail their self-check and therefore are unusable.

To Reproduce Steps to reproduce the behavior:

  1. Using a recent Linux distribution that supports FIPS, enable it with fips-mode-setup --enable and reboot
  2. Create a virtual machine with an emulated TPM 2.0 device (using for example virt-manager)
  3. Start the virtual machine
  4. Try to use the TPM chip from the virtual machine and/or look at the swtpm logs

Expected behavior The virtual machine can use the TPM device and the swtpm logs show no error

Desktop (please complete the following information):

Versions of relevant components

Log files

[...]
libtpms/tpm2: Entering failure mode; code: 6, location: TestSymmetricAlgorithm line 230
libtpms/tpm2: TPM2_Process: Entered failure mode through command:
80 01 00 00 00 0b 00 00 01 43 00

Additional context The issue is discussed in more details there: https://bugzilla.redhat.com/show_bug.cgi?id=2090219 Some algorithms are just blocked by FIPS through openssl. As mentioned in the bugzilla issue, adding options to swtpm for disabling those algorithms would be ideal (--disable-camellia, --disable-algX, ...)

jean-edouard commented 2 years ago

If the TPM spec doesn't have the flexibility necessary to disable those algorithms, maybe we could completely disable the features that require them? The thing is that, sadly, the current popularity spike of TPM is due to Windows 11 requiring its presence... However, Windows 11 doesn't actually leverage the TPM device by default, so having a mode where we just support the bare minimum functionality would be very helpful.

stefanberger commented 2 years ago

The TPM 2 (reference) code does not support runtime-disablement of compile-time enabled algorithms.

stefanberger commented 2 years ago

If the TPM spec doesn't have the flexibility necessary to disable those algorithms, maybe we could completely disable the features that require them?

This is not so easy, since this would break the upgrade path of virtual machines and their attached TPMs. A (suspended) VM that has used the TPM with some crypto algorithm would expect that the same algorithm is available after start/resume of the VM again otherwise how would it be able to for example decrypt its data then if some crypto algorithm got disabled?

jean-edouard commented 2 years ago

If the TPM spec doesn't have the flexibility necessary to disable those algorithms, maybe we could completely disable the features that require them?

This is not so easy, since this would break the upgrade path of virtual machines and their attached TPMs. A (suspended) VM that has used the TPM with some crypto algorithm would expect that the same algorithm is available after start/resume of the VM again otherwise how would it be able to for example decrypt its data then if some crypto algorithm got disabled?

If the new flags are local to the swtpm binary/process, and they are disabled by default, it shouldn't be a problem, as you'd have to change the VM definition to use them, right?

stefanberger commented 2 years ago

If the TPM spec doesn't have the flexibility necessary to disable those algorithms, maybe we could completely disable the features that require them?

This is not so easy, since this would break the upgrade path of virtual machines and their attached TPMs. A (suspended) VM that has used the TPM with some crypto algorithm would expect that the same algorithm is available after start/resume of the VM again otherwise how would it be able to for example decrypt its data then if some crypto algorithm got disabled?

If the new flags are local to the swtpm binary/process, and they are disabled by default, it shouldn't be a problem, as you'd have to change the VM definition to use them, right?

What I meant with the above is that compile-time disablement of algorithms is not possible since this would prevent all existing swtpms to read their state or prevent software inside a VM to decrypt data that was previously encrypted with a now-disabled algorithm. If anything, the TPM 2 code would have to be changed to support runtime-disablement of algorithms and the set of disabled algorithms could only reasonably be set once at the initial creation of the TPM 2 and would have to be carried forward by the state of the TPM 2 from then on. That would be the only way to support disabling algorithms so that a VM can never use those algorithms and we don't get surprises that all of a sudden data cannot be decrypted anymore since algorithms have been disabled inside the TPM 2 because the crypto library disabled them but they were previously available and used. One wouldn't want that kind of a surprise.

So when creating a VM one would have to decide which algorithms to disable and no algorithms that were left enabled could be disabled from then on by the crypto library because software inside the VM may have used these algorithms already and expects them to be there from then on.

berrange commented 2 years ago

I've not tried to reproduce the scenario myself, but I strongly suspect that FIPS enablement is just one example of a more general problem. The crypto algorithms exposed by openssl are inherently dynamic. The algorithms available in the build environment cannot be assumed to be available in a runtime environment even ignoring FIPS. We have to expect there may be fewer available at runtime.

Turning on FIPS is one thing that will influence what algorithms openssl reports. In RHEL / Fedora distros though there is also the global crypto policy in /etc/crypto-policies, which is a runtime per host configuration mechanism that might influence which algorithms openssl reports.

IOW, restricting algorithms to only FIPS permitted algorithms at compile time, as well as causing upgrade issues, is also not likely to solve the more general problem. Ultimately I don't see how we can avoid selecting algorithms at the time of instantiating the vTPM, instead of at compile time.

kraxel commented 2 years ago

What I meant with the above is that compile-time disablement of algorithms is not possible since this would prevent all existing swtpms to read their state or prevent software inside a VM to decrypt data that was previously encrypted with a now-disabled algorithm. If anything, the TPM 2 code would have to be changed to support runtime-disablement of algorithms and the set of disabled algorithms could only reasonably be set once at the initial creation of the TPM 2 and would have to be carried forward by the state of the TPM 2 from then on.

Yes, that should probably be a swtpm_setup feature, i.e. have a cmd line option to pick algorithms, or check all algorithms whenever they are actually enabled, or both.

jean-edouard commented 2 years ago

What I meant with the above is that compile-time disablement of algorithms is not possible since this would prevent all existing swtpms to read their state or prevent software inside a VM to decrypt data that was previously encrypted with a now-disabled algorithm. If anything, the TPM 2 code would have to be changed to support runtime-disablement of algorithms and the set of disabled algorithms could only reasonably be set once at the initial creation of the TPM 2 and would have to be carried forward by the state of the TPM 2 from then on.

Yes, that should probably be a swtpm_setup feature, i.e. have a cmd line option to pick algorithms, or check all algorithms whenever they are actually enabled, or both.

I was not thinking about a compile-time option, but a runtime one. It would also be much better in my opinion if it wasn't a swtpm_setup feature, because that would make it system-wide (right?), which would cause the issues initially mentioned about suspend and migrate.

berrange commented 2 years ago

It would also be much better in my opinion if it wasn't a swtpm_setup feature, because that would make it system-wide (right?), which would cause the issues initially mentioned about suspend and migrate.

No it wouldn't. swtpm_setup is run once when a VM is first provisioned to populate the VMs initial vTPM state. This state is preserved thereafter, for the lifetime of the VM, including across suspend/migrate/snapshot and so on. IOW swtpm_setup is exactly the right place to be selecting algorithms for a VM.

jejb commented 2 years ago

Having runtime configurable algorithms (whether on the command line or via a config file) would also help me with testing. A lot of my TPM projects run test suites using a swtpm. The most common use case I'm thinking of is disabling sha1 to make sure all the test suites still pass when we start getting TPMs without that algorithm, but I'm sure there are other cases.

I accept that once you start using a TPM with a particular algorithm configuration, you always have to keep exactly that config, which is why I suspect a file based runtime config would be better than a command line switch based one.

stefanberger commented 2 years ago

Current solution to avoid libtpms failures is now here: PR #704

stefanberger commented 2 years ago

I accept that once you start using a TPM with a particular algorithm configuration, you always have to keep exactly that config, which is why I suspect a file based runtime config would be better than a command line switch based one.

The set of disabled algorithms will have to become part of the permanent state of the TPM 2 to be able to stay with the TPM 2 instance and migrate along with it.

elmarco commented 2 years ago

The set of disabled algorithms will have to become part of the permanent state of the TPM 2 to be able to stay with the TPM 2 instance and migrate along with it.

Not necessarily, you could rely on the user (libvirt) to set the right arguments. Of course, it would be better if there was a check to avoid potential mis-configuration.

kraxel commented 2 years ago

The set of disabled algorithms will have to become part of the permanent state of the TPM 2 to be able to stay with the TPM 2 instance and migrate along with it.

Not necessarily, you could rely on the user (libvirt) to set the right arguments. Of course, it would be better if there was a check to avoid potential mis-configuration.

Make swtpm_setup store the algorithm list (an enable list looks more robust to me than a disable list) next to the other state in the --tpmstate directory looks reasonable to me.

stefanberger commented 2 years ago

Make swtpm_setup store the algorithm list (an enable list looks more robust to me than a disable list) next to the other state in the --tpmstate directory looks reasonable to me.

Can I edit this file then? Is it being migrated?

stefanberger commented 2 years ago

And regarding an enabled list versus disabled list. It's not possible to disable some algorithms that are so essential to the TPM 2 to work, such as AES and possibly RSA. Actually one of the problems with runtime disabling the algorithms is figuring out in the TPM 2 code what side effects the disablement of each individual one has. And for that I would work with a disabled list.

berrange commented 2 years ago

It's not possible to disable some algorithms that are so essential to the TPM 2 to work, such as AES and possibly RSA

For those cases I think it would be acceptable for swtpm_setup to exit with a fatal error reporting that the host crypto config is lacking mandatory algorithms needed for TPM2.

stefanberger commented 2 years ago

I have not been able to enable fips mode on Fedora 35 or 36 using fips-mode-setup --enable and a reboot. On F35 with openssl 1.1 nothing seems to change and on F36 the best effects I got were that all self-tests failed, RSA-2048 and also AES-128 as well as AES-256. Is Fedora missing an OpenSSL config file? And now, for some reason, even F36 in FIPS mode doesn't show any failures anymore when leaving FIPS mode on in swtpm.

kraxel commented 2 years ago

And regarding an enabled list versus disabled list. It's not possible to disable some algorithms that are so essential to the TPM 2 to work, such as AES and possibly RSA. Actually one of the problems with runtime disabling the algorithms is figuring out in the TPM 2 code what side effects the disablement of each individual one has. And for that I would work with a disabled list.

The reason I think a enable list is more robust is that it takes out an indirection. A enable list specifies the list of algorithms required directly (and in case one of them isn't available you'll just throw an error and exit). With a disable list the algorithms supported by the swtpm is composed from multiple sources: compile time configuration (swtpm), runtime configuration (openssl), disable list.

AES/RSA: I think they can either be added to the enable list unconditionally, or we define the enable list to only include algorithms which are actually optional. The former is probably more future-proof (i.e. works better in case a future tpm spec changes the list of mandatory algorithms).

stefanberger commented 2 years ago

The reason I think a enable list is more robust is that it takes out an indirection. A enable list specifies the list of algorithms required directly (and in case one of them isn't available you'll just throw an error and exit). With a disable list the algorithms supported by the swtpm is composed from multiple sources: compile time configuration (swtpm), runtime configuration (openssl), disable list.

Does OpenSSL provide any means to determine which algorithms the FIPS mode has disabled, like introspection of some sort? This would avoid unnecessary trial and error to determine what can be used and what cannot be used.

The difficulty with the TPM2 code is is that it is not prepared for runtime disablement of algorithms at all. So the only way this would work is to start out with a list of algorithms that are required to be enabled, which in the beginning would be all of them, and as one algorithm after the other is disable-able this list would shrink. From what I had seen in a CentOS9 environment that I put into FIPS mode it is only RSA-PSS signing scheme. I wonder whether that's it? Neither TDES nor Camellia were disabled there it seems.

berrange commented 2 years ago

Does OpenSSL provide any means to determine which algorithms the FIPS mode has disabled, like introspection of some sort? This would avoid unnecessary trial and error to determine what can be used and what cannot be used.

Note there's nothing particularly special about FIPS in terms of supported algorithms. FIPS is just one possible host OS crypto policy for selecting algorithms.

Taking one of my Fedora 36 servers as an example, the initial crypto policy is 'DEFAULT' which allows a great many options

# update-crypto-policies 
Setting system policy to DEFAULT
Note: System-wide crypto policies are applied on application start-up.
It is recommended to restart the system for the change of policies
to fully take place.
# openssl ciphers 
TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-CCM:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES256-CCM:AES128-GCM-SHA256:AES128-CCM:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-CCM:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-CCM:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:PSK-AES256-GCM-SHA384:PSK-CHACHA20-POLY1305:PSK-AES256-CCM:PSK-AES128-GCM-SHA256:PSK-AES128-CCM:PSK-AES256-CBC-SHA:PSK-AES128-CBC-SHA256:PSK-AES128-CBC-SHA:DHE-PSK-AES256-GCM-SHA384:DHE-PSK-CHACHA20-POLY1305:DHE-PSK-AES256-CCM:DHE-PSK-AES128-GCM-SHA256:DHE-PSK-AES128-CCM:DHE-PSK-AES256-CBC-SHA:DHE-PSK-AES128-CBC-SHA256:DHE-PSK-AES128-CBC-SHA:ECDHE-PSK-CHACHA20-POLY1305:ECDHE-PSK-AES256-CBC-SHA:ECDHE-PSK-AES128-CBC-SHA256:ECDHE-PSK-AES128-CBC-SHA:RSA-PSK-AES256-GCM-SHA384:RSA-PSK-CHACHA20-POLY1305:RSA-PSK-AES128-GCM-SHA256:RSA-PSK-AES256-CBC-SHA:RSA-PSK-AES128-CBC-SHA256:RSA-PSK-AES128-CBC-SHA

I can change the crypto policy to 'FUTURE' which limits the host to a very restrictive set hoped to be immune to near-term crypto analysis attacks. We can see this limits openssl very significantly:

# vi /etc/crypto-policies/config 
# update-crypto-policies 
Setting system policy to FUTURE
Note: System-wide crypto policies are applied on application start-up.
It is recommended to restart the system for the change of policies
to fully take place.
# openssl ciphers 
TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-CCM:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-CCM:PSK-AES256-GCM-SHA384:PSK-CHACHA20-POLY1305:PSK-AES256-CCM:DHE-PSK-AES256-GCM-SHA384:DHE-PSK-CHACHA20-POLY1305:DHE-PSK-AES256-CCM:ECDHE-PSK-CHACHA20-POLY1305

I can pretend my machine userspace is in FIPS mode by just manually asking for the FIPS cipher set in the crypto policies (without actually turning on kernel FIPS support). With this we can get an indication of what openssl allows in FIPS mode, which is kind of half-way between the two above examples

# vi /etc/crypto-policies/config 
# update-crypto-policies 
Setting system policy to FIPS
Note: System-wide crypto policies are applied on application start-up.
It is recommended to restart the system for the change of policies
to fully take place.
# openssl ciphers 
TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-CCM:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-CCM:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-CCM:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:PSK-AES256-GCM-SHA384:PSK-AES256-CCM:PSK-AES128-GCM-SHA256:PSK-AES128-CCM:PSK-AES256-CBC-SHA:PSK-AES128-CBC-SHA256:PSK-AES128-CBC-SHA:DHE-PSK-AES256-GCM-SHA384:DHE-PSK-AES256-CCM:DHE-PSK-AES128-GCM-SHA256:DHE-PSK-AES128-CCM:DHE-PSK-AES256-CBC-SHA:DHE-PSK-AES128-CBC-SHA256:DHE-PSK-AES128-CBC-SHA:ECDHE-PSK-AES256-CBC-SHA:ECDHE-PSK-AES128-CBC-SHA256:ECDHE-PSK-AES128-CBC-SHA

The general point is that it would be wrong to fixate on a particular set of FIPS ciphers, but rather need to just query openssl library to ask what is available in the currently running state. I'm not sure what specific openssl API is being invoked by the 'openssl ciphers' cli command to extra this cipher list though

stefanberger commented 2 years ago

Thanks. I edited the policy of my F36 system to FIPS (vi /etc/crypto-policies/config) and rebooted. Strangely enough it didn't affect the functioning of F36-packaged swtpm and libtpms at all. Everything worked as before, no failure during selftest. No FIPS mode needed to be disabled.

stefanberger commented 2 years ago

The same is true for Fedora 35 with OpenSSL 1.1. That's as if FIPS mode didn't disable anything the TPM 2 needs on these systems and we are fully compliant already. What am I missing?

stefanberger commented 2 years ago

I had tested with this command line (as root and as non-root):

swtpm_setup --tpmstate ./ --overwrite --pcr-banks sha256 --overwrite --create-ek-cert --create-platform-cert

Another test was running a swtpm in one terminal:

mkdir /tmp/myvtpm
swtpm socket --tpmstate dir=/tmp/myvtpm --tpm2 --ctrl type=tcp,port=2322    --server type=tcp,port=2321 --flags not-need-init

In other terminal:

export TPM_COMMAND_PORT=2321 TPM_PLATFORM_PORT=2322   TPM_SERVER_NAME=localhost TPM_INTERFACE_TYPE=socsim   TPM_SERVER_TYPE=raw
tssstartup -st

Starting a VM (on Fedora 35) that had to create the initial state of the vTPM also worked just fine. From these tests I can only conclude that TPM 2 must be FIPS compliant.

berrange commented 2 years ago

Thanks. I edited the policy of my F36 system to FIPS (vi /etc/crypto-policies/config) and rebooted. Strangely enough it didn't affect the functioning of F36-packaged swtpm and libtpms at all. Everything worked as before, no failure during selftest. No FIPS mode needed to be disabled.

Ok, that's probably a sign that merely messing with crypto-policies is insufficient to properly simulate the effect of running in FIPS mode for purposes of testing swtpm.

stefanberger commented 2 years ago

FYI: This is how TPM2 advertises its implemented algorithms:

$ tssgetcapability -cap 0
33 algorithms
   TPM_ALG_RSA
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: object
   TPM_ALG_TDES
    TPMA_ALGORITHM: symmetric
   TPM_ALG_SHA1
    TPMA_ALGORITHM: hash
   TPM_ALG_HMAC
    TPMA_ALGORITHM: hash
    TPMA_ALGORITHM: signing
   TPM_ALG_AES
    TPMA_ALGORITHM: symmetric
   TPM_ALG_MGF1
    TPMA_ALGORITHM: hash
    TPMA_ALGORITHM: method
   TPM_ALG_KEYEDHASH
    TPMA_ALGORITHM: hash
    TPMA_ALGORITHM: object
    TPMA_ALGORITHM: signing
    TPMA_ALGORITHM: encrypting
   TPM_ALG_XOR
    TPMA_ALGORITHM: symmetric
    TPMA_ALGORITHM: hash
   TPM_ALG_SHA256
    TPMA_ALGORITHM: hash
   TPM_ALG_SHA384
    TPMA_ALGORITHM: hash
   TPM_ALG_SHA512
    TPMA_ALGORITHM: hash
   TPM_ALG_RSASSA
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: signing
   TPM_ALG_RSAES
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: encrypting
   TPM_ALG_RSAPSS
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: signing
   TPM_ALG_OAEP
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: encrypting
   TPM_ALG_ECDSA
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: signing
   TPM_ALG_ECDH
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: method
   TPM_ALG_ECDAA
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: signing
   TPM_ALG_SM2
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: signing
    TPMA_ALGORITHM: method
   TPM_ALG_ECSCHNORR
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: signing
   TPM_ALG_ECMQV
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: method
   TPM_ALG_KDF1_SP800_56A
    TPMA_ALGORITHM: hash
    TPMA_ALGORITHM: method
   TPM_ALG_KDF2
    TPMA_ALGORITHM: hash
    TPMA_ALGORITHM: method
   TPM_ALG_KDF1_SP800_108
    TPMA_ALGORITHM: hash
    TPMA_ALGORITHM: method
   TPM_ALG_ECC
    TPMA_ALGORITHM: asymmetric
    TPMA_ALGORITHM: object
   TPM_ALG_SYMCIPHER
    TPMA_ALGORITHM: object
   TPM_ALG_CAMELLIA
    TPMA_ALGORITHM: symmetric
   TPM_ALG_CMAC
    TPMA_ALGORITHM: symmetric
    TPMA_ALGORITHM: signing
   TPM_ALG_CTR
    TPMA_ALGORITHM: symmetric
    TPMA_ALGORITHM: encrypting
   TPM_ALG_OFB
    TPMA_ALGORITHM: symmetric
    TPMA_ALGORITHM: encrypting
   TPM_ALG_CBC
    TPMA_ALGORITHM: symmetric
    TPMA_ALGORITHM: encrypting
   TPM_ALG_CFB
    TPMA_ALGORITHM: symmetric
    TPMA_ALGORITHM: encrypting
   TPM_ALG_ECB
    TPMA_ALGORITHM: symmetric
    TPMA_ALGORITHM: encrypting

For example, the availability of crypto scheme TPM_ALG_OFB and symmetric algs TPM_ALG_TDES, TPM_ALG_AES, and TPM_ALG_CAMELLIA automatically implies that tdes-ofb, aes-ofb, and camellia-ofb are available and not one of them is missing, at least per the compile time options of the reference code. Test suites or programs that read the algorithm list may make these assumptions and I am not sure how they would react if these assumption were not to hold. I can certainly not speak about what programs do on windows for example. The point is though that I am not quite clear on how to disable algorithms during runtime, but the safer choice would be to simulate compile-time disablement, meaning that if 'ofb' is disabled tdes-ofb, aes-ofb, and camellia-ofb are all disable. Users don't give control over individual disablement of tes-ofb for example while leaving the other ones available. This is just one example and there are more with combinations of rsa and hashes and so on.

kraxel commented 2 years ago

but the safer choice would be to simulate compile-time disablement, meaning that if 'ofb' is disabled tdes-ofb, aes-ofb, and camellia-ofb are all disable. Users don't give control over individual disablement of tes-ofb for example while leaving the other ones available.

Sounds good to me. I see no reason why compile-time configuration and runtime-configuration should behave in different ways.

stefanberger commented 2 years ago

Sounds good to me. I see no reason why compile-time configuration and runtime-configuration should behave in different ways.

Also, the TPM 2 internally works with a bit vector of enabled algorithms, such as flags set for des or ctr for example. So, we wouldn't allow disabling of fine granularity like des-128-ctr but only des and/or ctr which then disables des and/or ctr entirely.

berrange commented 2 years ago

Also, the TPM 2 internally works with a bit vector of enabled algorithms, such as flags set for des or ctr for example. So, we wouldn't allow disabling of fine granularity like des-128-ctr but only des and/or ctr which then disables des and/or ctr entirely.

Hmmm, that could be troublesome, as I could certainly anticipate the need to disable based on key size

stefanberger commented 2 years ago

Hmmm, that could be troublesome, as I could certainly anticipate the need to disable based on key size

I guess we need to get this right...

The TPM2 internal-self test works with this above mentioned vector where each algorithm Id has a bit set. Keysizes don't matter there at all and test cases with different key sizes are enabled during compile time. We could filter out those test cases then.

Also, ideally we would give a user fine-grained control over each algorithm that is implemented and provide a string like this here:

aes-128-ctr,aes-128-ofb,aes-128-cbc,aes-128-cfb,aes-128-ecb,
des-128-ctr,des-128-ofb,des-128-cbc,des-128-cfb,des-128-ecb,
camellia-128-ctr,camellia-128-ofb,camellia-128-cbc,camellia-128-cfb,camellia-128-ecb,
[...]

Let's say the user only chooses the following:

aes-128-ctr,camellia-128-ecb

What does the TPM 2 now advertise in terms of implemented algorithms (as shown here)? aes, ctr, camellia, and ecb? If these are advertised and programs (test suites) read the capabilities they were so far able to conclude that aes-...-ctr, camellia-...-ctr, aes-...-ecb, and camellia-...-ecb are supported. But this isn't the case anymore and I am not sure which programs will react unfavorably to this. So I would be concerned that this gives too much control to users and causes bug reports that don't have a solution.

berrange commented 2 years ago

Hmm, yes, this is a tricky problem. I don't know much about the TPM requirements, but perhaps the solution here varies depending on scenario ? IIRC, this whole discussion originated with a problem of self-tests failing due to missing algorithms, and it was trying to test all compiled in algorithms upfront, regardless of the OS needing to use it.

How strict are the rules around self tests ? If we report support for 'aes' and 'ctr' do we need to self-test with all key sizes, or only one key size, or is it up to impl to decide ? eg can we report support for 'aes' and 'ctr', self test only aes-256-ctr, and report an error if the guest OS later tried to use aes-128-ctr that the guest OS is able to gracefully handle ?

stefanberger commented 2 years ago

How strict are the rules around self tests ?

The TPM 2 reference code, which is the specification of the TPM 2, will cause a self-test to be run before an algorithms is used the first time or a full self test if instructed to do so, which the OS may do by sending a command to it. If the self test fails for an algorithm the TPM 2 will go into failure mode since something is broken. It's a crypto device after all, so it should probably react like this (or at least the spec defines that it will react like this).

I guess what it comes down to for runtime-filtering is to define a language for the TPM 2 to filter-out algorithms. My current thinking would be to stick as closely as possibly to the defined algorithm Ids of the TPM 2 and their names and then maybe we need to add things like this:

sym-key-size>=192,rsa-key-size>=2048,ecc-key-size>=256

However, would this be correct to put aes,des, camellia, and sm4 under 'sym-key' and require a size >= 192 and this is equal strength for all of them? Or do we have to go to granularity like this?

aes-key-size>=128,camellia-key-size>=192

I don't know... But from the perspective of the TPM 2 code this latter here would be better.

If we report support for 'aes' and 'ctr' do we need to self-test with all key sizes, or only one key size, or is it up to impl to decide ?

I guess we would have to put additional filters into the code that skip over test cases with too small keys and just have them ignored. Other code paths where the user may want to use key a runtime-disabled key that is too small would then reject the operation.

So from my perspective the problems are like this

jejb commented 2 years ago

Also, the TPM 2 internally works with a bit vector of enabled algorithms, such as flags set for des or ctr for example. So, we wouldn't allow disabling of fine granularity like des-128-ctr but only des and/or ctr which then disables des and/or ctr entirely.

Actually, this isn't true of Ken's TPM implementation. Each symmetric algorithm has a bits specifier and TDES is no different. You seem to have inherited his TDES_KEY_SIZES_BITS in your TpmProfile.h, so I think you could disable des-128 while keeping des-192 if you wanted. The same is true of AES: we can disable any of the 128, 192 or 256 key bit sizes individually.

stefanberger commented 2 years ago

Actually, this isn't true of Ken's TPM implementation. Each symmetric algorithm has a bits specifier and TDES is no different. You seem to have inherited his TDES_KEY_SIZES_BITS in your TpmProfile.h, so I think you could disable des-128 while keeping des-192 if you wanted. The same is true of AES: we can disable any of the 128, 192 or 256 key bit sizes individually.

With an appropriate language we will be able to runtime-disable them and that's the only way of doing this. We cannot just completely disable algorithms and keysizes etc. anymore since applications inside VMs may already be using them and expect them to be there while these VMs are around.

stefanberger commented 2 years ago

WIP: https://github.com/stefanberger/libtpms/tree/stefanberger/runtime_disable_algorithms

stefanberger commented 2 years ago

PR #704 resolved the issue for now by disabling FIPS mode in OpenSSL. Anything beyond that that requires profiles is a much bigger undertaking on the level of libtpms and swtpm.