Bug 1950046 (CVE-2021-3505)

Summary: CVE-2021-3505 libtpms: RSA keys weaker than expected
Product: [Other] Security Response Reporter: Mauro Matteo Cascella <mcascell>
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED WONTFIX QA Contact:
Severity: low Docs Contact:
Priority: low    
Version: unspecifiedCC: davide, marcandre.lureau, stefanb, virt-maint
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: libtpms 0.8.0 Doc Type: If docs needed, set a value
Doc Text:
A flaw was found in libtpms. The TPM 2 implementation returns 2048 bit keys with ~1984 bit strength due to a bug in the TCG specification. The bug is in the key creation algorithm in RsaAdjustPrimeCandidate(), which is called before the prime number check. The highest threat from this vulnerability is to data confidentiality.
Story Points: ---
Clone Of: Environment:
Last Closed: 2021-10-29 08:57:48 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 1942902, 1950048, 1950063, 1950064    
Bug Blocks: 1945068, 1950378    

Description Mauro Matteo Cascella 2021-04-15 16:06:34 UTC
The TPM 2 implementation returns 2048 bit keys with ~1984 bit strength due to a bug in the TPM 2 key creation algorithm that cannot easily be fixed. The bug is in RsaAjustPrimeCandidate, which is called before the prime number check. Upgrading to a fixed release (0.8.0+) is not sufficient. The only way to fix it is to unseal all data, delete the old TPM state file, generate a new one, then reseal the data.

Note: the bug is based on the TCG reference code. The TCG specification was updated in late 2019 and libtpms' key creation algorithm fixed in version 0.8.0.

Upstream issue:
https://github.com/stefanberger/libtpms/issues/183

Upstream commits:
https://github.com/stefanberger/libtpms/commit/625171be0c8225824740b5d0fb7e8562f6a1c6a8
https://github.com/stefanberger/libtpms/commit/c1f7bf55099fcd427715aa65e130475c6e836a6b

Comment 1 Mauro Matteo Cascella 2021-04-15 16:07:11 UTC
Created libtpms tracking bugs for this issue:

Affects: fedora-all [bug 1950048]

