惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

有赞技术团队
有赞技术团队
B
Blog
IT之家
IT之家
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
人人都是产品经理
人人都是产品经理
博客园 - 聂微东
量子位
博客园 - 叶小钗
T
Tailwind CSS Blog
小众软件
小众软件
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
雷峰网
雷峰网
博客园 - 三生石上(FineUI控件)
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Blog — PlanetScale
Blog — PlanetScale
V
V2EX
博客园_首页
I
InfoQ
B
Blog RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog

博客园 - 木头's

.Net读取数字证书信息和扩展域信息 APACHE2.0 TOMCAT5.0 SSL 配置 smimedecryptvbs ASP.NET, Javascript tips: Encrypt /Sign /Verify signed message using Capicom ActiveX Using CAPICOM to obtain an SSL Certificate net平台下的数字签名技术的讲解 java数字签名(签名生成,用证书验证签名) Apache安全应用资源文档 国外PKI/CA体系发展状况 CA基本常识:X.509标准 - 木头's - 博客园 PKI体系的十大风险 在职必看!受益无穷的28条职场语录 启用客户端证书并在 SharePoint Portal Server 2003 的内容搜索中使用客户端证书 一个基于RSA算法的Java数字签名例子 实现在 Linux 下 Tomcat 的双向SSL认证 JAVA对数字证书的常用操作 一组数据摘要算法的效率测试 一首歌曲,一种心情 职场必读
.NET and Certificate Stores
木头's · 2007-08-16 · via 博客园 - 木头's

Introduction:
The cryptography support included with .NET Framework 1.1 and 1.0 does not include support for accessing Windows cryptographic certificate stores. While support for hashing, encryption and X509v3 certificates is available using classes of the System.Security.Cryptography and System.Security.Cryptography.X509Certificates namespaces, there is no direct support for instantiating managed certificates from system certificate stores, nor is there currently support for generation or verification of CMS/PKCS#7 signatures. While there are indications that broader support for certificate stores and pkcs will be available in future releases of the .net framework, it is useful to have basic system certificate store access from managed code which can target .net framework 1.0/1.1. This article shows two approaches in C# for accessing certificate stores from .net framework using:

  • CAPICOM 2 COM interop
  • Platform Invoke (P/Invoke) with native cryptoAPI libraries.
CAPICOM 2 Interop:

Much of the useful certificate store functionality of cryptoAPI has been encapsulated in CAPICOM. CAPICOM provides advanced capability, including support for pkcs7 signatures, envelopes, encryption, Authenticode signatures and advanced certificate store access. CAPICOM requires an end user component dll installation and registration, and deployment of a .net interop assembly. An interop assembly for CAPICOM can be easily built using:

     tlbimp capicom.dll /namespace:CAPICOM /out:Interop.CAPICOM.dll

This is essentially the same command executed by VS.net when the COM reference is added. Note that the interop assembly has explicitly been given the namespace CAPICOM while the assembly is titled Interop.CAPICOM. The simple C# application below is compiled using:

      csc /r:interop.capicom.dll FindCertnet.cs

To execute the application, the Interop.CAPICOM.dll assembly must be in the application directory, or if Strong Name signed, can be deployed to the GAC for shared access by other .net applications referencing CAPICOM. The application demonstrates basic certificate store access using CAPICOM. It also demonstrates different ways of using a Certificates enumeration, including the indexer. Casting to the ICertContext interface provides the context that can be used with X509Certificate(IntPtr handle) constructor, although with CAPICOM installed, all the functionality is available from the interop assembly. A few properties of an X509Certificate object are displayed:


