Search code examples
c#.netwpfcertificatex509certificate2

.NET Core throws WindowsCryptographicException: Access is denied on X509Store.Add


I write a method to install a certificate:

public void Install(StoreName storeName, StoreLocation storeLocation)
{
    using var store = new X509Store(storeName, storeLocation);
    store.Open(OpenFlags.ReadWrite);
    store.Add(cert);
}

and invoke it by passing StoreName.Root, StoreLocation.CurrentUser

certificateManager.Install(StoreName.Root, StoreLocation.CurrentUser);

will result in:

Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Access is denied.
   at Internal.Cryptography.Pal.StorePal.Add(ICertificatePal certificate)
   at System.Security.Cryptography.X509Certificates.X509Store.Add(X509Certificate2 certificate)
   at Pixeval.Persisting.WebApi.CertificateManager.Install(StoreName storeName, StoreLocation storeLocation) in C:\NotSystem\Coding\projects\visualstudio\csharp\Pixeval\Persisting\WebApi\CertificateManager.cs:line 99
   at Pixeval.App.InstallFakeCaCertificate() in C:\NotSystem\Coding\projects\visualstudio\csharp\Pixeval\App.xaml.cs:line 129
   at Pixeval.App.OnStartup(StartupEventArgs e) in C:\NotSystem\Coding\projects\visualstudio\csharp\Pixeval\App.xaml.cs:line 68
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__139_0(Object state)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
   at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.Run()
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run()
   at Pixeval.App.Main()

after googling I found mostly relevant questions are asking for StoreLocation.LocalMachine, I didn't found any solution for install a certificate at StoreLocation.CurrentUser

Note: I cannot reproduce this issue because it's posted by one of the users of my application


Solution

  • There are two issues, one is associated with configuration and another with the code itself.

    Issue 1:

    The exception is raised because CurrentUser.Root store is readonly. It seems that your systems administrator configured GPO to restrict users from writing to this store:

    enter image description here

    Issue 2:

    Even if you fix this, the code may fail in a different way: it may hang/freeze. This is because when you install certificates to CurrentUser.Root, a popup is invoked (you can't avoid this pop-up) to confirm the operation:

    enter image description here

    I haven't tested, but if the code is invoked in a background thread, then the code may fail, because UI thread is accessed from background thread.

    If the application works as a service/batch/imersonated context (such as web app, for example), the pop-up will be shown in a separate session, not on main screen, thus no one will be able to press confirmation button.

    Therefore, you SHALL NOT install certificates in CurrentUser.Root outside of currently interactively logged user context and be sure there is anyone who can press confirmation buttons. And avoid this code execution from bckground tasks.