X.509数字签名

 

 Zju.GUI.App_TemporaryKey.pfx文件:

公钥加密技术12号标准(Public Key Cryptography Standards #12PKCS#12)为存储和传输用户或服务器私钥、公钥和证书指定了一个可移植的格式。它是一种二进制格式,这些文件也称为PFX文件。开发人员通常需要将PFX文件转换为某些不同的格式,如PEMJKS,以便可以为使用SSL通信的独立Java客户端或WebLogic Server使用.

pfx可能是证书的备份文件,这时可双击相关文件即可导入证书,如果要求输入密码,则输入当初设定的密码即可。

PKI"Public Key Infrastructure"的缩写,意为"公钥基础设施",是一个用非对称密码算法原理和技术实现的、具有通用性的安全基础设施。PKI利用数字证书标识密钥持有人的身份,通过对密钥的规范化管理,为组织机构建立和维护一个可信赖的系统环境,透明地为应用系统提供身份认证、数据保密性和完整性、抗抵赖等各种必要的安全保障,满足各种应用系统的安全需求。简单的说,PKI是提供公钥加密和数字签名服务的系统,目的是为了自动管理密钥和证书,保证网上数字信息传输的机密性、真实性、完整性和不可否认性。

 

1X.509 简介

什么是数字证书
数字证书就是互联网通讯中标志通讯各方身份信息的一系列数据,提供了一种在Internet上验证您身份的方式,其作用类似于司机的驾驶执照或日常生活中的身份证。它是由一个由权威机构-----CA机构,又称为证书授权(Certificate Authorit y)中心发行的,人们可以在网上用它来识别对方的身份。数字证书是一个经证书授权 中心数字签名的包含公开密钥拥有者信息以及公开密钥的文件。最简单的证书包含一 个公开密钥、名称以及证书授权中心的数字签名。一般情况下证书中还包括密钥的有 效时间,发证机关(证书授权中心)的名称,该证书的序列号等信息,证书的格式遵循 ITUT X.509国际标准。
一个标准的X.509数字证书包含以下一些内容:
 
证书的版本信息;
 
证书的序列号,每个证书都有一个唯一的证书序列号;
 
证书所使用的签名算法;
 
证书的发行机构名称,命名规则一般采用X.500格式;
 
证书的有效期,现在通用的证书一般采用UTC时间格式,它的计时范围为1950-2049;
 
证书所有人的名称,命名规则一般采用X.500格式;
 
证书所有人的公开密钥;
 
证书发行者对证书的签名。

二、为什么要用数字证书
1)对身份合法性验证的要求
以明文方式存储、传送的用户名和口令存在着被截获、破译等诸多安全隐患。同时,还有维护不便的缺点。因此,需要一套安全、可靠并易于维护的用户身份管理和合法性验证机制来确保应用系统的安全性。
2)对数据保密性和完整性的要求
企业应用系统中的数据一般都是明文,在基于网络技术的系统中,这种明文数据很容易泄密或被篡改,必须采取有效的措施保证数据的保密性和完整性。
3)传输安全性要求
以明文方式在网上传输的数据,很容易被截获以至泄密,必须对通信通道进行加密保护。利用通信专线的传统方式已经远远不能满足现代网络应用发展的需求,必须寻求一种新的方法来保证基于互联网技术的传输安全需求。
4)对数字签名和不可否认的要求
不可抵赖性为了防止事件发起者事后抵赖,对于规范业务,避免法律纠纷起着很大的作用。传统不可抵赖性是通过手工签名完成的,在网络应用中,需要一种具有同样功能的机制来保证不可抵赖性,那就是数字签名技术。