Comment 5 Marc-Andre Lureau 2021-04-16 10:59:33 UTC
It is likely a breaking change, as it was not introduced in 0.7 branch (see https://github.com/stefanberger/libtpms/commit/153a9579e84c83c38d404bd12fd5267f82fd07a1). Also, I think a CVE was requested earlier and not accepted.

Comment 6 Stefan Berger 2021-04-16 13:07:50 UTC
When a TPM 2 (instance) is upgraded from libtpms 0.7.x to 0.8.x it will continue using the weak key generation algorithm since otherwise nothing would decrypt anymore with keys derived from the TPM 2's current seeds. If the seeds are reset, which is only possible via firmware, then the code will switch to use the new key generation algorithm for seed-derive keys since after resetting the seeds the keys are expected to be different than before and nothing is expected to decrypt anymore with seeed-derived keys. So it shouldn't break anything from the point of view of the user, he just doesn't get the better keys because we cannot just switch over. Newly created TPM 2 instance using libtpms 0.8 would use the fixed key generation algorithm.

Comment 7 Marc-Andre Lureau 2021-04-16 14:27:28 UTC
Stefan, why is the fix not backported to 0.7 branch then?

Comment 8 Stefan Berger 2021-04-16 14:43:38 UTC
(In reply to Marc-Andre Lureau from comment #7)
> Stefan, why is the fix not backported to 0.7 branch then?

Because it changes the state file of the TPM 2 to keep track of the 'age' of the seeds. I don't backport these kind of changes.

Comment 9 Marc-Andre Lureau 2021-04-16 14:46:57 UTC
(In reply to Stefan Berger from comment #8)
> (In reply to Marc-Andre Lureau from comment #7)
> > Stefan, why is the fix not backported to 0.7 branch then?
> 
> Because it changes the state file of the TPM 2 to keep track of the 'age' of
> the seeds. I don't backport these kind of changes.

Could it keep the current age instead? Only newly state would get a new age. (if that makes sense)

Comment 10 Stefan Berger 2021-04-16 14:52:53 UTC
(In reply to Marc-Andre Lureau from comment #9)
> (In reply to Stefan Berger from comment #8)
> > (In reply to Marc-Andre Lureau from comment #7)
> > > Stefan, why is the fix not backported to 0.7 branch then?
> > 
> > Because it changes the state file of the TPM 2 to keep track of the 'age' of
> > the seeds. I don't backport these kind of changes.
> 
> Could it keep the current age instead? Only newly state would get a new age.
> (if that makes sense)

How do you distinguish between an old seed requiring to run the weak key generation algorithm and a new seed then? Sorry, but this doesn't make sense. You need to track that 1 bit of information. Besides that, the patches have already been merged a long time ago and libtpms 0.8.x fixes the issue.

Comment 11 Marc-Andre Lureau 2021-04-16 15:07:06 UTC
(In reply to Stefan Berger from comment #10)
> How do you distinguish between an old seed requiring to run the weak key
> generation algorithm and a new seed then? Sorry, but this doesn't make

The age doesn't let you make that difference? What's the age for then?

> sense. You need to track that 1 bit of information. Besides that, the
> patches have already been merged a long time ago and libtpms 0.8.x fixes the
> issue.

We don't usually rebase versions in RHEL released products, we backport fixes or just WONTFIX.

Please help us make the best decision

Comment 12 Stefan Berger 2021-04-16 15:21:07 UTC
(In reply to Marc-Andre Lureau from comment #11)
> (In reply to Stefan Berger from comment #10)
> > How do you distinguish between an old seed requiring to run the weak key
> > generation algorithm and a new seed then? Sorry, but this doesn't make
> 
> The age doesn't let you make that difference? What's the age for then?

Yes, the age let's you make the difference but the age was introduced as part of the patches to fix the issue. This changes the state format the TPM 2's state is written in and I don't want to backport it since it's too easy to loose the upgrade path.

> 
> > sense. You need to track that 1 bit of information. Besides that, the
> > patches have already been merged a long time ago and libtpms 0.8.x fixes the
> > issue.
> 
> We don't usually rebase versions in RHEL released products, we backport
> fixes or just WONTFIX.
> 
> Please help us make the best decision

In this case I would say that if you start a new version of RHEL you could still go with libtpms-0.8.x, if you cannot upgrade it then mark it as WONTFIX.

Comment 13 Marc-Andre Lureau 2021-04-16 15:40:34 UTC
(In reply to Stefan Berger from comment #12)
> > The age doesn't let you make that difference? What's the age for then?
> 
> Yes, the age let's you make the difference but the age was introduced as
> part of the patches to fix the issue. This changes the state format the TPM
> 2's state is written in and I don't want to backport it since it's too easy
> to loose the upgrade path.

How did you handle migration from 0.7/non-aged to 0.8 ? In CHANGES, it is said downgrade is not possible, not upgrade. There must be a way to distinguish fixed from non-fixed version then.


> > > sense. You need to track that 1 bit of information. Besides that, the
> > > patches have already been merged a long time ago and libtpms 0.8.x fixes the
> > > issue.
> > 
> > We don't usually rebase versions in RHEL released products, we backport
> > fixes or just WONTFIX.
> > 
> > Please help us make the best decision
> 
> In this case I would say that if you start a new version of RHEL you could
> still go with libtpms-0.8.x, if you cannot upgrade it then mark it as
> WONTFIX.

If it would just be me, I would upgrade to 0.8, but this brings a lot of other changes that might be too risky too.

Mauro, what do you think?

Comment 14 Marc-Andre Lureau 2021-04-16 15:47:39 UTC
> In CHANGES, it is said downgrade is not possible, not upgrade. There must be a way to distinguish fixed from non-fixed version then.

The new state wouldnt be backward compatible though, but it's not worse that forcefully upgrading to 0.8.

Comment 15 Stefan Berger 2021-04-16 15:48:42 UTC
(In reply to Marc-Andre Lureau from comment #13)
> (In reply to Stefan Berger from comment #12)
> > > The age doesn't let you make that difference? What's the age for then?
> > 
> > Yes, the age let's you make the difference but the age was introduced as
> > part of the patches to fix the issue. This changes the state format the TPM
> > 2's state is written in and I don't want to backport it since it's too easy
> > to loose the upgrade path.
> 
> How did you handle migration from 0.7/non-aged to 0.8 ? In CHANGES, it is
> said downgrade is not possible, not upgrade. There must be a way to
> distinguish fixed from non-fixed version then.

When TPM 2 reads the statefile of the TPM 2 and the blob containing a seed is of version <x, where version <x does not track the age of the seed, it assigns it the default value representing the state of an old seed. The state writing side will write the blob in version x which now contains the age of the seed and the next time we read the state from the file we pick up the age from the blob.

Comment 16 Mauro Matteo Cascella 2021-04-17 14:53:45 UTC
In reply to comment #13:
> (In reply to Stefan Berger from comment #12)
> > > We don't usually rebase versions in RHEL released products, we backport
> > > fixes or just WONTFIX.
> > > 
> > > Please help us make the best decision
> > 
> > In this case I would say that if you start a new version of RHEL you could
> > still go with libtpms-0.8.x, if you cannot upgrade it then mark it as
> > WONTFIX.
> 
> If it would just be me, I would upgrade to 0.8, but this brings a lot of
> other changes that might be too risky too.
> 
> Mauro, what do you think?

I was aware that backporting the fix to 0.7.x (the only versions we currently ship) would have been tricky, but decided to allocate a CVE anyway because that was the right thing to do. I would probably lean towards WONTFIX here: this is not an important/critical issue and probably not worth the effort given the above comments.

As for whether or not to rebase, I don't know what implications - mostly from a functional/compatibility point of view - an upgrade to 0.8 would entail. That said, as you know, a number of potentially-security-sensitive fixes didn't get CVEs in the past (e.g., https://github.com/stefanberger/libtpms/blob/stable-0.7.0/CHANGES) and I see the risk of not backporting a security fix just because it didn't get a CVE. With this in mind IMHO rebasing should be a serious option to consider - if possible - alongside a more thorough handling of CVEs going forward (we can help with the latter part).

Comment 17 Mauro Matteo Cascella 2021-04-17 15:30:00 UTC
Statement:

Versions of `libtpms` prior to 0.8.0 generate weaker than expected TPM 2 RSA keys due to the flawed key creation algorithm. Red Hat Enterprise Linux 8 Advanced Virtualization is therefore affected by this flaw, as it ships an older version of the package (0.7.x).

Comment 18 Mauro Matteo Cascella 2021-04-17 15:30:02 UTC
Mitigation:

There is no mitigation for this issue. Upgrading to a fixed release (0.8.0+) is necessary but not sufficient. The only way to fix it is to unseal all data, delete the old TPM state file, generate a new one with the fixed key generation algorithm, then reseal the data.