当在 Web 服务器需要一个使用
HttpWebRequest 和
HttpWebResponse 类时,您可以发送客户端证书。若要获取可用于通过使用
HttpWebRequest 类发送客户端证书的证书,使用下列方法之一:
方法 1
使用
x509 证书 类来读取该证书从一个.cer 文件,然后设置
ClientCertificates 属性。
方法 2
使用 CryptoAPI 调用来获得证书从证书存储区,然后将
x509 证书 类设置为您接收到来自证书存储区的证书。然后,您可以设置
ClientCertificates 属性。
发送客户端证书的要求
在使用 ASP.NET 应用程序,请确保完成以下要求:
- LOCAL_MACHINE 注册表配置单元中,而不是在 CURRENT_USER 注册表配置单元,必须安装客户端证书。若要确认客户端证书的安装位置,请按照下列步骤操作:
- 单击 开始、 单击 运行,键入 mmc,然后单击 确定。
- 在 文件 菜单上单击 添加/删除管理单元。
- 在 添加/删除管理单元 对话框中单击 添加。
- 在 添加独立管理单元 对话框中单击 证书,然后单击 添加。
- 在 证书管理单元 对话框中单击 计算机帐户,然后单击 下一步
- 选择计算机 对话框中单击 完成。
- 在 添加独立管理单元 对话框中单击 关闭,然后单击 确定。
- 展开 证书 (本地计算机),展开 个人,然后单击 证书。
在右窗格中应列出该客户端证书。
- 您必须授予 ASP.NET 用户私人密钥以便客户端证书的帐户权限。若要为 ASP.NET 用户帐户权限的客户端证书的私钥,使用 $ WinHttpCertCfg.exe 工具。有关详细的信息请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
823193
(http://support.microsoft.com/kb/823193/ ) 如何获得 Windows HTTP 5.1 证书和跟踪工具
有关如何使用此工具,请访问下面的 Microsoft 开发人员网络 (MSDN) 的网站的详细信息:
使用.cer 文件
方法 1 会更易于使用,但方法要求您拥有一个.cer 文件。如果您没有安装的.cer 文件,使用 Microsoft Internet 资源管理器导出.cer 文件。
下面的源代码介绍如何获取证书的.cer 文件可以使用与 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
;
}
}
使用 CryptoAPI 调用
如果您必须获取该证书从证书存储区,CryptoAPI 函数用于获取该的证书,然后将其存储在
x509 证书 的类对象。
X509CertificateCollection 类枚举存储区中的所有证书,然后将其置于
X509CertificateCollection 类对象中。
如果您要获取某个特定证书,必须更改类代码使用
CertFindCertificateInStore 函数获取特定的证书。此函数被声明 Wincrypt.h 文件中。 或者,您可以枚举
X509CertificateCollection 函数来查找所需的证书。
下面的代码示例使用从
CertEnumCertificatesInStore 函数返回的集合中的第一个证书
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
;
}
}
}
有关更多的信息,请访问下面的 Microsoft 开发人员网络 (MSDN) 的网站: