Open vcsjones opened 2 years ago
Tagging subscribers to this area: @dotnet/area-system-security, @vcsjones See info in area-owners.md if you want to be subscribed.
Unhandled exception. Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Invalid flags specified. at System.Security.Cryptography.CngKey.set_IsEphemeral(Boolean value) at System.Security.Cryptography.CngKey.Create(CngAlgorithm algorithm, String keyName, CngKeyCreationParameters creationParameters)The Microsoft PCP / TPM provider, and likely other 3rd party CNG Providers, may not support custom properties. As the `get` for `IsEphemeral` correctly calls out: https://github.com/dotnet/runtime/blob/5877e8b713742b6d80bd1aa9819094be029e3e1f/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/CngKey.StandardProperties.cs#L100-L102 However, generating a key always tries to call the `set`, and if it fails, throws an exception: https://github.com/dotnet/runtime/blob/5877e8b713742b6d80bd1aa9819094be029e3e1f/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/CngKey.StandardProperties.cs#L122-L123 This makes using `CngKey.Create` or `CngKey.Import` with some providers difficult to work with.
Author: | vcsjones |
---|---|
Assignees: | - |
Labels: | `area-System.Security` |
Milestone: | - |
I think the set
should continue to throw, however the places where we use it in Create
and Import
should consider ignoring the exception. Since the expectation is the get
will fail anyway, it doesn't matter if the set
succeeded in this circumstance or not.
I think the set should continue to throw, however the places where we use it in Create and Import should consider ignoring the exception.
Since the set is private, the only differences between the set ignoring the error and the callers eating the exception is the latter allows break on exception to work, and has more code.
A more reasonable change would probably be:
if (_isEphemeral != 0) { return _isEphemeral > 0; }
before checking the CNG property (which should then memoize the answer).Yeah, unfortunately there is no easy work-around either. The CngKey() constructor that takes the provider and key handles is private. So I cannot implement my own Import method. And DeriveKeyMaterial() needs to be passed a CngKey. This simple .Net code becomes messy because everything has to be done using p/invoke calls to NCrypt.dll.
CngKey ephKey = CngKey.Import(ephblob, CngKeyBlobFormat.EccPublicBlob, KspKeyController.KspProvider);
priv.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hmac;
priv.HmacKey = null;
byte[] prk = priv.DeriveKeyMaterial(ephKey);
The really strange thing for me anyway, is that it works on Server 2012 R2. But fails in Win10, Server 2016, and Server 2019. This is with the "SafeNet Key Storage Provider".
Consider this:
This will fail with:
The Microsoft PCP / TPM provider, and likely other 3rd party CNG Providers, may not support custom properties.
As the
get
forIsEphemeral
correctly calls out:https://github.com/dotnet/runtime/blob/5877e8b713742b6d80bd1aa9819094be029e3e1f/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/CngKey.StandardProperties.cs#L100-L102
However, generating a key always tries to call the
set
, and if it fails, throws an exception:https://github.com/dotnet/runtime/blob/5877e8b713742b6d80bd1aa9819094be029e3e1f/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/CngKey.StandardProperties.cs#L122-L123
This makes using
CngKey.Create
orCngKey.Import
with some providers difficult to work with.