2
votes

I am sending an XML request using C# HttpWebRequest to a Web Service authenticating through a client certificate (the certificate has been provided by a public authority and it's valid and correctly installed in the server certificate store).

Here is my code:

    public void CallWebService()
    {
        var _url = webServiceUrl;
        var _action = "soapActionToCall";
        X509Certificate2 Cert = null;

        try
        {
            //Search for the certificate in the store
            X509Store Store = new X509Store(StoreName.Root);
            Store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection Coll = Store.Certificates.Find(X509FindType.FindBySubjectName, "certifcateCommonName", false);
            if (Coll != null && Coll.Count > 0)
            {
                Cert = Coll[0];
            }
            else
                throw new Exception("Certificate non found!");

            //Method to create the soap XML envelope
            XmlDocument soapEnvelopeXml = CreateSoapEnvelope(typeOfService);
            HttpWebRequest webRequest = CreateWebRequest(_url, _action, soapEnvelopeXml.InnerText.Length);

            webRequest.ClientCertificates.Add(Cert);
            InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);

            // begin async call to web request.
            IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);

            // suspend this thread until call is complete. You might want to
            // do something usefull here like update your UI.
            asyncResult.AsyncWaitHandle.WaitOne();

            // get the response from the completed web request.
            string soapResult;
            using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
            {
                using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
                {
                    soapResult = rd.ReadToEnd();
                }

                //Display the XML result
                txtResponse.Text = soapResult;
            }
        }
        catch (WebException webEx)
        {
            WebResponse errResp = webEx.Response;
            string text = "";
            XmlDocument xmlRsp = null;
            string error = "";

            if (errResp != null)
            {
                using (Stream respStream = errResp.GetResponseStream())
                {
                    StreamReader reader = new StreamReader(respStream);
                    text = reader.ReadToEnd();
                }

                xmlRsp = new XmlDocument();
                xmlRsp.LoadXml(text);
                if (xmlRsp.GetElementsByTagName("soapenv:Fault").Count > 0)
                    error = xmlRsp.SelectSingleNode("//error").InnerText;

                if (error.Length > 0)
                    throw new Exception(error);
                else
                    throw webEx;
            }
            else
                throw webEx;

        }
    }

    private HttpWebRequest CreateWebRequest(string url, string action, int contentLength)
    {
        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
        webRequest.Headers.Add("SOAPAction", action);
        webRequest.Host = "host";
        webRequest.ContentType = "text/xml;charset=\"utf-8\"";
        webRequest.ContentLength = contentLength; 
        webRequest.Accept = "text/xml";
        webRequest.Method = "POST";
        ServicePointManager.Expect100Continue = true;
        // { Ssl3 = 48, Tls = 192, Tls11 = 768, Tls12 = 3072, } }.
        ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

        // allows for validation of SSL conversations
        ServicePointManager.ServerCertificateValidationCallback = delegate(
        Object obj, X509Certificate certificate, X509Chain chain,
        SslPolicyErrors errors)
        {
            return (true);
        };


        return webRequest;
    }

    private XmlDocument CreateSoapEnvelope()
    {
        XmlDocument soapEnvelop = new XmlDocument();
        soapEnvelop.Load("XmlFileToSend.xml");
        return soapEnvelop;
    }

    private void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
    {
        using (Stream stream = webRequest.GetRequestStream())
        {
            soapEnvelopeXml.Save(stream);
        }
    }

I am always retrieving the error "The request was aborted: Could not create SSL/TLS secure channel." when the code enter the method InsertSoapEnvelopeIntoWebRequest at the webRequest.GetRequestStream() line. Do someone have idea to help me?

1

1 Answers

2
votes

I've just solved a very similar issue. In my case, as soon as we attached a client certificate to the WebRequestHandler we got the "The request was aborted: Could not create SSL/TLS secure channel." error.

In out case the solution was to give the IIS_IUSRS user group permission to read the private key of the client certificate. As soon as that was done, the error went away.

You can do that in the Certificates snap-in in mmc. Find the client certificate in the appropriate store, right click it -> All tasks -> Manage private keys -> Add the user or usergroup that executes you process (IIS_IUSRS works if you're running on IIS) and make sure it has the "Read" permission.