使用WCF仅使用公钥来使用Web服务

时间:2015-10-02 12:21:05

标签: wcf x509

我正在使用WCF使用第三方的Web服务。我有一个PFX证书文件,我通过ClientCredentials.ClientCertificate.SetCertificate方法附加。我正在使用“消息安全版”WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10

一切正常。现在第三方证书即将到期,所以他们发布了新证书。但是,这次只是公钥的P7B文件。

当我尝试使用此证书时,我收到一条NotSupportedException,上面写着“X.509证书中没有私钥。”

我的代码中没有任何部分提供私钥密码,因此我假设这意味着私钥未被使用。如果是这种情况,如何仅使用公钥来使用此Web服务?或者我误解了什么? (非常可能)

修改
好的,这是一些代码。我正在使用的服务客户端类由svcutil生成,并已通过部分类进行修改以实现IDisposable。这些是相关的片段:

private ServiceResponse CallService(ServiceParameters serviceParameters)
{
    ...
    using (var client = new ThirdPartyServiceClient())
    {
        SetClientCredentials(client);
        client.RemoteCall(serviceParameters);
    }
    ...
}

private void SetClientCredentials(ThirdPartyServiceClient client)
{
    if (client.ClientCredentials == null)
    {
        throw new InvalidOperationException("ClientCredentials was null and certificate could not be set");
    }

    client.ClientCredentials.ClientCertificate.SetCertificate(
        StoreLocation.LocalMachine,
        StoreName.My,
        X509FindType.FindBySubjectName,
        _configuration.CertificateSubject);
}

这是我的WCF配置:

  <system.serviceModel>
    <bindings>
      <customBinding>
        <binding name="ThirdPartyServiceBinding">
          <security includeTimestamp="true" enableUnsecuredResponse="true" authenticationMode="CertificateOverTransport" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" />
          <textMessageEncoding messageVersion="Soap11WSAddressing10" />
          <httpsTransport requireClientCertificate="true" />
        </binding>
      </customBinding>
    </bindings>
    <client>
      <endpoint address="https://third-party.com/service" binding="customBinding" bindingConfiguration="ThirdPartyServiceBinding" contract="Namespace.To.ProxyClasses" name="ThirdPartyService" />
    </client>
  </system.serviceModel>

client.RemoteCall(serviceParameters);调用抛出异常,堆栈跟踪为

Server stack trace: 
   at System.IdentityModel.Tokens.X509AsymmetricSecurityKey.GetSignatureFormatter(String algorithm)
   at System.IdentityModel.SignedXml.ComputeSignature(SecurityKey signingKey)
   at System.ServiceModel.Security.WSSecurityOneDotZeroSendSecurityHeader.CompletePrimarySignatureCore(SendSecurityHeaderElement[] signatureConfirmations, SecurityToken[] signedEndorsingTokens, SecurityToken[] signedTokens, SendSecurityHeaderElement[] basicTokens, Boolean isPrimarySignature)
   at System.ServiceModel.Security.WSSecurityOneDotZeroSendSecurityHeader.CreateSupportingSignature(SecurityToken token, SecurityKeyIdentifier identifier)
   at System.ServiceModel.Security.SendSecurityHeader.SignWithSupportingToken(SecurityToken token, SecurityKeyIdentifierClause identifierClause)
   at System.ServiceModel.Security.SendSecurityHeader.SignWithSupportingTokens()
   at System.ServiceModel.Security.SendSecurityHeader.CompleteSecurityApplication()
   at System.ServiceModel.Security.SecurityAppliedMessage.OnWriteMessage(XmlDictionaryWriter writer)
   at System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage(Message message, BufferManager bufferManager, Int32 initialOffset, Int32 maxSizeQuota)
   at System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.WriteMessage(Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset)
   at System.ServiceModel.Channels.HttpOutput.SerializeBufferedMessage(Message message, Boolean shouldRecycleBuffer)
   at System.ServiceModel.Channels.HttpOutput.Send(TimeSpan timeout)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.SendRequest(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Namespace.To.ProxyClasses.ThirdPartyService.RemoteCall(ServiceParameters request)
   [back up the normal call hierarchy of my code]

1 个答案:

答案 0 :(得分:0)

使用邮件安全性,您可以使用私钥对文档进行签名,并使用其他方公钥加密文档。他们可以使用私钥对其进行解密,并且可以使用您的公钥验证您的签名。听起来他们更换了他们的密钥,因此他们为您提供了新的公钥。如果他们的公钥没有可公开验证的信任链,那么您需要将其公钥作为可信密钥安装在本地证书存储中。如果您不这样做并且它们不可公开验证,那么您将获得关于无法验证链信任的例外情况。如果你的钥匙即将到期,那么他们需要一把公钥来识别你,你需要他们不应该拥有的私人一半。