<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Decrypt my World : CryptoAPI</title><link>http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx</link><description>Tags: CryptoAPI</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>"Invalid provider type specified" error when accessing X509Certificate2.PrivateKey on CNG certificates</title><link>http://blogs.msdn.com/alejacma/archive/2009/12/22/invalid-provider-type-specified-error-when-accessing-x509certificate2-privatekey.aspx</link><pubDate>Tue, 22 Dec 2009 09:58:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9940002</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9940002.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9940002</wfw:commentRss><description>&lt;P&gt;Hi all,&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You may get the following &lt;STRONG&gt;exception&lt;/STRONG&gt; when trying to access &lt;A href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.privatekey.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.privatekey.aspx"&gt;X509Certificate2&lt;SPAN class=nu&gt;.&lt;/SPAN&gt;PrivateKey&lt;/A&gt; on a &lt;STRONG&gt;.NET 3.5&lt;/STRONG&gt; (or older) app:&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;System.Security.Cryptography.&lt;STRONG&gt;CryptographicException&lt;/STRONG&gt;: &lt;STRONG&gt;Invalid provider type specified&lt;/STRONG&gt;.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)&lt;BR&gt;at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle&amp;amp; safeProvHandle, SafeKeyHandle&amp;amp; safeKeyHandle)&lt;BR&gt;at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()&lt;BR&gt;at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)&lt;BR&gt;at System.Security.Cryptography.X509Certificates.&lt;STRONG&gt;X509Certificate2.get_PrivateKey&lt;/STRONG&gt;()&lt;BR&gt;&lt;/EM&gt;"&lt;/P&gt;
&lt;P&gt;When this happened to me, I used my &lt;A href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx"&gt;CryptoAPI Tracer&lt;/A&gt; on the problematic app to find out which CryptoAPI was failing&amp;nbsp;and causing that exception. This was the one:&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;CryptAcquireContextA&lt;/STRONG&gt; (0x448)&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;IN&lt;BR&gt;pszContainer&lt;BR&gt;0078a948 "anycontainername"&lt;BR&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;pszProvider&lt;BR&gt;00773fb8 "&lt;STRONG&gt;Microsoft Software Key Storage P&lt;/STRONG&gt;"&lt;BR&gt;00773fd8 "&lt;STRONG&gt;rovider&lt;/STRONG&gt;"&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;dwProvType&lt;BR&gt;0&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;dwFlags&lt;BR&gt;0&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;OUT&lt;BR&gt;hProv&lt;BR&gt;NULL&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;RESULT&lt;BR&gt;CryptAcquireContextA (0x448) FAILED&lt;BR&gt;&lt;STRONG&gt;LastErrorValue&lt;/STRONG&gt;: (HRESULT) &lt;STRONG&gt;0x80090014&lt;/STRONG&gt; (2148073492) - &lt;STRONG&gt;Invalid provider type specified&lt;/STRONG&gt;.&lt;BR&gt;LastStatusValue: (NTSTATUS) 0 - STATUS_WAIT_0&lt;BR&gt;&lt;/EM&gt;"&lt;/P&gt;
&lt;P&gt;So the &lt;STRONG&gt;certificate&lt;/STRONG&gt; I was using was associated to &lt;STRONG&gt;Microsoft Software Key Storage Provider&lt;/STRONG&gt;, which&amp;nbsp;is not a &lt;STRONG&gt;CSP&lt;/STRONG&gt; but a &lt;STRONG&gt;KSP&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/bb931355(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/bb931355(VS.85).aspx"&gt;CNG Key Storage Providers&lt;/A&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;Unlike Cryptography API (CryptoAPI), &lt;STRONG&gt;Cryptography API: Next Generation (CNG)&lt;/STRONG&gt; separates cryptographic providers from &lt;STRONG&gt;key storage providers (KSPs)&lt;/STRONG&gt;. KSPs can be used to create, delete, export, import, open and store keys. Depending on implementation, they can also be used for asymmetric encryption, secret agreement, and signing. Microsoft installs the following KSPs &lt;STRONG&gt;beginning with Windows Vista and Windows Server 2008&lt;/STRONG&gt;.&lt;/EM&gt; &lt;BR&gt;"&lt;/P&gt;
&lt;P&gt;This is a &lt;STRONG&gt;CNG certificate&lt;/STRONG&gt;! This is what &lt;STRONG&gt;CertUtil.exe&lt;/STRONG&gt; returns on the private key of that certificate:&lt;/P&gt;
&lt;P&gt;"&lt;BR&gt;&lt;EM&gt;Key Container = ...&lt;BR&gt;Unique container name: ...&lt;BR&gt;&lt;STRONG&gt;Provider&lt;/STRONG&gt; = &lt;STRONG&gt;Microsoft Software Key Storage Provider&lt;/STRONG&gt;&lt;BR&gt;Private key is NOT exportable&lt;BR&gt;Encryption test passed&lt;BR&gt;&lt;/EM&gt;"&lt;/P&gt;
&lt;P&gt;So certutil.exe knows how to deal with this kind of CNG certificates. I used my CryptoAPI Tracer on CertUtil, and this tool is using &lt;STRONG&gt;CryptAcquireCertificatePrivateKey&lt;/STRONG&gt; &lt;STRONG&gt;instead of CryptAcquireContext&lt;/STRONG&gt; to access the keys of the cert. CryptAcquireCertificatePrivateKey has specific &lt;STRONG&gt;flags&lt;/STRONG&gt; to deal with &lt;STRONG&gt;CNG&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/aa379885(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379885(VS.85).aspx"&gt;CryptAcquireCertificatePrivateKey Function&lt;/A&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG&lt;/STRONG&gt;&lt;BR&gt;This function will attempt to obtain the key by using CryptoAPI. If that fails, this function will attempt to obtain the key by using the Cryptography API: Next Generation (CNG).&lt;BR&gt;The pdwKeySpec variable receives the CERT_NCRYPT_KEY_SPEC flag if CNG is used to obtain the key.&lt;BR&gt;...&lt;BR&gt;pdwKeySpec [out] &lt;BR&gt;CERT_NCRYPT_KEY_SPEC&lt;BR&gt;The key is a CNG key.&lt;/EM&gt;&lt;BR&gt;"&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;.NET is not CNG aware yet (at least up to version 3.5 SP1)&lt;/STRONG&gt;. It uses CryptAcquireContext instead of CryptAcquireCertificatePrivateKey and CryptAcquireContext has no flags to deal with CNG. &lt;/P&gt;
&lt;P&gt;A possible &lt;STRONG&gt;workaround&lt;/STRONG&gt; to this may be to &lt;STRONG&gt;use CryptoAPI/CNG API directly&lt;/STRONG&gt; to deal with CNG keys. That is what certutil.exe does. But if&amp;nbsp;we want&amp;nbsp;an easier and&amp;nbsp;&lt;STRONG&gt;pure .NET solution&lt;/STRONG&gt; which understands CNG, this will help to implement it:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.codeplex.com/clrsecurity" mce_href="http://www.codeplex.com/clrsecurity"&gt;CLR Security&lt;/A&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;Security.Cryptography.dll&lt;/STRONG&gt; provides a new set of algorithm implementations to augment the built in .NET framework supported algorithms. It also provides some APIs to extend the existing framework cryptography APIs. Within this project you will find:&lt;BR&gt;§ A CNG implementation of the AES, RSA, and TripleDES encryption algorithms &lt;BR&gt;§ A CNG implementation of a random number generator &lt;BR&gt;§ A class that allows dynamically creating algorithms both from this library as well as all of the algorithms that ship with .NET 3.5 &lt;BR&gt;§ An enumerator over all of the installed CNG providers on the current machine &lt;BR&gt;§ Extension methods that allow access to all of the keys installed in a CNG provider, as well as all of the algorithms the provider supports&lt;/EM&gt; &lt;BR&gt;"&lt;/P&gt;
&lt;P&gt;If you want to use CNG with this dll, you have to do the following:&lt;/P&gt;
&lt;P&gt;1) Change .NET version to 3.5. As far as I know the dll requires us to move at least to that version.&lt;/P&gt;
&lt;P&gt;2) Reference Security.Cryptography.dll in your project.&lt;/P&gt;
&lt;P&gt;3) Include "using Security.Cryptography.X509Certificates;" statement (in C#, of course)&amp;nbsp;to &lt;STRONG&gt;activate CNG extensions&lt;/STRONG&gt; for standard &lt;STRONG&gt;X509Certificate2&lt;/STRONG&gt; class.&lt;/P&gt;
&lt;P&gt;Then you may check whether the cert has a CNG key using the extension&lt;STRONG&gt; .HasCngKey()&lt;/STRONG&gt; for X509Certificate2. If you have a CNG key, you can then instantiate an &lt;STRONG&gt;RSACng&lt;/STRONG&gt; object using the extension &lt;STRONG&gt;.GetCngPrivateKey()&lt;/STRONG&gt; for X509Certificate2. You can then i.e. decrypt with &lt;STRONG&gt;RSACng.DecryptValue()&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9940002" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/RSACryptoServiceProvider/default.aspx">RSACryptoServiceProvider</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CNG/default.aspx">CNG</category></item><item><title>Access Violation exception when loading a certificate in .NET (Windows Server 2003)</title><link>http://blogs.msdn.com/alejacma/archive/2009/11/12/access-violation-exception-when-loading-a-certificate-in-net-windows-server-2003.aspx</link><pubDate>Thu, 12 Nov 2009 15:32:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9921383</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9921383.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9921383</wfw:commentRss><description>&lt;P&gt;Hi all&lt;/P&gt;
&lt;P&gt;You may get an &lt;STRONG&gt;Access Violation&lt;/STRONG&gt; exception when&lt;STRONG&gt; loading a certificate&lt;/STRONG&gt; into a &lt;STRONG&gt;X509Certificate2&lt;/STRONG&gt; object, only &lt;STRONG&gt;after&lt;/STRONG&gt; installing &lt;STRONG&gt;KB 938397 hotfix&lt;/STRONG&gt; (&lt;STRONG&gt;crypt32.dll v5.131.3790.4095&lt;/STRONG&gt;) at &lt;A href="http://support.microsoft.com/kb/938397" mce_href="http://support.microsoft.com/kb/938397"&gt;Applications that use the Cryptography API cannot validate an X.509 certificate in Windows Server 2003&lt;/A&gt;. &lt;/P&gt;
&lt;P&gt;Note that the issue won't happen with Windows Server 2003 SP2 version of crypt32.dll (v5.131.3790.3959).&lt;/P&gt;
&lt;P&gt;Note that the issue only happens with &lt;STRONG&gt;Base64 encoded certificate&lt;/STRONG&gt; files. DER encoded certificate files&amp;nbsp;work just fine.&lt;/P&gt;
&lt;P&gt;The good news is that a newer hotfix, &lt;STRONG&gt;KB 950474&lt;/STRONG&gt;, installs a newer version of &lt;STRONG&gt;crypt32.dll&lt;/STRONG&gt; that &lt;STRONG&gt;fixes the issue&lt;/STRONG&gt;:&amp;nbsp;&lt;STRONG&gt;v5.131.3790.4271&lt;/STRONG&gt;. You can get it here: &lt;A href="http://support.microsoft.com/kb/950474" mce_href="http://support.microsoft.com/kb/950474"&gt;Error message when you run the SharePoint Products and Technologies Configuration Wizard on a Windows Server 2003-based computer: "Application has generated an exception that could not be handled"&lt;/A&gt;.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;PS: What are you still doing with Windows Server 2003? Have you tried the new &lt;STRONG&gt;&lt;A href="http://www.microsoft.com/windowsserver2008/en/us/default.aspx" mce_href="http://www.microsoft.com/windowsserver2008/en/us/default.aspx"&gt;Windows Server 2008 R2&lt;/A&gt;&lt;/STRONG&gt;? &lt;STRONG&gt;IT JUST ROCKS!!!!&lt;/STRONG&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9921383" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Windows+Server+2003/default.aspx">Windows Server 2003</category></item><item><title>Working with CNG in .NET 3.5</title><link>http://blogs.msdn.com/alejacma/archive/2009/10/14/working-with-cng-in-net-3-5.aspx</link><pubDate>Wed, 14 Oct 2009 10:37:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9907086</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9907086.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9907086</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Do you want to work with &lt;STRONG&gt;CNG&lt;/STRONG&gt; and&lt;STRONG&gt; .NET 3.5&lt;/STRONG&gt; and don't want to &lt;A href="http://msdn.microsoft.com/en-us/library/ms867087.aspx" mce_href="http://msdn.microsoft.com/en-us/library/ms867087.aspx"&gt;P/Invoke&lt;/A&gt; into &lt;A href="http://msdn.microsoft.com/en-us/library/aa380256(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380256(VS.85).aspx"&gt;CryptoAPI&lt;/A&gt; &amp;amp; &lt;A href="http://msdn.microsoft.com/en-us/library/aa376214(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa376214(VS.85).aspx"&gt;CNG API&lt;/A&gt;? Check out &lt;A href="http://clrsecurity.codeplex.com/Wiki/View.aspx?title=Security.Cryptography.dll"&gt;&lt;FONT color=#3e62a6&gt;Security.Cryptography.dll&lt;/FONT&gt;&lt;/A&gt;&amp;nbsp;library&amp;nbsp;at &lt;A href="http://www.codeplex.com/clrsecurity" mce_href="http://www.codeplex.com/clrsecurity"&gt;CLR Security&lt;/A&gt;:&lt;/P&gt;
&lt;P&gt;"&lt;BR&gt;&lt;EM&gt;Security.Cryptography.dll provides a new set of algorithm implementations to augment the built in .NET framework supported algorithms. It also provides some APIs to extend the existing framework cryptography APIs. Within this project you will find:&lt;BR&gt;§ A CNG implementation of the AES, RSA, and TripleDES encryption algorithms &lt;BR&gt;§ A CNG implementation of a random number generator &lt;BR&gt;§ A class that allows dynamically creating algorithms both from this library as well as all of the algorithms that ship with .NET 3.5 &lt;BR&gt;§ An enumerator over all of the installed CNG providers on the current machine &lt;BR&gt;§ Extension methods that allow access to all of the keys installed in a CNG provider, as well as all of the algorithms the provider supports &lt;BR&gt;&lt;/EM&gt;"&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9907086" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CNG/default.aspx">CNG</category></item><item><title>CryptographicException: The data to be decrypted exceeds the maximum for this modulus of 0 bytes</title><link>http://blogs.msdn.com/alejacma/archive/2009/10/09/cryptographicexception-the-data-to-be-decrypted-exceeds-the-maximum-for-this-modulus-of-0-bytes.aspx</link><pubDate>Fri, 09 Oct 2009 14:06:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9905407</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9905407.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9905407</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;Some time ago a customer of mine was getting the following &lt;A href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cryptographicexception.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cryptographicexception.aspx"&gt;CryptographicException&lt;/A&gt; when calling&amp;nbsp;&lt;A href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.encryptedxml.decryptdocument.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.encryptedxml.decryptdocument.aspx"&gt;EncryptedXml.DecryptDocument&lt;/A&gt;&amp;nbsp;method to decrypt an &lt;A href="http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.aspx"&gt;XmlDocument&lt;/A&gt; in their &lt;STRONG&gt;.NET&lt;/STRONG&gt; app:&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&amp;nbsp;[System.Security.Cryptography.CryptographicException] = {"&lt;STRONG&gt;The data to be decrypted exceeds the maximum for this modulus of 0 bytes&lt;/STRONG&gt;"}&lt;BR&gt;_HResult = -2146233296&lt;BR&gt;_HResult =&lt;STRONG&gt; 0x80131430&lt;/STRONG&gt;&lt;BR&gt;No Inner Exception&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;This was&amp;nbsp;only happening with a &lt;STRONG&gt;smart card certificate &lt;/STRONG&gt;associated to a specific &lt;STRONG&gt;third-party CSP &lt;/STRONG&gt;(non-MS).&lt;/P&gt;
&lt;P&gt;In order to troubleshoot this, I used my &lt;A href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx"&gt;CryptoAPI Tracer script&lt;/A&gt;&amp;nbsp;to get some traces while reproducing the issue. Thanks to my script I could see these &lt;STRONG&gt;calls&lt;/STRONG&gt; that .NET is making to the third-party CSP behind the scenes (I will omit key container and CSP names as they are not needed to understand the issue):&lt;/P&gt;&lt;PRE&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;

&lt;STRONG&gt;CryptAcquireContextA&lt;/STRONG&gt; (0x570)

&lt;STRONG&gt;IN&lt;/STRONG&gt;
&lt;STRONG&gt;pszContainer&lt;/STRONG&gt;
001bf1a0 "&lt;STRONG&gt;Cert Container Name&lt;/STRONG&gt;"

&lt;STRONG&gt;pszProvider&lt;/STRONG&gt;
001b4698 "&lt;STRONG&gt;Third-party CSP&lt;/STRONG&gt;"

dwProvType
PROV_RSA_FULL

dwFlags
0

&lt;STRONG&gt;OUT&lt;/STRONG&gt;
&lt;STRONG&gt;hProv&lt;/STRONG&gt;
&lt;STRONG&gt;0x1bea28&lt;/STRONG&gt;

RESULT
CryptAcquireContextA (0x570) SUCCEEDED

&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;

&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;

&lt;STRONG&gt;CryptGetUserKey&lt;/STRONG&gt; (0x570)

&lt;STRONG&gt;IN&lt;/STRONG&gt;
&lt;STRONG&gt;hProv&lt;/STRONG&gt;
&lt;STRONG&gt;0x1bea28&lt;/STRONG&gt;

dwKeySpec
AT_KEYEXCHANGE

&lt;STRONG&gt;OUT&lt;/STRONG&gt;
&lt;STRONG&gt;hUserKey&lt;/STRONG&gt;
&lt;STRONG&gt;0x1bf1a0&lt;/STRONG&gt;

RESULT
CryptGetUserKey (0x570) SUCCEEDED

&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;

&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;

CryptGetKeyParam (0x570)

IN
hKey
0x1bf1a0

dwParam
KP_ALGID

pbData
NULL

dwDataLen
0

dwFlags
0

OUT
dwDataLen
4

RESULT
CryptGetKeyParam (0x570) SUCCEEDED

&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;

&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;

CryptGetKeyParam (0x570)

IN
hKey
0x1bf1a0

dwParam
KP_ALGID

pbData
0x1bd228

dwDataLen
4

dwFlags
0

OUT
bData
001bd228 0000a400

dwDataLen
4

RESULT
CryptGetKeyParam (0x570) SUCCEEDED

&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;

&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;

&lt;STRONG&gt;CryptGetKeyParam&lt;/STRONG&gt; (0x570)

&lt;STRONG&gt;IN&lt;/STRONG&gt;
&lt;STRONG&gt;hKey&lt;/STRONG&gt;
&lt;STRONG&gt;0x1bf1a0&lt;/STRONG&gt;

&lt;STRONG&gt;dwParam&lt;/STRONG&gt;
&lt;STRONG&gt;KP_KEYLEN&lt;/STRONG&gt;

pbData
NULL

&lt;STRONG&gt;dwDataLen
0&lt;/STRONG&gt;

dwFlags
0

&lt;STRONG&gt;OUT
dwDataLen
4&lt;/STRONG&gt;

RESULT
CryptGetKeyParam (0x570) SUCCEEDED

&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;

&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;

&lt;STRONG&gt;CryptGetKeyParam&lt;/STRONG&gt; (0x570)

&lt;STRONG&gt;IN
hKey
0x1bf1a0&lt;/STRONG&gt;

&lt;STRONG&gt;dwParam
KP_KEYLEN&lt;/STRONG&gt;

&lt;STRONG&gt;pbData
0x1bd228&lt;/STRONG&gt;

&lt;STRONG&gt;dwDataLen
4&lt;/STRONG&gt;

dwFlags
0

&lt;STRONG&gt;OUT
bData
001bd228 00000000&lt;/STRONG&gt;

&lt;STRONG&gt;dwDataLen
4&lt;/STRONG&gt;

RESULT
CryptGetKeyParam (0x570) SUCCEEDED

&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;

&lt;/PRE&gt;
&lt;P&gt;These calls mean the following: before .NET tries to decrypt the XML, it asks the CSP for some information on the key it will use to decrypt, like its length (&lt;A href="http://msdn.microsoft.com/en-us/library/aa379949(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379949(VS.85).aspx"&gt;CryptGetKeyParam&lt;/A&gt; API with &lt;STRONG&gt;KP_KEYLEN&lt;/STRONG&gt; flag). For some unknown reason the &lt;STRONG&gt;third-party CSP is returning a length of 0 for the key&lt;/STRONG&gt;&amp;nbsp;(&lt;STRONG&gt;pbData&lt;/STRONG&gt; points to &lt;STRONG&gt;0&lt;/STRONG&gt;), which is &lt;STRONG&gt;invalid&lt;/STRONG&gt;, thus .NET won't continue with the decryption and will raise the exception we've seen. Why is the CSP returning an invalid length? Only the CSP developers can answer that question.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;In my customer's particular case, the CSP developers quickly localized and fixed the issue.&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9905407" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Debugging/default.aspx">Debugging</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Debugger+scripts/default.aspx">Debugger scripts</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category></item><item><title>X509Certificate creates temporary files which are never deleted</title><link>http://blogs.msdn.com/alejacma/archive/2009/09/30/x509certificate-creates-temporary-files-which-are-never-deleted.aspx</link><pubDate>Wed, 30 Sep 2009 11:52:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9901214</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9901214.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9901214</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;When creating an &lt;STRONG&gt;X509Certificate&lt;/STRONG&gt; object in&amp;nbsp;your &lt;STRONG&gt;.NET&lt;/STRONG&gt; application ("&lt;EM&gt;X509Certificate cert = new X509Certificate(certBytes);&lt;/EM&gt;") you may see that two &lt;STRONG&gt;0kb files&lt;/STRONG&gt; are created in the &lt;STRONG&gt;Temp folder&lt;/STRONG&gt; of your &lt;STRONG&gt;Windows Server 2003&lt;/STRONG&gt;, and are &lt;STRONG&gt;never deleted&lt;/STRONG&gt;. After creating many of those objects the Temp folder fills up and the app won't function properly.&lt;/P&gt;
&lt;P&gt;The cause of this issue is the following bug:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://support.microsoft.com/kb/931908" mce_href="http://support.microsoft.com/kb/931908"&gt;On a Windows Server 2003-based client computer, the system does not delete a temporary file that is created when an application calls the "CryptQueryObject" function&lt;/A&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate(VS.71).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate(VS.71).aspx"&gt;X509Certificate&lt;/A&gt; class uses &lt;A href="http://msdn.microsoft.com/en-us/library/aa380264(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380264(VS.85).aspx"&gt;CryptQueryObject&lt;/A&gt; API behind the scenes. Fortunatelly there is a fix for this referenced on the link above.&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9901214" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Windows+Server+2003/default.aspx">Windows Server 2003</category></item><item><title>How to timestamp Authenticode signatures when our proxy requires authentication</title><link>http://blogs.msdn.com/alejacma/archive/2009/09/29/how-to-timestamp-authenticode-signatures-when-our-proxy-requires-authentication.aspx</link><pubDate>Tue, 29 Sep 2009 13:47:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9900789</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9900789.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9900789</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;The other day a customer of mine&amp;nbsp;was trying to add an &lt;STRONG&gt;Authenticode signature with timestamp&lt;/STRONG&gt; to their PowerShell scripts with &lt;STRONG&gt;PowerShell&lt;/STRONG&gt; itself&amp;nbsp;and its &lt;A href="http://technet.microsoft.com/en-us/library/dd347598.aspx" mce_href="http://technet.microsoft.com/en-us/library/dd347598.aspx"&gt;Set-AuthenticodeSignature cmdlet&lt;/A&gt;. He was able to sign the scripts just fine, but when using the timestamp option the cmdlet was&lt;STRONG&gt; not&lt;/STRONG&gt; &lt;STRONG&gt;honoring Internet&lt;/STRONG&gt; &lt;STRONG&gt;Explorer Proxy settings&lt;/STRONG&gt; and the &lt;STRONG&gt;timestamping process failed&lt;/STRONG&gt;. &lt;/P&gt;
&lt;P&gt;If you have never seen how to add such a signature with PowerShell, check the following &lt;STRONG&gt;sample&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P&gt;First we can create a &lt;STRONG&gt;test certificate&lt;/STRONG&gt; in i.e. a cmd.exe:&lt;/P&gt;&lt;PRE&gt;c:\&amp;gt;&lt;STRONG&gt;makecert&lt;/STRONG&gt; -n "CN=PowerShell Local Certificate Root" -a sha1 -eku 1.3.6.1.5.5.7.3.3 -r -sv root.pvk root.cer -ss Root -sr localMachine
c:\&amp;gt;&lt;STRONG&gt;makecert&lt;/STRONG&gt; -pe -n "CN=Powershell User" -ss MY -a sha1 -eku 1.3.6.1.5.5.7.3.3 -iv root.pvk -ic root.cer
&lt;/PRE&gt;
&lt;P&gt;Then we can create a &lt;STRONG&gt;signature with timestamp&lt;/STRONG&gt; in PowerShell:&lt;/P&gt;&lt;PRE&gt;C:\PS&amp;gt;$cert=&lt;STRONG&gt;Get-ChildItem&lt;/STRONG&gt; -Path cert:\CurrentUser\my -CodeSigningCert
C:\PS&amp;gt;&lt;STRONG&gt;Set-AuthenticodeSignature&lt;/STRONG&gt; -filepath c:\notepad.exe -certificate $cert -IncludeChain All -TimeStampServer "http://timestamp.globalsign.com/scripts/timstamp.dll" 
&lt;/PRE&gt;
&lt;P&gt;Additionally, remember that we have several other ways to do Authenticode signing as I already commented here:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/alejacma/archive/2008/02/20/how-to-sign-exe-files-with-an-authenticode-certificate-vb-net.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/02/20/how-to-sign-exe-files-with-an-authenticode-certificate-vb-net.aspx"&gt;How to sign EXE files with an Authenticode certificate (VB.NET)&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/alejacma/archive/2008/12/11/how-to-sign-exe-files-with-an-authenticode-certificate-part-2.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/12/11/how-to-sign-exe-files-with-an-authenticode-certificate-part-2.aspx"&gt;How to sign EXE files with an Authenticode certificate (part 2)&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;So my customer tried to use &lt;STRONG&gt;signtool.exe&lt;/STRONG&gt; instead, with the same results: IE proxy settings are not getting used at all and they get an error like the following: &lt;/P&gt;&lt;PRE&gt;C:\Program Files\Microsoft SDKs\Windows\v6.1\Bin&amp;gt;&lt;STRONG&gt;signtool timestamp&lt;/STRONG&gt; /v /t http://timestamp.globalsign.com/scripts/timstamp.dll c:\notepad.exe

Timestamping: c:\notepad.exe
SignTool Error: &lt;STRONG&gt;The specified timestamp server could not be reached&lt;/STRONG&gt;.
SignTool Error: An error occurred while attempting to timestamp: c:\notepad.exe

Number of files successfully timestamped: 0
Number of errors: 1
&lt;/PRE&gt;
&lt;P&gt;&lt;BR&gt;Note that if we open Internet Explorer and enter &lt;A href="http://timestamp.globalsign.com/scripts/timstamp.dll"&gt;http://timestamp.globalsign.com/scripts/timstamp.dll&lt;/A&gt; into the address bar, IE presents the credentials dialog box to send to the proxy and we can access the timestamp server without problems.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;The &lt;STRONG&gt;cause of this issue&lt;/STRONG&gt; is the following:&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;All signing&amp;nbsp;methods we saw in my previous posts (SignTool, CAPICOM, etc.) end up using &lt;A href="http://msdn.microsoft.com/en-us/library/aa387734(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa387734(VS.85).aspx"&gt;SignerSignEx&lt;/A&gt; API to sign, and &lt;A href="http://msdn.microsoft.com/en-us/library/cc300159(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/cc300159(VS.85).aspx"&gt;SignerTimeStampEx&lt;/A&gt; API to timestamp the signature. The same applies to PowerShell's Set-AuthenticodeSignature cmdlet. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;SignerTimeStampEx&lt;/STRONG&gt; will connect to the remote timestamp server in a very simple way, without using any proxy info or user credentials. And this is not configurable in any way.&lt;/P&gt;
&lt;P&gt;So I'm afraid all signing methods we have at our disposal suffer from this &lt;STRONG&gt;limitation&lt;/STRONG&gt; in the API. &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;In order to timestamp code, it is necessary to have unrestricted access to the Internet&lt;/STRONG&gt;. &lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/alejacma/archive/2008/12/11/how-to-sign-exe-files-with-an-authenticode-certificate-part-2.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/12/11/how-to-sign-exe-files-with-an-authenticode-certificate-part-2.aspx"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;I hope this helps.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9900789" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category></item><item><title>How to get information from a CRL (.NET)</title><link>http://blogs.msdn.com/alejacma/archive/2009/04/01/how-to-get-information-from-a-crl-net.aspx</link><pubDate>Wed, 01 Apr 2009 12:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9525923</guid><dc:creator>alejacma</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9525923.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9525923</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;C# sample&lt;/STRONG&gt; uses &lt;STRONG&gt;CryptoAPI&lt;/STRONG&gt; to read the info of a &lt;STRONG&gt;CRL&lt;/STRONG&gt; (&lt;STRONG&gt;Certificate Revocation List&lt;/STRONG&gt;)&amp;nbsp;stored in a file:&lt;/P&gt;&lt;PRE&gt;using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace GetCRLInfo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void getInfoButton_Click(object sender, EventArgs e)
        {
            // Variables
            //
            Boolean bResult = false;
            IntPtr pvContext = IntPtr.Zero;
            Win32.CRL_CONTEXT CRLContext;
            Win32.CRL_INFO CRLInfo;
            Int32 csz = 0;
            StringBuilder psz = null;
            IntPtr rgCRLEntry = IntPtr.Zero;
            Win32.CRL_ENTRY CRLEntry;
            String strSerialNumber = "";
            IntPtr pByte = IntPtr.Zero;
            Byte bByte = 0;
            IntPtr rgExtension = IntPtr.Zero;
            Win32.CERT_EXTENSION CRLExtension;
            Int32 cbFormat = 0;
            StringBuilder pbFormat = null;
            String strCRLReasonCode = "";
            
            // Clean screen
            //
            issuerTextBox.Text = "";
            revocationListBox.Items.Clear();

            try
            {
                // Get CRL context
                //
                bResult = Win32.&lt;STRONG&gt;CryptQueryObject&lt;/STRONG&gt;(
                    Win32.CERT_QUERY_OBJECT_FILE,
                    fileTextBox.Text,
                    Win32.CERT_QUERY_CONTENT_FLAG_CRL,
                    Win32.CERT_QUERY_FORMAT_FLAG_BINARY,
                    0,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    ref pvContext
                );
                if (!bResult)
                {
                    throw new Exception("CryptQueryObject error #" + Marshal.GetLastWin32Error());
                }

                CRLContext = (Win32.CRL_CONTEXT)Marshal.PtrToStructure(pvContext, typeof(Win32.&lt;STRONG&gt;CRL_CONTEXT&lt;/STRONG&gt;));

                // Get CRL info
                //
                CRLInfo = (Win32.CRL_INFO)Marshal.PtrToStructure(CRLContext.pCrlInfo, typeof(Win32.&lt;STRONG&gt;CRL_INFO&lt;/STRONG&gt;));

                // Get CRL issuer
                //
                csz = Win32.CertNameToStr(
                    Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                    ref CRLInfo.Issuer,
                    Win32.CERT_X500_NAME_STR,
                    null,
                    0
                );
                if (csz &amp;lt;= 0)
                {
                    throw new Exception("CertNameToStr error #" + Marshal.GetLastWin32Error());
                }

                psz = new StringBuilder(csz);

                csz = Win32.&lt;STRONG&gt;CertNameToStr&lt;/STRONG&gt;(
                    Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                    ref CRLInfo.Issuer,
                    Win32.CERT_X500_NAME_STR,
                    psz,
                    csz
                );
                if (csz &amp;lt;= 0)
                {
                    throw new Exception("CertNameToStr error #" + Marshal.GetLastWin32Error());
                }

                // Show CRL issuer
                //
                issuerTextBox.Text = psz.ToString();

                // Get revocation list
                //
                rgCRLEntry = CRLInfo.rgCRLEntry;
                for (int i = 0; i &amp;lt; CRLInfo.cCRLEntry; i++)
                {
                    // Get the serial number of one revoked certificate
                    //
                    strSerialNumber = "";

                    CRLEntry = (Win32.CRL_ENTRY)Marshal.PtrToStructure(rgCRLEntry, typeof(Win32.&lt;STRONG&gt;CRL_ENTRY&lt;/STRONG&gt;));

                    pByte = CRLEntry.SerialNumber.pbData;
                    for (int j = 0; j &amp;lt; CRLEntry.SerialNumber.cbData; j++)
                    {
                        bByte = Marshal.ReadByte(pByte);
                        strSerialNumber = bByte.ToString("X").PadLeft(2, '0') + " " + strSerialNumber;
                        pByte = (IntPtr)((Int32)pByte + Marshal.SizeOf(typeof(Byte)));
                    }

                    // Get the CRL Reason Code of that revoked certificate
                    //
                    strCRLReasonCode = "";

                    rgExtension = Win32.&lt;STRONG&gt;CertFindExtension&lt;/STRONG&gt;(
                        Win32.szOID_CRL_REASON_CODE,
                        CRLEntry.cExtension,
                        CRLEntry.rgExtension
                    );
                    if (rgExtension.Equals(IntPtr.Zero))
                    {
                        throw new Exception("CertFindExtension found no CRL Reason Code");
                    }
                    
                    CRLExtension = (Win32.CERT_EXTENSION)Marshal.PtrToStructure(rgExtension, typeof(Win32.&lt;STRONG&gt;CERT_EXTENSION&lt;/STRONG&gt;));

                    // Format that CRL Reason Code so we can show it
                    //
                    cbFormat = 0;
                    pbFormat = null;
                    bResult = Win32.&lt;STRONG&gt;CryptFormatObject&lt;/STRONG&gt;(
                        Win32.X509_ASN_ENCODING,
                        0,
                        0,
                        IntPtr.Zero,
                        Win32.szOID_CRL_REASON_CODE,
                        CRLExtension.Value.pbData,
                        CRLExtension.Value.cbData,
                        null,
                        ref cbFormat
                    );
                    if (!bResult)
                    {
                        throw new Exception("CryptFormatObject error #" + Marshal.GetLastWin32Error());
                    }

                    pbFormat = new StringBuilder(cbFormat);

                    bResult = Win32.&lt;STRONG&gt;CryptFormatObject&lt;/STRONG&gt;(
                        Win32.X509_ASN_ENCODING,
                        0,
                        0,
                        IntPtr.Zero,
                        Win32.szOID_CRL_REASON_CODE,
                        CRLExtension.Value.pbData,
                        CRLExtension.Value.cbData,
                        pbFormat,
                        ref cbFormat
                    );
                    if (!bResult)
                    {
                        throw new Exception("CryptFormatObject error #" + Marshal.GetLastWin32Error());
                    }

                    strCRLReasonCode = pbFormat.ToString();

                    // Show Serial Number and CRL Reason Code
                    //
                    revocationListBox.Items.Add(strSerialNumber + "\t--&amp;gt;\t" + strCRLReasonCode);

                    // Continue with the next entry in the list
                    //
                    rgCRLEntry = (IntPtr)((Int32)rgCRLEntry + Marshal.SizeOf(typeof(Win32.&lt;STRONG&gt;CRL_ENTRY&lt;/STRONG&gt;)));
                }
            }
            catch (Exception ex)
            {
                // Show errors
                //
                MessageBox.Show(ex.Message);
            }
            finally
            {
                // Do some clean up
                //
                if (!pvContext.Equals(IntPtr.Zero))
                {
                    Win32.&lt;STRONG&gt;CertFreeCRLContext&lt;/STRONG&gt;(pvContext);
                }
            }
        }
    }
}

