Skip to content
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

CLR IsEphemeral hinders use of some CNG Providers #71310

Open
vcsjones opened this issue Jun 26, 2022 · 4 comments
Open

CLR IsEphemeral hinders use of some CNG Providers #71310

vcsjones opened this issue Jun 26, 2022 · 4 comments

Comments

@vcsjones
Copy link
Member

Consider this:

CngKey.Create(
    CngAlgorithm.Rsa,
    null,
    new CngKeyCreationParameters { Provider = CngProvider.MicrosoftPlatformCryptoProvider });

This will fail with:

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:

// Third party Key providers, and Windows PCP KSP won't recognize this property;
// and Win32 layer does not enforce error return contract.
// Therefore, they can return whatever error code they think appropriate.

However, generating a key always tries to call the set, and if it fails, throws an exception:

if (errorCode != ErrorCode.ERROR_SUCCESS)
throw errorCode.ToCryptographicException();

This makes using CngKey.Create or CngKey.Import with some providers difficult to work with.

@ghost
Copy link

ghost commented Jun 26, 2022

Tagging subscribers to this area: @dotnet/area-system-security, @vcsjones
See info in area-owners.md if you want to be subscribed.

Issue Details

Consider this:

CngKey.Create(
    CngAlgorithm.Rsa,
    null,
    new CngKeyCreationParameters { Provider = CngProvider.MicrosoftPlatformCryptoProvider });

This will fail with:

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:

// Third party Key providers, and Windows PCP KSP won't recognize this property;
// and Win32 layer does not enforce error return contract.
// Therefore, they can return whatever error code they think appropriate.

However, generating a key always tries to call the set, and if it fails, throws an exception:

if (errorCode != ErrorCode.ERROR_SUCCESS)
throw errorCode.ToCryptographicException();

This makes using CngKey.Create or CngKey.Import with some providers difficult to work with.

Author: vcsjones
Assignees: -
Labels:

area-System.Security

Milestone: -

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Jun 26, 2022
@vcsjones
Copy link
Member Author

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.

@bartonjs
Copy link
Member

bartonjs commented Jul 6, 2022

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:

  • Make the set ignore the error.
  • Make the set also set a field saying it's ephemeral. Then change get_IsEphemeral to something like (if (_isEphemeral != 0) { return _isEphemeral > 0; } before checking the CNG property (which should then memoize the answer).
  • Figure out what the Name/UniqueName/etc properties do when called with an ephemeral key that doesn't know it's ephemeral. Consider making them update the ephemeralness.

@jeffhandley jeffhandley added this to the Future milestone Aug 2, 2022
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Aug 2, 2022
@samintz
Copy link

samintz commented Mar 30, 2023

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".

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

No branches or pull requests

4 participants