WCF邮件安全性在服务器证书更改后停止工作

WCF邮件安全性在服务器证书更改后停止工作

问题描述:

我们的服务器/服务证书已过期,并且我们发布了新的证书。将其替换到证书存储区(作为SSL服务器证书没有问题),将运行该服务的AppPoolIdentity的访问权限设置为私钥。 我的服务配置:WCF邮件安全性在服务器证书更改后停止工作

<system.serviceModel> 
<extensions> 
    <behaviorExtensions> 
    <add name="A2AValidation" type="SPOZUS_T2S_A2A.A2AValidation+CustomBehaviorSection, SPOZUS_T2S_A2A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
    </behaviorExtensions> 
</extensions> 
<protocolMapping> 
    <add scheme="http" binding="wsHttpBinding" /> 
    <add scheme="https" binding="wsHttpBinding" /> 
</protocolMapping> 
<bindings> 
    <wsHttpBinding> 
    <binding name="MessageSecurityBinding"> 
     <security mode="Message"> 
     <message clientCredentialType="Certificate" establishSecurityContext="true" negotiateServiceCredential="true" /> 
     </security> 
    </binding> 
    </wsHttpBinding> 
</bindings> 
<services> 
    <service behaviorConfiguration="ClientSecBehavior" name="SPOZUS_T2S_A2A.Service"> 
    <endpoint address="" behaviorConfiguration="A2AValidationBehavior" bindingNamespace="https://DRW2012IIS.XXX.XXXX.XX:10002/A2A" binding="wsHttpBinding" bindingConfiguration="MessageSecurityBinding" name="A2AmessageEndpoint" contract="SPOZUS_T2S_A2A.IService" /> 
    <endpoint address="mex" binding="mexHttpsBinding" name="A2AMessageEndpointMex" contract="IMetadataExchange" /> 
    <host> 
     <baseAddresses> 
     <add baseAddress="http://DRW2012IIS.XXX.XXXX.XX:10002/A2A/" /> 
     </baseAddresses> 
    </host> 
    </service> 
</services> 
<behaviors> 
    <endpointBehaviors> 
    <behavior name="A2AValidationBehavior"> 
     <A2AValidation /> 
    </behavior> 
    </endpointBehaviors> 
    <serviceBehaviors> 
    <behavior name="ClientSecBehavior"> 
     <serviceMetadata httpGetEnabled="true" /> 
     <serviceDebug includeExceptionDetailInFaults="true" /> 
     <serviceCredentials> 
     <clientCertificate> 
      <authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck" trustedStoreLocation="LocalMachine" mapClientCertificateToWindowsAccount="true" /> 
     </clientCertificate> 
     <serviceCertificate findValue="DRW2012IIS.XXX.XXXX.XX" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" /> 
     </serviceCredentials> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> 

当我从浏览器访问该服务它抛出错误:

[CryptographicException: Invalid provider type specified. 
] 
    System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer) +5273481 
    System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle) +94 
    System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair() +136 
    System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize) +203 
    System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey() +240 
    System.ServiceModel.Security.SecurityUtils.GetKeyContainerInfo(X509Certificate2 certificate) +42 
    System.ServiceModel.Security.SecurityUtils.CanKeyDoKeyExchange(X509Certificate2 certificate) +10 
    System.ServiceModel.Security.SecurityUtils.EnsureCertificateCanDoKeyExchange(X509Certificate2 certificate) +64 