public class Win32
{
    #region APIs

    [DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern Boolean &lt;STRONG&gt;CryptQueryObject&lt;/STRONG&gt;(
        Int32 dwObjectType,
        [MarshalAs(UnmanagedType.LPWStr)]String pvObject,
        Int32 dwExpectedContentTypeFlags,
        Int32 dwExpectedFormatTypeFlags,
        Int32 dwFlags,
        IntPtr pdwMsgAndCertEncodingType,
        IntPtr pdwContentType,
        IntPtr pdwFormatType,
        IntPtr phCertStore,
        IntPtr phMsg,
        ref IntPtr ppvContext
        );

    [DllImport("CRYPT32.DLL", EntryPoint = "CertFreeCRLContext", SetLastError = true)]
    public static extern Boolean &lt;STRONG&gt;CertFreeCRLContext&lt;/STRONG&gt;(
        IntPtr pCrlContext
    );

    [DllImport("CRYPT32.DLL", EntryPoint = "CertNameToStr", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern Int32 &lt;STRONG&gt;CertNameToStr&lt;/STRONG&gt;(
        Int32 dwCertEncodingType,
        ref CRYPTOAPI_BLOB pName,
        Int32 dwStrType,
        StringBuilder psz,
        Int32 csz
    );

    [DllImport("CRYPT32.DLL", EntryPoint = "CertFindExtension", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr &lt;STRONG&gt;CertFindExtension&lt;/STRONG&gt;(
        [MarshalAs(UnmanagedType.LPStr)]String pszObjId,
        Int32 cExtensions,
        IntPtr rgExtensions
    );

    [DllImport("CRYPT32.DLL", EntryPoint = "CryptFormatObject", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern Boolean &lt;STRONG&gt;CryptFormatObject&lt;/STRONG&gt;(
        Int32 dwCertEncodingType,
        Int32 dwFormatType,
        Int32 dwFormatStrType,
        IntPtr pFormatStruct,
        [MarshalAs(UnmanagedType.LPStr)]String lpszStructType,
        IntPtr pbEncoded,
        Int32 cbEncoded,
        StringBuilder pbFormat,
        ref Int32 pcbFormat
    );

    #endregion APIs

    #region Structs

    [StructLayout(LayoutKind.Sequential)]
    public struct &lt;STRONG&gt;CRL_CONTEXT&lt;/STRONG&gt;
    {
        public Int32 dwCertEncodingType;
        public IntPtr pbCrlEncoded;
        public Int32 cbCrlEncoded;
        public IntPtr pCrlInfo;
        public IntPtr hCertStore;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct &lt;STRONG&gt;CRL_INFO&lt;/STRONG&gt;
    {
        public Int32 dwVersion;
        public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
        public CRYPTOAPI_BLOB Issuer;
        public FILETIME ThisUpdate;
        public FILETIME NextUpdate;
        public Int32 cCRLEntry;
        public IntPtr rgCRLEntry;
        public Int32 cExtension;
        public IntPtr rgExtension;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct &lt;STRONG&gt;CRYPT_ALGORITHM_IDENTIFIER&lt;/STRONG&gt;
    {
        [MarshalAs(UnmanagedType.LPStr)]public String pszObjId;
        public CRYPTOAPI_BLOB Parameters;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct &lt;STRONG&gt;CRYPTOAPI_BLOB&lt;/STRONG&gt;
    {
        public Int32 cbData;
        public IntPtr pbData;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct &lt;STRONG&gt;FILETIME&lt;/STRONG&gt;
    {
        public Int32 dwLowDateTime;
        public Int32 dwHighDateTime;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct &lt;STRONG&gt;CRL_ENTRY&lt;/STRONG&gt;
    {
        public CRYPTOAPI_BLOB SerialNumber;
        public FILETIME RevocationDate;
        public Int32 cExtension;
        public IntPtr rgExtension;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct &lt;STRONG&gt;CERT_EXTENSION&lt;/STRONG&gt;
    {
        [MarshalAs(UnmanagedType.LPStr)]public String pszObjId;
        public Boolean fCritical;
        public CRYPTOAPI_BLOB Value;
    }

    #endregion Structs

    #region Consts

    public const Int32 &lt;STRONG&gt;CERT_QUERY_OBJECT_FILE&lt;/STRONG&gt; = 0x00000001;
    public const Int32 &lt;STRONG&gt;CERT_QUERY_CONTENT_CRL&lt;/STRONG&gt; = 3;
    public const Int32 &lt;STRONG&gt;CERT_QUERY_CONTENT_FLAG_CRL&lt;/STRONG&gt; = 1 &amp;lt;&amp;lt; CERT_QUERY_CONTENT_CRL;
    public const Int32 &lt;STRONG&gt;CERT_QUERY_FORMAT_BINARY&lt;/STRONG&gt; = 1;
    public const Int32 &lt;STRONG&gt;CERT_QUERY_FORMAT_BASE64_ENCODED&lt;/STRONG&gt; = 2;
    public const Int32 &lt;STRONG&gt;CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED&lt;/STRONG&gt; = 3;
    public const Int32 &lt;STRONG&gt;CERT_QUERY_FORMAT_FLAG_BINARY&lt;/STRONG&gt; = 1 &amp;lt;&amp;lt; CERT_QUERY_FORMAT_BINARY;
    public const Int32 &lt;STRONG&gt;CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED&lt;/STRONG&gt; = 1 &amp;lt;&amp;lt; CERT_QUERY_FORMAT_BASE64_ENCODED;
    public const Int32 &lt;STRONG&gt;CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED&lt;/STRONG&gt; = 1 &amp;lt;&amp;lt; CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED;
    public const Int32 &lt;STRONG&gt;CERT_QUERY_FORMAT_FLAG_ALL&lt;/STRONG&gt; = CERT_QUERY_FORMAT_FLAG_BINARY | CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED | CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED;

    public const Int32 &lt;STRONG&gt;X509_ASN_ENCODING&lt;/STRONG&gt; = 0x00000001;
    public const Int32 &lt;STRONG&gt;PKCS_7_ASN_ENCODING&lt;/STRONG&gt; = 0x00010000;

    public const Int32 &lt;STRONG&gt;X509_NAME&lt;/STRONG&gt; = 7;

    public const Int32 &lt;STRONG&gt;CERT_SIMPLE_NAME_STR&lt;/STRONG&gt; = 1;
    public const Int32 &lt;STRONG&gt;CERT_OID_NAME_STR&lt;/STRONG&gt; = 2;
    public const Int32 &lt;STRONG&gt;CERT_X500_NAME_STR&lt;/STRONG&gt; = 3;

    public const String &lt;STRONG&gt;szOID_CRL_REASON_CODE&lt;/STRONG&gt; = "2.5.29.21";

    #endregion
}

&lt;/PRE&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9525923" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/P_2F00_Invoke/default.aspx">P/Invoke</category></item><item><title>How to create a self-signed certificate with CryptoAPI (C++)</title><link>http://blogs.msdn.com/alejacma/archive/2009/03/16/how-to-create-a-self-signed-certificate-with-cryptoapi-c.aspx</link><pubDate>Mon, 16 Mar 2009 15:36:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9481301</guid><dc:creator>alejacma</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9481301.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9481301</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;C++ sample &lt;/STRONG&gt;shows how to use &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa376039(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa376039(VS.85).aspx"&gt;CertCreateSelfSignCertificate&lt;/A&gt; API to create a &lt;STRONG&gt;self-signed certificate&lt;/STRONG&gt;. The private/public key pair will be created in the &lt;STRONG&gt;machine profile&lt;/STRONG&gt; and the certificate will be stored in the &lt;STRONG&gt;Trusted Root CA&lt;/STRONG&gt; &lt;STRONG&gt;store&lt;/STRONG&gt; of that same profile:&lt;/P&gt;&lt;PRE&gt;#include "stdio.h"
#include "conio.h"
#include "windows.h"
#include "wincrypt.h"
#include "tchar.h"

int &lt;STRONG&gt;SelfSignedCertificateTest&lt;/STRONG&gt;()
{
  // &lt;STRONG&gt;CREATE KEY PAIR FOR SELF-SIGNED CERTIFICATE IN MACHINE PROFILE&lt;/STRONG&gt;

  HCRYPTPROV hCryptProv = NULL;
  HCRYPTKEY hKey = NULL;

  __try 
  {
    // Acquire key container
    _tprintf(_T("CryptAcquireContext... "));
    if (!&lt;STRONG&gt;CryptAcquireContext&lt;/STRONG&gt;(&amp;amp;hCryptProv, _T("alejacma"), NULL, PROV_RSA_FULL, &lt;STRONG&gt;CRYPT_MACHINE_KEYSET&lt;/STRONG&gt;)) 
    {
      // Error
      _tprintf(_T("Error 0x%x\n"), GetLastError());

      // Try to create a new key container
      _tprintf(_T("CryptAcquireContext... "));
      if (!&lt;STRONG&gt;CryptAcquireContext&lt;/STRONG&gt;(&amp;amp;hCryptProv, _T("alejacma"), NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET | &lt;STRONG&gt;CRYPT_MACHINE_KEYSET&lt;/STRONG&gt;))
      {
        // Error
        _tprintf(_T("Error 0x%x\n"), GetLastError());
        return 0;
      }
      else 
      {
        _tprintf(_T("Success\n"));
      }
    }
    else
    {
      _tprintf(_T("Success\n"));
    }

    // Generate new key pair
    _tprintf(_T("CryptGenKey... "));
    if (!&lt;STRONG&gt;CryptGenKey&lt;/STRONG&gt;(hCryptProv, AT_SIGNATURE, 0x08000000 /*RSA-2048-BIT_KEY*/, &amp;amp;hKey))
    {
      // Error
      _tprintf(_T("Error 0x%x\n"), GetLastError());
      return 0;
    }
    else
    {
      _tprintf(_T("Success\n"));
    }
  }
  __finally
  {
    // Clean up  
     
    if (hKey) 
    {
      _tprintf(_T("CryptDestroyKey... "));
      &lt;STRONG&gt;CryptDestroyKey&lt;/STRONG&gt;(hKey);
      _tprintf(_T("Success\n"));
    } 
    if (hCryptProv) 
    {
      _tprintf(_T("CryptReleaseContext... "));
      &lt;STRONG&gt;CryptReleaseContext&lt;/STRONG&gt;(hCryptProv, 0);
      _tprintf(_T("Success\n"));
    }
  }

  // &lt;STRONG&gt;CREATE SELF-SIGNED CERTIFICATE AND ADD IT TO ROOT STORE IN MACHINE PROFILE&lt;/STRONG&gt;

  PCCERT_CONTEXT pCertContext = NULL;
  BYTE *pbEncoded = NULL;
  HCERTSTORE hStore = NULL;
  HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey = NULL;
  BOOL fCallerFreeProvOrNCryptKey = FALSE;

  __try 
  {             
    // Encode certificate Subject
    LPCTSTR pszX500 = _T("CN=Alejacma, T=Test");
    DWORD cbEncoded = 0;
    _tprintf(_T("CertStrToName... "));
    if (!&lt;STRONG&gt;CertStrToName&lt;/STRONG&gt;(X509_ASN_ENCODING, pszX500, CERT_X500_NAME_STR, NULL, pbEncoded, &amp;amp;cbEncoded, NULL))
    {
      // Error
      _tprintf(_T("Error 0x%x\n"), GetLastError());
      return 0;
    }
    else
    {
      _tprintf(_T("Success\n"));
    }

    _tprintf(_T("malloc... "));
    if (!(pbEncoded = (BYTE *)malloc(cbEncoded)))
    {
      // Error
      _tprintf(_T("Error 0x%x\n"), GetLastError());
      return 0;
    }
    else
    {
      _tprintf(_T("Success\n"));
    }

    _tprintf(_T("CertStrToName... "));
    if (!&lt;STRONG&gt;CertStrToName&lt;/STRONG&gt;(X509_ASN_ENCODING, pszX500, CERT_X500_NAME_STR, NULL, pbEncoded, &amp;amp;cbEncoded, NULL))
    {
      // Error
      _tprintf(_T("Error 0x%x\n"), GetLastError());
      return 0;
    }
    else
    {
      _tprintf(_T("Success\n"));
    }

    // Prepare certificate Subject for self-signed certificate
    &lt;STRONG&gt;CERT_NAME_BLOB&lt;/STRONG&gt; SubjectIssuerBlob;
    memset(&amp;amp;SubjectIssuerBlob, 0, sizeof(SubjectIssuerBlob));
    SubjectIssuerBlob.cbData = cbEncoded;
    SubjectIssuerBlob.pbData = pbEncoded;

    // Prepare key provider structure for self-signed certificate
    &lt;STRONG&gt;CRYPT_KEY_PROV_INFO&lt;/STRONG&gt; KeyProvInfo;
    memset(&amp;amp;KeyProvInfo, 0, sizeof(KeyProvInfo));
    KeyProvInfo.pwszContainerName = _T("alejacma");
    KeyProvInfo.pwszProvName = NULL;
    KeyProvInfo.dwProvType = PROV_RSA_FULL;
    KeyProvInfo.dwFlags = &lt;STRONG&gt;CRYPT_MACHINE_KEYSET&lt;/STRONG&gt;;
    KeyProvInfo.cProvParam = 0;
    KeyProvInfo.rgProvParam = NULL;
    KeyProvInfo.dwKeySpec = AT_SIGNATURE;

    // Prepare algorithm structure for self-signed certificate
    &lt;STRONG&gt;CRYPT_ALGORITHM_IDENTIFIER&lt;/STRONG&gt; SignatureAlgorithm;
    memset(&amp;amp;SignatureAlgorithm, 0, sizeof(SignatureAlgorithm));
    SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;

    // Prepare Expiration date for self-signed certificate
    &lt;STRONG&gt;SYSTEMTIME&lt;/STRONG&gt; EndTime;
    GetSystemTime(&amp;amp;EndTime);
    EndTime.wYear += 5;

    // Create self-signed certificate
    _tprintf(_T("CertCreateSelfSignCertificate... "));
    pCertContext = &lt;STRONG&gt;CertCreateSelfSignCertificate&lt;/STRONG&gt;(NULL, &amp;amp;SubjectIssuerBlob, 0, &amp;amp;KeyProvInfo, &amp;amp;SignatureAlgorithm, 0, &amp;amp;EndTime, 0);
    if (!pCertContext)
    {
      // Error
      _tprintf(_T("Error 0x%x\n"), GetLastError());
      return 0;
    }
    else
    {
      _tprintf(_T("Success\n"));
    }

    // Open Root cert store in machine profile
    _tprintf(_T("CertOpenStore... "));
    hStore = &lt;STRONG&gt;CertOpenStore&lt;/STRONG&gt;(CERT_STORE_PROV_SYSTEM, 0, 0, &lt;STRONG&gt;CERT_SYSTEM_STORE_LOCAL_MACHINE&lt;/STRONG&gt;, L"Root");
    if (!hStore)
    {
      // Error
      _tprintf(_T("Error 0x%x\n"), GetLastError());
      return 0;
    }
    else
    {
      _tprintf(_T("Success\n"));
    }

    // Add self-signed cert to the store
    _tprintf(_T("CertAddCertificateContextToStore... "));
    if (!&lt;STRONG&gt;CertAddCertificateContextToStore&lt;/STRONG&gt;(hStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, 0))
    {
      // Error
      _tprintf(_T("Error 0x%x\n"), GetLastError());
      return 0;
    }
    else
    {
      _tprintf(_T("Success\n"));
    }

    // Just for testing, verify that we can access self-signed cert's private key
    DWORD dwKeySpec;
    _tprintf(_T("CryptAcquireCertificatePrivateKey... "));
    if (!&lt;STRONG&gt;CryptAcquireCertificatePrivateKey&lt;/STRONG&gt;(pCertContext, 0, NULL, &amp;amp;hCryptProvOrNCryptKey, &amp;amp;dwKeySpec, &amp;amp;fCallerFreeProvOrNCryptKey))
    {
      // Error
      _tprintf(_T("Error 0x%x\n"), GetLastError());
      return 0;
    }
    else
    {
      _tprintf(_T("Success\n"));
    }                                           
  }
  __finally
  {
    // Clean up
    
    if (!pbEncoded) {
      _tprintf(_T("free... "));
      free(pbEncoded);
      _tprintf(_T("Success\n"));
    }
    
    if (hCryptProvOrNCryptKey) 
    {
      _tprintf(_T("CryptReleaseContext... "));
      &lt;STRONG&gt;CryptReleaseContext&lt;/STRONG&gt;(hCryptProvOrNCryptKey, 0);
      _tprintf(_T("Success\n"));
    }
    
    if (pCertContext)
    {
      _tprintf(_T("CertFreeCertificateContext... "));
      &lt;STRONG&gt;CertFreeCertificateContext&lt;/STRONG&gt;(pCertContext);
      _tprintf(_T("Success\n"));
    }
    
    if (hStore)
    {
      _tprintf(_T("CertCloseStore... "));
      &lt;STRONG&gt;CertCloseStore&lt;/STRONG&gt;(hStore, 0);
      _tprintf(_T("Success\n"));
    }
  }
}

int _tmain(int argc, _TCHAR* argv[])
{
  &lt;STRONG&gt;SelfSignedCertificateTest&lt;/STRONG&gt;();
  
  _tprintf(_T("&amp;lt;&amp;lt; Press any key&amp;gt;&amp;gt;\n"));
  _getch();
  return 0;
}
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9481301" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category></item><item><title>CryptUIDlgViewCertificate installs a CA certificate without my consent</title><link>http://blogs.msdn.com/alejacma/archive/2009/02/16/cryptuidlgviewcertificate-installs-a-ca-certificate-without-my-consent.aspx</link><pubDate>Mon, 16 Feb 2009 19:41:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9426102</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9426102.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9426102</wfw:commentRss><description>&lt;P&gt;Hi all&lt;/P&gt;
&lt;P&gt;The other day I posted &lt;A id=bp___v___r___postlist___EntryItems_ctl00_PostTitle href="http://blogs.msdn.com/alejacma/archive/2009/02/13/how-to-view-a-certificate-programatically-c.aspx"&gt;How to view a certificate programatically (C#)&lt;/A&gt;&amp;nbsp;which includes a C# sample that we can use to &lt;STRONG&gt;view a certificate&lt;/STRONG&gt; with &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380289(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380289(VS.85).aspx"&gt;&lt;FONT color=#006ff7&gt;CryptUIDlgViewCertificate&lt;/FONT&gt;&lt;/A&gt; API. This API shows the same &lt;STRONG&gt;dialog&lt;/STRONG&gt; that appears when we double-click on the cert file in &lt;STRONG&gt;Explorer&lt;/STRONG&gt;. &lt;/P&gt;
&lt;P&gt;When testing the sample, I tried it on a &lt;STRONG&gt;.cer file&lt;/STRONG&gt; of a &lt;STRONG&gt;root CA&lt;/STRONG&gt; which I &lt;STRONG&gt;didn't trust&lt;/STRONG&gt; (yet). I just wanted to&amp;nbsp;view the cert, but I got a very big surprise when I realized &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380289(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380289(VS.85).aspx"&gt;&lt;FONT color=#006ff7&gt;CryptUIDlgViewCertificate&lt;/FONT&gt;&lt;/A&gt; was showing the cert and &lt;STRONG&gt;installing it&lt;/STRONG&gt; at the same time on my &lt;STRONG&gt;Trusted Root Certification Authorities&lt;/STRONG&gt; store! &lt;STRONG&gt;Without my consent&lt;/STRONG&gt;! I always get a big warning when I try to install a root CA cert on my machine. Why not this time? And, in any case, I just wanted to view the cert, and not install it!&lt;/P&gt;
&lt;P mce_keep="true"&gt;Actually, I repeated the test just by double-clicking on the cert file in &lt;STRONG&gt;Explorer&lt;/STRONG&gt; and&amp;nbsp;the &lt;STRONG&gt;same thing&lt;/STRONG&gt; happened: I saw the dialog with the CA cert and at the same time it got installed without my consent.&lt;/P&gt;
&lt;P mce_keep="true"&gt;It turned out that this is a &lt;STRONG&gt;feature of Windows&lt;/STRONG&gt; called &lt;STRONG&gt;Automatic Root Certificates Update&lt;/STRONG&gt;. &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380289(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380289(VS.85).aspx"&gt;&lt;FONT color=#006ff7&gt;CryptUIDlgViewCertificate&lt;/FONT&gt;&lt;/A&gt; ends up calling &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa376078.aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa376078.aspx"&gt;CertGetCertificateChain&lt;/A&gt; API to build a certificate chain, and this API calls an internal AutoUpdate function. If &lt;STRONG&gt;AutoUpdate&lt;/STRONG&gt; detects that &lt;STRONG&gt;Microsoft trusts the CA &lt;/STRONG&gt;when building the chain, it &lt;STRONG&gt;installs the CA cert automatically&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A class="" href="http://technet.microsoft.com/en-us/library/cc734054.aspx" mce_href="http://technet.microsoft.com/en-us/library/cc734054.aspx"&gt;Event ID 8 - Automatic Root Certificates Update Configuration&lt;BR&gt;&lt;/A&gt;"&lt;BR&gt;&lt;EM&gt;The Automatic Root Certificates Update component is designed to automatically check the list of trusted authorities on the Microsoft Windows Update Web site. Specifically, there is a list of trusted root certification authorities (CAs) stored on the local computer. When an application is presented with a certificate issued by a CA, it will check the local copy of the trusted root CA list. If the certificate is not in the list, the Automatic Root Certificates Update component will contact the Microsoft Windows Update Web site to see if an update is available. If the CA has been added to the Microsoft list of trusted CAs, its certificate will automatically be added to the trusted certificate store on the computer.&lt;/EM&gt;&lt;BR&gt;"&lt;/P&gt;
&lt;P mce_keep="true"&gt;In my case, my test CA cert was not on my local copy of the trusted root CA list (&lt;STRONG&gt;Third-Party Root Certification Authorities&lt;/STRONG&gt;), but on &lt;STRONG&gt;Microsoft Windows Update Web site&lt;/STRONG&gt;. It’s a root CA cert that I got from Spanish Police, and Microsoft trusts them.&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9426102" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category></item><item><title>How to view a certificate programatically (C#)</title><link>http://blogs.msdn.com/alejacma/archive/2009/02/13/how-to-view-a-certificate-programatically-c.aspx</link><pubDate>Fri, 13 Feb 2009 11:36:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9418026</guid><dc:creator>alejacma</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9418026.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9418026</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;C#&lt;/STRONG&gt; sample shows a &lt;STRONG&gt;dialog&lt;/STRONG&gt; to &lt;STRONG&gt;view&lt;/STRONG&gt; a &lt;STRONG&gt;certificate&lt;/STRONG&gt;&amp;nbsp;and its &lt;STRONG&gt;properties&lt;/STRONG&gt;. This is the same dialog that appears when we double-click on the cert file in Explorer. I'll use &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380289(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380289(VS.85).aspx"&gt;CryptUIDlgViewCertificate&lt;/A&gt; API and its &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380645(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380645(VS.85).aspx"&gt;CRYPTUI_VIEWCERTIFICATE_STRUCT&lt;/A&gt; structure to achieve this:&lt;/P&gt;&lt;PRE&gt;...
using System.Security.Cryptography.X509Certificates;
using System.Runtime.InteropServices;

namespace MyNamespace
{
    public partial class MyClass
    {
...
        public const int &lt;STRONG&gt;CRYPTUI_DISABLE_ADDTOSTORE&lt;/STRONG&gt; = 0x00000010;

        [DllImport("CryptUI.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean &lt;STRONG&gt;CryptUIDlgViewCertificate&lt;/STRONG&gt;(
            ref CRYPTUI_VIEWCERTIFICATE_STRUCT pCertViewInfo,
            ref bool pfPropertiesChanged
        );

        public struct &lt;STRONG&gt;CRYPTUI_VIEWCERTIFICATE_STRUCT&lt;/STRONG&gt;
        {
            public int dwSize;
            public IntPtr hwndParent;
            public int dwFlags;
            [MarshalAs(UnmanagedType.LPWStr)]
            public String szTitle;
            public IntPtr pCertContext;
            public IntPtr rgszPurposes;
            public int cPurposes;
            public IntPtr pCryptProviderData; // or hWVTStateData
            public Boolean fpCryptProviderDataTrustedUsage;
            public int idxSigner;
            public int idxCert;
            public Boolean fCounterSigner;
            public int idxCounterSigner;
            public int cStores;
            public IntPtr rghStores;
            public int cPropSheetPages;
            public IntPtr rgPropSheetPages;
            public int nStartPage;
        }

        private void MySampleFunction()
        {
            // Get the cert
            X509Certificate2 cert = new &lt;STRONG&gt;X509Certificate2&lt;/STRONG&gt;(@"C:\temp\mycert.cer");

            // Show the cert
            CRYPTUI_VIEWCERTIFICATE_STRUCT certViewInfo = new CRYPTUI_VIEWCERTIFICATE_STRUCT();
            certViewInfo.dwSize = Marshal.SizeOf(certViewInfo);
            certViewInfo.pCertContext = cert.Handle;
            certViewInfo.szTitle = "Certificate Info";
            certViewInfo.dwFlags = CRYPTUI_DISABLE_ADDTOSTORE;
            certViewInfo.nStartPage = 0;
            bool fPropertiesChanged = false;
            if (!&lt;STRONG&gt;CryptUIDlgViewCertificate&lt;/STRONG&gt;(ref certViewInfo, ref fPropertiesChanged))
            {
                int error = Marshal.GetLastWin32Error();
                MessageBox.Show(error.ToString());
            }
        }
    }
}
&lt;/PRE&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9418026" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/P_2F00_Invoke/default.aspx">P/Invoke</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category></item><item><title>SHA-2 support on Windows XP</title><link>http://blogs.msdn.com/alejacma/archive/2009/01/23/sha-2-support-on-windows-xp.aspx</link><pubDate>Fri, 23 Jan 2009 16:12:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9372620</guid><dc:creator>alejacma</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9372620.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9372620</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;If you try to use any &lt;STRONG&gt;SHA-2&lt;/STRONG&gt; algorithm (&lt;STRONG&gt;SHA-256, SHA-384 and SHA-512&lt;/STRONG&gt;) on&amp;nbsp;&lt;STRONG&gt;Windows XP&lt;/STRONG&gt;, you may get&amp;nbsp;the following error when using i.e. &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa379908(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379908(VS.85).aspx"&gt;CryptCreateHash&lt;/A&gt;: &lt;STRONG&gt;NTE_BAD_ALGID&lt;/STRONG&gt; or &lt;STRONG&gt;-2146893816&lt;/STRONG&gt; or &lt;STRONG&gt;0x80090008&lt;/STRONG&gt; or &lt;STRONG&gt;"Invalid algorithm specified"&lt;/STRONG&gt;. Same algorithms are supported on Vista, though.&lt;/P&gt;
&lt;P&gt;Can we use SHA-2 algorithms in Windows XP at all?&amp;nbsp;The answer is yes, but it will depend on the CSP (Cryptographic Service Provider) that we use to perform the cryptographic operations.&lt;/P&gt;
&lt;P&gt;According to our documentation, &lt;STRONG&gt;Windows XP SP3&lt;/STRONG&gt; &lt;STRONG&gt;supports all SHA-2 algorithms except SHA-224&lt;/STRONG&gt;:&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A class="" href="http://download.microsoft.com/download/6/8/7/687484ed-8174-496d-8db9-f02b40c12982/Overview%20of%20Windows%20XP%20Service%20Pack%203.pdf" mce_href="http://download.microsoft.com/download/6/8/7/687484ed-8174-496d-8db9-f02b40c12982/Overview%20of%20Windows%20XP%20Service%20Pack%203.pdf"&gt;Overview of Windows XP Service Pack 3&lt;/A&gt; &lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;Implements and supports the SHA2 hashing algorithms (SHA256, SHA384, and SHA512) in X.509 certificate validation. This has been added to the crypto module rsaenh.dll.&lt;/EM&gt;&lt;BR&gt;"&lt;/P&gt;
&lt;P&gt;Our &lt;STRONG&gt;"Microsoft Base/Strong/Enhanced Cryptographic Providers"&lt;/STRONG&gt; are implemented on &lt;STRONG&gt;Rsaenh.dll&lt;/STRONG&gt;. If you try to use &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa379908(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379908(VS.85).aspx"&gt;CryptCreateHash&lt;/A&gt;&amp;nbsp;with any SHA-2 &lt;STRONG&gt;Algid&lt;/STRONG&gt; (&lt;STRONG&gt;CALG_SHA_256, CALG_SHA_384, CALG_SHA_512&lt;/STRONG&gt;)&amp;nbsp;and any of these CSP, you will still get a NTE_BAD_ALGID error on XP SP3. Why? The issue is that those Algid's are only valid with providers of type &lt;STRONG&gt;PROV_RSA_AES&lt;/STRONG&gt;, and these CSP are of type &lt;STRONG&gt;PROV_RSA_FULL&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;"Microsoft Enhanced RSA and AES Cryptographic Provider"&lt;/STRONG&gt; (or &lt;STRONG&gt;"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"&lt;/STRONG&gt; as it's called on Windows XP SP3) is implemented in rsaenh.dll and is of type PROV_RSA_AES.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Note that technically speaking, &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa386979(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa386979(VS.85).aspx"&gt;Microsoft AES Cryptographic Provider&lt;/A&gt; is just Microsoft Enhanced Cryptographic Provider with support for AES encryption algorithms.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;If you open &lt;STRONG&gt;regedit.exe&lt;/STRONG&gt; and go to &lt;STRONG&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults&lt;/STRONG&gt;, you will be able to see the available &lt;STRONG&gt;Providers&lt;/STRONG&gt; in the system ("Microsoft Enhanced Cryptographic Provider v1.0", "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)", etc.) and the &lt;STRONG&gt;Provider Types&lt;/STRONG&gt; ("Type 001" which is "RSA Full (Signature and Key Exchange)", "Type 024" which is "RSA Full and AES"). For each Provider you will also see which &lt;STRONG&gt;dll&lt;/STRONG&gt; implements (rsaenh.dll, etc.) it and its Provider Type (1, 24, etc.). For each Provider Type you will see the name of the default Provider for that type. On Vista, default Provider for PROV_RSA_AES is "Microsoft Enhanced RSA and AES Cryptographic Provider", and on XP is "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)".&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Regarding &lt;STRONG&gt;SHA-224&lt;/STRONG&gt; support, SHA-224 offers &lt;STRONG&gt;less security&lt;/STRONG&gt; than SHA-256 but takes the same amount of resources. Also SHA-224 is not generally used by protocols and applications. The NSA's Suite B standards also do not include it. &lt;STRONG&gt;We have no plans to add it&lt;/STRONG&gt; on future versions of our CSPs.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Fortunately, Microsoft's CryptoAPI is based on a model which allows us to use any&amp;nbsp;CSP which implements any algorithm. So we don't and won't implement SHA-224 in our own CSPs, but that doesn't mean that we can't use SHA-224 at all on Windows. We just need a &lt;STRONG&gt;third-party&lt;/STRONG&gt; CSP which implements it, or create our own.&lt;/P&gt;
&lt;P mce_keep="true"&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9372620" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/Windows+Vista/default.aspx">Windows Vista</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Windows+XP/default.aspx">Windows XP</category></item><item><title>CryptSignHash fails with NTE_BAD_KEYSET</title><link>http://blogs.msdn.com/alejacma/archive/2008/12/23/cryptsignhash-fails-with-nte-bad-keyset.aspx</link><pubDate>Tue, 23 Dec 2008 14:39:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9249817</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9249817.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9249817</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;The other day I worked on the following issue:&amp;nbsp;a customer of mine had developed an &lt;STRONG&gt;ActiveX&lt;/STRONG&gt; which they used&amp;nbsp;to &lt;STRONG&gt;sign&lt;/STRONG&gt; some data in &lt;STRONG&gt;Internet Explorer&lt;/STRONG&gt;. Their signing code was based on &lt;STRONG&gt;CryptoAPI&lt;/STRONG&gt; and worked just fine with some certs, but failed with others with a &lt;STRONG&gt;NTE_BAD_KEYSET&lt;/STRONG&gt; error.&lt;/P&gt;
&lt;P&gt;So we took some traces with my &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx"&gt;CryptoAPI Tracer script&lt;/A&gt; to see which API was returning the error exactly.&lt;/P&gt;
&lt;P&gt;This is the API that failed with NTE_BAD_KEYSET error:&lt;/P&gt;&lt;PRE&gt;&lt;STRONG&gt;CryptSignHashA&lt;/STRONG&gt; (0x1f2c)

IN
hHash
0x3346208

&lt;STRONG&gt;dwKeySpec&lt;/STRONG&gt;
&lt;STRONG&gt;AT_KEYEXCHANGE&lt;/STRONG&gt;

sDescription
NULL

dwFlags
0

pbSignature
NULL

dwSigLen
46500472

OUT
dwSigLen
46500472

RESULT
CryptSignHashA (0x1f2c) &lt;STRONG&gt;FAILED&lt;/STRONG&gt;
LastErrorValue: (HRESULT) &lt;STRONG&gt;0x80090016 (2148073494) -  Keyset does not exist&lt;/STRONG&gt;
LastStatusValue: (NTSTATUS) 0xc0000034 - Object Name not found
&lt;/PRE&gt;
&lt;P&gt;My post &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2008/05/27/cryptacquirecontext-fails-with-nte-bad-keyset.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/05/27/cryptacquirecontext-fails-with-nte-bad-keyset.aspx"&gt;CryptAcquireContext fails with NTE_BAD_KEYSET&lt;/A&gt; refers to CryptAcquireContext API, but the causes of the error should be the same: keys don't exist or we have no permissions to access them.&lt;/P&gt;
&lt;P&gt;We can see above that we are trying to&amp;nbsp;&lt;STRONG&gt;sign&lt;/STRONG&gt; with &lt;STRONG&gt;AT_KEYEXCHANGE&lt;/STRONG&gt; keys.&lt;/P&gt;
&lt;P&gt;&lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380280(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380280(VS.85).aspx"&gt;CryptSignHash Function&lt;BR&gt;&lt;/A&gt;"&lt;BR&gt;&lt;EM&gt;dwKeySpec [in] &lt;BR&gt;Identifies the private key to use from the provider's container. It can be AT_KEYEXCHANGE or AT_SIGNATURE. &lt;BR&gt;The signature algorithm used is specified when the key pair is originally created.&lt;BR&gt;&lt;/EM&gt;"&lt;/P&gt;
&lt;P&gt;Summing up, we may have two public/private &lt;STRONG&gt;key pairs&lt;/STRONG&gt;: &lt;STRONG&gt;AT_KEYEXCHANGE&amp;nbsp;&lt;/STRONG&gt;and &lt;STRONG&gt;AT_SIGNATURE&lt;/STRONG&gt;. When we generate the keys, we specify which ones we are creating.&lt;/P&gt;
&lt;P&gt;&lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa379941(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379941(VS.85).aspx"&gt;CryptGenKey Function&lt;/A&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;In addition to generating session keys for symmetric algorithms, this function can also generate public/private key pairs. Each CryptoAPI client generally possesses two public/private key pairs. To generate one of these key pairs, set the Algid parameter to one of the following values.&lt;BR&gt;Value Meaning &lt;BR&gt;AT_KEYEXCHANGE Key exchange &lt;BR&gt;AT_SIGNATURE Digital signature&lt;/EM&gt; &lt;BR&gt;"&lt;/P&gt;
&lt;P&gt;When we enroll a cert, keys of a given type get created and associated to it. We can use &lt;STRONG&gt;certutil&lt;/STRONG&gt; utility on a cert (i.e. "&lt;EM&gt;certutil -dump -v cert.pfx&lt;/EM&gt;") to check if its &lt;STRONG&gt;KeySpec&lt;/STRONG&gt; is AT_KEYEXCHANGE or AT_SIGNATURE. In this particular case, &lt;STRONG&gt;working certs&lt;/STRONG&gt; have &lt;STRONG&gt;AT_KEYEXCHANGE&lt;/STRONG&gt; KeySpec, and &lt;STRONG&gt;failing certs&lt;/STRONG&gt; have &lt;STRONG&gt;AT_SIGNATURE&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;So &lt;STRONG&gt;we are trying to sign with AT_KEYEXCHANGE keys but the certificates only have AT_SIGNATURE keys&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;When we &lt;STRONG&gt;get the CSP&lt;/STRONG&gt; of our certificate via API, we can find out which kind of &lt;STRONG&gt;keys&lt;/STRONG&gt; are associated to it:&lt;/P&gt;
&lt;P&gt;&lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa379885(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379885(VS.85).aspx"&gt;CryptAcquireCertificatePrivateKey&lt;/A&gt;&lt;BR&gt;"&lt;BR&gt;&lt;EM&gt;pdwKeySpec [out] &lt;BR&gt;The address of a DWORD variable that receives additional information about the key. This can be one of the following values.&lt;BR&gt;Value Meaning &lt;BR&gt;AT_KEYEXCHANGE The key pair is a key exchange pair. &lt;BR&gt;AT_SIGNATURE The key pair is a signature pair.&lt;/EM&gt; &lt;BR&gt;"&lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;sample&lt;/STRONG&gt; shows &lt;STRONG&gt;how to&lt;/STRONG&gt; &lt;STRONG&gt;use CryptAcquireCertificatePrivateKey&amp;nbsp;to&lt;/STRONG&gt; &lt;STRONG&gt;get the CSP of a certificate and its Keyspec, and sign with it&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P&gt;&lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2008/01/23/how-to-sign-and-verify-with-cryptoapi-and-a-user-certificate.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/01/23/how-to-sign-and-verify-with-cryptoapi-and-a-user-certificate.aspx"&gt;How to sign and verify with CryptoAPI and a user certificate&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Note: in this sample I only sign with AT_SIGNATURE. We should modify the sample to get the right KeySpec with CryptAcquireCertificatePrivateKey and pass it to CryptSignHash so it uses the right keys to sign.&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9249817" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category></item><item><title>How to sign EXE files with an Authenticode certificate (part 2)</title><link>http://blogs.msdn.com/alejacma/archive/2008/12/11/how-to-sign-exe-files-with-an-authenticode-certificate-part-2.aspx</link><pubDate>Thu, 11 Dec 2008 12:59:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9196078</guid><dc:creator>alejacma</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9196078.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9196078</wfw:commentRss><description>&lt;P&gt;Hi all, welcome back,&lt;/P&gt;
&lt;P&gt;The other day a customer of mine was having an &lt;STRONG&gt;issue&lt;/STRONG&gt; with &lt;STRONG&gt;SignTool.exe&lt;/STRONG&gt; when &lt;STRONG&gt;signing&lt;/STRONG&gt; an &lt;STRONG&gt;EXE&lt;/STRONG&gt; file. The EXE file was getting &lt;STRONG&gt;corrupted&lt;/STRONG&gt;/unusable after signing it.&lt;/P&gt;
&lt;P&gt;When troubleshooting this issue, I had the chance to play a bit more&amp;nbsp;with SignTool and check what it does behind the scenes. &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Note: I already talked a bit about signing EXEs in post &lt;/EM&gt;&lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2008/02/20/how-to-sign-exe-files-with-an-authenticode-certificate-vb-net.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/02/20/how-to-sign-exe-files-with-an-authenticode-certificate-vb-net.aspx"&gt;&lt;EM&gt;How to sign EXE files with an Authenticode certificate (VB.NET)&lt;/EM&gt;&lt;/A&gt;&lt;EM&gt;. This new post will add more details and samples.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;SignTool.exe&lt;/STRONG&gt; uses &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa387712(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa387712(VS.85).aspx"&gt;CAPICOM.SignedCode&lt;/A&gt; class and its &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa387717(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa387717(VS.85).aspx"&gt;Sign&lt;/A&gt; method to do the signing.&lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;VBScript&lt;/STRONG&gt; shows how we may use &lt;STRONG&gt;CAPICOM&lt;/STRONG&gt; to do the signing programmatically:&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;Option Explicit

Dim szCertName, szExeToSign
szCertName = "My cert Subject"
szExeToSign = "MyApplication.exe"

Const CAPICOM_CURRENT_USER_STORE = 2
Const CAPICOM_STORE_OPEN_READ_ONLY = 0
Const CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME = 1
Const CAPICOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_DESCRIPTION = 2

' Get certificate for signing
'
Dim objStore
Set objStore = WScript.CreateObject("&lt;STRONG&gt;CAPICOM.Store&lt;/STRONG&gt;")
objStore.Open CAPICOM_CURRENT_USER_STORE, "My", CAPICOM_STORE_OPEN_READ_ONLY
Dim objSigningCert
Set objSigningCert = objStore.&lt;STRONG&gt;Certificates.Find&lt;/STRONG&gt;(CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, szCertName).Item(1)

' Create a signer for the code
'
Dim objSigner
Set objSigner = WScript.CreateObject("&lt;STRONG&gt;CAPICOM.Signer&lt;/STRONG&gt;")
objSigner.&lt;STRONG&gt;Certificate&lt;/STRONG&gt; = objSigningCert

' Sign the file
'
Dim objSignedCode
Set objSignedCode = WScript.CreateObject("&lt;STRONG&gt;CAPICOM.SignedCode&lt;/STRONG&gt;")
objSignedCode.&lt;STRONG&gt;FileName&lt;/STRONG&gt; = szExeToSign
objSignedCode.&lt;STRONG&gt;Sign&lt;/STRONG&gt; objSigner
objSignedCode.&lt;STRONG&gt;TimeStamp&lt;/STRONG&gt; "http://timestamp.globalsign.com/scripts/timstamp.dll"

WScript.Echo "Done!"
&lt;/PRE&gt;
&lt;P&gt;Note that&amp;nbsp;this sample also shows how to &lt;STRONG&gt;time stamp a signature&lt;/STRONG&gt; programmatically.&lt;/P&gt;
&lt;P&gt;This sample was also reproducing my customer's issue. So&amp;nbsp;I checked what CAPICOM does behind the scenes to further troubleshoot the issue.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;CAPICOM.SignedCode.Sign&lt;/STRONG&gt; uses &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380292(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380292(VS.85).aspx"&gt;CryptUIWizDigitalSign&lt;/A&gt; API to do the signing. &lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;VB.NET &lt;/STRONG&gt;sample uses &lt;STRONG&gt;CryptUIWizDigitalSign &lt;/STRONG&gt;through &lt;STRONG&gt;P/Invoke&lt;/STRONG&gt; to do the signing programmatically:&lt;/P&gt;&lt;PRE&gt;&amp;lt;SAMPLE file="Crypto.vb"&amp;gt;

Imports System.Runtime.InteropServices
Imports System.Security.Cryptography
Imports System.ComponentModel
Imports System.Windows.Forms

Public Class Crypto

    ' #define CRYPTUI_WIZ_NO_UI     1
    Public Const &lt;STRONG&gt;CRYPTUI_WIZ_NO_UI&lt;/STRONG&gt; As Int32 = 1

    ' #define CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE     0x01
    Public Const &lt;STRONG&gt;CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE&lt;/STRONG&gt; As Int32 = 1

    ' #define CRYPTUI_WIZ_DIGITAL_SIGN_CERT                    0x01
    Public Const &lt;STRONG&gt;CRYPTUI_WIZ_DIGITAL_SIGN_CERT&lt;/STRONG&gt; As Int32 = 1

    ' typedef struct _CRYPTUI_WIZ_DIGITAL_SIGN_INFO {  
    '   DWORD dwSize;  
    '   DWORD dwSubjectChoice;  
    '   union {    
    '       LPCWSTR pwszFileName;    
    '       PCCRYPTUI_WIZ_DIGITAL_SIGN_BLOB_INFO pSignBlobInfo;  
    '   };  
    '   DWORD dwSigningCertChoice;  
    '   union {    
    '       PCCERT_CONTEXT pSigningCertContext;    
    '       PCCRYPTUI_WIZ_DIGITAL_SIGN_STORE_INFO pSigningCertStore;    
    '       PCCRYPTUI_WIZ_DIGITAL_SIGN_CERT_PVK_INFO pSigningCertPvkInfo;  
    '   };  
    '   LPCWSTR pwszTimestampURL;  
    '   DWORD dwAdditionalCertChoice;  
    '   PCCRYPTUI_WIZ_DIGITAL_SIGN_EXTENDED_INFO pSignExtInfo;
    ' } CRYPTUI_WIZ_DIGITAL_SIGN_INFO;
    &amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _
    Public Structure &lt;STRONG&gt;CRYPTUI_WIZ_DIGITAL_SIGN_INFO&lt;/STRONG&gt;
        Public dwSize As Int32
        Public dwSubjectChoice As Int32
        &amp;lt;MarshalAs(UnmanagedType.LPWStr)&amp;gt; Public pwszFileName As String
        Public dwSigningCertChoice As Int32
        Public pSigningCertContext As IntPtr
        Public pwszTimestampURL As String
        Public dwAdditionalCertChoice As Int32
        Public pSignExtInfo As IntPtr
    End Structure

    ' typedef struct _CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT {  
    '      DWORD dwSize;  
    '      DWORD cbBlob;  
    '      BYTE* pbBlob;
    ' } CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT;
    &amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _
    Public Structure &lt;STRONG&gt;CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT&lt;/STRONG&gt;
        Public dwSize As Int32
        Public cbBlob As Int32
        Public pbBlob As IntPtr
    End Structure

    ' BOOL WINAPI CryptUIWizDigitalSign(
    '      DWORD dwFlags,
    '      HWND hwndParent,
    '      LPCWSTR pwszWizardTitle,
    '      PCCRYPTUI_WIZ_DIGITAL_SIGN_INFO pDigitalSignInfo,
    '      PCCRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT* ppSignContext
    ' );
    &amp;lt;DllImport("Cryptui.dll", CharSet:=CharSet.Unicode, SetLastError:=True)&amp;gt; _
    Public Shared Function &lt;STRONG&gt;CryptUIWizDigitalSign&lt;/STRONG&gt;( _
        ByVal dwFlags As Int32, _
        ByVal hwndParent As IntPtr, _
        ByVal pwszWizardTitle As String, _
        ByRef pDigitalSignInfo As CRYPTUI_WIZ_DIGITAL_SIGN_INFO, _
        ByRef ppSignContext As IntPtr _
    ) As Boolean
    End Function

    ' BOOL WINAPI CryptUIWizFreeDigitalSignContext(
    '   PCCRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT pSignContext
    ' );
    &amp;lt;DllImport("Cryptui.dll", CharSet:=CharSet.Auto, SetLastError:=True)&amp;gt; _
    Public Shared Function &lt;STRONG&gt;CryptUIWizFreeDigitalSignContext&lt;/STRONG&gt;( _
        ByVal pSignContext As IntPtr _
    ) As Boolean
    End Function

End Class

&amp;lt;/SAMPLE&amp;gt;

&amp;lt;SAMPLE file="Module1.vb"&amp;gt;

Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports SignExe.Crypto
Imports System.Security.Cryptography.X509Certificates
Imports System.IO

Module Module1

    Sub Main()

        ' Parameters
        Dim certPath As String = "MyCert.pfx"
        Dim exePath As String = "MyApplication.exe"
        Dim sigPath As String = "signature.sig"

        ' Variables
        '
        Dim cert As X509Certificate2
        Dim digitalSignInfo As CRYPTUI_WIZ_DIGITAL_SIGN_INFO
        Dim pSignContext As IntPtr
        Dim pSigningCertContext As IntPtr
        Dim signContext As CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT
        Dim fileOut As FileStream
        Dim binWriter As BinaryWriter
        Dim blob() As Byte

        Try
            ' Get certificate context
            '
            cert = New &lt;STRONG&gt;X509Certificate2&lt;/STRONG&gt;(certPath, "")
            pSigningCertContext = cert.Handle

            ' Prepare signing info: exe and cert
            '
            digitalSignInfo = New CRYPTUI_WIZ_DIGITAL_SIGN_INFO
            digitalSignInfo.dwSize = Marshal.SizeOf(digitalSignInfo)
            digitalSignInfo.dwSubjectChoice = CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE
            digitalSignInfo.pwszFileName = exePath
            digitalSignInfo.dwSigningCertChoice = CRYPTUI_WIZ_DIGITAL_SIGN_CERT
            digitalSignInfo.pSigningCertContext = pSigningCertContext
            digitalSignInfo.pwszTimestampURL = vbNullString
            digitalSignInfo.dwAdditionalCertChoice = 0
            digitalSignInfo.pSignExtInfo = IntPtr.Zero

            ' Sign exe
            '
            If (Not &lt;STRONG&gt;CryptUIWizDigitalSign&lt;/STRONG&gt;( _
                CRYPTUI_WIZ_NO_UI, _
                IntPtr.Zero, _
                vbNullString, _
                digitalSignInfo, _
                pSignContext _
            )) Then
                Throw New Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizDigitalSign")
            End If

            ' Get the blob with the signature
            '
            signContext = Marshal.PtrToStructure(pSignContext, GetType(CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT))
            blob = New Byte(signContext.cbBlob) {}
            Marshal.Copy(signContext.pbBlob, blob, 0, signContext.cbBlob)

            ' Store the signature in a new file
            '
            fileOut = File.Open(sigPath, FileMode.Create)
            binWriter = New BinaryWriter(fileOut)
            binWriter.Write(blob)
            binWriter.Close()
            fileOut.Close()

            ' Free blob
            '
            If (Not &lt;STRONG&gt;CryptUIWizFreeDigitalSignContext&lt;/STRONG&gt;(pSignContext)) Then
                Throw New Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizFreeDigitalSignContext")
            End If

            ' We are done
            Console.WriteLine("Done!!!")

        Catch ex As Win32Exception
            ' Any expected errors?
            '
            Console.WriteLine(ex.Message + " error#" + ex.NativeErrorCode.ToString)
        Catch ex As Exception
            ' Any unexpected errors?
            '
            Console.WriteLine(ex.Message)
        End Try

        ' We are done
        '
        Console.WriteLine("&amp;lt;&amp;lt; Press any key to continue &amp;gt;&amp;gt;")
        Console.ReadKey()

    End Sub

End Module

&amp;lt;/SAMPLE&amp;gt;&lt;/PRE&gt;
&lt;P&gt;This sample was also reproducing the issue. So I checked what CryptUIWizDigitalSign does behind the scenes.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;CryptUIWizDigitalSign&lt;/STRONG&gt; API uses &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa387734(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa387734(VS.85).aspx"&gt;SignerSignEx&lt;/A&gt; API to do the signing.&lt;/P&gt;
&lt;P mce_keep="true"&gt;The following &lt;STRONG&gt;VC++&lt;/STRONG&gt; sample uses &lt;STRONG&gt;SignerSignEx&lt;/STRONG&gt; API to do the signing programmatically:&lt;/P&gt;&lt;PRE&gt;#include "windows.h"
#include "Wincrypt.h"
#include "stdio.h"
#include "conio.h"


// STRUCTS

typedef &lt;STRONG&gt;struct _SIGNER_FILE_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	LPCWSTR pwszFileName;  
	HANDLE hFile;
} SIGNER_FILE_INFO,  *PSIGNER_FILE_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_BLOB_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	GUID *pGuidSubject;  
	DWORD cbBlob;  
	BYTE *pbBlob;  
	LPCWSTR pwszDisplayName;
} SIGNER_BLOB_INFO,  *PSIGNER_BLOB_INFO;

typedef&lt;STRONG&gt; struct _SIGNER_SUBJECT_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	DWORD *pdwIndex;  
	DWORD dwSubjectChoice;  
	union {    
		SIGNER_FILE_INFO *pSignerFileInfo;    
		SIGNER_BLOB_INFO *pSignerBlobInfo;  
	} ;
} SIGNER_SUBJECT_INFO,  *PSIGNER_SUBJECT_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_CERT_STORE_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	PCCERT_CONTEXT pSigningCert;  
	DWORD dwCertPolicy;  
	HCERTSTORE hCertStore;
} SIGNER_CERT_STORE_INFO,  *PSIGNER_CERT_STORE_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_SPC_CHAIN_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	LPCWSTR pwszSpcFile;  
	DWORD dwCertPolicy;  
	HCERTSTORE hCertStore;
} SIGNER_SPC_CHAIN_INFO,  *PSIGNER_SPC_CHAIN_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_CERT&lt;/STRONG&gt; {  
	DWORD cbSize;  
	DWORD dwCertChoice;  
	union {    
		LPCWSTR pwszSpcFile;    
		SIGNER_CERT_STORE_INFO *pCertStoreInfo;    
		SIGNER_SPC_CHAIN_INFO *pSpcChainInfo;  
	} ;  
	HWND hwnd;
} SIGNER_CERT,  *PSIGNER_CERT;

typedef&lt;STRONG&gt; struct _SIGNER_ATTR_AUTHCODE&lt;/STRONG&gt; {  
	DWORD cbSize;  
	BOOL fCommercial;  
	BOOL fIndividual;  
	LPCWSTR pwszName;  
	LPCWSTR pwszInfo;
} SIGNER_ATTR_AUTHCODE,  *PSIGNER_ATTR_AUTHCODE;

typedef &lt;STRONG&gt;struct _SIGNER_SIGNATURE_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	ALG_ID algidHash;  
	DWORD dwAttrChoice;  
	union {    
		SIGNER_ATTR_AUTHCODE *pAttrAuthcode;  
	} ;  
	PCRYPT_ATTRIBUTES psAuthenticated;  
	PCRYPT_ATTRIBUTES psUnauthenticated;
} SIGNER_SIGNATURE_INFO,  *PSIGNER_SIGNATURE_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_PROVIDER_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	LPCWSTR pwszProviderName;  
	DWORD dwProviderType;  
	DWORD dwKeySpec;  
	DWORD dwPvkChoice;  
	union {    
		LPWSTR pwszPvkFileName;    
		LPWSTR pwszKeyContainer;  
	} ;
} SIGNER_PROVIDER_INFO,  *PSIGNER_PROVIDER_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_CONTEXT&lt;/STRONG&gt; {  
	DWORD cbSize;  
	DWORD cbBlob;  
	BYTE *pbBlob;
} SIGNER_CONTEXT,  *PSIGNER_CONTEXT;


// EXPORTS 

typedef HRESULT (WINAPI* &lt;STRONG&gt;SignerFreeSignerContextType&lt;/STRONG&gt;)(
  __in  SIGNER_CONTEXT *pSignerContext
);

typedef HRESULT (WINAPI *&lt;STRONG&gt;SignerSignExType&lt;/STRONG&gt;)(
  __in      DWORD dwFlags,
  __in      SIGNER_SUBJECT_INFO *pSubjectInfo,
  __in      SIGNER_CERT *pSignerCert,
  __in      SIGNER_SIGNATURE_INFO *pSignatureInfo,
  __in_opt  SIGNER_PROVIDER_INFO *pProviderInfo,
  __in_opt  LPCWSTR pwszHttpTimeStamp,
  __in_opt  PCRYPT_ATTRIBUTES psRequest,
  __in_opt  LPVOID pSipData,
  __out     SIGNER_CONTEXT **ppSignerContext
);


// MAIN

void main()
{
	// PARAMETERS

	// File to sign
	LPCWSTR pwszFileName = L"C:\\TEST\\MyApplication.exe";

	// Signing Cert Subject
	LPCWSTR pwszCertSubject = L"My cert Subject";

	// VARIABLES
	HRESULT hResult = S_OK;
	BOOL bResult = TRUE;
	HMODULE hMssign32 = NULL;
	SignerSignExType pfSignerSignEx = NULL;
	SignerFreeSignerContextType pfSignerFreeSignerContext = NULL;
	HANDLE hFile = NULL;
	HCERTSTORE hCertStore = NULL; 
	PCCERT_CONTEXT pCertContext = NULL;
	DWORD dwIndex = 0;
	SIGNER_FILE_INFO signerFileInfo;
	SIGNER_SUBJECT_INFO signerSubjectInfo;
	SIGNER_CERT_STORE_INFO signerCertStoreInfo;
	SIGNER_CERT signerCert;
	SIGNER_SIGNATURE_INFO signerSignatureInfo;
	SIGNER_CONTEXT * pSignerContext = NULL;

	// MAIN

	// Attach a debugger now!
	printf("&amp;lt;&amp;lt; Press any key to continue&amp;gt;&amp;gt;\n");
	_getch();

	// Load library containing SignerSignEx and SignerFreeSignerContext
	printf("LoadLibrary...");
	hMssign32 = &lt;STRONG&gt;LoadLibrary&lt;/STRONG&gt;(L"&lt;STRONG&gt;Mssign32.dll&lt;/STRONG&gt;");
	if (!hMssign32)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Get SignerSignEx function
	printf("GetProcAddress(SignerSignEx)...");
	pfSignerSignEx = (SignerSignExType) &lt;STRONG&gt;GetProcAddress&lt;/STRONG&gt;(hMssign32, "&lt;STRONG&gt;SignerSignEx&lt;/STRONG&gt;");
	if (!pfSignerSignEx)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Get SignerFreeSignerContext function
	printf("GetProcAddress(SignerFreeSignerContext)...");
	pfSignerFreeSignerContext = (SignerFreeSignerContextType) &lt;STRONG&gt;GetProcAddress&lt;/STRONG&gt;(hMssign32, "&lt;STRONG&gt;SignerFreeSignerContext&lt;/STRONG&gt;");
	if (!pfSignerFreeSignerContext)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Open file to sign
	printf("CreateFile...");
	hFile = &lt;STRONG&gt;CreateFile&lt;/STRONG&gt;(
		pwszFileName,
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL
	);
	if (!hFile)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Open MY cert store
	printf("CertOpenStore...");
	hCertStore = &lt;STRONG&gt;CertOpenStore&lt;/STRONG&gt;(
		CERT_STORE_PROV_SYSTEM, 
		0,
		NULL,
		CERT_SYSTEM_STORE_CURRENT_USER,
		L"MY"
	);                 
	if (!hCertStore)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Find signing cert in MY cert store
	printf("CertFindCertificateInStore...");
	pCertContext = &lt;STRONG&gt;CertFindCertificateInStore&lt;/STRONG&gt;(
		hCertStore,
		X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
		0,
		CERT_FIND_SUBJECT_STR,
		(void *)pwszCertSubject,
		NULL
	);
	if (!pCertContext)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Prepare SIGNER_FILE_INFO struct
	signerFileInfo.cbSize = sizeof(SIGNER_FILE_INFO);
	signerFileInfo.pwszFileName = pwszFileName;
	signerFileInfo.hFile = hFile;

	// Prepare SIGNER_SUBJECT_INFO struct
	signerSubjectInfo.cbSize = sizeof(SIGNER_SUBJECT_INFO);
	dwIndex = 0;
	signerSubjectInfo.pdwIndex = &amp;amp;dwIndex;
	signerSubjectInfo.dwSubjectChoice = 1; // SIGNER_SUBJECT_FILE
	signerSubjectInfo.pSignerFileInfo = &amp;amp;signerFileInfo;

	// Prepare SIGNER_CERT_STORE_INFO struct
	signerCertStoreInfo.cbSize = sizeof(SIGNER_CERT_STORE_INFO);
	signerCertStoreInfo.pSigningCert = pCertContext;
	signerCertStoreInfo.dwCertPolicy = 2; // SIGNER_CERT_POLICY_CHAIN
	signerCertStoreInfo.hCertStore = NULL;

	// Prepare SIGNER_CERT struct
	signerCert.cbSize = sizeof(SIGNER_CERT);
	signerCert.dwCertChoice = 2; // SIGNER_CERT_STORE
	signerCert.pCertStoreInfo = &amp;amp;signerCertStoreInfo;
	signerCert.hwnd = NULL;

	// Prepare SIGNER_SIGNATURE_INFO struct
	signerSignatureInfo.cbSize = sizeof(SIGNER_SIGNATURE_INFO);
	signerSignatureInfo.algidHash = CALG_SHA1;
	signerSignatureInfo.dwAttrChoice = 0; // SIGNER_NO_ATTR
	signerSignatureInfo.pAttrAuthcode = NULL;
	signerSignatureInfo.psAuthenticated = NULL;
	signerSignatureInfo.psUnauthenticated = NULL;

	// Sign file with cert
	printf("SignerSignEx...");
	hResult = pf&lt;STRONG&gt;SignerSignEx&lt;/STRONG&gt;(
		0,
		&amp;amp;signerSubjectInfo,
		&amp;amp;signerCert,
		&amp;amp;signerSignatureInfo,
		NULL,
		NULL,
		NULL,
		NULL,
		&amp;amp;pSignerContext
	);
	if (S_OK != hResult)
	{
		printf("Error #%d\n", hResult); goto cleanup;
	}
	printf("Done!\n");

	printf("\nSUCCESS!!!\n");

	// Clean up
cleanup:

	if (pSignerContext)
	{
		hResult = pf&lt;STRONG&gt;SignerFreeSignerContext&lt;/STRONG&gt;(pSignerContext);
	}

	if (pCertContext)
	{
		bResult = &lt;STRONG&gt;CertFreeCertificateContext&lt;/STRONG&gt;(pCertContext);
	}

	if (hCertStore)
	{
		bResult = &lt;STRONG&gt;CertCloseStore&lt;/STRONG&gt;(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG);
	}

	if (hFile)
	{
		bResult = &lt;STRONG&gt;CloseHandle&lt;/STRONG&gt;(hFile);
	}

	if (hMssign32)
	{
		bResult = &lt;STRONG&gt;FreeLibrary&lt;/STRONG&gt;(hMssign32);
	}

	// Exit
	printf("&amp;lt;&amp;lt; Press any key to exit &amp;gt;&amp;gt;\n");
	_getch();
	return;
}
&lt;/PRE&gt;
&lt;P&gt;This sample was also reproducing the issue.&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Finally we saw that the &lt;STRONG&gt;issue&lt;/STRONG&gt; was not in SignTool.exe / CAPICOM.SignCode.Sign / CryptUIWizDigitalSign / SignerSignEx, but in the &lt;STRONG&gt;EXE itself&lt;/STRONG&gt;!&lt;/P&gt;
&lt;P&gt;I run Visual Studio's &lt;A class="" href="http://support.microsoft.com/kb/177429/en-us" mce_href="http://support.microsoft.com/kb/177429/en-us"&gt;Dumpbin.exe&lt;/A&gt; with its &lt;STRONG&gt;"/HEADER"&lt;/STRONG&gt; parameter to list the problematic EXE's &lt;STRONG&gt;PE&lt;/STRONG&gt; &lt;STRONG&gt;header&lt;/STRONG&gt; information before and after signing it (the &lt;A class="" href="http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx" mce_href="http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx"&gt;Microsoft Portable Executable and Common Object File Format Specification &lt;/A&gt;gives detailed information about PE header information).&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Before signing&lt;/STRONG&gt;, I could see the following &lt;STRONG&gt;Optional Header Value&lt;/STRONG&gt;:&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;1400&lt;/STRONG&gt; [ &lt;STRONG&gt;C40&lt;/STRONG&gt;] RVA [size] of &lt;STRONG&gt;Certificates Directory&lt;/STRONG&gt;&lt;BR&gt;&lt;/EM&gt;&lt;BR&gt;&lt;STRONG&gt;After signing&lt;/STRONG&gt;, I could see the following value:&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;1400&lt;/STRONG&gt; [ &lt;STRONG&gt;1650&lt;/STRONG&gt;] RVA [size] of &lt;STRONG&gt;Certificates Directory&lt;/STRONG&gt;&lt;BR&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Certificates Directory &lt;/STRONG&gt;points to the &lt;STRONG&gt;location of the code signing signature in the binary&lt;/STRONG&gt;. So an &lt;STRONG&gt;EXE which has not been signed&lt;/STRONG&gt; should contain the following values:&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;0&lt;/STRONG&gt; [ &lt;STRONG&gt;0&lt;/STRONG&gt;] RVA [size] of &lt;STRONG&gt;Certificates Directory&lt;/STRONG&gt;&lt;/EM&gt;&lt;BR&gt;&lt;BR&gt;Which was not our case. So SignerSignEx was not corrupting the EXE when signing it. It was already corrupted before that, even if it was successfully running before signing!&lt;/P&gt;
&lt;P&gt;Just for testing, I opened the problematic EXE with a &lt;STRONG&gt;binary editor&lt;/STRONG&gt; before signing it. I looked for "00 14 00 00 04 0c 00 00" bytes (correspondent to "1400 [ C40] RVA [size] of Certificates Directory" values), changed them to "00 00 00 00 00 00 00 00" and signed the EXE. It worked! Now the EXE is not corrupted and I can see the Digital Signature in Explorer, the certificate I used to sign, launch the EXE and run it as expected.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Manually modifying the PE header is not supported by Microsoft.&lt;/STRONG&gt; If you face a similar issue, you should work with the team that developed the EXE and focus on why the EXE got generated with an invalid PE header in the first place. &lt;/P&gt;
&lt;P&gt;I looked on the Internet and found that there are some &lt;STRONG&gt;third-party tools&lt;/STRONG&gt; which may help us to &lt;STRONG&gt;see&lt;/STRONG&gt; &lt;STRONG&gt;and modify the PE header&lt;/STRONG&gt; if needed for testing purposes, for example &lt;A class="" href="http://www.pazera-software.com/products/peinfo/" mce_href="http://www.pazera-software.com/products/peinfo/"&gt;PEInfo 0.9 BETA&lt;/A&gt; which I haven't tried so I can't neither recommend nor discourage its use.&lt;/P&gt;
&lt;P&gt;I&amp;nbsp;hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;A href="http://blogs.msdn.com/alejacma/archive/2008/02/20/how-to-sign-exe-files-with-an-authenticode-certificate-vb-net.aspx"&gt;&lt;/A&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9196078" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CAPICOM/default.aspx">CAPICOM</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/P_2F00_Invoke/default.aspx">P/Invoke</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category></item><item><title>CryptographicException: Unable to open the access token of the current thread</title><link>http://blogs.msdn.com/alejacma/archive/2008/07/30/cryptographicexception-unable-to-open-the-access-token-of-the-current-thread.aspx</link><pubDate>Wed, 30 Jul 2008 10:41:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8791188</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8791188.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8791188</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;When working with &lt;STRONG&gt;RSACryptoServiceProvider&lt;/STRONG&gt;, we may get an exception like the following:&lt;/P&gt;&lt;PRE&gt;System.Security.Cryptography.&lt;STRONG&gt;CryptographicException&lt;/STRONG&gt;: &lt;STRONG&gt;Unable to open the access token of the current thread&lt;/STRONG&gt;
   at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
   at System.Security.Cryptography.Utils._GetKeyParameter(SafeKeyHandle hKey, UInt32 paramID)
   at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle&amp;amp; safeProvHandle, SafeKeyHandle&amp;amp; safeKeyHandle)
   at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
&lt;/PRE&gt;
&lt;P&gt;I've seen this exception i.e. when signing an XML with a certificate associated to a specific Cryptographic Service Provider (CSP).&lt;/P&gt;
&lt;P&gt;Let's use my &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx"&gt;CryptoAPI Tracer script&lt;/A&gt;&amp;nbsp;to get all &lt;STRONG&gt;CryptoAPI calls&lt;/STRONG&gt; that .NET is making &lt;STRONG&gt;behind the scenes&lt;/STRONG&gt;. This will help us to know exactly what's going on.&lt;/P&gt;
&lt;P&gt;We can see in the logs generated by the script the call to &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx"&gt;CryptAcquireContext&lt;/A&gt; we make to get the &lt;STRONG&gt;key container&lt;/STRONG&gt; of the certificate. We can&amp;nbsp;also see the &lt;STRONG&gt;CSP&lt;/STRONG&gt; associated to the certificate:&lt;/P&gt;&lt;PRE&gt;&lt;STRONG&gt;CryptAcquireContextA&lt;/STRONG&gt; (0xd8c)

IN
pszContainer
00228620  "2e065b6c-027a-4746-bdf3-901a9980"
00228640  "66ea"

pszProvider
00205e60  "&lt;STRONG&gt;Third-party CSP&lt;/STRONG&gt;"

dwProvType
PROV_RSA_FULL

dwFlags
0

OUT
hProv
0x228248

RESULT
CryptAcquireContextA (0xd8c) SUCCEEDED
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;Note: I won't use the real name of the third-party CSP where I detected this issue. This post is for illustration purposes only. I don't prettend to blame anyone in particular.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Then .NET makes the following call to &lt;A class="" href="http://msdn2.microsoft.com/en-us/library/aa379949.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa379949.aspx"&gt;CryptGetKeyParam&lt;/A&gt; to find out the &lt;STRONG&gt;size of a buffer&lt;/STRONG&gt; which will hold the value of the &lt;STRONG&gt;algorithm&lt;/STRONG&gt; &lt;STRONG&gt;of the key&lt;/STRONG&gt;:&lt;/P&gt;&lt;PRE&gt;&lt;STRONG&gt;CryptGetKeyParam&lt;/STRONG&gt; (0xd8c)

&lt;STRONG&gt;IN&lt;/STRONG&gt;
hKey
0x230058

&lt;STRONG&gt;dwParam&lt;/STRONG&gt;
&lt;STRONG&gt;KP_ALGID&lt;/STRONG&gt;

&lt;STRONG&gt;pbData&lt;/STRONG&gt;
&lt;STRONG&gt;NULL&lt;/STRONG&gt; 

&lt;STRONG&gt;dwDataLen&lt;/STRONG&gt;
&lt;STRONG&gt;0&lt;/STRONG&gt;

dwFlags
0

&lt;STRONG&gt;OUT&lt;/STRONG&gt;
&lt;STRONG&gt;dwDataLen&lt;/STRONG&gt;
&lt;STRONG&gt;4&lt;/STRONG&gt;

RESULT
CryptGetKeyParam (0xd8c) FAILED
LastErrorValue: (HRESULT) &lt;STRONG&gt;0x80010125&lt;/STRONG&gt; (2147549477) - &lt;STRONG&gt;Unable to open the access token of the current thread&lt;/STRONG&gt;
LastStatusValue: (NTSTATUS) 0xc0000034 - Object Name not found.
&lt;/PRE&gt;
&lt;P&gt;Note on &lt;STRONG&gt;IN parameters&lt;/STRONG&gt;: &lt;/P&gt;
&lt;P&gt;- This &lt;STRONG&gt;hKey&lt;/STRONG&gt; value is the key handle. &lt;/P&gt;
&lt;P&gt;- This &lt;STRONG&gt;dwParam&lt;/STRONG&gt; value indicates that we want the algorithm of the key. &lt;/P&gt;
&lt;P&gt;- This &lt;STRONG&gt;pbData&lt;/STRONG&gt; value indicates that there is no buffer available yet. &lt;/P&gt;
&lt;P&gt;- This &lt;STRONG&gt;pdwDataLen&lt;/STRONG&gt; value is 0 because we want to find out the size that we need for the pbData buffer. &lt;/P&gt;
&lt;P&gt;- &lt;STRONG&gt;dwFlags&lt;/STRONG&gt; should always be 0. &lt;/P&gt;
&lt;P&gt;This call is returning 4 in &lt;STRONG&gt;dwDataLen&lt;/STRONG&gt;, which is correct as the &lt;STRONG&gt;ALGID&lt;/STRONG&gt; will be 4 bytes long. But the API is also returning the error &lt;STRONG&gt;0x80010125&lt;/STRONG&gt; (2147549477) - "&lt;STRONG&gt;Unable to open the access token of the current thread&lt;/STRONG&gt;". CryptoAPI just passes the parameters to the CSP and returns the results. The&amp;nbsp;call to the API is 100% correct, but the CSP is not honoring it. This is &lt;STRONG&gt;not a bug in .NET or CryptoAPI&lt;/STRONG&gt;. This is a &lt;STRONG&gt;bug on the CSP&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;If you are facing this issue please &lt;STRONG&gt;contact the CSP&amp;nbsp;provider&lt;/STRONG&gt;. At least in&amp;nbsp;the case of the third-party CSP where we found the issue they were already aware of it. They immediately sent an upgrade to our customers which fixed this issue.&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8791188" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/RSACryptoServiceProvider/default.aspx">RSACryptoServiceProvider</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Debugging/default.aspx">Debugging</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Debugger+scripts/default.aspx">Debugger scripts</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category></item><item><title>Threading issues with RSACryptoServiceProvider</title><link>http://blogs.msdn.com/alejacma/archive/2008/06/30/Threading-issues-with-RSACryptoServiceProvider-.aspx</link><pubDate>Mon, 30 Jun 2008 16:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8671346</guid><dc:creator>alejacma</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8671346.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8671346</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;When using &lt;STRONG&gt;RSACryptoServiceProvider&lt;/STRONG&gt; in i.e.&amp;nbsp;&lt;STRONG&gt;ASP.NET&lt;/STRONG&gt;&amp;nbsp;you may get the following exception under a heavy load scenario:&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;STRONG&gt;"System.Security.Cryptography.CryptographicException: CryptoAPI cryptographic service provider (CSP) for this implementation could not be acquired".&lt;/STRONG&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;We've seen in past posts (&lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2007/12/03/rsacryptoserviceprovider-fails-when-used-with-asp-net.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/12/03/rsacryptoserviceprovider-fails-when-used-with-asp-net.aspx"&gt;sample&lt;/A&gt;) how we can use my &lt;A class="" title="CryptoAPI Tracer script" href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2007/10/31/cryptoapi-tracer.aspx"&gt;&lt;FONT color=#006ff7&gt;CryptoAPI Tracer script&lt;/FONT&gt;&lt;/A&gt;&amp;nbsp;to take a look to the &lt;STRONG&gt;CryptoAPI&lt;/STRONG&gt;&amp;nbsp;calls that&amp;nbsp;RSACryptoServiceProvider makes behind the scenes. &lt;/P&gt;
&lt;P&gt;In this case we can see that RSACryptoServiceProvider constructor calls &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx"&gt;CryptAcquireContext&lt;/A&gt; API. The first call to CryptAcquireContext API fails with error &lt;STRONG&gt;NTE_BAD_KEYSET&lt;/STRONG&gt; ("&lt;STRONG&gt;Keyset does not exist&lt;/STRONG&gt;"). Then a second call is attempted to create the key set, but it fails with error &lt;STRONG&gt;NTE_EXISTS&lt;/STRONG&gt; ("&lt;STRONG&gt;Object already exists&lt;/STRONG&gt;"). So it seems the keyset is there, but it can't be accessed. Concurrency issues? Maybe. Check this article first to verify that we don't get these errors for another reason: &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2008/05/27/cryptacquirecontext-fails-with-nte-bad-keyset.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/05/27/cryptacquirecontext-fails-with-nte-bad-keyset.aspx"&gt;CryptAcquireContext fails with NTE_BAD_KEYSET&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;So we are having concurrency issues.&amp;nbsp;Consider the application performs the following sequence in two steps:&lt;BR&gt;1) Open a given named machine key container.&lt;BR&gt;2) If open fails, create that named machine key container.&lt;/P&gt;
&lt;P&gt;This sequence is not an automatic operation. If multiple threads are attempting to do the same sequence and assume 2 threads attempt to create the same named machine key container, the second call will fail with "key container already exists". &lt;/P&gt;
&lt;P&gt;As we've seen this is what RSACryptoServiceProvider constructor&amp;nbsp;does similar to any application calling CryptAcquireContext API&amp;nbsp;twice.&lt;/P&gt;
&lt;P&gt;If the application is always working with the same RSA key in a named key container, key containers must be acquired only once in the process using CryptAcquireContext. When multiple threads are using the same RSA instance for encryption/decryption, the instance methods are &lt;STRONG&gt;not&lt;/STRONG&gt; &lt;STRONG&gt;thread safe&lt;/STRONG&gt;. &lt;/P&gt;
&lt;P&gt;At the &lt;STRONG&gt;CryptoAPI&lt;/STRONG&gt; level we've already seen &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2008/06/30/Threading-issues-with-CryptoAPI.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/06/30/Threading-issues-with-CryptoAPI.aspx"&gt;threading issues&lt;/A&gt; when dealing with key handles in applications. When calling CryptoAPI directly we have a lot more control when the key handle is obtained, the type of handle, how it is used and whether it is thread safe. e.g. After a RSA key handle has been obtained by using the &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380199(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380199(VS.85).aspx"&gt;CryptGetUserKey &lt;/A&gt;function, RSA operations are thread safe.&lt;/P&gt;
&lt;P&gt;There is not much control when using RSACryptoServiceProvider as it doesn’t expose key handles.&lt;/P&gt;
&lt;P&gt;These are some &lt;STRONG&gt;suggestions&lt;/STRONG&gt; to minimize threading issues in ASP.NET:&lt;/P&gt;
&lt;P&gt;1) Set &lt;A class="" href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspparameters.keycontainername.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspparameters.keycontainername.aspx"&gt;CspParameters.KeyContainer&lt;/A&gt; name when creating an RSACryptoServiceProvider object. Never use the default one, NEVER! This is prone to store corruption. We talked about &lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2008/05/28/don-t-use-default-key-containers-if-possible.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/05/28/don-t-use-default-key-containers-if-possible.aspx"&gt;this&lt;/A&gt; already.&lt;/P&gt;
&lt;P&gt;2) Explicitely call &lt;STRONG&gt;Dispose&lt;/STRONG&gt; on the RSACrytpoServiceProvider object when possible. This way, we don't rely on the Garbage Collector to "eventually" release the CSP.&lt;/P&gt;
&lt;P&gt;3) Set &lt;A class="" href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspproviderflags.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspproviderflags.aspx"&gt;UseMachineKeyStore&lt;/A&gt; in &lt;A class="" href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspparameters.flags.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.cspparameters.flags.aspx"&gt;CspParameters.Flags&lt;/A&gt;&amp;nbsp;when creating an RSACryptoServiceProvider. This flag tells RSACryptoServiceProvider to use "machine location" for storing RSA public/private key pair instead of the "current user" location. This is equivalent to calling CryptAcquireContext API with &lt;STRONG&gt;CRYPT_MACHINE_KEYSET&lt;/STRONG&gt;. Make sure all the threads using the RSA instance are running under the same account.&lt;/P&gt;
&lt;P&gt;4) Don't set &lt;A class="" href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.persistkeyincsp.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.persistkeyincsp.aspx"&gt;RSACryptoServiceProvider.PersistKeyInCSP&lt;/A&gt; to False. This will cause the key container to be deleted when RSA instance is released or garbage collected. If multiple threads are trying to access the same named key container, the state of that named key container could be in a temporary cleaned up state and it cannot be acquired.&lt;/P&gt;
&lt;P&gt;5) Another option would be for us to instantiate RSACryptoServiceProvider once as part of Web Application initialization and then use that same instance for encryption or decryption under a &lt;STRONG&gt;critical section&lt;/STRONG&gt; like lock (i.e. Mutex). This would also avoid reacquiring key container multiple times from the same process.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8671346" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/RSACryptoServiceProvider/default.aspx">RSACryptoServiceProvider</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptAcquireContext/default.aspx">CryptAcquireContext</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/System.Security/default.aspx">System.Security</category></item></channel></rss>