三、数字证书原理介绍
数字证书采用公钥体制,即利用一对互相匹配的密钥进行加密、解密。每个用户自己设定一把特定的仅为本人所知的私有密钥(私钥),用它进行解密和签名;同时设定一把公共密钥(公钥)并由本人公开,为一组用户所共享,用于加密和验证签名。当发送一份保密文件时,发送方使用接收方的公钥对数据加密,而接收方则使用 自己的私钥解密,这样信息就可以安全无误地到达目的地了。通过数字的手段保证加 密过程是一个不可逆过程,即只有用私有密钥才能解密。在公开密钥密码体制中,常用的一种是RSA体制。其数学原理是将一个大数分解成两个质数的乘积,加密和解密用的是两个不同的密钥。即使已知明文、密文和加密密钥(公开密钥),想要推导出解密密钥(私密密钥),在计算上是不可能的。按现在的计算机技术水平,要破解目前采用的1024RSA密钥,需要上千年的计算时间。公开密钥技术解决了密钥发布的管理问题,商户可以公开其公开密钥,而保留其私有密钥。购物者可以用人人皆知的公开密钥对发送的信息进行加密,安全地传送给商户,然后由商户用自己的私有密钥 进行解密。

用户也可以采用自己的私钥对信息加以处理,由于密钥仅为本人所有,这样就产生了别人无法生成的文件,也就形成了数字签名。采用数字签名,能够确认以下两点:
1)保证信息是由签名者自己签名发送的,签名者不能否认或难以否认;
2)保证信息自签发后到收到为止未曾作过任何修改,签发的文件是真实文件。
数字签名具体做法是:
1)将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。在数学上保证:只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性。
2)将该报文摘要值用发送者的私人密钥加密,然后连同原报文一起发送给接收者,而产生的报文即称数字签名。
3)接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较。如相等则说明报文确实来自所称的发送者。 

四、证书与证书授权中心
CA
机构,又称为证书授证(Certificate Authority)中心,作为电子商务交易中受信任的第三方,承担公钥体系中公钥的合法性检验的责任。CA中心为每个使用公开密钥的用户发放一个数字证书,数字证书的作用是证明证书中列出的用户合法拥有证书中列出的公开密钥。CA机构的数字签名使得攻击者不能伪造和篡改证书。它负责产生、分配并管理所有参与网上交易的个体所需的数字证书,因此是安全电子交易的核心环节。

 

2X509 User/Password

Transfer Security

  Transfer Security 主要包括三个方面: "消息完整性(Message Integrity)""消息机密性 (Message Confidentiality)" "交互验证(Mutual Authentication)"

  消息完整性必须确保消息在传输过程中没有被篡改,接收的消息是完整且正确的;消息机密性必须确保消息不会被任何第三方查阅,消息内容不会泄漏给任何非相关人员;而交互认证则是指客户端和服务器必须通过某种信任机制才能建立正确的连接,同时交互认证还要监测并阻止拒绝服务攻击(DOS)。通常的做法是对消息进行数字签名来确保其完整性,使用非对称加密算法来阻止消息内容外泄,而用户名/密码、X.509 数字证书等方式则可以用来验证对方身份,在这里我们主要讲述如何在WCF中使用用户名/密码的身份验证方式.

创建x.509数字证书:

通过X.509证书实现密钥的交换和签名;用自己的证书(包含私钥)签名,用其他人证书(公钥)进行加密,验签的过程;

生成证书,该证书的用途可用于签名,也可用于解密(将证书的公钥导出到其他电脑后通过公钥加密)生成证书的方式有两种

通过外部CA证书颁发机构申请证书

通过.net Makecert.exe工具通过命令行创建证书(这种方式才生的证书无法实现验证证书的合法性和可用性)