[ArgumentException: It is likely that certificate 'CN=DRW2012IIS.XXX.XXXX.XX, OU=IT, O=XXXXX, L=XXXXX, S=XXXX, C=XX' may not have a private key that is capable of key exchange or the process may not have access rights for the private key. Please see inner exception for detail.] 
    System.ServiceModel.Security.SecurityUtils.EnsureCertificateCanDoKeyExchange(X509Certificate2 certificate) +336 
    System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateServerX509TokenProvider() +35 
    System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateLocalSecurityTokenProvider(RecipientServiceModelSecurityTokenRequirement recipientRequirement) +64 
    System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateSecurityTokenProvider(SecurityTokenRequirement requirement) +59 
    System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateTlsnegoServerX509TokenProvider(RecipientServiceModelSecurityTokenRequirement recipientRequirement) +261 
    System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateTlsnegoSecurityTokenAuthenticator(RecipientServiceModelSecurityTokenRequirement recipientRequirement, Boolean requireClientCertificate, SecurityTokenResolver& sctResolver) +829 
    System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, SecurityTokenResolver& outOfBandTokenResolver) +709 
    System.ServiceModel.Security.SymmetricSecurityProtocolFactory.OnOpen(TimeSpan timeout) +208 
    System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout) +21 
    System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +347 
    System.ServiceModel.Security.SecurityListenerSettingsLifetimeManager.Open(TimeSpan timeout) +81 
    System.ServiceModel.Channels.SecurityChannelListener`1.OnOpen(TimeSpan timeout) +221 
    System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +347 
    System.ServiceModel.Dispatcher.ChannelDispatcher.OnOpen(TimeSpan timeout) +73 
    System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +347 
    System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) +130 
    System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +347 
    System.ServiceModel.Security.SecuritySessionSecurityTokenAuthenticator.OnOpen(TimeSpan timeout) +130 
    System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout) +21 
    System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +347 
    System.ServiceModel.Security.CommunicationObjectSecurityTokenAuthenticator.Open(TimeSpan timeout) +16 
    System.ServiceModel.Security.SecuritySessionServerSettings.OnOpen(TimeSpan timeout) +842 
    System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout) +21 
    System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +347 
    System.ServiceModel.Security.SecurityListenerSettingsLifetimeManager.Open(TimeSpan timeout) +125 
    System.ServiceModel.Channels.SecurityChannelListener`1.OnOpen(TimeSpan timeout) +221 
    System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +347 
    System.ServiceModel.Dispatcher.ChannelDispatcher.OnOpen(TimeSpan timeout) +73 
    System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +347 
    System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) +130 
    System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +347 
    System.ServiceModel.HostingManager.ActivateService(ServiceActivationInfo serviceActivationInfo, EventTraceActivity eventTraceActivity) +130 
    System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath, EventTraceActivity eventTraceActivity) +738 

[ServiceActivationException: The service '/TEST/A2A/Service.svc' cannot be activated due to an exception during compilation. The exception message is: It is likely that certificate 'CN=DRW2012IIS.XXX.XXXX.XX, OU=IT, O=XXXXX, L=XXXXX, S=XXXX, C=XX' may not have a private key that is capable of key exchange or the process may not have access rights for the private key. Please see inner exception for detail..] 
    System.Runtime.AsyncResult.End(IAsyncResult result) +604003 
    System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +238 
    System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +178 

看来这个问题是与证书主题名称中使用大写的主题名称。我已经重新发布了小写域名规范的证书,现在就可以使用。

我们也有这个确切的错误信息,并花了相当长的时间缩小了问题。我们使用Octopus Deploy来安装我们的PFX证书,Tentacle作为LocalSystem运行。

有几个有趣的发现:

  1. 奇怪的是,事实证明,本地系统没有足够的权限来安装私钥到正确的文件夹(通常是C:\ ProgramData \微软\加密\ RSA \ MachineKeys)。管理控制台(mmc.exe)中的证书管理单元显示通常的“您有与此证书相对应的私钥”消息。我不确定这是通常的设置还是公司政策。
  2. 安装过程中触手没有错误。可能会产生一个错误,但会被吞下。也许八达通支持可以帮助这一点。
  3. Octopus Tentacle如果已经存在,不会重新安装证书,这会将问题隐藏一段时间,正如我们最初手动安装证书一样。
  4. 安装证书的帐户需要对该文件夹的写入权限,而使用它们的帐户需要读取权限。确保权限正确解决了我们的问题。