ASP.NET website hangs or slows requests sometimes when getting private key for X509Certificate

We started seeing requests to only one of our 2 webservers slowing down for a period of 10 minutes, every so often, but usually during the afternoon or evening when there's less load on the server. Primary workload on the system is between 7am-3pm with peaks in the early hours.

In Application Insights I noticed one particular URL taking the top spot for slowest duration every time this happens. Other requests had an average duration of anywhere between 1-60 seconds, but this one url had between 1-5 minutes. The only thing it does is load a X509 certificate (store=My, location=Local Machine, FindByThumbprint), sign a SAML request and redirecting to some external federated login. So that url is my main suspect at the moment, but I admit the problem could be something else as well, this is just the beginning of my investigation.

I managed to grab a full memory dump when this was happening and looking at !threadpool in WinDbg I see this:

0:1091> !threadpool
CPU utilization: 3%
Worker Thread: Total: 1066 Running: 1066 Idle: 0 MaxLimit: 32767 MinLimit: 20
Work Request in Queue: 1612
    Unknown Function: 000007fefa2e1750  Context: 000000005dbe79a0
    Unknown Function: 000007fefa2e1750  Context: 000000005dbeab98
    <removed for clarity, but there's 1600+ more of these lines...>
--------------------------------------
Number of Timers: 0
--------------------------------------
Completion Port Thread:Total: 48 Free: 4 MaxFree: 40 CurrentLimit: 48 MaxLimit: 1000 MinLimit: 20

Looking at the output of !threads a lot of them has a lock count of 1, proceeding with !syncblk and 100 threads are in this same state:

0:1091> !syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info  SyncBlock Owner
 2887 00000000348b9bd8            1         1 0000000064978170 7d941056   00000005473a6ee8 System.Security.Cryptography.RSACryptoServiceProvider
 2909 0000000028c94338            1         1 0000000067eb4020 75b01055   00000001c6fdf368 System.Security.Cryptography.RSACryptoServiceProvider
 2916 0000000064623438            1         1 0000000064ab2590 39981062   0000000286cb3470 System.Security.Cryptography.RSACryptoServiceProvider
 3995 00000000359dc7c8            1         1 0000000064ab1dc0 490c1061   00000003072c7728 System.Security.Cryptography.RSACryptoServiceProvider
 4162 0000000028f89988            1         1 0000000064ab15f0 390c1060   00000002c7c78e28 System.Security.Cryptography.RSACryptoServiceProvider
 4658 00000000644f4c38            1         1 0000000064ab0e20 5b601059   000000044838cf30 System.Security.Cryptography.RSACryptoServiceProvider
 5144 00000000381a3828            1         1 0000000064978940 97541057   00000002478b7418 System.Security.Cryptography.RSACryptoServiceProvider
 6331 00000000623165f8            1         1 0000000064b30ba0 a3f41063   00000002c7c79e28 System.Security.Cryptography.RSACryptoServiceProvider
18628 00000000685b4288            1         1 000000006acb98d0 94841117   0000000140cad820 System.Security.Cryptography.RSACryptoServiceProvider
19806 00000000640cd0e8            1         1 0000000067edfb70 6ac81222   000000044842d358 System.Security.Cryptography.RSACryptoServiceProvider
20552 00000000685d4b98            1         1 000000006abf5040 1ae81116   000000040082fc88 System.Security.Cryptography.RSACryptoServiceProvider
<in total there's about 100 lines like these...>
-----------------------------
Total           61342
CCW             8
RCW             12
ComClassFactory 0
Free            30023

The callstack on them are the same and looks like this:

