send a client certificate by using the HttpWebRequest and HttpWebResponse classes

How to send a client certificate by using the HttpWebRequest and HttpWebResponse classes in Microsoft Visual C# .NET

Requirements

To send a client certificate from Microsoft ASP.NET applications, you must have the following hotfixes or service packs installed:
Microsoft .NET Framework 1.0
You must install the .NET Framework 1.0 Service Pack 3 (SP3), or you must install hotfix 817854. For more information, click the following article number to view the article in the Microsoft Knowledge Base:
817854  FIX: ASP.NET Web application cannot deliver a client certificate to a security-enhanced Web site
.NET Framework 1.1
You must install the .NET Framework 1.1 Service Pack 1 (SP1), or you must install hotfix 831138. For more information, click the following article number to view the article in the Microsoft Knowledge Base:
831138  FIX: A .NET Framework application that uses the System.Net.WebRequest method very frequently experiences OutOfMemoryException errors

On This Page

INTRODUCTION

This article discusses how to send a client certificate by using the HttpWebRequest and HttpWebResponse classes in Microsoft Visual C# NET.

MORE INFORMATION

You can send a client certificate when the Web server requires one by using the HttpWebRequest and the HttpWebResponse classes. To obtain a certificate that can be used for sending a client certificate by using the HttpWebRequest class, use one of the following methods:
Method 1
Use the X509Certificate class to read the certificate from a .cer file, and then set the ClientCertificates property.
Method 2
Use CryptoAPI calls to obtain the certificate from the certificate store, and then set the X509Certificate class to the certificate that you received from the certificate store. You can then set the ClientCertificates property.

Requirements for sending a client certificate

When you work with ASP.NET applications, make sure the following requirements are completed:
  • The client certificate must be installed in theLOCAL_MACHINE registry hive and not in the CURRENT_USER registry hive. Toconfirm where the client certificate is installed, follow these steps:
    1. Click Start, click Run, type mmc, and then click OK.
    2. On the File menu, click Add/Remove Snap-in.
    3. In the Add/Remove Snap-in dialog box, click Add.
    4. In the Add Standalone Snap-in dialog box, click Certificates, and then click Add.
    5. In the Certificates Snap-in dialog box, click Computer account, and then click Next
    6. In the Select Computer dialog box, click Finish.
    7. In the Add Standalone Snap-in dialog box, click Close, and then click OK.
    8. Expand Certificates (Local Computer), expand Personal, and then click Certificates.
    In the right pane, the client certificate should belisted.
  • You must give the ASP.NET user account permissions to theprivate key for the client certificate. To give the ASP.NET user accountpermissions to the private key for the client certificate, use theWinHttpCertCfg.exe tool. For more information, click the following article number to view the article in the Microsoft Knowledge Base:
    823193  How to get Windows HTTP 5.1 certificate and trace tools
    For more information about how to use this tool,visit the following Microsoft Developer Network (MSDN) Web site:
    WinHttpCertCfg.exe, a certificate configuration tool http://msdn2.microsoft.com/en-us/library/aa384088.aspx

Using a .cer file

Method 1 is easier to use, but method requires that you have a .cer file. If you do not have the .cer file installed, use Microsoft Internet Explorer to export the .cer file.

The following source code describes how to obtain a certificate from a .cer file that you can use with the HttpWebRequest class.
//Uncomment the following code if you need a proxy. The boolean true is used to bypass the local address.
//WebProxy proxyObject = new WebProxy("Your Proxy value",true); 
//GlobalProxySelection.Select = proxyObject;

// Obtain the certificate. 
try
{
	//You must change the path to point to your .cer file location. 
	X509Certificate Cert = X509Certificate.CreateFromCertFile("C:\\mycert.cer");
	// Handle any certificate errors on the certificate from the server.
	ServicePointManager.CertificatePolicy = new CertPolicy();
	// You must change the URL to point to your Web server.
	HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://YourServer/sample.asp");
	Request.ClientCertificates.Add(Cert);
	Request.UserAgent = "Client Cert Sample";
	Request.Method = "GET";
	HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();
	// Print the repsonse headers.
	Console.WriteLine("{0}",Response.Headers);
	Console.WriteLine();
	// Get the certificate data.
	StreamReader sr = new StreamReader(Response.GetResponseStream(), Encoding.Default);
	int count;
	char [] ReadBuf = new char[1024];
	do
	{
		count = sr.Read(ReadBuf, 0, 1024);
		if (0 != count)
		{
			Console.WriteLine(new string(ReadBuf));
		}
						
	}while(count > 0);
}
catch(Exception e)
{
	Console.WriteLine(e.Message);
}
	

//Implement the ICertificatePolicy interface.
class CertPolicy: ICertificatePolicy
{
	public bool CheckValidationResult(ServicePoint srvPoint, 
X509Certificate certificate, WebRequest request, int certificateProblem)
	{
		// You can do your own certificate checking.
		// You can obtain the error values from WinError.h.

		// Return true so that any certificate will work with this sample.
		return true;
	}
}

