Permit CngKey backed ECDH interoperability from different KSPs #80571
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a proof-of-concept for fixing ECDiffieHellman that uses CNG keys when performing the exchange with a
ECDiffieHellmanCngPublicKey
.The original issue is #71009.
Some background, first.
ECDiffieHellman
, unlike other asymmetric cryptographic types, has a dedicated type calledECDiffieHellmanCngPublicKey
. The latter type always uses the Microsoft Software Key Storage Provider for the public key. Even if the originalECDiffieHellman
was created with the right KSP, when the ECDHCngPublicKey is created, it is exported from the current provider, and shoved in to the Microsoft Software Key Storage Provider. That occurs here:runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECDiffieHellmanCngPublicKey.cs
Lines 83 to 88 in 6e1ca64
This is problematic when the other party
ECDiffieHellman
is not in the Microsoft Software Key Storage Provider.NCryptSecretAgreement
does not perform cross CNG provider agreement:So cross provider ECDH doesn't work at the CNG level.
To fix this, I originally thought about making an internal implementation of
Import
that preserves the provider. However, this proved problematic for some providers. The Microsoft Platform Crypto Provider, for example, forbids importing keys. Even public ones. So going from PCP -> Software Provider -> PCP doesn't work.This lead to me to preserve the CngKey handle itself in the ECDHCngPublicKey. This way, if two
ECDiffieHellmanCng
instances start from the same provider, the provider is preserved.The original
Import
method does not return this stashed handle. This is intentional, and it hydrates the blob. This is becauseImport
is public. I would not want this method to start returning aCngKey
object that is a handle to the original private key. So it continues to use the public blobs.What this PR does is allow two
ECDiffieHellmanCng
objects to interoperate with each other if they were both constructed from aCngKey
that are not in the Software Storage Provider.What this PR does not do is try to further fix "cross" provider interoperability. My general thought here is that our guidance should be
CngKey
s should be from the same provider. This can be a future improvement. The largest barrier to implementing this is any kind of testability. I have no CNG provider that permits imports other than the software one. So testing this would require making blind changes.@bartonjs apologies for the probably excessive background, and I would appreciate your input if you think I am off the mark on the approach for this one.