views:

550

answers:

1

Trying to do basic SSL-authenticated Web Service using Visual Studio 2008 .NET 3.5 "Service Reference" object created from WSDL. We have tried three methods 1) Setting Client Certificates (to match server-supplied), 2) setting store for server-supplied, and 3) using custom server validator.

The .NET exception (detailed below) is consistent (for three methods described below) "Could not establish trust relationship for the SSL/TLS secure channel with authority 'ABC.DEF.com'."

Ethereal capture is consistent (for three methods described below) and shows what looks like correct Client and Service handshaking for the SERVER-SUPPLIED certificate version of SSL. That is, we see all the basic message described here (http://en.wikipedia.org/wiki/Transport%5FLayer%5FSecurity#Simple%5FTLS%5Fhandshake):

Client --> Server: Client Hello
Server --> Client: Server Hello, Certificate, Server Hello Done
Client --> Server: Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
Server --> Client: Change Cipher Spec, Encrypted Handshake Message.

After receipt of last (which we assume to be the SSL MAC message), Client immediately closes (TCP FIN/ACK) connection

1) Attempt at setting client credentials using what the server has supplied (w/ the expectation that the X509 library will use this to validate what the server is supplying during SSL negotiation, but w/ the understanding that this could very well be meant only to be supplied from client to server during client-supplied certificate negotiation)

 X509Certificate2 _cert = new X509Certificate2("\\SomePath\...\ServerSuppliedCert.cer");

        getPrequalInfo_v1 _getInfo = new getPrequalInfo_v1();  // WEB SERVICE-SPECIFIC
        _getInfo.arg0 = GetRequestArgs();       // WEB SERVICE-SPECIFIC
        PreQualBeanClient _preq = new PreQualBeanClient();    // WEB SERVICE-SPECIFIC


        _preq.ClientCredentials.ClientCertificate.Certificate = _cert; 

        getPrequalInfo_v1Response _resp = new getPrequalInfo_v1Response();  // WEB SERVICE-SPECIFIC
        _resp = _preq.getPrequalInfo_v1(_getInfo);  // << EXCEPTION RAISED HERE,    // WEB SERVICE-SPECIFIC

2) Attempting to create store for ostensible use of validating service certificate (again, could totally be wrong approach)

X509Certificate2Collection _collection = new X509Certificate2Collection();
        _store = new X509Store(StoreLocation.CurrentUser);
        _store.Open(OpenFlags.ReadOnly);
        X509Certificate2 _cert = new X509Certificate2("\\SomePath\...\ServerSuppliedCert.cer");
        _collection.Add(_cert);
        _store.AddRange(_collection);
        _store.Close();

        getPrequalInfo_v1 _getInfo = new getPrequalInfo_v1();  // WEB SERVICE-SPECIFIC
        _getInfo.arg0 = GetRequestArgs();       // WEB SERVICE-SPECIFIC
        PreQualBeanClient _preq = new PreQualBeanClient();    // WEB SERVICE-SPECIFIC

        _preq.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode
            = System.ServiceModel.Security.X509CertificateValidationMode.PeerOrChainTrust;
        _preq.ClientCredentials.ServiceCertificate.Authentication.TrustedStoreLocation = _store.Location;

        getPrequalInfo_v1Response _resp = new getPrequalInfo_v1Response();  // WEB SERVICE-SPECIFIC
        _resp = _preq.getPrequalInfo_v1(_getInfo);  // << EXCEPTION RAISED HERE,    // WEB SERVICE-SPECIFIC

3) Here we have tried to create a customer service credential validator. NOTE that in this case the MyX509CertificateValidator.Validate method does NOT appear to be called at all.

            getPrequalInfo_v1 _getInfo = new getPrequalInfo_v1();  // WEB SERVICE-SPECIFIC
        _getInfo.arg0 = GetRequestArgs();       // WEB SERVICE-SPECIFIC
        PreQualBeanClient _preq = new PreQualBeanClient();    // WEB SERVICE-SPECIFIC

        _preq.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode
            = System.ServiceModel.Security.X509CertificateValidationMode.Custom;
        _preq.ClientCredentials.ServiceCertificate.Authentication.CustomCertificateValidator
            = new MyX509CertificateValidator("Name");


        getPrequalInfo_v1Response _resp = new getPrequalInfo_v1Response();  // WEB SERVICE-SPECIFIC
        _resp = _preq.getPrequalInfo_v1(_getInfo);  // << EXCEPTION RAISED HERE,    // WEB SERVICE-SPECIFIC

We have the following relevant part of the WSDL

<soap:address location='https://ABC.DEF.com/.../PreQualBean'/&gt;

.NET Exception, which is common to the three methods described:

System.ServiceModel.Security.SecurityNegotiationException was unhandled
Message="Could not establish trust relationship for the SSL/TLS secure channel with authority 'ABC.DEF.com'."
Source="mscorlib"
StackTrace:
Server stack trace:
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
...

w/ inner exception InnerException: System.Security.Authentication.AuthenticationException
Message="The remote certificate is invalid according to the validation procedure." Source="System"
StackTrace:
at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
...

+2  A: 

Looks like the CA that signed the server certificate (or some certificate in the chain, if signed with an intermediate CA) is not trusted by the clients. You could try adding the signer(s) of the server certificate to the client's Trust store.

You can also get more detailed information on the problem as well as ignore it by doing something like:

      ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertificate;
...
public static bool ValidateServerCertificate(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
   // Here you can display the sslPolicyErrors and/or go through the chain to see which certificate(s) is(are) causing the problem.
   return true; // returning true here will probably "fix" your client side problem
}
Gonzalo
Thanks, that did it!
Barryman9000