Using CryptoAPI calls

If you must obtain the certificate from the certificate store, use the CryptoAPI functions to obtain the certificate, and then store it in an X509Certificate class object. The X509CertificateCollection class enumerates all the certificates in a store and then puts them in an X509CertificateCollection class object.

If you want to obtain a specific certificate, you must change the class code to obtain a specific certificate by using the CertFindCertificateInStore function. This function is declared in the Wincrypt.h file. Alternatively, you can enumerate the X509CertificateCollection function to find the certificate that you want.

The following sample code uses the first certificate in the collection that is returned from the CertEnumCertificatesInStore function.
using System;
using System.Net;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.InteropServices;

namespace SelectClientCert
{
	/// Sample that describes how how to select client cetificate and send it to the server.

	class MyCerts{

		private static int CERT_STORE_PROV_SYSTEM = 10;
		private static int CERT_SYSTEM_STORE_CURRENT_USER = (1 << 16);
		///private static int CERT_SYSTEM_STORE_LOCAL_MACHINE = (2 << 16);

		[DllImport("CRYPT32", EntryPoint="CertOpenStore", CharSet=CharSet.Unicode, SetLastError=true)]
		public static extern IntPtr CertOpenStore(
			int storeProvider, int encodingType,
			int hcryptProv, int flags, string pvPara);

		[DllImport("CRYPT32", EntryPoint="CertEnumCertificatesInStore", CharSet=CharSet.Unicode, SetLastError=true)]
		public static extern IntPtr CertEnumCertificatesInStore(
			IntPtr storeProvider,
			IntPtr prevCertContext);

		[DllImport("CRYPT32", EntryPoint="CertCloseStore", CharSet=CharSet.Unicode, SetLastError=true)]
		public static extern bool CertCloseStore(
			IntPtr storeProvider,
			int flags);
		
		X509CertificateCollection m_certs;

		public MyCerts(){
			m_certs = new X509CertificateCollection();
		}

		public int Init()
		{
			IntPtr storeHandle;
			storeHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, "MY");
			IntPtr currentCertContext;
			currentCertContext = CertEnumCertificatesInStore(storeHandle, (IntPtr)0);
			int i = 0;
			while (currentCertContext != (IntPtr)0) 
			{
				m_certs.Insert(i++, new X509Certificate(currentCertContext));
				currentCertContext = CertEnumCertificatesInStore(storeHandle, currentCertContext);
			}
			CertCloseStore(storeHandle, 0);

			return m_certs.Count;
		}
		
		public X509Certificate this [int index]
		{
			get 
			{
				// Check the index limits.
				if (index < 0 || index > m_certs.Count)
					return null;
				else
					return m_certs[index];
			}
		}
	};
	class MyHttpResource
	{
		String m_url;

		public MyHttpResource(string url){
			m_url = url;
		}

		public void GetFile(){

			HttpWebResponse  result = null;

			try{
			
				HttpWebRequest req = (HttpWebRequest)WebRequest.Create(m_url);
				req.Credentials  = CredentialCache.DefaultCredentials;

				///Method1
				//req.ClientCertificates.Add(X509Certificate.CreateFromCertFile("D:\\Temp\\cert\\c1.cer"));
		
				///Method2
				///Uses interop services
				MyCerts mycert = new MyCerts();
				if(mycert.Init() > 0)
					req.ClientCertificates.Add(mycert[0]);

				result = (HttpWebResponse)req.GetResponse();
				
				Stream ReceiveStream = result.GetResponseStream();
				Encoding encode = System.Text.Encoding.GetEncoding("utf-8");

				StreamReader sr = new StreamReader( ReceiveStream, encode );
				Console.WriteLine("\r\nResponse stream received");

				Char[] read = new Char[256];
				int count = sr.Read( read, 0, 256 );

				Console.WriteLine("HTTP Response...\r\n");
				while (count > 0) 
				{
					String str = new String(read, 0, count);
					Console.Write(str);
					count = sr.Read(read, 0, 256);
				}

			} 
			catch(WebException e) 
			{
            
				Console.WriteLine("\r\nError:");
				#if (DEBUG)
					Console.WriteLine(e.ToString());
				#else		
					Console.WriteLine(e.Message); 				
				#endif

			} 
			finally 
			{
				if ( result != null ) {
					result.Close();
				}
			}
				
		}
	
	}

	class CertSample
	{
		static void Main(string[] args)
		{
			try
			{
				if (args.Length < 1)
				{
					Console.WriteLine("No url is entered to download, returning.\n");
					Console.WriteLine("Usage: CertSample <urltoget>\n");
					Console.WriteLine("  e.g: CertSample https://servername \n"); 

					return;
				}

				MyHttpResource hr = new MyHttpResource(args[0]);
				hr.GetFile();
			}
			catch(Exception e)
			{
				Console.WriteLine(e.ToString());
			}
			return;
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值