0:1056> !dumpstack
OS Thread Id: 0x7d94 (1056)
Current frame: ntdll!ZwCreateFile+0xa
Child-SP         RetAddr          Caller, Callee
00000000697ec1c0 000007fefc053507 rsaenh!CreateSystemDirectory+0x106, calling ntdll!ZwCreateFile
00000000697ec1d0 00000000770688d4 ntdll!RtlFreeSid+0x24, calling ntdll!RtlFreeHeap
00000000697ec2a0 000007fefc0531d3 rsaenh!CreateNestedDirectories+0x1fd, calling rsaenh!CreateSystemDirectory
00000000697ec380 000007fef3671dc3 nlssorting!SortGetSortKey+0x1cb8, calling nlssorting!_security_check_cookie
00000000697ec420 0000000077077bae ntdll!RtlAllocateHeap+0x17e, calling ntdll!memset
00000000697ec470 000007fefde63b73 shell32!SHGetFolderPathEx+0x52, calling shell32!operator delete
00000000697ec490 000007fefde63b0c shell32!SHKnownFolderFromCSIDL+0x59, calling shell32!memcmp
00000000697ec4c0 000007fefde63cd7 shell32!SHGetFolderPathW+0x161, calling shell32!_security_check_cookie
00000000697ec530 000007fefc053047 rsaenh!GetUserStorageArea+0x2b5, calling rsaenh!CreateNestedDirectories
00000000697ec5c0 000007fef80ff226 clr!SString::Set+0x52, calling MSVCR120_CLR0400!wcsncpy_s
00000000697ec5f0 000007fef80697c5 clr!SVR::gc_heap::allocate_small+0x22f, calling clr!SVR::gc_heap::adjust_limit_clr
00000000697ec630 0000000077078695 ntdll!RtlpAllocateUserBlock+0x45, calling ntdll!ExpInterlockedPopEntrySList
00000000697ec640 000007fef81063e5 clr!SBuffer::ReallocateBuffer+0x29, calling clr!operator new
00000000697ec650 000007fef80ffe9f clr!TypeName::TypeNameParser::GetIdentifier+0x113, calling clr!_security_check_cookie
00000000697ec660 00000000770a8c37 ntdll!bsearch+0xaf
00000000697ec6b0 0000000077081190 ntdll!RtlpLocateActivationContextSection+0xf0, calling ntdll!bsearch
00000000697ec730 0000000077080f99 ntdll!RtlpFindNextActivationContextSection+0x89, calling ntdll!RtlpLocateActivationContextSection
00000000697ec860 000000007708051e ntdll!RtlDosApplyFileIsolationRedirection_Ustr+0x6ce, calling ntdll!_security_check_cookie
00000000697ec9e0 000007fefc053d7e rsaenh!ReadContainerInfo+0x139, calling rsaenh!GetUserStorageArea
00000000697ece50 000007fef2d4508d (MethodDesc 000007fef2c1f250 +0x2d System.Xml.Serialization.XmlSerializationReader.ReadEndElement())
00000000697ece90 0000000077077b14 ntdll!RtlAllocateHeap+0xe4, calling ntdll!RtlpLowFragHeapAllocFromContext
00000000697ecfa0 000000007707ef59 ntdll!RtlAnsiStringToUnicodeString+0x89, calling ntdll!RtlMultiByteToUnicodeN
00000000697ed010 0000000076e442bb kernel32!CLOSE_LOCAL_HANDLE_INTERNAL+0x68, calling ntdll!RtlLeaveCriticalSection
00000000697ed040 0000000076e43ef5 kernel32!RegOpenKeyExInternalA+0x135, calling kernel32!CLOSE_LOCAL_HANDLE_INTERNAL
00000000697ed0d0 0000000076e43dad kernel32!RegOpenKeyExA+0x1d, calling kernel32!RegOpenKeyExInternalA
00000000697ed110 000007fefc0422ed rsaenh!InitExpOffloadInfo+0x1dc, calling rsaenh!_security_check_cookie
00000000697ed1d0 0000000077077bae ntdll!RtlAllocateHeap+0x17e, calling ntdll!memset
00000000697ed230 0000000076e515aa kernel32!HeapFree+0xa, calling ntdll!RtlFreeHeap
00000000697ed240 000000007707d650 ntdll!RtlInitializeCriticalSection+0xf0, calling ntdll!RtlEnterCriticalSection
00000000697ed2a0 000007fefc0535ba rsaenh!OpenUserKeyGroup+0x3e, calling rsaenh!ReadContainerInfo
00000000697ed2e0 000007fefc05441c rsaenh!NTagLogonUser+0x3fa, calling rsaenh!OpenUserKeyGroup
00000000697ed3e0 000007fefc0424e1 rsaenh!CPAcquireContext+0x1f6, calling rsaenh!NTagLogonUser
00000000697ed420 000007fefcd933c0 KERNELBASE!GetProcAddress+0x5c, calling ntdll!LdrGetProcedureAddress
00000000697ed460 000007fefc344897 cryptsp!CryptAcquireContextA+0xbef
00000000697ed510 000007fef7fe6a93 clr!CallDescrWorkerInternal+0x83
00000000697ed5d0 000007fefc343c66 cryptsp!CryptAcquireContextW+0xce, calling cryptsp!CryptAcquireContextA
00000000697ed650 000007feff2701cd advapi32!CryptAcquireContextWStub+0x11, calling advapi32!CryptAcquireContextW
00000000697ed680 000007fef819ca0e clr!FieldDesc::GetRefValue+0x3e, calling clr!FieldDesc::GetInstanceField
00000000697ed690 000007fef819c509 clr!CryptoHelper::WszCryptAcquireContext_SO_TOLERANT+0x78, calling advapi32!CryptAcquireContextWStub
00000000697ed6c0 000007fef81b671d clr!CryptoHelper::STRINGREFToUnicode+0x4d, calling MSVCR120_CLR0400!memcpy
00000000697ed6f0 000007fef819c91c clr!COMCryptography::OpenCSP+0x1d4, calling clr!CryptoHelper::WszCryptAcquireContext_SO_TOLERANT
00000000697ed800 000007fef81ba7a7 clr!COMCryptography::_OpenCSP+0x167, calling clr!COMCryptography::OpenCSP
00000000697ed880 000007fef7feb3aa clr!ObjHeader::GetSyncBlock+0x1ab, calling clr!ClassLoader::AvailableClasses_LockHolder::~AvailableClasses_LockHolder
00000000697ed8f0 000007fef76fa6c2 (MethodDesc 000007fef6b73438 +0x52 System.Security.Cryptography.Utils.CreateProvHandle(System.Security.Cryptography.CspParameters, Boolean)), calling 000007fef81ba640 (stub for System.Security.Cryptography.Utils._OpenCSP(System.Security.Cryptography.CspParameters, UInt32, System.Security.Cryptography.SafeProvHandle ByRef))
00000000697ed988 000007fef81ba6e1 clr!COMCryptography::_OpenCSP+0xa1, calling clr!LazyMachStateCaptureState
00000000697ed9c0 000007fef76fa6c2 (MethodDesc 000007fef6b73438 +0x52 System.Security.Cryptography.Utils.CreateProvHandle(System.Security.Cryptography.CspParameters, Boolean)), calling 000007fef81ba640 (stub for System.Security.Cryptography.Utils._OpenCSP(System.Security.Cryptography.CspParameters, UInt32, System.Security.Cryptography.SafeProvHandle ByRef))
00000000697eda20 000007fef76faddd (MethodDesc 000007fef6b73498 +0x5d System.Security.Cryptography.Utils.GetKeyPairHelper(System.Security.Cryptography.CspAlgorithmType, System.Security.Cryptography.CspParameters, Boolean, Int32, System.Security.Cryptography.SafeProvHandle ByRef, System.Security.Cryptography.SafeKeyHandle ByRef)), calling (MethodDesc 000007fef6b73438 +0 System.Security.Cryptography.Utils.CreateProvHandle(System.Security.Cryptography.CspParameters, Boolean))
00000000697eda40 000007fef64d78a5 (MethodDesc 000007fef5dd2588 +0xf5 System.Security.Cryptography.CAPI.CryptFindOIDInfo(UInt32, System.Security.Cryptography.SafeLocalAllocHandle, System.Security.Cryptography.OidGroup)), calling clr!JIT_ByRefWriteBarrier
00000000697edaa0 000007fef7743387 (MethodDesc 000007fef6b87ff8 +0x87 System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()), calling (MethodDesc 000007fef6b73498 +0 System.Security.Cryptography.Utils.GetKeyPairHelper(System.Security.Cryptography.CspAlgorithmType, System.Security.Cryptography.CspParameters, Boolean, Int32, System.Security.Cryptography.SafeProvHandle ByRef, System.Security.Cryptography.SafeKeyHandle ByRef))
00000000697edaf0 000007fef77432e7 (MethodDesc 000007fef6b87fe8 +0xc7 System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32, System.Security.Cryptography.CspParameters, Boolean)), calling (MethodDesc 000007fef6b87ff8 +0 System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair())
00000000697edb40 000007fef64da173 (MethodDesc 000007fef5d43320 +0xe3 System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()), calling (MethodDesc 000007fef6b87fe8 +0 System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32, System.Security.Cryptography.CspParameters, Boolean))
00000000697edcd0 000007fe9df0ac59 (MethodDesc 000007fe9cabc310 +0x39 <our http handler>.ProcessRequest(System.Web.HttpContext))
00000000697edd10 000007feeedc55f6 (MethodDesc 000007feeeb3c8f0 +0x316 System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute())
<removed the rest for brevity...>

Looking at the HttpContext for that request matches the url I suspected in App Insights. Any idea what is going on here and why it's blocking while getting the PrivateKey for the certificate?

Please advise if there's something else I should be looking for in WinDbg or what I can do to otherwise debug this behavior.