对于需要解密的证书需要把公钥导出给其他电脑,让对方用这个公钥加密,用于签名的证书,则需要把公钥导出给其他电脑,用公钥来验证自己的身份和报文是否被篡改。

 远程计算获取到公钥文件后直接导入到计算机的证书管理器的其他人目录下如图3,加密的时候需要读取本地计算其他人(Local Computer"Other People)下的证书加密和验证签

  先获取需要加密/加签的明文,对于加密操作则读取本地计算机其他人目录下的证书信息,对于签名操作则需要读取本地计算机"个人下面的证书。加密/加签需要的证书名称通过配置文件获取。

 调用加密/加签算法进行对报文的加密/加签操作;使用.net标准的类库实现。

加密算法说明

EncryptedXml 类是 .NET Framework 中用于 XML 加密的主类。XML 加密是对所有或部分 XML 文档或任意数据进行加密的一种基于标准的、可互操作的方法。.NET Framework XML 加密类实现了位于 http://www.w3.org/TR/xmldsig-core/ 的万维网联合会 (W3C) XML 加密规范。无论何时需要在应用程序或组织之间以标准方式共享加密的 XML 数据,都可使用 EncryptedXml 类。任何使用此类进行加密的数据均可通过符合 W3C XML 加密规范的任何实现进行解密。 XML 加密用 <EncryptedData> 元素替换任何明文 XML 元素或文档,此元素包含明文 XML 或任意数据的加密(或密文)表示形式。<EncryptedData> 元素可以选择包含有关在何处查找用于对密文进行解密的密钥的信息,以及关于使用哪种加密算法对明文进行加密的信息。除了允许对用于解密 <EncryptedData> 元素值的密钥进行加密外,<EncryptedKey> 元素在样式和用法方面与 <EncryptedData> 元素类似。注意,<EncryptedKey> 元素和 <EncryptedData> 元素从不包含未加密的密钥。使用下列方法之一交换密钥信息:

Ø       不包含任何密钥信息。如果选择此选项,则双方必须在交换加密数据之前在算法和密钥上取得一致。

Ø       <RetrievalMethod> 元素的统一资源标识符 (URI) 属性中包含密钥位置。双方必须事先就密钥位置取得一致,并且必须将此位置保密。

Ø       包含一个字符串名称,此名称映射到 <KeyName> 元素中的密钥。双方必须在交换加密数据之前在密钥名称映射上取得一致,并且必须将此映射保密。

Ø       <EncryptedKey> 元素中包含加密密钥。双方必须在交换加密数据之前在对加密密钥进行解密的密钥上取得一致。可以有选择地包含将对 <EncryptedKey> 元素中的密钥进行解密的密钥的名称或位置。

加签算法说明

SignedXml 类是 .NET Framework 中用于 XML 签名和验证 (XMLDSIG) 的主类。 XMLDSIG 是一种基于标准且可互操作的方法,用于对 XML 文档的全部或部分或者可通过统一资源标识符 (URI) 查找的其他数据进行签名和验证。.NET Framework XMLDSIG 类实现了 WWW 联合会 (W3C) 有关 XML 签名和验证的规范,可从 http://www.w3.org/TR/xmldsig-core/ 获得该规范。

无论何时需要在应用程序或组织之间采用标准方式共享已签名的 XML 数据,都可使用 SignedXml 类。 使用此类签名的任何数据都可以通过符合 XMLDSIG W3C 规范的任何实现进行验证。

XMLDSIG 将创建一个 <Signature> 元素,该元素包含用于 XML 文档或可通过 URI 查找的其他数据的数字签名。 <Signature> 元素可以有选择地包含有关在何处查找用于验证签名的密钥以及使用哪种加密算法进行签名等信息。

通过 SignedXml 类,可以创建以下三种 XML 数字签名:

签名类型

说明

被包封签名

该签名包含于被签名的 XML 文档中。

包封签名

已签名的 XML 包含于 <Signature> 元素中。

分离签名

该签名位于与被签名的数据不同的单独文档中。

使用下列方法之一交换密钥信息:

Ø       不包含任何密钥信息。 如果您选择此选项,则双方必须在交换数字签名之前在算法和密钥上取得一致。

Ø       <EncryptedKey> 元素中包括公钥。

Ø       <RetrievalMethod> 元素的 URI 属性中包括密钥的位置。双方必须事先就密钥位置取得一致,并且必须将此位置保密。

Ø       <KeyName> 元素中包括映射到密钥的字符串名称。 双方必须在交换加密数据之前在密钥名称映射上取得一致,并且必须将此映射保密。

将生成的密文;密文中包含加密证书信息和加签证书的信息提供给服务端解密和验签使用

发送到目的地

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  服务端接收解密/验签报文的过程,通过对报文的加密/加签和证书的管理实现对客户端传输的控制和安全上管理。可以很好保证报文的安全不会在传输过程中被篡改和截获。

满足的前提条件

Ø       在证书管理器中存在解密用的服务器证书和验签用的客户端证书

接收到加密/加签的报文后首先抽取中间的证书信息(包含证书名称)

Ø       获取到证书名称后匹配本地计算中是会存在这本证书对于验证签名的证书统一存放在本地计算机"其他人目录下,对于解密的证书统一存放在本地计算机"个人目录下 ,如果没有找到相应的证书则抛出异常终止这个过程

Ø       调用.net SignedXml类库验证报文的合法性-是否在传输过程中被篡改和证实客户端的身份,如果发现验证不通过比如被篡改过饿抛出异常终止这个过程。

Ø       验证通过后对于需要解密的报文调用.net EncryptedXml类库进行解密,最终变成明文进行后续的处理

 

  要使用userName/password方式来验证身份,我们需要为服务器装一个证书,创建证书的作用是因为用户名和密码在clientservice传输的过程中需要加密,否则就没有安全性了,x.509rd使用非对称加密加技术.用公钥加密客户端用户名和密码,在服务端用私钥来解密,所以我们得创建这样的证书.使用vs2008tool中的command命令下执行:makecert -r -pe -n "CN=Temp" -ss My -sky exchange .我们就可以为服务器生成Temp的证书.

例子:createcert.bat :

echo off

echo if you are not on VS 2005 Command prompt, press ctrl-C

pause

setlocal

echo ************

echo cert create starting

echo ************

 

set SERVER_NAME=PanoramaServer.Com

echo ************

echo Server cert setup starting

echo %SERVER_NAME%

echo ************

echo making server cert

echo ************

makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange

 

pause

 

clearupcert.bat

 

echo off

 

echo if you are not on VS 2005 Command prompt, press ctrl-C

pause

 

setlocal

echo ************

echo cert cleanup starting

echo ************

 

set SERVER_NAME=PanoramaServer.Com

echo -------------------------

echo del service certs

echo -------------------------

certmgr.exe -del -r LocalMachine -s My -c -n %SERVER_NAME%

 

pause

 

Usage: MakeCert [ basic|extended options] [outputCertificateFile]

Extended Options

-sk <keyName>      Subject's key container name; To be created if not present

 -pe                 Mark generated private key as exportable

 -ss <store>        Subject's certificate store name that stores the output

                     certificate

 -sr <location>     Subject's certificate store location.

                        <CurrentUser|LocalMachine>. Default to 'CurrentUser'

 -#   <number>       Serial Number from 1 to 2^31-1. Default to be unique

 -$   <authority>    The signing authority of the certificate

                        <individual|commercial>

 -n   <X509name>     Certificate subject X500 name (eg: CN=Fred Dews)

 -?                  Return a list of basic options

 -!                  Return a list of extended options

 -tbs <file>         Certificate or CRL file to be signed

 -sc <file>         Subject's certificate file

 -sv <pvkFile>      Subject's PVK file; To be created if not present

 -ic <file>         Issuer's certificate file

 -ik <keyName>      Issuer's key container name

 -iv <pvkFile>      Issuer's PVK file

 -is <store>        Issuer's certificate store name.

 -ir <location>     Issuer's certificate store location

                        <CurrentUser|LocalMachine>. Default to 'CurrentUser'

 -in <name>         Issuer's certificate common name.(eg: Fred Dews)

 -a   <algorithm>    The signature algorithm

                        <md5|sha1>. Default to 'md5'

 -ip <provider>     Issuer's CryptoAPI provider's name

 -iy <type>         Issuer's CryptoAPI provider's type

 -sp <provider>     Subject's CryptoAPI provider's name

 -sy <type>         Subject's CryptoAPI provider's type

 -iky <keytype>      Issuer key type

                        <signature|exchange|<integer>>.

 -sky <keytype>      Subject key type

                        <signature|exchange|<integer>>.

 -l   <link>         Link to the policy information (such as a URL)

 -cy <certType>     Certificate types

                        <end|authority>

 -b   <mm/dd/yyyy>   Start of the validity period; default to now.

 -m   <number>       The number of months for the cert validity period

 -e   <mm/dd/yyyy>   End of validity period; defaults to 2039

 -h   <number>       Max height of the tree below this cert

 -len <number>       Generated Key Length (Bits)

 -r                  Create a self signed certificate

 -nscp               Include netscape client auth extension

 -crl                Generate a CRL instead of a certificate

 -eku <oid[<,oid>]> Comma separated enhanced key usage OIDs

 -?                  Return a list of basic options

 -!                  Return a list of extended options

 

选择IE工具-INTERNET选项-〉内容-〉证书,可以查看,导入,导出安装的证书,

 

< WCF   solution:WCFValidationContract>

  WCFValidationClient WCF client.    

  WCFValidationServices 主要是实现contract的类  

  WCFValidationHost..用于启动WCF.

  创建服务

  [ServiceContract]
  public interface IUserName//对应solution中的WCFValidationContract.IUserName
  {
    [OperationContract]
    bool test();
  }
  public class UserName:IUserName//对应solution中的WCFValidationServices.UserName
  {
    #region IUserName Members
    public bool test()
    {
      return true;
    }
    #endregion
  }

  我们通过继承 UserNamePasswordValidator 来创建一个自定义验证器。

//对应solution中的WCFValidationServices.MyValidation
  
  public override void Validate(string userName, string password)
    {
      //the follow code is testing only.u can read userName and password from DataBase.
      if (userName != "user" || password != "pwd")
      {
        throw new Exception("Unknown Username or Password");
      }
    }

  服务端的配置文件如下:

(host的配置文件)
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <system.serviceModel>
  <behaviors>
   <serviceBehaviors>
    <behavior name="UserNameBehavior">
     <serviceMetadata httpGetEnabled="true"/>
     <serviceDebug includeExceptionDetailInFaults="true"/>
     <serviceCredentials>
      <issuedTokenAuthentication allowUntrustedRsaIssuers="true"></issuedTokenAuthentication>
      <clientCertificate>
       <authentication certificateValidationMode="None"/>
      </clientCertificate>
      <serviceCertificate findValue="Temp" storeLocation="CurrentUser" x509FindType="FindBySubjectName"/>
      <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCFValidationServices.MyValidation,WCFValidationServices"/>
     </serviceCredentials>
    </behavior>
   </serviceBehaviors>
  </behaviors>
  <bindings>
   <wsHttpBinding>
    <binding name="userBinding">
     <security mode="Message">
      <message clientCredentialType="UserName"/>
     </security>
    </binding>
   </wsHttpBinding>
  </bindings>
  <services>
   <service behaviorConfiguration="UserNameBehavior" name="WCFValidationServices.UserName">
    <endpoint address="" binding="wsHttpBinding" bindingConfiguration="userBinding" name  ="username" contract="WCFValidation.IUserName">
     </endpoint>
    <host>
     <baseAddresses>
      <add baseAddress="http://localhost/userName"/>
     </baseAddresses>
    </host>
   </service>
  </services>
 </system.serviceModel>
</configuration>

WCF Samples下载地址 http://download.csdn.net/source/792492也可以到MSDN上下载FindPrivateKey的使用介绍

http://msdn.microsoft.com/zh-cn/vbasic/aa717039.aspx4.

  创建客户端

  启动服务器后,创建客户端代理文件。注意自动生成的客户端配置文件中包含了服务器数字证书的相关信息。(用svcutil自动生成的)

<?xml version="1.0" encoding="utf-8"?><configuration>
 <system.serviceModel>
  <bindings>
   <wsHttpBinding>
    <binding name="username" closeTimeout="00:01:00" openTimeout="00:01:00"
      receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
      transactionFlow="false" hostNameComparisonMode="StrongWildcard"
      maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
      messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
      allowCookies="false">
     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
       maxBytesPerRead="4096" maxNameTableCharCount="16384" />
     <reliableSession ordered="true" inactivityTimeout="00:10:00"
       enabled="false" />
     <security mode="Message">
      <transport clientCredentialType="Windows" proxyCredentialType="None"
        realm="" />
      <message clientCredentialType="UserName" negotiateServiceCredential="true"
        algorithmSuite="Default" establishSecurityContext="true" />
     </security>
    </binding>
   </wsHttpBinding>
  </bindings>
  <client>
   <endpoint address="http://localhost/userName" binding="wsHttpBinding"
     bindingConfiguration="username" contract="IUserName" name="username">
    <identity>
     <certificate  encodedValue="AwAAAAEAAAAUAAAAqxw7

daba6mcItJ/tKIAFZfz3TCggAAAAAQAAAPcBAAAwggHzMIIBXKADAgECAhAciN6V

Y5e8ik4b7Ia5KvftMA0GCSqGSIb3DQEBBAUAMBMxETAPBgNVBAMTC

E15U2VydmVyMB4XDTA4MTEyMDA2MTQwNloXDTM5MTIzMTIzNTk1OVow

EzERMA8GA1UEAxMITXlTZXJ2ZXIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AM

IGJAoGBALK4gy7ldnVwSjemT3bQjKSEGd/zBjNqYDHf9kwUopwvuHpE287yWD

1ytKaYYZf7uEdEtNYKwWeOwSNLEPqxUSW4jF92IqfQwkxa0bQdZQK/Y3TpmseX/

hsOtW0FBXV3Ftqq+acrWVkG/J/HFM1eeIyPggVI/QqclrKjBQeikjMdAgMBAAGjSDBGMEQ

+abkJqz9ejhjvzJwx2CJYe843h98fooTPPbSs6rQrfQOxb/KoaxbKoxUaALQsGssEXkN2ImS0jsOUm9aVNnRNWpKMhzA==" />
    </identity>
   </endpoint>
  </client>
 </system.serviceModel>
</configuration>

  以配置文件是由svcutil工具生成的.我们在客户端写以下代码来调用服务:

 UserNameClient aa = new UserNameClient();
 aa.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
 aa.ClientCredentials.UserName.UserName = "user";
 aa.ClientCredentials.UserName.Password = "pwd";
 bool flag = aa.test();
 Console.WriteLine(flag.ToString());
 Console.ReadKey();

  这时我们可以在控制应用程序中显示True这个值.当我们输入一个错误的密码时如:

aa.ClientCredentials.UserName.UserName = "123";
 aa.ClientCredentials.UserName.Password = "123";

  客户端就会有异常:messageSecurityException

 

3x.509数字证书验证

X.509是由国际电信联盟(ITU-T)制定的数字证书标准。X.509是一种基于公开密钥体制的鉴别业务密钥管理,拥有证书的用户都有两把密钥,一把叫公钥,一把叫私钥.私钥的保密性很高,一般情况下只用户本人知道.公钥是是其他用户都可利用的公共密钥.比如说我们的serverTemp的数字证书.我们Client端就可以使用Server的公钥对消息进行加密并发送消息给Server,然后server端通过私钥来解密消息.凡是被公钥加密过的消息一般情况下只能由私钥来解密,可见私钥的重要性所在.WCF userName/password中就是使用公钥来加密用户名和密码的.下面我们谈谈在WCF中使用X.509认证方式。WCF的服务端和客户端之间,如果不作任何安全处理(即服务端的<security mode="None">),则所有传输的消息将以明文方传输,在internet/intranet环境下是很不安全的,这就是用证书的目。当我们使用UserName方式,通常每次都要从数据库读取用户名/密码信息进行验证,比较麻烦,开销也大.所以在我们也可以使用x.509方式来验证.下面我们以一个Demo来说明如何使用x.509的身份验证方式.

X509的验证比userName/passoword的系统开销小。因为userName/Password需要读取用户数据并进行配对,用户数据一般存储在数据库中。对于X.529这种验证个人觉的这种验证适合B/S结构的。

使用vs2008tool建立名为client 得证书。

 

makecert -r -pe -n "CN=client" -ss My -sky exchange .

[ServiceContract]
  public interface IX509//对应solution中的WCFValidationContract.IX509
  {
    [OperationContract]
    bool test();
  }
  public class X509:IX509//对应solution中的WCFValidationServices.X509
 {
    #region IX509 Members
    public bool test()
    {      
      return true;
    }
    #endregion
  }

  我们通过继承 X509CertificateValidator来创建一个自定义验证器。//对应solution中的WCFValidationServices.X509Validation

  class X509Validation :X509CertificateValidator
  {
    public override void Validate(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate)
    {
      //we can use Thumbprint SignatureAlgorithm subject name and so one for validation.
      //the sample only use SerialNumber.
      //如果客户端序列号与此不同的话,就报异常,通常情况我们会在客户端进行异常处理的.
//The socket connection was aborted. This could be caused by an error processing your message or a
      // receive timeout being exceeded by the remote host, or an underlying network resource issue.
      //Local socket timeout was '00:00:59.9844000'
//
这是因为WCF没有将服务实例释放而导致辞的。
//
我们可以判断客户端的SerialNumber和服务端存储的客户端是否相同
      if (certificate.SerialNumber.ToLower() != "6bfa829a7453219e402c534671154e4e") 
        throw new Exception("Certificate Error!");
    }
  }

服务端配置文件:

<system.serviceModel>
  <behaviors>
   <serviceBehaviors>
    <behavior name="X509Behavior">
     <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost/X509"/>    
     <serviceDebug includeExceptionDetailInFaults="true"/>
     <serviceCredentials>
      <clientCertificate>
       <authentication customCertificateValidatorType= "WCFValidationServices.X509Validation,WCFValidationServices"
        certificateValidationMode="Custom" />
      </clientCertificate>
      <serviceCertificate findValue="MyServer" storeLocation="CurrentUser" x509FindType="FindBySubjectName"/>
     </serviceCredentials>
    </behavior>
   </serviceBehaviors>
  </behaviors>
  <bindings>
   <netTcpBinding>
    <binding name="x509Binding" >
     <security mode="Transport">
      <transport clientCredentialType ="Certificate"/>
     </security>
    </binding>
   </netTcpBinding>
  </bindings>
  <services>
   <service behaviorConfiguration="X509Behavior" name="WCFValidationServices.X509">
    <endpoint address="" binding="netTcpBinding" bindingConfiguration="x509Binding" name  ="X509" contract="WCFValidation.IX509">
     </endpoint>
    <host>
     <baseAddresses>
      <add baseAddress="net.tcp://localhost:8082/X509"/>
     </baseAddresses>
    </host>
   </service>
  </services>
 </system.serviceModel>

 

 创建客户端:

启动服务器后,创建客户端代理文件。注意自动生成的客户端配置文件中包含了服务器数字证书的相关信息。<system.serviceModel>
  <behaviors>
   <endpointBehaviors>
    <behavior name="NewBehavior">
     <clientCredentials>
      <clientCertificate storeLocation="CurrentUser" findValue="client" x509FindType="FindBySubjectName" />
      <serviceCertificate>
       <authentication certificateValidationMode="None"/>//因为我们使用的是非信任证书
      </serviceCertificate>
     </clientCredentials>
    </behavior>
   </endpointBehaviors>
  </behaviors>
  <bindings>
   <netTcpBinding>
    <binding name="X509" >   
     <security mode="Transport">
      <transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" />
      <message clientCredentialType="Windows" />
     </security>
    </binding>
   </netTcpBinding>
  </bindings>
  <client>
   <endpoint address="net.tcp://localhost:8082/X509" binding="netTcpBinding" behaviorConfiguration="NewBehavior"
     bindingConfiguration="X509" contract="IX509" name="X509">
    <identity>
     <dns value="MyServer" />
    </identity>
   </endpoint>
  </client>客户端由Svcutil工具生成的,在这里就不贴出来了。

  客户端代码:

X509Client validate = new X509Client("X509");
bool result=validate.test();
validate.Close();
Console.WriteLine(result.ToString());
Console.ReadKey();

  如果能成功能过验证的话:ConsoleApplication将会输入正确的结果:True,否则的话会报异常。

 

 

posted on 2009-01-17 20:02  oyl  阅读(1775)  评论(0编辑  收藏  举报

导航