-
Notifications
You must be signed in to change notification settings - Fork 339
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
"Key not valid for use in specified state" - happens in .Net Framework 4.7.2 only, not on .Net Core 2.2 #1201
Comments
Same issue, .NET 4.7.2 and Microsoft.Identity.Client 4.1.0. Same code works in .NET 4.6.2 and Microsoft.Identity.Client 4.1.0. |
As far as I could figure what happens is that on 4.7.2. the library tries to export certificate with private key and if it is marked as non exportable it fails. If the key is exportable, then it works fine. It's strange though that depending on framework version the library reads the key in a different manner. |
@henrik-me, @MarkZuber, @bgavrilMS |
Hitting this very problem today. It would be great if the authentication would work without needing the private key to be exportable. |
If the behavior is not planned to be fixed, then a better error message is a must. This is a really confusing experience. |
@henning-krause @ilya-spv @inghak @William-Au-Yeung |
Nope. My code is reading the certificate out from the certificate store only. X509Store store = new X509Store(settings.CertificateStoreName, settings.CertificateStoreLocation);
try
{
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificate = store.Certificates.Find(
findType: X509FindType.FindByThumbprint,
findValue: settings.CertificateThumbprint,
validOnly: false); // Don't validate certs, since the test root isn't installed.
if (certificate == null || certificate.Count == 0)
{
throw new FatalErrorException(Invariant($"Cannot load the requested certificate (Thumbprint: {settings.CertificateThumbprint}, Store: {settings.CertificateStoreName}, Location: {settings.CertificateStoreLocation})"));
}
X509Certificate2 serviceCertificate = certificate[0];
try
{
var privateKey = serviceCertificate.PrivateKey;
Debug.Assert(privateKey != null, "Make sure private key is available");
return serviceCertificate;
}
catch (CryptographicException)
{
throw new FatalErrorException(Invariant($"Cannot read the private key of the requested certificate (Thumbprint: {serviceCertificate.Thumbprint})"));
}
}
finally
{
store.Close();
} |
@jmprieur if I import my certificate from a file, it is pretty much irrelevant whether I specify Ephemeral or Exportable - I can do any of those things. But if I want to use a certificate from a store (like @William-Au-Yeung), ephemeral is not an option (since the key is already persisted on the system) and I might not be able to control the "exportable" setting, because I'm forced to use a specific certificate which was not marked as exportable when the key was imported. |
I agree @henning-krause |
@jmprieur No, the requirement that the certificate must be exportable should be removed. I don't see why this is required. The code should be able to sign the JWT without exporting the private parameters. |
I just took a quick look at Lines 81 to 116 in 396913a
Why can't you just take the certificate.PrivateKey, cast it to RSA and call SignData on it? var rsa = (RSA) certificate.PrivateKey;
rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); Still, that code wouldn't work with certificates created with the Windows CNG provider, because X509Certificate2.PrivateKey can't handle those. You would need to target a later .NET version and use the X509Certificate2.GetPrivateKey() extension method for that. |
I completely agree that there should not be any rule that the certificate should be exportable. The code in the old ADAL library works just fine without certificate being exportable. Likewise this library does work on .net 4.6.2. So it would be strange if that just won't be allowed |
It's 2021, but I am hitting the same issue after updating to net472 from net462. Seems the fix above doesn't work. |
@zihzhan - please open a new issue. |
Which Version of MSAL are you using ?
Microsoft.Identity.Client Version=3.0.8
Platform
my library in .Net Core
and a web job console in .Net Framework 4.7.2
What authentication flow has the issue?
Other? - please describe;
Is this a new or existing app?
C. This is a new app or experiment
Repro
Expected behavior
No exception. I should be able to authenticate a connection to my Azure SQL Database. I have run the same code on .Net Core console project, and it has been working.
Actual behavior
I got this exception in my .Net Framework 4.7.2 console project:
Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: Functions.PollBuilds ---> System.AggregateException: One or more errors occurred. ---> System.Security.Cryptography.CryptographicException: Key not valid for use in specified state.
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.Utils._ExportKey(SafeKeyHandle hKey, Int32 blobType, Object cspObject)
at System.Security.Cryptography.RSACryptoServiceProvider.ExportParameters(Boolean includePrivateParameters)
at System.Security.Cryptography.RSA.ToXmlString(Boolean includePrivateParameters)
at Microsoft.Identity.Client.Platforms.net45.NetDesktopCryptographyManager.GetCryptoProviderForSha256(X509Certificate2 certificate)
at Microsoft.Identity.Client.Platforms.net45.NetDesktopCryptographyManager.SignWithCertificate(String message, X509Certificate2 certificate)
at Microsoft.Identity.Client.Internal.JsonWebToken.Sign(ClientAssertionCertificateWrapper credential, Boolean sendCertificate)
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialHelper.CreateClientCredentialBodyParameters(ICoreLogger logger, ICryptographyManager cryptographyManager, ClientCredentialWrapper clientCredential, String clientId, AuthorityEndpoints endpoints, Boolean sendX5C)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Identity.Client.ApiConfig.Executors.ConfidentialClientExecutor.d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Scm.Authentication.Settings.ClientCertificateSettings.d__12.MoveNext()
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task
1.GetResultCore(Boolean waitCompletionNotification) at System.Threading.Tasks.Task
1.get_Result()at Scm.Authentication.AzureDatabaseBase.CreateConnection()
Possible Solution
Additional context/ Logs / Screenshots
Add any other context about the problem here, such as logs and screebshots. Logging is described at https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/logging
The text was updated successfully, but these errors were encountered: