C#调用带SSL及服务端证书的WS-Security WebService遇TLS错误求助
Let's break this down step by step—since you've already got the call working in SoapUI, we can map that successful configuration directly to your WCF setup, which seems to be mixing up the roles of your TLS and WSS certificates.
1. Clarify the Two Certificates' Roles
First, let's align with your SoapUI setup:
- TLS Certificate: Used for SSL/TLS handshake mutual authentication (this is the "SSL certificate" you select in SoapUI options)
- WSS Certificate: Used for WS-Security message signing (this is the certificate you add in SoapUI's Outgoing WS-Security Configurations with Binary Security Token)
Your current WCF config is conflating these two—let's fix that.
2. Update app.config to Separate Transport & Message Layer Configs
Adjust your configuration to explicitly assign each certificate to its correct layer:
<system.serviceModel> <client> <endpoint address="ADDR" binding="customBinding" bindingConfiguration="customB" behaviorConfiguration="myBehavior" contract="ServiceReference1.MyClient" name="Name"> <identity> <dns value="DNS-CERTIFICATE-VALUE"/> </identity> </endpoint> </client> <behaviors> <endpointBehaviors> <behavior name="myBehavior"> <clientCredentials supportInteractive="false"> <!-- WS-Security Message Signing Certificate (WSS Cert) --> <clientCertificate findValue="WSS_CERT_THUMBPRINT" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" /> <!-- Service Certificate Validation (keep your existing settings) --> <serviceCertificate> <defaultCertificate findValue="WSS_CERT_THUMBPRINT" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" /> <authentication certificateValidationMode="None" revocationMode="NoCheck" trustedStoreLocation="LocalMachine" /> </serviceCertificate> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> <bindings> <customBinding> <binding name="customB"> <textMessageEncoding messageVersion="Soap11" /> <!-- Message Layer: WS-Security Mutual Certificate Signing --> <security authenticationMode="MutualCertificate" includeTimestamp="false" securityHeaderLayout="Lax" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"> <localClientSettings detectReplays="false" /> </security> <!-- Transport Layer: TLS Mutual Authentication (assign your TLS Cert here) --> <httpsTransport requireClientCertificate="true"> <clientCertificate findValue="TLS_CERT_THUMBPRINT" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" /> </httpsTransport> </binding> </customBinding> </bindings> </system.serviceModel>
Key changes here:
- Moved the TLS certificate to
<httpsTransport><clientCertificate>(this handles the SSL handshake client auth, matching SoapUI's SSL certificate setting) - Kept the WSS certificate in
<clientCredentials.clientCertificate>(this handles WS-Security message signing, matching SoapUI's outgoing security config)
3. Clean Up Code-Level Overrides
Your current ServerCertificateValidationCallback skips all server certificate checks, which can mask underlying issues (like a mismatched DNS name in the server cert). Let's temporarily comment this out to get clearer error messages:
// ServicePointManager.ServerCertificateValidationCallback += delegate { return true; }; // Comment out for debugging ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // Keep this if the server uses TLS 1.2
If you need to specify certificates via code instead of config, make sure you target the correct layer:
Assign TLS Certificate (Transport Layer)
var client = new ServiceReference1.MyClient(); // Fetch TLS certificate from store var store = new X509Store(StoreName.My, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadOnly); var tlsCert = store.Certificates.Find(X509FindType.FindByThumbprint, "TLS_CERT_THUMBPRINT", false)[0]; store.Close(); // Assign to transport layer var transportElement = client.Endpoint.Binding.CreateBindingElements().Find<HttpsTransportBindingElement>(); transportElement.ClientCertificate = tlsCert;
Assign WSS Certificate (Message Layer)
// Fetch WSS certificate from store var store = new X509Store(StoreName.My, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadOnly); var wssCert = store.Certificates.Find(X509FindType.FindByThumbprint, "WSS_CERT_THUMBPRINT", false)[0]; store.Close(); // Assign to message layer signing client.ClientCredentials.ClientCertificate.Certificate = wssCert;
4. Verify Certificate Permissions
Ensure both certificates are installed in LocalMachine\My (via certlm.msc) and that the account running your app (e.g., IIS App Pool, local service account) has read access to the private keys:
- Open
certlm.msc→ Navigate to Personal → Certificates - Right-click the certificate → All Tasks → Manage Private Keys
- Add your app's runtime account and grant it the Read permission
5. Enable WCF Tracing for Detailed Debugging
If you still get errors, enable WCF tracing to see exactly what's failing (e.g., certificate not found, private key inaccessible, protocol mismatch):
Add this to your app.config:
<system.diagnostics> <sources> <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true"> <listeners> <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\temp\wcf_trace.svclog" /> </listeners> </source> </sources> </system.diagnostics>
Run your app, then open the log file with SvcTraceViewer.exe (included with Visual Studio/WCF tools) to inspect the exact error details.
内容的提问来源于stack exchange,提问作者roger_b