using System; using System.Collections; using System.Security.Cryptography.X509Certificates; using CAPICOM; class FindCertnet { static private String storeName = "My"; static StoreClass oStore; static Certificates oCerts; static String filter = "yoursearchstring"; [STAThread] static void Main(string[] args) { oStore = new StoreClass(); oStore.Open( CAPICOM_STORE_LOCATION.CAPICOM_CURRENT_USER_STORE, storeName,CAPICOM_STORE_OPEN_MODE.CAPICOM_STORE_OPEN_EXISTING_ONLY | CAPICOM_STORE_OPEN_MODE.CAPICOM_STORE_OPEN_READ_ONLY ); oCerts = (Certificates)oStore.Certificates; oCerts = (Certificates)oCerts.Find( CAPICOM_CERTIFICATE_FIND_TYPE.CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME,filter, false); Console.WriteLine("\n{0} certificates match substring \"{1}\"", oCerts.Count, filter ); foreach(Certificate ocert in oCerts) //Certificates is IEnumerable ocert.Display() ; //---- alernate equivalent way to enumerate ---------- //IEnumerator certenum = oCerts.GetEnumerator() ; //while(certenum.MoveNext()){ // Certificate ocert = (Certificate) certenum.Current; // ocert.Display(); //} //--- get first cert using indexer, retrieve ICertContext and use from managed code ----- if(oCerts.Count>0){ Certificate firstcert = (Certificate)oCerts[1] ; firstcert.Display() ; ICertContext iCertCntxt = (ICertContext) firstcert; int certcntxt = iCertCntxt.CertContext ; IntPtr hCertCntxt = new IntPtr(certcntxt); if(hCertCntxt != IntPtr.Zero) { //use certcontext from managed code Console.WriteLine("CertContext:\t0x{0:X}", hCertCntxt.ToInt32()) ; X509Certificate foundcert = new X509Certificate(hCertCntxt); Console.WriteLine("\nFound certificate with SubjectName string \"{0}\"",filter); Console.WriteLine("SubjectName:\t{0}", foundcert.GetName()); Console.WriteLine("Serial No:\t{0}", foundcert.GetSerialNumberString()); Console.WriteLine("HashString:\t{0}" , foundcert.GetCertHashString()); } } } }

P/Invoke and cryptoAPI:
For simple cryptographic tasks, like accessing system certificate stores, another solution which requires no additional deployment to clients is Platform Invoke (P/Invoke) on the cryptoAPI libraries which are included with most recent Windows OS. The example below shows how to use .net P/Invoke to call several cryptoAPI unmanaged native functions from crypt32.dll and retrieving an IntPtr representing a certificate context which is used to instantiate an X509Certificate object in a similar way to the CAPICOM example above:

  • Open a system certificate store using CertOpenSystemStore()
  • Search for a certificate based on a substring of the SubjectName using CertFindCertificateInStore()
  • Instantiate a managed X509Certificate certificate using an IntPtr.
  • Free the certificate store and certificate contexts

using System; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.ComponentModel; public class WinCapi { /* HCERTSTORE WINAPI CertOpenSystemStore(HCRYPTPROV hprov, LPTCSTR szSubsystemProtocol); BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags); PCCERT_CONTEXT WINAPI CertFindCertificateInStore( HCERTSTORE hCertStore, DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType, const void* pvFindPara, PCCERT_CONTEXT pPrevCertContext); BOOL WINAPI CertFreeCertificateContext( PCCERT_CONTEXT pCertContext ); */ [DllImport("crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern IntPtr CertOpenSystemStore( IntPtr hCryptProv, string storename) ; [DllImport("crypt32.dll", SetLastError=true)] public static extern bool CertCloseStore( IntPtr hCertStore, uint dwFlags) ; [DllImport("crypt32.dll", SetLastError=true)] public static extern IntPtr CertFindCertificateInStore( IntPtr hCertStore, uint dwCertEncodingType, uint dwFindFlags, uint dwFindType, [In, MarshalAs(UnmanagedType.LPWStr)]String pszFindString, IntPtr pPrevCertCntxt) ; [DllImport("crypt32.dll", SetLastError=true)] public static extern bool CertFreeCertificateContext( IntPtr hCertStore) ; } public class SimpleCert { const string MY = "MY"; const string OTHERS = "AddressBook"; const uint PKCS_7_ASN_ENCODING = 0x00010000; const uint X509_ASN_ENCODING = 0x00000001; const uint CERT_FIND_SUBJECT_STR = 0x00080007; static uint MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING ; static string lpszCertSubject = "yoursearchstring" ; public static void Main(){ IntPtr hSysStore = IntPtr.Zero; IntPtr hCertCntxt = IntPtr.Zero; hSysStore = WinCapi.CertOpenSystemStore(IntPtr.Zero, MY) ; Console.WriteLine("Store Handle:\t0x{0:X}", hSysStore.ToInt32()); if(hSysStore != IntPtr.Zero) { hCertCntxt=WinCapi.CertFindCertificateInStore( hSysStore, MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_STR, lpszCertSubject , IntPtr.Zero) ; if(hCertCntxt != IntPtr.Zero){ //use certcontext from managed code Console.WriteLine("CertContext:\t0x{0:X}", hCertCntxt.ToInt32()) ; X509Certificate foundcert = new X509Certificate(hCertCntxt); Console.WriteLine("\nFound certificate with SubjectName string \"{0}\"",lpszCertSubject); Console.WriteLine("SubjectName:\t{0}", foundcert.GetName()); Console.WriteLine("Serial No:\t{0}", foundcert.GetSerialNumberString()); Console.WriteLine("HashString:\t{0}" , foundcert.GetCertHashString()); } else Console.WriteLine("Could not find SubjectName containing string \"{0}\"", lpszCertSubject); } //------- Clean Up ----------- if(hCertCntxt != IntPtr.Zero) WinCapi.CertFreeCertificateContext(hCertCntxt); if(hSysStore != IntPtr.Zero) WinCapi.CertCloseStore(hSysStore, 0) ; } }

CertFindCertificateInStore() has comprehensive support and options for searching certificate stores in many different ways. The example above shows one simple implementation.

For more advanced certificate store access via P/Invoke (including memory stores, deleting stores etc..), the cryptoAPI function CertOpenStore() can be used. A typical managed prototype (for C#) might be:

 [DllImport("crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern IntPtr CertOpenStore(
IntPtr storeProvider,
uint dwMsgAndCertEncodingType,
IntPtr hCryptProv,
uint dwFlags,
String cchNameString) ;


References: